如何添加N天到时间T(占夏令时)?

fea*_*ool 5 ruby time

我有一个Time对象T.什么是向T添加N天的合理方法?

我提出的最好的感觉有点折磨:

require 'date'
def add_days(time, days)
  time.to_date.next_day(days).to_time
end
Run Code Online (Sandbox Code Playgroud)

PS:如果你在美国,正确答案必须满足:

add_days(Time.new(2013, 3, 10, 0), 1) == Time.new(2013, 3, 11, 0)
Run Code Online (Sandbox Code Playgroud)

如果您在欧盟,正确的答案必须满足:

add_days(Time.new(2013, 3, 31, 0), 1) == Time.new(2013, 4, 1, 0)
Run Code Online (Sandbox Code Playgroud)

PPS:这是一个Ruby问题,而不是Rails问题.

Ser*_*sev 9

Time有一个接受秒的+方法.

N = 3

t = Time.now + N * 86400 # 24 * 60 * 60 
Run Code Online (Sandbox Code Playgroud)

或者,如果您携带ActiveSupport,则更容易

require 'active_support/core_ext'

t = Time.now + N.days
Run Code Online (Sandbox Code Playgroud)

你显然可以自己做帮手

class Fixnum
  def days
    self * 86400
  end
end

t = Time.now # => 2013-01-31 16:06:31 +0700

t + 3.days # => 2013-02-03 16:06:31 +0700
Run Code Online (Sandbox Code Playgroud)

  • 添加这样的秒将在DST边界上给出错误的答案 (3认同)

fea*_*ool 6

似乎已成为我的风格,我正在回答我自己的问题.

由于跨越DST/ST的过渡相当罕见(并且在世界的许多地方,不存在),更有效的方法是首先添加(n_days*24*60*60)秒,然后检查UTC偏移是否已经改变.如果有,则创建更正的时间对象.

像这样:

def add_days(time, n_days)
  t2 = time + (n_days * 24 * 60 * 60)
  utc_delta = time.utc_offset - t2.utc_offset
  (utc_delta == 0) ? t2 : t2 + utc_delta
end
Run Code Online (Sandbox Code Playgroud)

这种方法可以避免大量额外的对象创建,并且可以正确处理夏令时的转换(至少在我当前的时区,太平洋时间):

>> t1 = Time.new(2013, 3, 10, 0, 0, 0)
=> 2013-03-10 00:00:00 -0800  # midnight Mar 3, 2013 Pacific Standard Time
>> t2 = add_days(t1, 1)
=> 2013-03-11 00:00:00 -0700  # midnight Mar 4, 2013 Pacific Daylight Time
>> t2 - t1
=> 82800.0                    # a shorter than usual day

>> u1 = Time.new(2013, 11, 3, 0, 0, 0)
=> 2013-11-03 00:00:00 -0700  # midnight Nov 3, 2013 Pacific Daylight Time
>> u2 = add_days(u1, 1)
=> 2013-11-04 00:00:00 -0800  # midnight Nov 4, 2013 Pacific Standard Time
>> u2 - u1
=> 90000.0                    # a longer than usual day
Run Code Online (Sandbox Code Playgroud)


use*_*729 5

ActiveSupport :: TimeWithZone似乎很好地处理了这个问题

> t1 = ActiveSupport::TimeZone['Eastern Time (US & Canada)'].parse('2013-03-10')
 => Sun, 10 Mar 2013 00:00:00 EST -05:00 
Run Code Online (Sandbox Code Playgroud)

请注意下面的类类型:

 > t1.class
 => ActiveSupport::TimeWithZone 
Run Code Online (Sandbox Code Playgroud)

请注意以下从EST到EDT的变化:

> t1 + 1.day
 => Mon, 11 Mar 2013 00:00:00 EDT -04:00 
Run Code Online (Sandbox Code Playgroud)