Detecting Browser Time Zone with Rails

I recently revisited the problem of detecting browser time zone because I wanted to try the new time zone functionality in Rails 2.1. I found this post from Dave Johnson. To my disappointment this was the same solution Spongecell used in the personal calendar 3 years ago.

I wanted a simpler solution: one that doesn’t require a js cookie library, nor around filters, nor a UI with a combo box with 100s of time zone choices.

The solution presented is to send browser info using jquery and then storing the time zone in the session for use in all subsequent requests.

in the view (this is haml), this can be in your layout on all pages:

    - unless @time_zone
      = javascript_tag "$.get('/controller/time_zone',
      'offset_minutes':(-1 * (new Date()).getTimezoneOffset())})"

in the controller:

 before_filter :init_time_zone
  #sets the time zone for this request if a session time zone exists
  #if it doesn't the default is UTC

  def init_time_zone

    @time_zone = ActiveSupport::TimeZone[session[:time_zone_name]] if session[:time_zone_name]

    Time.zone = @time_zone.name if @time_zone

  end

  #this receives browser info from a jquery request and stores 

  #time zone info in the session
  def time_zone

    offset_seconds = params[:offset_minutes].to_i * 60

    @time_zone = ActiveSupport::TimeZone[offset_seconds]

    @time_zone = ActiveSupport::TimeZone["UTC"] unless @time_zone

    session[:time_zone_name] = @time_zone.name if @time_zone

    render :text => "success"

  end

in the formatter:
  def format_time(t)

    return "" unless t

    return t.in_time_zone.strftime('%Y-%m-%d %H:%M:%S %Z')

  end

Look how simple that is! I choose to default the time zone to UTC if one cannot be determined on the first attempt. Now the formatter will output all the UTC times you have in your db or anywhere in the user's browser's time zone.

If there is a better solution in Rails please let me know. We 'll see if this solution works for daylight saving time.

About these ads

6 Responses to Detecting Browser Time Zone with Rails

  1. noOne says:

    Hey,

    im implementing your code, and it works.

    But could you give me some hint how to do the javascript part with prototype?

    I do it like:

    var pars = ‘offset_minutes=’ + (-1 * (new Date()).getTimezoneOffset());
    new Ajax.Request(‘/controller/time_zone’, {
    method: ‘post’,
    parameters: pars});

    but with the ajax call render :text => ‘success’ is not really working, it displays the success text if called.

    thanks for your help!

  2. Chris Hobbs says:

    My prototype skilz are a little rusty but you could make the time_zone action return “” instead of “success” or post to a hidden div.

  3. Chris Hobbs says:

    Here’s a fix for DST:

    def time_zone
    offset_seconds = params[:offset_minutes].to_i * 60
    @time_zone = ActiveSupport::TimeZone.all.find { |z| ((z.now.dst? && z.utc_offset == offset_seconds-3600) || (!z.now.dst? && z.utc_offset == offset_seconds)) && ![“Arizona”,”Chihuahua”,”Mazatlan”].include?(z.name)}
    @time_zone = ActiveSupport::TimeZone[“UTC”] unless @time_zone
    session[:time_zone_name] = @time_zone.name if @time_zone
    render :text => “success”
    end

    You can see it ignores some time zones so that Denver will be picked above Arizona. Sorry Arizona.

    A more complete solution would have the browser detect if it’s in a tz that recognized dst. I’m going to have to write a plugin for all this.

  4. Mark says:

    Hi,

    Just ran into a similar problem. Have you seen a different solution?

    I am having a problem in that I need the TZ in the first page, and the TZ doesn’t exist until the page is loaded (and the javascript is executed).

    Any ideas? Thanks!

    • Chris Hobbs says:

      I’ve been thinking about tz formatting a little recently. I’d like to get the time zone from a service like simplegeo.

      For your problem I think you’d have to reload the page or reformat the times with js once time zone info is available. Perhaps use an intermediate page or div that displays “Loading…”.

      Alternatively, the server could make a call to simplegeo using the ip address of the client to get time zone.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: