Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

create a range of months between two dates in ruby

I need to create logfiles per month for a range of months. Therefor I need all [year,month] tuples in a given range

How do you do iterating over dates?

How can this be done if I'd need to iterate every day?

like image 599
edx Avatar asked Mar 21 '13 20:03

edx


4 Answers

For example:

((Date.today - 90)..Date.today).map{|d| [d.year, d.month]}.uniq
#=> [[2012, 12], [2013, 1], [2013, 2], [2013, 3]]
like image 184
pguardiario Avatar answered Nov 19 '22 02:11

pguardiario


  start_date = 1.year.ago.to_date
  end_date = Date.current.yesterday
  monthly = [Date.new(start_date.year, start_date.beginning_of_month.month, 1)]
  (start_date..end_date).each do |d|
    month_date = Date.new(d.year, d.next_month.beginning_of_month.month, 1)
    monthly << month_date if monthly.exclude?(month_date) && month_date < end_date - 1.month
  end
  monthly

=> [Fri, 01 Sep 2017, Sun, 01 Oct 2017, Wed, 01 Nov 2017, Fri, 01 Dec 2017, Sun, 01 Jan 2017, Thu, 01 Feb 2018, Thu, 01 Mar 2018, Sun, 01 Apr 2018, Tue, 01 May 2018, Fri, 01 Jun 2018, Sun, 01 Jul 2018, Wed, 01 Aug 2018]

like image 38
Sean M Avatar answered Nov 19 '22 02:11

Sean M


Ruby Date supports producing successive days and offers a next_month method which could be used to efficiently iterate over months.

Here's a generic method that adapts to the precision of your inputs:

require 'date'

def date_tuples(from,to)
  prec   = from.size
  start  = Date.new(*from)
  finish = Date.new(*to)

  filter_on = [:day,:mon].first(3-prec)
  filter = ->(d) { filter_on.all? {|attr| d.send(attr) == 1 } }

  (start..finish)
    .select(&filter)
    .map { |d| [d.year,d.mon,d.day].first(prec) }
end

[7] pry(main)> date_tuples([2012],[2015])
=> [[2012], [2013], [2014], [2015]]
[8] pry(main)> date_tuples([2012,10],[2013,3])
=> [[2012, 10], [2012, 11], [2012, 12], [2013, 1], [2013, 2], [2013, 3]]
[9] pry(main)> date_tuples([2012,10,25],[2012,11,6])
=> [[2012, 10, 25],
 [2012, 10, 26],
 [2012, 10, 27],
 [2012, 10, 28],
 [2012, 10, 29],
 [2012, 10, 30],
 [2012, 10, 31],
 [2012, 11, 1],
 [2012, 11, 2],
 [2012, 11, 3],
 [2012, 11, 4],
 [2012, 11, 5],
 [2012, 11, 6]]
like image 3
dbenhur Avatar answered Nov 19 '22 02:11

dbenhur


I came up with this solution to generate a list of all [year,month] tuples in the range:

first=[2012,10]
last=[2013,03]
(first[0]..last[0]).to_a.product((1..12).to_a).select{|ym|(first..last).cover?(ym)}
=> [[2012, 10], [2012, 11], [2012, 12], [2013, 1], [2013, 2], [2013, 3]]
like image 1
edx Avatar answered Nov 19 '22 02:11

edx