Rails рассчитывает диапазон дат в месяцах

Как рассчитать разницу двух дат в месяцах? Кроме того, если это имеет значение, я работаю с объектами Date, а не с DateTime. Кроме того, некоторые варианты округления могут быть приятными, поэтому я могу контролировать, хочу ли я округлить до или после частичных месяцев.

Спасибо!

Ответ 1

Вычитание одной даты или DateTime из другого приведет к количеству дней как дробной части, но это может быть оценено как Float или Fixnum по мере необходимости.

Например:

(Date.today - Date.today.advance(:months => -3)).to_f
# => 89.0

Прошло 89,0 дней между сегодняшним днем ​​и той же датой календаря три месяца назад. Если вы работаете с 30-дневными месяцами или 30.4375, как в среднем, вы заканчиваете 2.92 месяцами, прошедшими между тем и сейчас, или округлялись до ближайшего целого числа. 3.

Если вы хотите вычислить точное количество календарных месяцев, это сложнее, но может быть сделано.

Ответ 2

Это должно дать o.k. приближение:

Date1 - Date2 = difference_in_days
(difference_in_days/30).round = difference_in_months

Ответ 3

Что-то вроде этого более читаемо, чем вычисление секунд, и даст вам фактическую разницу календаря:

# Calculate differnce between two dates in months
# Produces b - a
def month_difference(a, b)
    difference = 0.0
    if a.year != b.year
        difference += 12 * (b.year - a.year)
    end
    difference + b.month - a.month
end

Если вам нужно разделить разницу в зависимости от дня, вы можете просто следовать шаблону

Ответ 4

Нам нужно что-то в этом направлении, но в том числе частичные месяцы. Таким образом, 1/31 до 2/1 все равно будет работать 2 месяца. Могу помочь!

def self.month_count(range)
  12 * (range.end.year - range.begin.year) + range.end.month - range.begin.month
end

Ответ 5

Этот ответ опаздывает на сторону, основывается на предыдущих ответах и, вероятно, может быть написан более кратко, однако он дает разницу в календарном расписании между двумя датами, учитывающими дни.

def difference_in_months(start_date, today)
  date_to_months(today) - date_to_months(start_date) + adjustment_for_days(start_date, today)
end

def date_to_months(date)
  date.year * 12 + date.month
end

def adjustment_for_days(earlier_date, later_date)
  if later_date.day == earlier_date.day
    0
  elsif later_date.day > earlier_date.day
    1
  else
   -1
  end
end

Ответ 7

как насчет этой практики?

current_date = start_date

while current_date < end_date
  # something  
  current_date = current_date.next_month
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

Он использует ActiveSupport Rails.