Forum: Ruby on Rails Re: Inferring timezone for HTTP headers

Announcement (2017-05-07): is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see and for other Rails- und Ruby-related community platforms.
364025223fa593e2e76111b31d76f406?d=identicon&s=25 Piet Hadermann (piet)
on 2007-01-11 09:36
(Received via mailing list)
You could also do a javascript redirect, sending the browser's local
time as a parameter and storing the difference with servertime in a
session variable.
And then everytime you need to display a time, add (or subtract) the

No example at hand, but I've done something like this in the past.



[] On Behalf Of Hammed Malik
  Sent: donderdag 11 januari 2007 5:24
  Subject: [Rails] Re: Inferring timezone for HTTP headers

  You could use javascript to transform the date into the client's
timezone. This post on _why's blog describes how to go about doing this:


  On 1/11/07, Veera <> wrote:


    I am encountering the classic 'hosting timezone
different from customer
    timezone' problem. The hosting timezone is CST, but
users all over the
    world are visiting the site.

    I understand I can make the Timezone selection a user
preference and use
    TZInfo ( to do the math.

    But, is there anyway to infer the client timezone from
the HTTP headers
    or the request object?


    Posted via
91a296784a35bb4efb6221abc282127d?d=identicon&s=25 Adam Greene (Guest)
on 2007-01-19 16:30
(Received via mailing list)
this is a tricky problem.  What you are probably interested in is
guessing someone's 'locale', not their timezone.  The reason is that
most locales change timezones once every year; but not all do.  Your
servers current timezone might be CST, but chances are that in a few
months it will switch to CDT.  Same with most of your clients.  Then it
gets even more complicated because when timezones switch is constantly
changing.  The USA, for one, is stipulating a change this year.  And to
make it even more complicated, you have 'odd' cases where places like
Arizona don't change their timezone at all throughout the year, while
other states like Indiana have 5 different locales (some areas don't
change timezones, others are in easter, some in central, etc).  It is

So, with that in mind, one solution, that as far as I know works for
almost all cases (see below for disclaimer ;) is this:
* have the client, in javascript, compute the UTC offset for two dates,
'2005-06-30' and '2005-12-30' (or any date that will always be in one
timezone and another date that will be in the other)
* using the two offsets, search through all possible locales for that
which has the same winter and summer UTC offsets.

For example:
summer_offset == -21600
winter_offset == -20600
matches the America/Los_Angeles locale

summer_offset == -21600
winter_offset == -21600
matches the Pacific/Galapagos locale

summer_offset == 34200
winter_offset == 37800
matches the 'Australia/Yancowinna' locale

this works, but isn't perfect because it is possible to match multiple
locales.  But you might be able to use a trimmed down list of locales
that highlight only the major ones.  The other catch is that you are
choosing two dates (in our case '2005-06-30' and '2005-12-30') which
you assume will always be in one timezone or the other; but what if
that is not always the case.  As far as I know it is *currently* the
case, but when timezones switch for different locales is always
changing, so this solution might not be future proof.

I have my logic so when a user registers for an account, I figure out
their current timezone.  I have two hidden form fields called
'summer_offset' and 'winter_offset'.  Then in javascript I do this:
try {
  $('summer_offset').value = -1 * (new Date(Date.UTC(2005, 6, 30, 0, 0,
0, 0))).getTimezoneOffset() * 60; // in seconds
  $('winter_offset').value = -1 * (new Date(Date.UTC(2005, 12, 30, 0, 0,
0, 0))).getTimezoneOffset() * 60; //in seconds
} catch (e) {}

in my controller, I pass the parameters to this method, which will spit
out a string containing the locale identifier:

  # trying to automatically determin a users time zone
  # this is possible, but note that the locale might be off (say the
local is America/Boise, but it chooses America/Denver instead)
  # if a timezone is not found, will return nil... you can then set the
default timezone to whatever you want: UTC perhaps?
  def find_time_zone(winter_offset, summer_offset)
    default_tz = nil
    return default_tz if winter_offset.blank? || summer_offset.blank?

    # look at two dates that will, by and large, reside *between* major
time changes within a zone.
    # ie, they won't fall on a day where the time is actually changing
    summer_date = "2005-06-30".to_time
    winter_date = "2005-12-30".to_time
    winter_offset = winter_offset.to_i
    summer_offset = summer_offset.to_i
    # this comes from the client, where they should have something like
so (for a html client):
    # $('summer_offset').value = -1 * (new Date(Date.UTC(2005, 6, 30,
0, 0, 0, 0))).getTimezoneOffset() * 60;
    sd_offset, wd_offset = nil
    # need to go through each timezone and find a match for the summer
and winter offsets
    default_tz = nil
    TZInfo::Timezone.all.reverse.each do |tz|
      # get the summer date and winter date total utc offset for the
      # This includes the utc offset plus any change with daylight
      sd_offset = tz.period_for_local(summer_date,
      wd_offset = tz.period_for_local(winter_date,
      # at first I thought I had to have this if PLUS another one where
the == were mixed like:
      # sd_offset == winter_offset && wd_offset == summer_offest.  This
check is not needed
      # because the summer_date and winter_date are aligned between the
client and the server.
      if sd_offset == summer_offset && wd_offset == winter_offset
        default_tz = tz

    unless sd_offset.blank? || wd_offset.blank?
      #THIS is a _tad_ elitest.  Ccan the US zones to try and better
match the locale.
      #If a timezone matches in the US, use THAT locale...otherwise use
the original one
      new_time_zone = TZInfo::Timezone.us_zones.find do |z|
        z.period_for_local(summer_date, false).utc_total_offset ==
sd_offset &&
        z.period_for_local(winter_date, false).utc_total_offset ==
      #we can add other 'cleanup' loops here if needed....
      default_tz = new_time_zone unless new_time_zone.blank?
    default_tz.blank? ? nil : default_tz.identifier

its a heavy approach, but it is the most complete that I could come up
with.  Let me know if you think it would work for you.

This topic is locked and can not be replied to.