How to Loop Through Months in Ruby on Rails

How to Loop through Months in Ruby on Rails

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

Rails: How to loop through month?

With the best_of_the_month scope defined to take month and year as params, the following code should work:

date = Date.new(2014,1,1)
@monthly_videos = []
while true
videos = Video.best_of_the_month(date.year, date.month)
@monthly_videos << videos
date += 1.month
break if date == Date.today.beginning_of_month
end

Loop through years + months

If you want to compute the upcoming months/years you could always use advance:

start = @user.created_at.to_date.beginning_of_month

Hash[(0..6).collect { |n| [ start.advance(months: n).month, 0 ] }]

That should properly step through days/months. You may want to just stick in dates instead of just the month number.

If you want to do "up to today" then try this:

date = @user.created_at.to_date.beginning_of_month
stop = Date.today.beginning_of_month
hash = { }

while (date <= stop)
hash[date] = 0

date = date.advance(months: 1)
end

Ruby/Rails how to iterate months over a DateTime range?

Use groupdate gem. For example (modified example from the docs):

visible_products = Product.where("created_at > ?", 1.week.ago).group_by_day

# {
# 2015-07-29 00:00:00 UTC => 50,
# 2013-07-30 00:00:00 UTC => 100,
# 2013-08-02 00:00:00 UTC => 34
# }

Also, this will be much faster, because your grouping/counting will be done by database itself, without the need to pass all the records via Product.all call to your Rails code, and without the need to create ActiveRecord object for each one (even irrelevant).

Loop through years + months

If you want to compute the upcoming months/years you could always use advance:

start = @user.created_at.to_date.beginning_of_month

Hash[(0..6).collect { |n| [ start.advance(months: n).month, 0 ] }]

That should properly step through days/months. You may want to just stick in dates instead of just the month number.

If you want to do "up to today" then try this:

date = @user.created_at.to_date.beginning_of_month
stop = Date.today.beginning_of_month
hash = { }

while (date <= stop)
hash[date] = 0

date = date.advance(months: 1)
end

Iterate every month with date objects

I have added following method to Date class:

class Date
def all_months_until to
from = self
from, to = to, from if from > to
m = Date.new from.year, from.month
result = []
while m <= to
result << m
m >>= 1
end

result
end
end

You use it like:

>> t = Date.today
=> #<Date: 2009-11-12 (4910295/2,0,2299161)>
>> t.all_months_until(t+100)
=> [#<Date: 2009-11-01 (4910273/2,0,2299161)>, #<Date: 2009-12-01 (4910333/2,0,2299161)>, #<Date: 2010-01-01 (4910395/2,0,2299161)>, #<Date: 2010-02-01 (4910457/2,0,2299161)>]

Ok, so, more rubyish approach IMHO would be something along:

class Month<Date
def succ
self >> 1
end
end

and

>> t = Month.today
=> #<Month: 2009-11-13 (4910297/2,0,2299161)>
>> (t..t+100).to_a
=> [#<Month: 2009-11-13 (4910297/2,0,2299161)>, #<Month: 2009-12-13 (4910357/2,0,2299161)>, #<Month: 2010-01-13 (4910419/2,0,2299161)>, #<Month: 2010-02-13 (4910481/2,0,2299161)>]

But you would need to be careful to use first days of month (or implement such logic in Month)...

Loop through years and months Ruby On Rails

month, year = nil, nil
Post.order("created_at desc") do |post|
if year != post.created_at.year
year = post.created_at.year
puts year
end

if month != post.created_at.month
month = post.created_at.month
puts "\t#{post.created_at.strftime("%B")}"
end

puts "\t\t#{post.name}"
end

Iterating months using ruby

ActiveSupport has beginning_of_month and end_of_month:

d = Date.today
#=> Fri, 13 Jul 2012
d.beginning_of_month
#=> Sun, 01 Jul 2012
d.end_of_month
#=> Tue, 31 Jul 2012

You can use Date#>> to shift dates forward monthwise:

(d>>2).end_of_month
#=> Sun, 30 Sep 2012
(d>>4).beginning_of_month
#=> Thu, 01 Nov 2012

Rails Iteration by month given range of dates

For anyone else facing the same problem, the solution is outlined below:

def self.chart_data(start = 1.year.ago)
total_count = total_count_by_month(start)

##############################################
start = start.to_date.beginning_of_month
today = Date.today.beginning_of_month
range = (start..today).select {|d| d.day == 1}
##############################################

range.map do |month|
{
created_at: month,
total_enquiries: total_count[] || 0
}
end
end

The chart's x-axis now iterates by month.

The solution is found here.

I'm still looking for solutions on how the chart dates might display (%b %Y) as opposed to the current format of (yyyy-mm-dd).

Ruby: Iterate over days in previous month

require 'date'

d = Date.today << 1 # << 1 is one month earlier
(Date.new(d.year, d.month, 1)..Date.new(d.year, d.month,-1)).each{|date| p date}


Related Topics



Leave a reply



Submit