When reviewing Rails apps, I often find many uses of
Date.today, each of which comes from Ruby itself. Although these methods seem convenient and accessible, they should be avoided inside of Rails apps, as they aren’t converted to the local time zone set inside Rails.
Imagine the following (admittedly naive) method inside an Order model:
def shipped? shipping_date < Date.today end
Time.now will both use the system time and time zone of the server that’s serving the request. In a cloud environment, this could be the time zone where the servers are physically located or, more commonly, it is simply UTC.
Imagine the application runs for a company based in New York and generally doing business in the Eastern Time zone. At 10 PM Eastern Time on January 17th 2019, one would expect an Order with a
2019-01-17 to not be
shipped? according to this logic. However, if the server time is UTC, the date will have already rolled over and
Date.today is going to return
2019-01-18, thus breaking this method in an unexpected way.
There is an easy solution, however:
Time.zone.now. In any Rails app, where the working time zone is set in
config.time_zone = 'Eastern Time (US & Canada)'
Time.zone.today will be automatically converted to that time zone.
In all cases inside a Rails app, one should use
Time.zone.now instead of
Time.zone.today instead of
Date.today to avoid unexpected bugs and time zone quirks. A good way to enforce the use of the Rails implementations of these is with RuboCop‘s built-in Rails::Date cop. RuboCop can be run locally or in CI. CodeClimate is a great SaaS tool that can run RuboCop and other static analysis for you and prevent merging of PRs that contain improper time zone usage.