Reputation: 2497
I am attempting to calculate the elapsed time in months between two dates in Ruby in tenths of a month. So, for example, the time from January 1, 2015 to February 14, 2015 would be 1.5 months.
I found this:
((date2.to_time - date1.to_time)/1.month.second).round(1)
Which is great but this assumes a 30 day month (1.month==30.days
). But obviously not all months are 30 days. I am looking for a formula that would account for the different lengths of months.
Upvotes: 2
Views: 152
Reputation: 18762
My solution, with some monkey patching of Date
class
require 'date'
class Date
COMMON_YEAR_DAYS_IN_MONTH = [nil, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
def days_in_month
return 29 if month == 2 && Date.gregorian_leap?(year)
COMMON_YEAR_DAYS_IN_MONTH[month]
end
def elapsed_month
((day.to_f/days_in_month.to_f))
end
def remaining_month
(1.0 - elapsed_month)
end
def diff_percent(d)
from, to = self > d ? [d, self] : [self, d]
to.elapsed_month + from.remaining_month + (to.month - from.month) - 1
end
end
from = Date.new(2015, 1, 1)
to = Date.new(2015, 8, 12)
p to.diff_percent(from).round(1) # Prints 7.4
p from.diff_percent(to).round(1) # Prints 7.4
Upvotes: 1
Reputation: 5756
If I understood well, you are looking for something like this:
require 'date'
def last_day_of_month(date)
(((date - date.day + 1) >> 1) - 1).day
end
def diff_in_months(date1, date2, precision=1)
if date2 < date1
return -diff_in_months(date2, date1, precision)
end
days_month_1 = last_day_of_month(date1)
ratio1 = (days_month_1 - date1.day + 1) / days_month_1.to_f
days_month_2 = last_day_of_month(date2)
ratio2 = date2.day / days_month_2.to_f
months_diff = (date2.year - date1.year) * 12 +
date2.month - date1.month - 1
(ratio1 + ratio2 + months_diff).round(precision)
end
date1 = Date.new(2015, 1, 1)
date2 = Date.new(2015, 2, 14)
date3 = Date.new(2015, 3, 14)
date4 = Date.new(2015, 4, 1)
date5 = Date.new(2016, 1, 1)
date6 = Date.new(2016, 2, 14)
diff_in_months(date1, date2) # 1.5
diff_in_months(date2, date1, 2) # -1.5
diff_in_months(date1, date3, 2) # 2.45
diff_in_months(date4, date4, 2) # 0.03 (1 day in 30)
diff_in_months(date5, date6, 2) # 1.48 (Feb'16 has 29 days)
Upvotes: 2