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
Ответ 6
Для этой функции есть помощник рельсов:
http://api.rubyonrails.org/classes/ActionView/Helpers/DateHelper.html#method-i-distance_of_time_in_words
Ответ 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.