Ruby on Rails'de iki Tarih arasındaki ay sayısını bulun


95

İki Ruby on Rails DateTime nesnem var. Aralarındaki ay sayısını nasıl bulabilirim? (Farklı yıllara ait olabileceklerini unutmayın)


5
Sorgulandığı ve burada cevap oldu: stackoverflow.com/questions/5887756/...
Tim baas

işaret ettiğiniz için teşekkürler. Aradım ama tökezlemedim.
phoenixwizard


Bağlantıyı sayılarla yapmayı tercih ederim. Massimiliano Peluso tarafından önerilen yöntemle yaptırdım
phoenixwizard

Sadece referansınız için verdim .. Yine de teşekkürler ..
sangeethkumar

Yanıtlar:


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

http://www.ruby-forum.com/topic/72120 adresinde daha fazla bilgi


25
Bu çözüm günleri dikkate almıyor. 28/4/2000 ile 1/5/2000 arasındaki ay sayısı 1 ay değil 0.
dgilperez

15
Günleri düşünmeden birine ihtiyacım var, bu yüzden bu benim için çalışıyor. +1
WattsInABox

1
Bu harika cevabın bir başka çeşidi:(12 * (date2.year - date1.year) + date2.month - date1.month).abs if date1 && date2
Stepan Zakharov

2 yıl arasında, yani 2017-05-20 ile 2018-05-20 arasındaki ayları getirmeye çalışırsak yanlış ay sayısı gösteriliyor. Çıktı 1 ayı gösterir.
Meraklı Geliştirici

1
@CuriousDeveloper Doğru ayları gösteriyor, yani 12
ts

40

Daha doğru bir cevap, uzaktaki günleri dikkate alır.

Eğer gelen aylık mesafeye düşünün Örneğin, 28/4/2000ve 1/5/2000olduğu 0ziyade 1, o zaman kullanabilirsiniz:

(date2.year - date1.year) * 12 + date2.month - date1.month - (date2.day >= date1.day ? 0 : 1)

1
örneğin birisinin maaşını kaç kez aldığını hesaplamak için her zaman ayın
Matthias

15

Bir dene

((date2.to_time - date1.to_time)/1.month.second).to_i

irb>Time.at("2014-10-01".to_time - "2014-12-01".to_time).month => 10 (Biçimlendirmeden vazgeçiyorum ...
Toby Joiner

Date nesnesini kullansanız bile, @ toby-joiner'ın yorumu yine de doğru olacaktır. Bunun nedeni, <Ekim> - <Aralık> 'ın -2 ay olması, ancak Time.at (-2months) .month'un -2 aya eşdeğer olmasıdır (yani -2% 12 # => 10). Önerdiğiniz yöntem, iki ay birbirini takip ederse ve bir yıldan az bir aralıktaysa işe yarayacaktır, ancak iki ay ters sırada (örneğin Ekim - Aralık) veya iki ay bir yıldan fazla ise başarısız olacaktır.
elreimundo

2
Arkasındaki fikir hoşuma gitti, ancak tarih aralığı gerçekten uzarsa bu yanlış. Benim örnekte Date.new(2014, 10, 31), Date.new(1997, 4, 30)I 213 yerine 210 ay sonra yapılmıştır. Bunun nedeni 1.month.seconds, bir aydaki ortalama saniye değil, 30 gün içindeki saniye sayısıdır. Başkalarının hatasız kalması için olumsuz oylama.
Joe Eifert

1
30 gün olmayan bir ay seçerseniz bu işe yaramayacak
dima

2
bu yöntem çok doğru değil.
serseri

9

Soruyu "tarihlerin aylarının başlangıcı arasında kaç 1. gün vardır" şeklinde yeniden ifade edebilir ve ardından işlevsel tarzda veri dönüşümlerini kullanabilirsiniz:

(date1.beginning_of_month...date2.beginning_of_month).select { |date| date.day == 1 }.size

Ve asıl soruya geri dönmek için, günleri (ilkinde yaptığınız gibi) toplayabilir ve toplamların ortalamasını alabilirsiniz.
Joe Eifert

9

Her ikisinin de tarih olduğunu varsayarsak: ((date2 - date1).to_f / 365 * 12).round basit.


Çok güzel çözüm! Temiz, basit ve hatta yıllar boyunca çalışır - yani, Şubat 2018 ile Aralık 2017 arasındaki ay aralığı.
jeffdill2

1
Saatler, dakikalar ve saniyeleri hesaba katması gerekiyor ((date2 - date1).to_f / 60 / 60 / 24 / 365 * 12).round
scarver2

1
@ scarver2 Hesaplamanızdan aldığınız sayı çok uzak. Tek yaptığımız günler almak ve onları aylara çevirmek, bu çok doğru değil çünkü ayda 30.4167 gün varsayıyor, ama çok yakın ve sonra yine de yuvarlanıyor.
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

2

Bulduğum başka bir çözüm (daha önce burada yayınlanmış bir çözüm oluşturdu), sonucun bir ayın kesirlerini içermesini istiyorsanız. Mesela mesafe 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...

1
Yalnızca gerçekte geçen ayları göstermek istiyorsanız, yerle dolaşmayı deneyin
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

1
Bunu detaylandırırsan faydalı olur mu? Genel olarak SO cevapları, kodun ne yaptığı ve neden bir çözüm olarak çalıştığı hakkında bir açıklama içerir
Single Entity

1

İki tarih arasındaki tam ay sayısına (ondalık sayılar dahil) ihtiyacım vardı ve bunun için aşağıdaki yöntemi yazdım.

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

Diyelim ki 26 Eylül - 26 Eylül (aynı gün) karşılaştırılırsa 1 gün olarak hesaplıyorum. Buna ihtiyacınız yoksa, yöntemdeki ilk satırı kaldırabilirsiniz:period_end = period_end + 1.day

Aşağıdaki özellikleri geçer:

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

btw, Rails'in ActiveSupport'una güveniyor
mtrolle

1

İşte bir kaba zorlama çeşidi:

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 her zaman daha büyük olmalıdır date1


0

İşte başka bir yöntem. Bu, iki tarih arasındaki tam ay sayısını hesaplamaya yardımcı olacaktır.

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

0

Her durum için çözüm

(date1..date2).map { |date| date.strftime('%m.%Y') }.uniq.size
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.