如何在Ruby on Rails中循环月份

13

我需要在 Ruby on Rails 应用程序中循环遍历几个月。对于每个月,我需要找到该月的第一天和最后一天。这些日期随后用于单独查询以查找在这些日期内发生的事件并对其进行计算。

最初,我尝试了类似以下的代码:

(11.months.ago.to_date.month..Date.today.month).each do |m|
  start_date = '01-#{m}-#{Date.today.year}'.to_date.beginning_of_month
  end_date = '01-#{m}-#{Date.today.year}'.to_date.end_of_month
end

当11个月前回到上一年时,这种情况下年份不会更新。我认为这种类型的for/each循环不起作用。我还尝试将数字映射到数组并使用相同的方法,但收到了一个错误。

如何最好地完成这样的任务?


你是否期望任意的开始/结束日期? - Substantial
5个回答

17

这是一种实现方法:

number_of_months = 0..11
number_of_months.to_a.reverse.each do |month_offset|
  start_date = month_offset.months.ago.beginning_of_month
  end_date = month_offset.months.ago.end_of_month
  puts "Start date : #{start_date} End date : #{end_date}"
end

Start date : 2012-01-01 00:00:00 -0700 End date : 2012-01-31 23:59:59 -0700
Start date : 2012-02-01 00:00:00 -0700 End date : 2012-02-29 23:59:59 -0700
Start date : 2012-03-01 00:00:00 -0700 End date : 2012-03-31 23:59:59 -0600
Start date : 2012-04-01 00:00:00 -0600 End date : 2012-04-30 23:59:59 -0600
Start date : 2012-05-01 00:00:00 -0600 End date : 2012-05-31 23:59:59 -0600
Start date : 2012-06-01 00:00:00 -0600 End date : 2012-06-30 23:59:59 -0600
Start date : 2012-07-01 00:00:00 -0600 End date : 2012-07-31 23:59:59 -0600
Start date : 2012-08-01 00:00:00 -0600 End date : 2012-08-31 23:59:59 -0600
Start date : 2012-09-01 00:00:00 -0600 End date : 2012-09-30 23:59:59 -0600
Start date : 2012-10-01 00:00:00 -0600 End date : 2012-10-31 23:59:59 -0600
Start date : 2012-11-01 00:00:00 -0600 End date : 2012-11-30 23:59:59 -0700
Start date : 2012-12-01 00:00:00 -0700 End date : 2012-12-31 23:59:59 -0700 

是的,这是在 ruby 1.8.7 上使用 rails 3.0.10 - Prakash Murthy

14

首先,计算两个日期之间的月数 (Massimiliano Peluso提供):

start_date = 13.months.ago.to_date
# => Wed, 16 Nov 2011

end_date = Date.today
# => Sun, 16 Dec 2012

number_of_months = (end_date.year*12+end_date.month)-(start_date.year*12+start_date.month)
# => 13

从开始月份开始,每个月计算后找到第一个/最后一个日期,并将其附加到累加器数组中。

dates = number_of_months.times.each_with_object([]) do |count, array|
  array << [start_date.beginning_of_month + count.months,
            start_date.end_of_month + count.months]
end
# => ...
现在dates将包含一个数组,其中嵌套Date对应于每个月的第一天和最后一天。这个dates数组很容易遍历以进行处理。
dates
# => [[Tue, 01 Nov 2011, Wed, 30 Nov 2011], [Thu, 01 Dec 2011, Fri, 30 Dec 2011], ...

dates[0].first
# => Tue, 01 Nov 2011

dates[0].last
# => Wed, 30 Nov 2011

dates[0].last.class
# => Date

这经过测试,可在Rails 3.2.5 / Ruby 1.9.3p194中正常工作。


谢谢 - 我认为这是最好的解释,也是在我的情况下实现最干净的方法(还进行了年份调整)。 - Justin
1
“Fri, 30 Dec 2011” 不是十二月的最后一天。 - mikdiet
1
@mikdiet 在这里是正确的。如果开始日期不在一个31天的月份,这个方法将不会返回一个有31天的月份的最后一天。 - undefined

12
(start_date..end_date).select{|date| date.day == 1}.map{|date| [date.beginning_of_month, date.end_of_month]}

7
time_start = 13.months.ago
time_end = 0.seconds.ago
time = time_start
while time < time_end
  puts("m:#{time.month} y:#{time.year}")
  time = time.advance(months: 1)
end

好的,“Date.advance”方法似乎不再存在。您可以使用“Date.next_month”或“mydate >> 1”来提前一个月的时间。请参阅http://www.ruby-doc.org/stdlib-2.1.2/libdoc/date/rdoc/Date.html#method-i-next_month。 - Pierre-Adrien
或者 time += 1.month - jonnysamps

0

从(包括)some_date开始的接下来12个月的起始和结束日期:

(0..11).map do |m| 
  start_date = some_date.at_beginning_of_month + m.month
  end_date = start_date.at_end_of_month
end

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接