Rails时间奇怪:"从现在起x天"

Max*_*ams 17 ruby timezone ruby-on-rails activesupport

当用户注册我的某个网站进行免费试用时,我将其帐户到期时间设置为"14.days.from_now".然后在主页上我显示他们剩下多少天,我得到:

(user.trial_expires - Time.now)/86400 
Run Code Online (Sandbox Code Playgroud)

(因为一天有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?
Run Code Online (Sandbox Code Playgroud)

我想也许这与时区有关 - 我注意到从现在起1天的时间是在BST,从现在起2天的时间是在GMT.所以,我尝试使用localtime并得到了相同的结果!

>> 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
Run Code Online (Sandbox Code Playgroud)

那么我想知道差别有多大,而事实证明,这整整一个钟头了.所以它看起来像一些时区的怪异,或者至少与我不理解的时区有关.目前我的时区是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
Run Code Online (Sandbox Code Playgroud)

所以现在我又困惑了.现在怎么能加上两天的秒,减去现在,减去两天的秒,是一小时的秒?额外的小时在哪里潜入?

mik*_*kej 19

正如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
Run Code Online (Sandbox Code Playgroud)

如果您有11:09:27并且添加了几天,即使DST已经更改,您在结果日仍然会得到11:09:27.当你在几秒钟内完成计算时,这会导致额外的一小时.

一些想法:

  • 使用distance_of_time_in_words帮助程序方法可以向用户显示试验中剩余的时间.
  • 计算到期时间Time.now + (14 * 86400)而不是使用14.days.from_now- 但有些用户可能会声称他们已经失去了一小时的审判时间.
  • 无论实际注册时间如何,试验将在到期日的23:59:59到期.


Jon*_*röm 8

您可以使用Date类来计算今天和到期日之间的天数.

expire_date = Date.new(user.trial_expires.year, user.trial_expires.month, user.trial_expires.day)
days_until_expiration = (expire_date - Date.today).to_i
Run Code Online (Sandbox Code Playgroud)

  • `today = Date.new(now.year,now.month,now.day)`可以简化为`today = Date.today` (3认同)

Rob*_*elo 5

使用since,例如:14.days.since.to_date