8

Can I make Rails apply the same logic to my calculation in seconds as it does to my calculation in years?

puts "#{1.year.from_now} | #{1.year.to_i.seconds.from_now}"
 2017-03-23 18:48:06 UTC | 2017-03-24 00:48:06 UTC

I don’t understand where the 6-hour difference comes from.

djb
  • 5,591
  • 5
  • 41
  • 47

1 Answers1

11

The difference is 6 hours. And it is because 1 year in seconds (as converted by the to_i method) is defined as 365.25 days in Ruby on Rails core extensions:

>> 1.year.to_i / 60 / 60 / 24.0
=> 365.25

Those 0.25 days is the actual 6 hours difference. By doing this, RoR is trying to count in the leap years which (by basic approximation) occur once in 4 years. The same is also evident from the years definition in Rails source code.

On the other hand 1.year.from_now does a shift of a concrete calendar datetime instead. As if you turned pages on your wall calendar.

Community
  • 1
  • 1
Matouš Borák
  • 15,606
  • 1
  • 42
  • 53
  • 1
    Thank you. For the record, I was storing duration in seconds in a table and wanted it to be applied intelligently when I used it. I don't need precision above months, so I've ended up with `(duration.to_i / 1.month.to_i).months.from_now`. – djb Mar 23 '16 at 19:42
  • That's terrible. Good to know, and great answer, but still terrible. – Matt Johnson-Pint Mar 23 '16 at 23:47
  • @Matt Why? It seems quite reasonable to me as the `1.year` expression means just an abstract amount of time that does not relate to any concrete date and time. So ruby tries to account for leap years that usually occur once in 4 years. If it were not doing that (if `1.year` would be equal to just `365.days`) than a longer time range expression would be seriously wrong, e.g. `now + 10.years` could be off by 2 days. – Matouš Borák Mar 24 '16 at 05:42
  • 2
    Two reasons really. 1) No year has any fractional amount of days. It's either 365 days or 366, depending on which year you're talking about. The length of the average year is only useful when estimating, and if you're estimating then getting a result in seconds is too fine-grained precision. 2) 365.25 is the average length of the year on the *Julian* calendar. Most of us use the *Gregorian* calendar, which has an average year length of 365.2425 days. – Matt Johnson-Pint Mar 24 '16 at 16:32