Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is Date.today - 6.months + 6.months != Date.today?

In Ruby, on Halloween:

Date.today - 6.months + 6.months != Date.today

Do we need to update Ruby's date implementation? Do other languages have the same issue?

like image 929
B Seven Avatar asked Oct 31 '11 17:10

B Seven


People also ask

How many month is a year?

A year is divided into 12 months in the modern-day Gregorian calendar. The months are either 28, 29, 30, or 31 days long.

How many days are in a calendar?

There are two calendars--one for normal years with 365 days, and one for leap years with 366 days. Leap years are divisible by 4.


3 Answers

This happens if you do it to any month that doesn't have 31 days (i.e. 3 months would work just fine, but 1 month, or 6, or 8 would all make this happen).

If you do Date.today - 1.month, it looks like Rails sees that 9/31/2011 isn't a valid date, so it kicks it back an extra day to make it a valid date. However, when you go one month forward from the end of September, it'll leave it at 10/30/2011 since that's a valid date. Basically, Rails just tries to increment (or decrement) the month field and as long as it's a valid date, it won't adjust the day field.

One way to work around this is to use the .end_of_month (or .beginning_of_month) method on a Date object in Rails to make sure you're consistently getting the end or beginning of a month.

like image 186
Dylan Markow Avatar answered Oct 19 '22 16:10

Dylan Markow


No, this is expected and this isn't unique to Ruby either - try it in SQL, for example.

(Today - 6 months) is the last day (30th) of April - because there is no 31st. It's only the months we're dealing with, not a precise number of days.

Add 6 months to April 30th and you get October 30th.

Which, as you know is != October 31st.

like image 43
Widor Avatar answered Oct 19 '22 15:10

Widor


This is a weird feature of ActiveSupport time extensions.

> 6.months == 180.days
=> true 

but when you do date math with months, they are considered calendar months, not 30-day periods. Check this out:

> Date.today - 180.days + 180.days
=> Mon, 31 Oct 2011 

See https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/time/calculations.rb#L277 and dig further from there.

like image 6
Leonid Shevtsov Avatar answered Oct 19 '22 16:10

Leonid Shevtsov