Find number of months between two Dates in Ruby on Rails

Ruby on-RailsRubyDateRuby on-Rails-3.1

Ruby on-Rails Problem Overview


I have two Ruby on Rails DateTime objects. How to find the number of months between them? (Keeping in mind they might belong to different years)

Ruby on-Rails Solutions


Solution 1 - Ruby on-Rails

(date2.year * 12 + date2.month) - (date1.year * 12 + date1.month)

more info at http://www.ruby-forum.com/topic/72120

Solution 2 - Ruby on-Rails

A more accurate answer would consider days in the distance.

For example, if you consider that the month-distance from 28/4/2000 and 1/5/2000 is 0 rather than 1, then you can use:

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

Solution 3 - Ruby on-Rails

Give a try to

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

Solution 4 - Ruby on-Rails

Assuming both are dates: ((date2 - date1).to_f / 365 * 12).round simple.

Solution 5 - Ruby on-Rails

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:

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

Solution 6 - Ruby on-Rails

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

Solution 7 - Ruby on-Rails

I needed the exact number of months (including decimals) between two dates and wrote the following method for it.

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

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

Solution 8 - Ruby on-Rails

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...

Solution 9 - Ruby on-Rails

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

Solution 10 - Ruby on-Rails

Here's a brute forcing variant:

date1 = '2016-01-05'.to_date
date2 = '2017-02-27'.to_date
months = 0

months += 1 while (date2 << (count+1)) >= date1
puts months # => 13

date2 must be always greater than date1

Solution 11 - Ruby on-Rails

Solution for any cases

(date1..date2).map { |date| date.strftime('%m.%Y') }.uniq.size

Solution 12 - Ruby on-Rails

How about this? I've found it pretty clean

((date2 - date1) / 1.month).round

Solution 13 - Ruby on-Rails

Here is another method. This will help to calculate number of whole months between two dates

def months_difference(date_time_start, date_time_end)
  curr_months = 0
  while (date_time_start + curr_months.months) < date_time_end
    curr_months += 1
  end
  curr_months -= 1 if (date_time_start + curr_months.months) > date_time_end
  curr_months.negative? ? 0 : curr_months
end

Solution 14 - Ruby on-Rails

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionphoenixwizardView Question on Stackoverflow
Solution 1 - Ruby on-RailsMassimiliano PelusoView Answer on Stackoverflow
Solution 2 - Ruby on-RailsdgilperezView Answer on Stackoverflow
Solution 3 - Ruby on-RailsknotitoView Answer on Stackoverflow
Solution 4 - Ruby on-RailsAndreykulView Answer on Stackoverflow
Solution 5 - Ruby on-Railsshock_oneView Answer on Stackoverflow
Solution 6 - Ruby on-RailsAnkit VarshneyView Answer on Stackoverflow
Solution 7 - Ruby on-RailsmtrolleView Answer on Stackoverflow
Solution 8 - Ruby on-RailsZackView Answer on Stackoverflow
Solution 9 - Ruby on-RailsUğur YılmazView Answer on Stackoverflow
Solution 10 - Ruby on-RailsoleView Answer on Stackoverflow
Solution 11 - Ruby on-RailsNikolay ChuminView Answer on Stackoverflow
Solution 12 - Ruby on-RailsVictor BlascoView Answer on Stackoverflow
Solution 13 - Ruby on-RailsDhanush BalachandranView Answer on Stackoverflow
Solution 14 - Ruby on-Railsandres.araView Answer on Stackoverflow