I need to loop through several months in a Ruby on Rails application. For each month, I need to find the first and last day of that given month. These dates are then used in a separate query to find events occurring during those dates and running calculations on them.
Initially, I tried something like:
(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
Of course, the year isn't updated in this case in the event that 11 months ago involves going back to the previous year. And, I don't think this type of for/each loop works. I also tried mapping the numbers to an array and using the same method, but received an error.
What's the best way to accomplish something like this?
(start_date..end_date).select{|date| date.day == 1}.map{|date| [date.beginning_of_month, date.end_of_month]}
First, count the number of months between two dates (courtesy of 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
Then from the start month, counting each month thereafter, find the first/last dates and append to an accumulator array.
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
# => ...
Now dates
will contain an array with nested Date
pairs corresponding to the first and last date of each month. This dates
array will be easy to iterate for processing.
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
This is tested and working in Rails 3.2.5/Ruby 1.9.3p194
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With