Rails where() 和时区

3

我正在尝试使用以下方式查找今天(按当前时区)创建的“条目”:

Entry.where("DATE(created_at) = DATE(?) AND email = ?", Time.now, email)

Time.now返回的是当前时区的时间,但是查询似乎在搜索每个条目的created_at列的UTC时间。

有什么办法可以在服务器时区中找到今天创建的条目吗?

4个回答

17

在调用 SQL 中的 DATE() 函数后,时区信息就会丢失。需要牢记以下两点:

  1. 数据库中所有内容都是以 UTC 存储,包括 DATE() 的结果。
  2. 本地时区内的单个日期(即当天)可能跨越 UTC 内的两个日期,因此需要查看整个时间戳(包括双方的 UTC 日期组成部分),而不仅仅是(UTC)日期组成部分。

可以使用以下代码:

now = Time.now
Entry.where('created_at between :start and :end and email = :email',
    :start => now.beginning_of_day,
    :end   => now.end_of_day,
    :email => email
)

时间应该自动转换为UTC。您可能希望稍微不同地处理上限; 使用end_of_day会给您23:59:59,因此有一点空间可以让您捕获想要捕获的内容。您可以通过使用显式半开区间(而不是SQL的between使用的闭区间)来解决这个问题,如下所示:

now = Time.now
Entry.where('created_at >= :start and created_at < :end and email = :email',
    :start => now.beginning_of_day,
    :end   => now.tomorrow.beginning_of_day,
    :email => email
)

1

使用{{link1:Time.now.utc}}吗?


1
我想到了这一点,但它将根据UTC每天24小时的时间范围返回条目,而不是本地时间。对吗? - Matt Fordham

1

使用 Time.zone.now。这将使用一个 ActiveSupport::TimeWithZone 对象,在数据库搜索中使用时会自动转换为 UTC。


1
似乎与使用 Time.now 和 Time.now.utc 有相同的效果。看起来查询是使用 UTC 时间构建的,但这会给我在英格兰一天内的条目,而不是我本地的条目。 - Matt Fordham

0
首先,您应该获取时区,然后获取时区偏移量。 例如,当前时区为

America/Los_Angeles

查找时区偏移量:

 Time.now.in_time_zone(current_time_zone).utc_offset / 3600) * -1

7

在控制器中:
 start_date_format = DateTime.strptime(@start_date, date_format)
 start_date_format_with_hour = 
 DateTime.strptime((start_date_format.to_i + timezone_offset*60*60).to_s,'%s').strftime(date_format)

 end_date_format = DateTime.strptime(@end_date, date_format)
 end_date_format_with_hour = DateTime.strptime((end_date_format.to_i + timezone_offset*60*60).to_s,'%s').strftime(date_format)

 @filters_date = "invoices.created_at >= ? AND invoices.created_at < ?", start_date_format_with_hour, end_date_format_with_hour

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接