【问题标题】:Is Rails time broken for midnight?Rails 的时间会在午夜中断吗?
【发布时间】:2012-09-25 00:57:59
【问题描述】:

让我们看看日期:

1.9.2p320 :008 > Date.today
 => Wed, 03 Oct 2012 
1.9.2p320 :009 > Time.now
 => 2012-10-03 22:32:55 -0400

现在,既然是午夜了?

1.9.2p320 :005 > Date.today.midnight
 => Wed, 03 Oct 2012 00:00:00 UTC +00:00 

有道理。但是昨天呢?

1.9.2p320 :006 > Date.yesterday.midnight
 => Wed, 03 Oct 2012 00:00:00 UTC +00:00 

呃,这不太合理。今天的午夜和昨天的午夜一样吗?你不能是认真的!

1.9.2p320 :026 > Date.today.midnight == Date.yesterday.midnight
 => true 
1.9.2p320 :033 > 1.day.ago.midnight == Date.yesterday.midnight
 => true 
1.9.2p320 :034 > 1.day.ago.midnight == Date.today.midnight
 => true 

哦,你是认真的。明天呢?

1.9.2p320 :007 > Date.tomorrow.midnight
 => Fri, 05 Oct 2012 00:00:00 UTC +00:00 

等一下,如果今天午夜是 3 日 00:00,昨天午夜是 3 日 00:00,但明天午夜是 5 日 00:00,那么哪里是 4 日 00:00?

这里是:

1.9.2p320 :010 > 0.days.ago
 => Thu, 04 Oct 2012 02:34:58 UTC +00:00 
1.9.2p320 :011 > 0.days.ago.midnight
 => Thu, 04 Oct 2012 00:00:00 UTC +00:00

但不是零天前今天?显然不是。

是我,还是这根本不是内部一致的?在我看来 Date.today 应该与 0.days.ago 相同。

我知道days.ago 实际上是在使用 Time 对象,这是一个时区问题:

1.9.2p320 :030 > Date.today
 => Wed, 03 Oct 2012 
1.9.2p320 :021 > Time.now
 => 2012-10-03 22:40:09 -0400 
1.9.2p320 :023 > 0.days.ago
 => Thu, 04 Oct 2012 02:40:22 UTC +00:00 
1.9.2p320 :022 > Time.zone.now
 => Thu, 04 Oct 2012 02:40:14 UTC +00:00 

但似乎,鉴于这些是便利函数,将时区假设放入 one 便利函数而不是将其放入 另一个 便利函数是一种意思功能,从各方面来说,两者的含义相同。

即使撇开这一点不谈,它似乎也无法解释 Date.today.midnight == Date.yesterday.midnight 是——很简单——狂吠的事实。

既然我知道我不可能是第一个被这个咬伤的人,我问我错过了什么?

【问题讨论】:

    标签: ruby-on-rails date time timezone utc


    【解决方案1】:

    rossta 确定了罪魁祸首。使用Time.now.to_date 并在必要时指定时区可能会更好:

    > Time.now.in_time_zone("Asia/Tokyo")
      => Thu, 04 Oct 2012 12:54:43 JST +09:00 
    > Time.now.in_time_zone("Asia/Tokyo").to_date.midnight
     => Thu, 04 Oct 2012 00:00:00 JST +09:00 
    Time.now.in_time_zone("Asia/Tokyo").to_date.yesterday.midnight
     => Wed, 03 Oct 2012 00:00:00 JST +09:00 
    
    > Time.zone = "America/Los_Angeles"
     => "America/Los_Angeles" 
    > Time.now.in_time_zone
     => Wed, 03 Oct 2012 20:55:35 PDT -07:00 
    
    > Time.now.to_date # using the system time
     => Wed, 03 Oct 2012 
    > Time.now.to_date.midnight
     => Wed, 03 Oct 2012 00:00:00 PDT -07:00 
    > Time.now.to_date.yesterday.midnight
     => Tue, 02 Oct 2012 00:00:00 PDT -07:00 
    

    【讨论】:

      【解决方案2】:

      Rails 将基于相对日期计算,例如 yesterdaytomorrowmidnight 关闭 Date.current,这将尝试使用配置的 Time.zonehttps://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/date/calculations.rb#L46

      由于您的 Time.zone 设置为 UTC,因此您将不会得到与基于 Date.today 的计算相同的结果,后者将使用您计算机的时钟时间,除非您实际上处于 UTC 时间。

      所以,如果你和 UTC 之间的时间差大于午夜的时间,Date.yesterdayDate.today 实际上返回相同的日期!

      尝试使用Time.zone = 'Eastern Time (US & Canada)' 或您所在的任何时区设置您的 Rails 时区,然后重试您的示例。

      【讨论】:

      • 还要注意0.days.agoActiveSupport::TimeWithZone,而Date.todayDate。如果您关心时区,请在任何地方使用时间戳。如果您关心日期,请使用日期。如果你想把头发扯下来,可以打电话#midnight 等来混合它们。
      • 对。所以也许对原始问题的简短回答是,“是的,完全坏了。”
      • 另一种简短的回答是“不,你用错了”。计时非常复杂。 (不断更改时区偏移量,time zones beyond UTC +/- 12 hoursleap seconds,或者如何time elapsed depends on jurisdiction。)在不了解所涉及机制的情况下在日期和时间之间进行转换会受到伤害。
      • 这是真的,我理解这一点,但这并不能解释Date.todayDate.yesterday 之间的内部不一致。我的期望——我的论点是什么——是那些应该在时区内保持一致,无论是 UTC 还是其他。
      • 我确实解释了您观察到的不一致的原因。
      猜你喜欢
      • 2020-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-22
      相关资源
      最近更新 更多