Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I determine a timezone by the UTC offset?

Tags:

I have a scenario where I have a timezone offset (in minutes) and need to determine the timezone for it. I know that all the data is not available (for example, there may be several timezones with an offset of -240 minutes) but a "best guess" is acceptable.

My first pass looked like this:

foreach (var info in TimeZoneInfo.GetSystemTimeZones())
{
    if (info.BaseUtcOffset.TotalMinutes == timezoneOffset)
    {
         // do something here if this is a valid timezone
    }
}

This sorta works, but I need to account for daylight savings which is throwing me off somewhat. I added this terrible hack:

foreach (var info in TimeZoneInfo.GetSystemTimeZones())
{
    var extra = info.IsDaylightSavingTime(DateTime.Now) ? 60 : 0;
    if (info.BaseUtcOffset.TotalMinutes + extra == timezoneOffset)
    {
         // do something here if this is a valid timezone
    }
}

This works "well enough" in that I can show the user the correct time for them when daylight savings is not in effect and am about 70% correct during DST. Still... this is some awful code to my eyeballs.

Is there a better way to do this? More elegance would be good, and more accuracy would be better still.

Update

Technically I have access to any information Javascript can get regarding the date. I have a page on which I've placed a hidden field called "offset". I have a JQuery function that populates the offset field with the DateTime().getTimezoneOffset(). While I don't see anything on the DateTime object that will help, perhaps this will open other avenues for ideas.

like image 923
Sailing Judo Avatar asked Aug 13 '09 21:08

Sailing Judo


2 Answers

Short answer: you can't.

Daylight saving time make it impossible. For example, there is no way to determine, solely from UTC offset, the difference between Arizona and California in the summer, or Arizona and New Mexico in the winter (since Arizona does not observe DST).

There is also the issue of what time different countries observe DST. For example, in the US DST starts earlier and ends later than in Europe.

A close guess is possible (i.e. +/- an hour), but if you are using it to display time to users you will inevitably display the wrong time to some of them.


Update: From the comments, it looks like your primary goal is to display a timestamp in the user's local timezone. If that is what you want to do, you should send the time as a UTC timestamp, and then just rewrite it on the user's browser with Javascript. In the case that they don't have Javascript enabled, they would still see a usable UTC timestamp. Here is a function I came up with in this question, which I used in this Greasemonkey script. You may want to tweak it to suit your needs.

//@param timestamp An ISO-8601 timestamp in the form YYYY-MM-DDTHH:MM:SS±HH:MM
//Note: Some other valid ISO-8601 timestamps are not accepted by this function
function parseISO8601(timestamp)
{
  var regex = new RegExp("^([\\d]{4})-([\\d]{2})-([\\d]{2})T([\\d]{2}):([\\d]{2}):([\\d]{2})([\\+\\-])([\\d]{2}):([\\d]{2})$");
  var matches = regex.exec(timestamp);
  if(matches != null)
  {
    var offset = parseInt(matches[8], 10) * 60 + parseInt(matches[9], 10);
    if(matches[7] == "-")
      offset = -offset;

    return new Date(
      Date.UTC(
        parseInt(matches[1], 10),
        parseInt(matches[2], 10) - 1,
        parseInt(matches[3], 10),
        parseInt(matches[4], 10),
        parseInt(matches[5], 10),
        parseInt(matches[6], 10)
      ) - offset*60*1000
    );
  }
  return null;
}

Here is a function I use on my blog to display a parsed timestamp in the user's local timezone. Again, you can tweak it to the format you want.

var weekDays = new Array("Sunday", "Monday", "Tuesday", "Wednesday",
        "Thursday", "Friday", "Saturday");
var months = new Array("January", "February", "March", "April", "May", "June",
        "July", "August", "September", "October", "November", "December");

function toLocalTime(date)
{
  var hour = date.getHours();
  var ampm = (hour < 12 ? "am" : "pm");
  hour = (hour + 11)%12 + 1;

  var minutes = date.getMinutes();
  if(minutes < 10)
    minutes = "0" + minutes;

  return weekDays[date.getDay()] + ", "
       + months[date.getMonth()] + " "
       + date.getDate()          + ", "
       + date.getFullYear()      + " at "
       + hour                    + ":"
       + minutes                 + " "
       + ampm;
}
like image 118
Kip Avatar answered Nov 05 '22 19:11

Kip


Knowing just the offset from UTC, you can't tell what timezone you are in, because of DST. You could consider looking at the time part of the time to try to guess whether DST was in effect then or not, but political considerations make that nearly impossible, as different jurisdictions change the definition of DST.

like image 35
Ned Batchelder Avatar answered Nov 05 '22 20:11

Ned Batchelder