Temukan jumlah bulan antara dua Tanggal di Ruby on Rails

95

Saya memiliki dua objek DateTime Ruby on Rails. Bagaimana menemukan jumlah bulan di antara mereka? (Ingatlah bahwa mereka mungkin berasal dari tahun yang berbeda)

phoenixwizard
sumber
5
Telah ditanyai dan dijawab di sini: stackoverflow.com/questions/5887756/…
Tim Baas
terima kasih telah menunjukkannya. Saya mencari tetapi tidak menemukannya.
phoenixwizard
lihat tautan ini stackoverflow.com/questions/1065320/…
sangeethkumar
Saya lebih menginginkan tautan dalam angka. Saya menyelesaikannya dengan metode yang dirujuk oleh Massimiliano Peluso
phoenixwizard
Hanya saya memberikannya untuk referensi Anda .. Terima kasih ..
sangeethkumar

Jawaban:

179
(date2.year * 12 + date2.month) - (date1.year * 12 + date1.month)

info lebih lanjut di http://www.ruby-forum.com/topic/72120

Massimiliano Peluso
sumber
25
Solusi ini tidak memperhitungkan hari. Jumlah bulan antara 28/4/2000 dan 1/5/2000 bukanlah 1 bulan, tetapi 0.
dgilperez
15
Saya membutuhkannya tanpa mempertimbangkan hari jadi ini bekerja untuk saya. +1
WattsInABox
1
Hanya varian lain untuk jawaban hebat ini:(12 * (date2.year - date1.year) + date2.month - date1.month).abs if date1 && date2
Stepan Zakharov
Ini menunjukkan jumlah bulan yang salah jika kami mencoba mengambil bulan antara 2 tahun yaitu 2017-05-20 hingga 2018-05-20. Outputnya menunjukkan 1 bulan.
Curious Developer
1
@CuriousDeveloper Ini menunjukkan bulan yang benar yaitu 12
ts
40

Jawaban yang lebih akurat akan mempertimbangkan hari-hari di kejauhan.

Misalnya, jika Anda menganggap bahwa bulan-jarak dari 28/4/2000dan 1/5/2000adalah 0bukan 1, maka Anda dapat menggunakan:

(date2.year - date1.year) * 12 + date2.month - date1.month - (date2.day >= date1.day ? 0 : 1)
dgilperez.dll
sumber
1
misalnya untuk menghitung berapa kali seseorang menerima gajinya selalu pada tanggal 22 setiap bulan
Matthias
15

Cobalah

((date2.to_time - date1.to_time)/1.month.second).to_i
knotito
sumber
irb>Time.at("2014-10-01".to_time - "2014-12-01".to_time).month => 10 (Saya menyerah pada pemformatan ... tidak bisa mengetahuinya)
Toby Joiner
Meskipun Anda menggunakan objek Tanggal, komentar @ toby-joiner akan tetap benar. Alasannya adalah bahwa <Oktober> - <Desember> adalah -2 bulan, tetapi Time.at (-2months) .month memberikan bulan yang setara dengan -2 (yaitu -2% 12 # => 10). Metode yang Anda sarankan akan berhasil jika dua bulan mengikuti satu sama lain dan berjarak kurang dari satu tahun, tetapi akan gagal jika dua bulan dalam urutan terbalik (misalnya Oktober - Desember) atau jika dua bulan terpisah lebih dari satu tahun.
elreimundo
2
Saya suka ide di baliknya, tetapi tidak benar jika rentang tanggalnya menjadi sangat panjang. Dalam contoh saya, Date.new(2014, 10, 31), Date.new(1997, 4, 30)saya menerima 213, bukan 210 bulan. Alasannya 1.month.secondsadalah karena jumlah detik dalam 30 hari dan bukan rata-rata detik dalam sebulan. Merendahkan suara sehingga orang lain tetap bebas bug.
Joe Eifert
1
ini tidak akan berhasil jika Anda memilih bulan yang bukan 30 hari
dima
2
metode ini tidak terlalu akurat.
gelandangan
9

Anda dapat mengubah pertanyaan menjadi "berapa hari pertama ada di antara permulaan bulan dari tanggal", dan kemudian gunakan transformasi data gaya fungsional:

(date1.beginning_of_month...date2.beginning_of_month).select { |date| date.day == 1 }.size
shock_one
sumber
Dan untuk kembali ke pertanyaan awal, Anda dapat menjumlahkan hari-hari (seperti yang Anda lakukan dengan yang pertama) dan mengambil rata-rata dari jumlah tersebut.
Joe Eifert
9

Dengan asumsi keduanya adalah tanggal: ((date2 - date1).to_f / 365 * 12).round sederhana.

Andreykul
sumber
Solusi yang sangat bagus! Bersih, sederhana, dan bahkan berfungsi selama bertahun-tahun - yaitu rentang bulan antara Februari 2018 dan Desember 2017.
jeffdill2
1
Perlu memperhitungkan jam, menit, dan detik ((date2 - date1).to_f / 60 / 60 / 24 / 365 * 12).round
scarver2
1
@ scarver2 Nomor yang Anda peroleh dari perhitungan Anda sudah jauh. Yang kami lakukan hanyalah mengambil hari dan mengubahnya menjadi bulan, ini tidak super akurat karena mengasumsikan 30,4167 hari per bulan, tetapi sangat dekat dan kemudian berputar.
Andreykul
3
start_date = Date.today
end_date   = Date.today+90
months = (end_date.month+end_date.year*12) - (start_date.month+start_date.year*12)

//months = 3
Ankit Varshney
sumber
2

Solusi lain yang saya temukan (membangun solusi yang sudah diposting di sini) adalah jika Anda ingin hasilnya menyertakan pecahan bulan. Misalnya jaraknya 1.2 months.

((date2.to_time - date1.to_time)/1.month.second).round(1) #Tenth of a month Ex: 1.2
((date2.to_time - date1.to_time)/1.month.second).round(2) #Hundreth, ex: 1.23 months
etc...
Zack
sumber
1
coba raplacing putaran dengan lantai jika Anda ingin hanya menunjukkan bulan-bulan yang benar-benar berlalu
Matthias
2
def difference_in_months(date1, date2)
  month_count = (date2.year == date1.year) ? (date2.month - date1.month) : (12 - date1.month + date2.month)
  month_count = (date2.year == date1.year) ? (month_count + 1) : (((date2.year - date1.year - 1 ) * 12) + (month_count + 1))
  month_count
end
Uğur Yılmaz
sumber
1
Akan berguna jika Anda bisa menguraikan hal ini? Umumnya pada jawaban SO termasuk penjelasan tentang apa yang kode itu lakukan dan mengapa itu berfungsi sebagai solusi
Entitas Tunggal
1

Saya membutuhkan jumlah bulan yang tepat (termasuk desimal) antara dua tanggal dan menulis metode berikut untuk itu.

def months_difference(period_start, period_end)
  period_end = period_end + 1.day
  months = (period_end.year - period_start.year) * 12 + period_end.month - period_start.month - (period_end.day >= period_start.day ? 0 : 1)
  remains = period_end - (period_start + months.month)

  (months + remains/period_end.end_of_month.day).to_f.round(2)
end

Jika membandingkan katakanlah 26 September hingga 26 September (hari yang sama) saya menghitungnya sebagai 1 hari. Jika Anda tidak membutuhkannya, Anda dapat menghapus baris pertama dalam metode ini:period_end = period_end + 1.day

Ini melewati spesifikasi berikut:

expect(months_difference(Date.new(2017, 8, 1), Date.new(2017, 8, 31))).to eq 1.0
expect(months_difference(Date.new(2017, 8, 1), Date.new(2017, 8, 30))).to eq 0.97
expect(months_difference(Date.new(2017, 8, 1), Date.new(2017, 10, 31))).to eq 3.0
# Overlapping february (28 days) still counts Feb as a full month
expect(months_difference(Date.new(2017, 1, 1), Date.new(2017, 3, 31))).to eq 3.0
expect(months_difference(Date.new(2017, 2, 10), Date.new(2017, 3, 9))).to eq 1.0
# Leap year
expect(months_difference(Date.new(2016, 2, 1), Date.new(2016, 2, 29))).to eq 1.0
mtrolle
sumber
btw itu bergantung pada Rails 'ActiveSupport
mtrolle
1

Berikut varian pemaksaan kasar:

date1 = '2016-01-05'.to_date
date2 = '2017-02-27'.to_date
months = 0

months += 1 while (date2 << (count+1)) >= date1
puts months # => 13

date2 harus selalu lebih besar dari date1

ole
sumber
0

Ini metode lain. Ini akan membantu menghitung jumlah bulan penuh antara dua tanggal

def months_difference(date_time_start, date_time_end)
  curr_months = 0
  while (date_time_start + curr_months.months) < date_time_end
    curr_months += 1
  end
  curr_months -= 1 if (date_time_start + curr_months.months) > date_time_end
  curr_months.negative? ? 0 : curr_months
end
Dhanush Balachandran
sumber
0

Solusi untuk semua kasus

(date1..date2).map { |date| date.strftime('%m.%Y') }.uniq.size
Nikolay Chumin
sumber