2012-12-16 12 views
8

Ich brauche mehrere Monate in einer Ruby on Rails-Anwendung durchlaufen. Für jeden Monat muss ich den ersten und letzten Tag des jeweiligen Monats finden. Diese Daten werden dann in einer separaten Abfrage verwendet, um Ereignisse zu finden, die während dieser Daten auftreten, und Berechnungen für sie auszuführen.Wie durchlaufen Monate in Ruby on Rails

Anfangs habe ich versucht, so etwas wie:

(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 

Natürlich ist das Jahr, in diesem Fall nicht für den Fall aktualisiert, dass vor 11 Monaten wieder zum Vorjahr beinhaltet gehen. Und ich denke nicht, dass diese Art von for/each-Schleife funktioniert. Ich versuchte auch, die Zahlen zu einem Array zuzuordnen und die gleiche Methode zu verwenden, aber einen Fehler erhalten.

Was ist der beste Weg, um so etwas zu erreichen?

+0

Sind Sie beliebigen Start-/Enddaten erwartet? – Substantial

Antwort

10

Zuerst die Anzahl der Monate zwischen zwei Daten zählen (mit freundlicher Genehmigung von 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 

Dann vom Startmonat, jeden Monat zu zählen Danach finden Sie das erste/letzte Datum und fügen Sie es an ein Akkumulator-Array an.

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 
# => ... 

Jetzt dates wird ein Array mit verschachtelten Date Paare enthalten, um die ersten und letzten Tag des Monats entspricht. Dieses Array wird für die Verarbeitung leicht zu iterieren sein.

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 

Dies wird geprüft und Arbeiten in Rails 3.2.5/Rubin 1.9.3p194

+0

Danke - ich dachte, das war die beste Erklärung und war die sauberste Art in meinem Fall zu implementieren (auch angepasst seit Jahren). – Justin

+0

'Fr, 30 Dec 2011' ist nicht der letzte Tag im Dezember – MikDiet

12

Hier ist eine Möglichkeit, es zu tun:

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 
+0

Ja, das ist mit 'rails 3.0.10' auf' ruby ​​1.8.7' –

6
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 
+0

Nun scheint die' 'Date.advance'' Methode nicht mehr zu existieren. Sie können '' Date.next_month'' oder '' mydate >> 1'' verwenden, um 1 Monat vorzurücken. Siehe http://www.ruby-doc.org/stdlib-2.1.2/libdoc/date/rdoc/Date.html#method-i-next_month –

+0

Oder "time + = 1.month" – jonnysamps

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