GrégoireC
GrégoireC

Reputation: 279

Ruby - Get range of month between two dates

I generated a table called DimensionDate , which contains all dates between 2011,12,31 and 2032,1,1 .

Now, I would like to know the absolute range of a month between these two dates, for each date.

For example :

2012-01-01 is the number 1 month

2012-02-01 is the number 2 month

2013-01-01 is the number 13 month

2013-02-01 is the number 14 month

2014-01-01 is the number 25 month

2014-02-01 is the number 26 month

etc...

How could I do that ? Any Idea ? Thanks for your help

Upvotes: 1

Views: 1338

Answers (2)

hirolau
hirolau

Reputation: 13921

Something like this?

require 'date'

def months_between_dates(date_1, date_2)
  diff_in_years  = (date_1.year-date_2.year)*12
  diff_in_months = date_1.month-date_2.month
  return (diff_in_years + diff_in_months).abs
end

start_date  = Date.new(2011,12,31)
test_date   = Date.new(2013,01,01)
test_date_2 = Date.new(2014,02,01)

p months_between_dates(start_date, test_date)   # => 13
p months_between_dates(start_date, test_date_2) # => 26

Edit:

As a bonus here is a version with a default value if you know you will always compare with a specific date. The logic is the same, just short instead of readable:

# Call by passing one or two dates:
def delta_months(x, y=Date.new(2011,12,31))
  ((x.year-y.year)*12+(x.month-y.month)).abs 
end

p delta_months(test_date)  # => 13

Edit2:

As dax pointed out my function do not provide any form of validation, here is how you would implement that:

MIN_DATE, MAX_DATE = Date.new(2011,12,31), Date.new(2032,1,1)
date_range = MIN_DATE..MAX_DATE
test_date  = Date.new(2064,1,1)

raise "Date out of range, must be between #{MIN_DATE} and #{MAX_DATE}." unless date_range.cover? test_date # => Date out of range, must be between 2011-12-31 and 2032-01-01. (RuntimeError)
delta_months(test_date)  # Never called unless good date is provided.

Upvotes: 6

dax
dax

Reputation: 11007

Hirolau's answer is good but I think this can be made simpler/error proofed. Since the start time is absolute, you don't need to include it in the method's arguments. You can test it against the end time as well:

def dimensional_date_range(now)
  range = (now.year - 2012)*12 + (now.month)
  if range <= 240 
    range
  else
    "you're out of this dimension, man!"
  end
end

tested:

$ date =  Date.new(2014,02,01)
$ date2 = Date.new(2050,01,01)
$ dimensional_date_range(date)
 => 26
$ dimensional_date_range(date2)
 => "you're out of this dimension, man!"

Upvotes: 1

Related Questions