Найдите количество месяцев между двумя датами в Ruby on Rails

У меня есть два объекта Ruby on Rails DateTime. Как найти количество месяцев между ними? (Имейте в виду, что они могут принадлежать к разным годам)

Ответ 2

Более точный ответ будет рассматривать дни на расстоянии.

Например, если вы считаете, что месяц-расстояние от 28/4/2000 и 1/5/2000 меньше 0, а не 1, вы можете использовать:

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

Ответ 3

Попробуйте

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

Ответ 4

Вы можете перефразировать вопрос как "сколько 1-го дня существует между началами месяцев дат", а затем использовать преобразования в функциональном стиле:

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

Ответ 5

Еще одно решение, которое я нашел (построенное уже здесь решение), - это если вы хотите, чтобы результат включал доли месяца. Например, расстояние 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...

Ответ 6

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

Ответ 7

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

Ответ 8

Мне понадобилось точное количество месяцев (включая десятичные числа) между двумя датами и написал для него следующий метод.

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

Если сравнивать, скажем, с 26 сентября по 26 сентября (в тот же день), я рассчитываю его как 1 день. Если вам не нужно, что вы можете удалить первую строку в методе: period_end = period_end + 1.day

Он передает следующие спецификации:

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