这个奇怪的行为最近引起了我的注意,当时我正在本地环境中测试Rails应用程序,在该环境中我使用around_filter为注册用户设置时区(默认时区为UTC)。
我所做的是在我的应用程序中注册了一个新用户。我当前的时间是格林尼治标准时间晚上10点-5分(3月3日),该用户的created_at时间被保存到数据库中,直到UTC凌晨4点(3月4日)。现在,我知道这个时间是用时区设置保存在数据库中的,但问题来了:
我使用一个图形来直观地表示每天注册的用户,当我调用以下函数来告诉我过去几天注册的用户数量时:
from ||= Date.today - 1.month
to ||= Date.today
where(created_at: from..to).group('DATE(created_at)').count
它会说这个用户是在3月4日注册的,而从我的角度来看,它实际上是在3月份3日注册的。
我的问题是:我应该如何通过created_at列调用where函数和group,以便正确影响的日期(根据我的时区)?
或者还有什么我应该做的不同的事情吗?
我不是一个卢布爱好者,所以我会让其他人给出具体的代码,但我可以从一般的算法角度来回答。
如果您将UTC存储在数据库中,则还需要按UTC进行查询。
在确定查询范围(from
和to
)时,您需要知道"今天"在本地时区的开始和停止时间,并将它们分别转换为UTC。
例如,我在美国太平洋时区,今天是2015年3月7日。
from: 2015-03-07T00:00:00-08:00 = 2015-03-07T08:00:00Z
to: 2015-03-08T00:00:00-08:00 = 2015-03-08T08:00:00Z
如果您想像示例中所示那样减去一个月,请在转换为UTC之前执行。注意夏令时。不能保证补偿会是一样的。
此外,您还需要使用不包括上限的半开区间范围。我相信在Ruby中,这是用三个点(...
)而不是两个点来完成的(至少根据这个)。
分组通常有点困难。我想这是一个针对数据库的查询,对吧?好吧,如果您查询的数据库支持时区,那么您可以在分组之前使用它将日期转换为时区。类似这样的东西(伪代码):
groupby(DATE(CONVERT_TZ(created_at,'UTC','America/Los_Angeles')))
由于您没有说明您使用的数据库,所以我再具体不过了。CONVERT_TZ
在MySQL上可用,我相信Oracle和Postgres都有时区支持。
Date.today
将默认为系统设置的时区(顺便说一句,它应该始终是UTC,原因如下),所以如果您想使用UTC,只需在rails设置为UTC 的情况下执行Time.zone.now.to_date
即可
否则你应该做
Time.use_zone('UTC') do
Time.zone.now.to_date
end
之后,您应该通过执行object.created_at.in_time_zone('EST')
来显示created_at日期
在当前时区中显示