2

我看到打字100.days给了我[编辑:似乎给了我]一个 Fixnum 8640000

> 100.days.equal?(8640000)
 => true 

我原以为这两个值是可以互换的,直到我尝试了这个:

x = Time.now.to_date
=> Wed, 31 Oct 2012 
> [x + 100.days, x + 8640000]
=> [Fri, 08 Feb 2013, Mon, 07 May 25668] 

为什么以及如何将明显相等的值添加到相等的日期会产生不同的结果?

以上结果来自 Rails 控制台,使用 Rails 版本 3.1.3 和 Ruby 版本 1.9.2p320。(我知道,我应该升级到最新版本...)

4

2 回答 2

6

100.days不返回 Fixnum,它返回一个ActiveSupport::Duration,它在大多数操作下都非常努力地看起来像一个整数。

Date#+并被Time#+覆盖以检测是否添加了 Duration,如果是,则计算是否正确,而不是仅仅添加整数值(虽然 Time.+ 预计秒数,即 + 86400 提前 1 天,Date.+ 预计天数,因此 +86400 提前 86400 天)。

此外,还涵盖了一些特殊情况,例如在夏令时生效的当天添加一天。这也允许Time.now + 1.month提前 1 个日历月,而与当月的天数无关。

于 2012-10-31T22:33:06.090 回答
1

除了弗雷德里克的回答提供的内容之外,将 8640000 添加到日期与将 8640000 添加到时间不同,100.days100 天的正确名称也不是。

想想100.days意思是“给我 100 天的秒数”,而不是“这个值代表天数”。Rails 过去常常返回秒数,但变得花哨/更智能并将其更改为持续时间,以便日期数学可以做正确的事情 - 主要是。那个更花哨/更聪明的东西会通过掩盖真正发生的事情而导致像你遇到的问题,并且在你知道之前很难调试。

日期数学假定日值,而不是秒,而时间需要秒。因此,使用100 * 24 * 60 * 60 = 8640000

100 * 24 * 60 * 60               => 8640000
date = Date.parse('31 Oct 2012') => Wed, 31 Oct 2012
time = Time.new(2012, 10, 31)    => 2012-10-31 00:00:00 -0700

date + 8640000                   => Mon, 07 May 25668
time + 8640000                   => 2013-02-08 00:00:00 -0700
date + 100                       => Fri, 08 Feb 2013

有时处理时间和日期会很痛苦,而且您肯定会在忘记的地方遇到您编写的代码中的错误。这就是 ActiveSupport::Duration 部分通过为您处理一些日期/时间偏移来提供帮助的地方。最好的策略是使用日期/日期时间或时间,除非绝对必要,否则不要混合使用。如果您确实必须将它们混合在一起,那么将代码限制在方法中,这样您就可以在一个地方查看是否出现问题。

如果我需要处理比 Time 可以处理的更大的范围,我使用 Date 和 DateTime,再加上 DateTime 有一些其他有用的功能,否则我使用 Time 因为它与操作系统和 C 更紧密地耦合。(我在那里揭示了我的一些根源。 )

于 2012-10-31T22:54:42.867 回答