2012-12-16 11 views
8

Potrzebuję pętli przez kilka miesięcy w aplikacji Ruby on Rails. Dla każdego miesiąca muszę znaleźć pierwszy i ostatni dzień danego miesiąca. Daty te są następnie wykorzystywane w oddzielnym zapytaniu, aby znaleźć zdarzenia występujące podczas tych dat i przeprowadzać na nich obliczenia.Jak przelecieć przez miesiące w Ruby na szynach

Początkowo próbowałem coś takiego:

(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 

Oczywiście, lat nie jest aktualizowana w tym przypadku, w przypadku gdy 11 miesięcy temu polega wraca do poprzedniego roku. I, nie sądzę, że ten typ pętli/pętli działa. Próbowałem również mapowania liczb do tablicy i przy użyciu tej samej metody, ale otrzymałem błąd.

Jaki jest najlepszy sposób na osiągnięcie czegoś takiego?

+0

Czekasz arbitralnych start/daty zakończenia? – Substantial

Odpowiedz

10

pierwsze, policzyć liczbę miesięcy między dwiema datami (uprzejmości 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 

Następnie od początku miesiąca, licząc co miesiąc po czym znajdź pierwsze/ostatnie daty i dołącz do tablicy akumulatorów.

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

teraz dates zawiera tablicę zagnieżdżonych Date pary odpowiednio do pierwszego i ostatniego dnia każdego miesiąca. Ta macierz dates będzie łatwa do iteracji w celu przetworzenia.

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 

ten został przetestowany i działa w Rails 3.2.5/Ruby 1.9.3p194

+0

Dziękuję- Pomyślałem, że to było najlepsze wytłumaczenie i był najczystszym sposobem wdrożenia w moim przypadku (również dostosowanym przez lata). – Justin

+0

'Pt, 30 grudnia 2011' nie jest ostatnim dniem grudnia – MikDiet

12

Oto jeden ze sposobów, aby to zrobić:

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

Tak, to jest z 'rails 3.0.10' na' 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

No cóż, metoda' Date.advance'' wydaje się już nie istnieć. Możesz użyć '' Date.next_month'' lub 'mydate >> 1'', ​​aby przejść o 1 miesiąc w czasie. Zobacz http://www.ruby-doc.org/stdlib-2.1.2/libdoc/date/rdoc/Date.html#method-i-next_month –

+0

Lub 'time + = 1.month' – jonnysamps

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