ruby-on-rails - Rails 时间奇数 : "x days from now"

标签 ruby-on-rails ruby timezone activesupport

当用户注册到我的网站之一进行免费试用时,我将他们的帐户到期时间设置为“14.days.from_now”。然后在主页上我显示他们还剩多少天,这是我得到的:

(user.trial_expires - Time.now)/86400 

(因为一天有86400秒,即60 * 60 * 24)

有趣的是,结果超过 14,因此四舍五入为 15。在控制台中进行更仔细的调查后,这种情况只会在未来两天发生(如果您明白我的意思)。例如

>> Time.now
=> Fri Oct 29 11:09:26 0100 2010
>> future_1_day = 1.day.from_now
=> Sat, 30 Oct 2010 11:09:27 BST 01:00
#ten past eleven tomorrow

>> (future_1_day - Time.now)/86400
=> 0.999782301526931
#less than 1, what you'd expect right?

>> future_2_day = 2.day.from_now
=> Sun, 31 Oct 2010 11:09:52 GMT 00:00
>> (future_2_day - Time.now)/86400
=> 2.04162248861183
#greater than 2 - why?

我认为这可能与时区有关 - 我注意到从现在开始 1 天的时间是英国夏令时,而从现在开始 2 天的时间是格林威治标准时间。所以,我尝试使用本地时间并得到了相同的结果!

>> future_2_day = 2.day.from_now.localtime
=> Sun Oct 31 11:11:24 0000 2010
>> (future_2_day - Time.now)/86400
=> 2.04160829127315
>> (future_2_day - Time.now.localtime)/86400
=> 2.04058651585648

然后我想知道差异有多大,结果是 整整一个小时。所以看起来有些时区怪异,或者至少与我不理解的时区有关。目前我的时区是 BST(英国夏令时),现在比 UTC 晚一小时(直到这个星期天,它恢复到与 UTC 相同的时间)。

当我将两天添加到 Time.now 时,似乎引入了额外的一小时:检查一下。我从 Time.now 开始,加上两天,减去 Time.now,然后从结果中减去两天秒,剩下一个小时。

我只是突然想到,在拍脑袋的那一刻,这是因为时钟在星期天早上倒转:即在星期天早上 11 点 20 分,是两天多一个小时现在起。我正要删除所有这篇文章,但后来我注意到了这一点:我想‘啊,我可以通过使用 (24*daynum).hours 而不是 daynum.days 来解决这个问题,但我仍然得到相同的结果:即使我用秒!

>> (Time.now + (2*24).hours - Time.now) - 86400*2
=> 3599.99969500001
>> (Time.now + (2*24*3600).seconds - Time.now) - 86400*2
=> 3599.999855

所以现在我又糊涂了。现在加上两天的秒数,减去现在,减去两天的秒数怎么能等于一个小时的秒数呢?额外的一小时从哪里偷偷溜进来?

最佳答案

作为willcodejavaforfood已评论,这是由于本周末结束的夏令时。

添加持续时间时,ActiveSupport 中有一些代码可以补偿开始时间是 DST 而结果时间不是(反之亦然)。

def since(seconds)
  f = seconds.since(self)
  if ActiveSupport::Duration === seconds
    f
  else
    initial_dst = self.dst? ? 1 : 0
    final_dst   = f.dst? ? 1 : 0
    (seconds.abs >= 86400 && initial_dst != final_dst) ? f + (initial_dst - final_dst).hours : f
  end
rescue
  self.to_datetime.since(seconds)
end

如果您有 11:09:27 并添加天数,即使 DST 已更改,您仍然会在结果日获得 11:09:27。当您以秒为单位进行计算时,这会导致额外的一个小时。

几个想法:

  • 使用 distance_of_time_in_words 辅助方法向用户指示他们的试用期还剩多长时间。
  • 计算到期时间为 Time.now + (14 * 86400) 而不是使用 14.days.from_now - 但一些用户可能会声称他们已经失去了一个小时他们的审判。
  • 无论实际注册时间如何,都将试用设置为在到期日的 23:59:59 到期。

关于ruby-on-rails - Rails 时间奇数 : "x days from now",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4050991/

相关文章:

date - 如何在 Sails.js 中忽略时区

mysql - Rails where 子句与 Between 在 mysql 中不起作用

ruby - Controller 使用的测试服务的正确方法

r - 防止意外的时区转换

ruby - 如何执行一次并期望使用 RSpec 进行多次更改?

ruby - 如何使用 Ruby 一次向前和向后移动一屏文本?

java - 日期和时区(javascript、java、struts)

ruby-on-rails - 为 nil :NilClass 获取未定义的方法 `errors'

ruby-on-rails - 具有多个图像的嵌套回形针表单

ruby-on-rails - 数据库适配器的 Rails aws elastic beanstalk 部署错误