Ruby: get last day of month while sum

Viewed 57

Looking for a best way to get month with last day during adding operation.

For examle: I am getting last day of Movember and I need to add 1 month from this day, 1 full calendar month:

2.6.3 :002 > date = Date.strptime('November 30, 2020', '%B %d, %Y')
 => Mon, 30 Nov 2020 
2.6.3 :003 > date + 1.month
=> Wed, 30 Dec 2020 

This is wrong for me, because it will be 31 days in December.

Another example:

2.6.3 :005 > date2 = Date.strptime('February 29, 2020', '%B %d, %Y')
 => Sat, 29 Feb 2020 
2.6.3 :006 > date2 + 1.month
=> Sun, 29 Mar 2020 

I am expecting 31 of Mar instead of 29

For now - I know only one solution - something like:

2.6.3 :017 > (date + 1.month).end_of_month
=> Thu, 31 Dec 2020 
2.6.3 :018 > (date2 + 1.month).end_of_month
=> Tue, 31 Mar 2020

Is it the correct and best way?

2 Answers

I believe the solution you came up with is the right way to solve the problem. What I had in mind is very similar:

date.next_month.end_of_month

It's easy to do this with the pure-Ruby methods Date::new and Date#>>.

require 'date'

def end_of_n_months_hence(curr_date, n)
  (Date.new(curr_date.year, curr_date.month, 1) >> (n+1)) - 1
end
curr_date = Date.today
  #=> #<Date: 2020-11-25 ((2459179j,0s,0n),+0s,2299161j)>
end_of_n_months_hence(curr_date,  0)
  #=> #<Date: 2020-11-30 ((2459184j,0s,0n),+0s,2299161j)> 
end_of_n_months_hence(curr_date,  1)
  #=> #<Date: 2020-12-31 ((2459215j,0s,0n),+0s,2299161j)> 
end_of_n_months_hence(curr_date,  2)
  #=> #<Date: 2021-01-31 ((2459246j,0s,0n),+0s,2299161j)> 
end_of_n_months_hence(curr_date, -1)
  #=> #<Date: 2020-10-31 ((2459154j,0s,0n),+0s,2299161j)> 
end_of_n_months_hence(curr_date, -2)
  #=> #<Date: 2020-09-30 ((2459123j,0s,0n),+0s,2299161j)> 
end_of_n_months_hence(curr_date, 12)
  #=> #<Date: 2021-11-30 ((2459549j,0s,0n),+0s,2299161j)> 
end_of_n_months_hence(curr_date, 13)
  #=> #<Date: 2021-12-31 ((2459580j,0s,0n),+0s,2299161j)> 

I don't know Rails but I expect you could change the operative line of the method to:

  (curr_date >> n).end_of_month
Related