给定一个日期,我如何有效地计算给定序列中的下一个日期(每周,每月,每年)?

时间:2010-02-23 11:15:16

标签: ruby-on-rails ruby algorithm date

在我的应用程序中,我有各种日期序列,例如每周,每月和每年。鉴于过去的任意日期,我需要计算序列中的下一个 future 日期。

目前我正在使用次优循环。这是一个简化的例子(在Ruby / Rails中):

def calculate_next_date(from_date)
  next_date = from_date
  while next_date < Date.today
    next_date += 1.week # (or 1.month)
  end
  next_date
end

而不是执行一个循环(虽然简单,但效率很低,特别是在远处过去的日期),我想通过计算日期算术之间的周数(或几个月,几年)来做这个。两个日期,计算余数并使用这些值生成下一个日期。

这是正确的方法,还是我错过了一种特别聪明的'Ruby'解决方法?或者我应该坚持我的循环以简化这一切?

3 个答案:

答案 0 :(得分:15)

因为您将此问题标记为ruby-on-rails,所以我认为您使用的是Rails。 ActiveSupport引入了calculation模块,该模块提供了有用的#advance方法。

date = Date.today
date.advance(:weeks => 1)
date.advance(:days => 7)
# => next week

答案 1 :(得分:4)

我过去曾使用recurrence gem来达到此目的。还有一些其他宝石可以模拟here列出的重复事件。

答案 2 :(得分:2)

如果您使用Time对象,则可以使用Time.to_a将时间分解为数组(包含表示小时,日,月等的字段),调整相应字段,以及将数组传递回Time.localTime.utc以构建新的Time对象。

如果您使用的是Date课程,date +/- n会在n天后/更早的时间给您一个日期,date >>/<< n会在n个月之后/之前给您一个日期。

您可以使用更通用的Date.step而不是循环。例如,

from_date.step(Date.today, interval) {|d|
    # Each iteration of this block will be passed a value for 'd'
    #   that is 'interval' days after the previous 'd'.
}

其中interval是以天为单位的时间长度。

如果你所做的只是计算经过的时间,那么可能有更好的方法。如果您的日期存储为Date对象,那么执行date - Date.today将为您提供该日期与现在之间的天数。要计算月,年等,您可以使用以下内容:

# Parameter 'old_date' must be a Date object
def months_since(old_date)
    (Date.today.month + (12 * Date.today.year)) - (old_date.month + (12 * old_date.year))
end
def years_since(old_date)
    Date.today.year - old_date.year
end
def days_since(old_date)
    Date.today - old_date
end