Rails, timezones, and existentialism
As part of my day job working on Postmark, we encountered an odd issue in our Rails app. After a bunch of debugging and narrowing down the problem, we got it to the simplest example we could get.
What’s this? Today isn’t today?
Luckily, Ruby and Rails are open source. So, we can do some digging and figure out wtf is going on.
Let’s see what’s going on in Date.today
. We see that this method is part of Ruby’s standard library, which is written in C. I’m not familiar at all with C, but I found a great Stackoverflow post by Andrew Marshall which helps explain things. The important part of the code for us to pull out is that Date.today
uses the localtime
function, which returns values in the computer’s timezone. So, whatever timezone the server is set to, Date.today
will return that date.
Now, let’s take a look at #today?
. This isn’t part of Ruby’s standard library, but a part of Rails.
So, it compares the date of the server’s timezone to ::Date.current
. Date.current
is also defined in Rails
Now, we’re getting somewhere. If a time zone is set, then #today?
compares the server’s date to a date in an arbitrary timezone. The date of where I’m currently sitting isn’t going to be the same date of everyone in the world.
In our controller logic, we set Time.zone
equal to the user’s preferred timezone. So, for users in Australia who are in a UTC+11 timezone, it was quite often that #today?
returned false.
For our use case, we updated the code to use Date.current
instead of Date.today
. This way date comparisons were all made in the user’s timezone and we stopped questioning the meaning of time.