Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is Rails time broken for midnight?

Let's look at the date:

1.9.2p320 :008 > Date.today
 => Wed, 03 Oct 2012 
1.9.2p320 :009 > Time.now
 => 2012-10-03 22:32:55 -0400

Now, given that when is midnight?

1.9.2p320 :005 > Date.today.midnight
 => Wed, 03 Oct 2012 00:00:00 UTC +00:00 

Makes sense. But what about yesterday?

1.9.2p320 :006 > Date.yesterday.midnight
 => Wed, 03 Oct 2012 00:00:00 UTC +00:00 

Uh, that doesn't quite make sense. Midnight today is the same as midnight yesterday? You can't be serious!

1.9.2p320 :026 > Date.today.midnight == Date.yesterday.midnight
 => true 
1.9.2p320 :033 > 1.day.ago.midnight == Date.yesterday.midnight
 => true 
1.9.2p320 :034 > 1.day.ago.midnight == Date.today.midnight
 => true 

Oh, you are serious. What about tomorrow?

1.9.2p320 :007 > Date.tomorrow.midnight
 => Fri, 05 Oct 2012 00:00:00 UTC +00:00 

Wait, if midnight today is 00:00 on the 3rd, and midnight yesterday is 00:00 on the 3th, but midnight tomorrow is 00:00 on the 5th, where's 00:00 on the 4th?

Here it is:

1.9.2p320 :010 > 0.days.ago
 => Thu, 04 Oct 2012 02:34:58 UTC +00:00 
1.9.2p320 :011 > 0.days.ago.midnight
 => Thu, 04 Oct 2012 00:00:00 UTC +00:00

but isn't zero days ago today? Apparently not.

Is it me, or is this not at all internally consistent? It seem to me that Date.today should be the same as 0.days.ago.

I understand that days.ago is actually using the Time object, and that this is a time zone issue:

1.9.2p320 :030 > Date.today
 => Wed, 03 Oct 2012 
1.9.2p320 :021 > Time.now
 => 2012-10-03 22:40:09 -0400 
1.9.2p320 :023 > 0.days.ago
 => Thu, 04 Oct 2012 02:40:22 UTC +00:00 
1.9.2p320 :022 > Time.zone.now
 => Thu, 04 Oct 2012 02:40:14 UTC +00:00 

But it seems as though, given that these are convenience functions, it's kind of mean to throw a timezone assumption into one convenience function and not throw it into another convenience function, both of which, by all accounts, mean the same thing.

Even setting that aside, it doesn't seem to explain the fact that Date.today.midnight == Date.yesterday.midnight, which is– quite simply– barking mad.

Since I know that I can't be the first to have been bitten by this, I ask what am I missing?

like image 416
JohnMetta Avatar asked Oct 04 '12 02:10

JohnMetta


2 Answers

Rails will base relative date calculations such as yesterday, tomorrow, and midnight off of Date.current which will attempt to use the configured Time.zone: https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/date/calculations.rb#L46

Since your Time.zone is set to UTC, you won't get the same results as calculations based off Date.today, which will use your computer's clock time, unless you're actually sitting in UTC time.

So, if the time difference between you and UTC is greater than the time to midnight, Date.yesterday and Date.today actually return the same date!

Try setting your Rails time zone with Time.zone = 'Eastern Time (US & Canada)' or whatever time zone you're in and retry your examples.

like image 121
rossta Avatar answered Oct 18 '22 10:10

rossta


rossta identified the culprit. You may have better luck with Time.now.to_date and specifying the time zone if necessary:

> Time.now.in_time_zone("Asia/Tokyo")
  => Thu, 04 Oct 2012 12:54:43 JST +09:00 
> Time.now.in_time_zone("Asia/Tokyo").to_date.midnight
 => Thu, 04 Oct 2012 00:00:00 JST +09:00 
Time.now.in_time_zone("Asia/Tokyo").to_date.yesterday.midnight
 => Wed, 03 Oct 2012 00:00:00 JST +09:00 

> Time.zone = "America/Los_Angeles"
 => "America/Los_Angeles" 
> Time.now.in_time_zone
 => Wed, 03 Oct 2012 20:55:35 PDT -07:00 

> Time.now.to_date # using the system time
 => Wed, 03 Oct 2012 
> Time.now.to_date.midnight
 => Wed, 03 Oct 2012 00:00:00 PDT -07:00 
> Time.now.to_date.yesterday.midnight
 => Tue, 02 Oct 2012 00:00:00 PDT -07:00 
like image 37
zetetic Avatar answered Oct 18 '22 09:10

zetetic