Another solution that I found (built off a solution posted here already) is for if you want the result to include fractions of a month. For example the distance is 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...
You can rephrase the question as "how many 1st days is there between the beginnings of months of the dates", and then use functional-style data transformations:
If comparing let's say September 26th to September 26th (same day) I calculate it as 1 day. If you don't need that you can remove the first line in the method: period_end = period_end + 1.day
It passes the following specs:
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
If you want the real months,then you must consider the days, the next code take in count this.
# get the real years between date, it consider the months and days
def years_between_dates(since_date, until_date)
years = until_date.year - since_date.year
if (until_date.month < since_date.month) ||
(until_date.month == since_date.month && since_date.day > until_date.day)
years -= 1
end
years
end
# Get the months between dates, it consider the days
def difference_between_dates_in_months(since_date, until_date)
months = (years_between_dates(since_date, until_date) * 12)
until_month = until_date.month
since_month = since_date.month
if until_month > since_month
months += since_month - until_month
elsif until_month < since_month
months += 12 - since_month + until_month
end
months -= 1 if(since_date.day > until_date.day)
months
end