How Rails Works #1: A Timezone Overview

December 31st, 2008 by Radar

Today fowlduck and I were talking in the #rubyonrails channel and we both wondered about timezones and why they were so (apparently) screwy. It turns out all I (and he possibly also) forgot to do was to put config.timezone in the config/environment.rb. So what does this mysterious method do? Well:

In Rails 2.2…

  • 1. The Configuration Class
    This class begins all the way down on line #578 of railties/lib/initializer.rb in the Rails source. This just simply defines a class in the Rails module called Configuration. What we can get really excited about is on line #748 it defines an attr
    accessor for :timezone. This, as you probably already know defines two methods a setter (timezone=) and a getter (time_zone) in which we can store values.
  • 2. Your config/environment.rb file
    By default this timezone method will be set to nil. It’s up to you to set it in your config/environment.rb file which you do by doing something along these lines:
    Rails::Initializer.run do |config|
      config.timezone = "Adelaide"
    end
    

    This will set the timezone value to be the Adelaide Time zone, something like: #<ActiveSupport::TimeZone:0x30f4f8 @tzinfo=nil, @name=”Adelaide”, @utcoffset=34200>. You don’t have to set it to Adelaide, just try your nearest major city and it Should Just Work ™. If you don’t set this in your config/environment.rb date and time values returned from the database will not be set to whatever time zone you specify.

  • 3. Back to you, Jeff. When your application loads it processes the config/environment.rb file and runs the initializetimezone method which is defined further down. This does all kinds of magic! Look at all the pretty sparkles! It firstly checks if you’ve set a timezone in your config/environment.rb file and then if you have it sets the default time zone to be what you’ve specified. Additionally to this, it sets timezoneawareattributes to true so that when you do stuff like Topic.last.createdat it’ll actually return the time zoned version of that time. It does this by calling into play definereadmethodfortimezoneconversion(attrname) (click for juicy details) which either just returns the time or calls intimezone on the time returned which converts it into the time zone stored in Time.zone (which is actually Thread.current[:timezone] if there is one stored there or otherwise the zonedefault which was originally set when we called config.time_zone! What a mouthful!

    By default, ActiveRecord will store timestamps as UTC as shown by ActiveRecord::Base.default_timezone = :utc. If you don’t specify a time zone in your config/environment.rb this value defaults to :local, so all times will be stored as the local time in your database.

  • 4. And then… So, assuming you did as the above when you go into your script/console and type: Topic.last.createdat you’ll get back the time when the topic was created relative to Adelaide. To change this, just redefine Time.zone by doing Time.zone= “Paris” and then doing Topic.last.createdat will give you time when the topic was created relative to Paris.

Changelog

Updated on April 23rd, 2009 1. Fixed line number linkings, linking directly to 2-2-stable branch which, ideally, should now never change.

Tags:

Leave a Reply