Configuring timezones in rails can be tricky if one doesn’t understand the actual config settings and their use.
Time can also get really confusing when used in Rails app.
Consider Time.now and Time.zone.now
Time is a ruby library hence
Time.now will return system’s time. To change that for your Rails app use
Say, I have a server in UTC and all my users are in IST then my rails app
time_zone should be like,
#config/application.rb config.time_zone = ‘IST’
In Rails console,
Time.now #returns time in UTC
=> 2015-07-12 11:26:05 +0000
Time.zone.now #returns time in IST
=> Sun, 12 Jul 2015 16:56:46 IST +05:30
In fact, in rails use
Time.current which is a mix of both. Read code here.
ActiveRecord and DB timezones
(Considering MySQL here)
By default, our DB picks system’s timezone (here UTC) and our application here is using IST. Hence when we save a time using Rails app in IST, it actually is saved in UTC in our DB.
So ideally, if we have a time saved in DB as 2015-07-12 11:26:05 +0000 then we should retrieve this in our rails app (in IST) as datetime object Sun, 12 Jul 2015 16:56:05 IST +05:30.
There is another setting in Rails,
config.active_record.default_timezone, with default value as
:local (picks system’s timezone). This config is responsible to identify timezone for our ActiveRecord datetime objects.
So lets say, our DB is on another server with system timezone as UTC and our application is now on a server with system and application timezone as IST, which now means
Time.zone.now are same.
In this case,
config.active_record.default_timezone has value as IST (
:local) which will tell our system that the datetime values we are getting from DB are in IST timezone. Hence it will just convert the timezone of the value and not the datetime value itself resulting in wrong results,
- Actual datetime value in DB, 2015-07-12 11:26:05 +0000 (which is considered in IST timezone by our app due to active_record.default_timezone)
- Retrieved datetime value in app, Sun, 12 Jul 2015 11:26:05 IST +05:30
To handle these situation we just have to set,
#config/application.rb config.active_record.default_timezone = :utc
And now the expectation of ActiveRecord datetime object’s timezone from our app will be of UTC which is actually same as DB’s timezone.