Auto detect a time zone with JavaScript

June 8th, 2007 by Josh Fraser

This blog post will attempt to explain how to automatically detect your user’s time zone using JavaScript. If you’re in a hurry, you can skip directly to the demo or just grab the files

Previous attempts to solve this problem:

Server side:

Time is not included in an HTTP request. This means that there is no way to get your user’s time zone using a server side scripting language like PHP.

IP address geocoding:

Another method that people have used to address this problem is to geocode your visitors IP address. IP geocoding is what is used when you go to a website and are shown an ad to “meet other singles in Boulder”. Unfortunately, for simply detecting a timezone, IP geo-coding is an expensive way to go. Just check out the prices for Maxmind and ip2location. There’s no way I’m paying for that. I did find a free provider called hostip, but it is worthless as it couldn’t decide whether I live in CA or NC.

With JavaScript:

The common JavaScript that is used to detect a visitor’s timezone is:

var myDate = new Date();
document.write(myDate.getTimezoneOffset());

As I started reading up on the getTimezoneOffset code I realized it was too buggy to be used in any critical application. The function returned inconsistent results in different browsers and it never seemed to account for daylight savings time correctly. It quickly became clear that I was going to have to write my own script if I wanted this to work.

How I ended up doing it:

There are basically two things needed to figure out a visitors time zone. First, we need to determine the time offset from Greenwich Mean Time (GMT). This can easily be done by creating two dates (one local, and one in GMT) and comparing the time difference between them:

var rightNow = new Date();
var jan1 = new Date(rightNow.getFullYear(),
    0, 1, 0, 0, 0, 0);
var temp = jan1.toGMTString();
var jan2 = new Date(temp.substring(0,
    temp.lastIndexOf(" ")-1));
var std_time_offset = (jan1 - jan2) / (1000 * 60 * 60);

The second thing that you need to know is whether the location observes daylight savings time (DST) or not. Since DST is always observed during the summer, we can compare the time offset between two dates in January, to the time offset between two dates in June. If the offsets are different, then we know that the location observes DST. If the offsets are the same, then we know that the location DOES NOT observe DST.

var june1 = new Date(rightNow.getFullYear(),
    6, 1, 0, 0, 0, 0);
temp = june1.toGMTString();
var june2 = new Date(temp.substring(0,
    temp.lastIndexOf(" ")-1));
var daylight_time_offset = (june1 - june2)
    / (1000 * 60 * 60);
var dst;
if (std_time_offset == daylight_time_offset) {
    dst = "0"; // daylight savings time is NOT observed
} else {
    dst = "1"; // daylight savings time is observed
}

Once, I had this code written, the next step was to compile a list of the various time zones around the world along with their opinions on DST. I actually ended up using the list of time zones from Microsoft Windows. It was rather time consuming to compile this list, so I hope you can make use of my work to save yourself some time.

Please let me know if you have any comments, questions or problems with this code. As with anything that I post on this blog, feel free to use this code however you want. Just don’t blame me if it breaks.

Update (06/27/07):

My code wasn’t correctly detecting timezones in the lower hemisphere.  I  have added hemisphere detection for all our Aussie friends out there.  I also fixed a bug in the convert() function that was leaving off the + sign at certain offsets.  Thanks Val for pointing this out and helping me with the fix.

29 Responses to “Auto detect a time zone with JavaScript”

  1. Mahesh Says:

    Hey this script really helped me .. thanks

  2. Val Says:

    Hi,
    Excellent code, but one mistake exist I think.
    For southern hemisphere summer and winter are different.
    So if you swap daylight_time_offset and std_time_offset - it will work for southerners, but will not for northerners:-)
    Probably checking the sign of difference for Jan and July will allow to detect hemisphere (if daylight savings exist at all).
    Also not sure why Brisbane in HTML has no daylight savings?
    Cheers,
    Val.

  3. joshfraz Says:

    Val,

    Thanks for your comment. You are right that summer and winter take place at different times in each hemisphere. However, my code should work correctly in both hemispheres. Let me try and explain.

    Take Antarctica for example. Their DST goes from Sept 30 - March 18. My code compares the time on Jan 1st (during DST) to the time on June 1st (not during DST). Since these times are different I know that DST is observed. I don’t care if it is observed during summer or winter. I only care that that the two times are different. The same formula works whether DST occurs from March to Sept or Sept to March.

    I double checked Brisbane on timeanddate.com and it says that they are not observing daylight saving time in 2007. This of course could be wrong. I would appreciate it if you can send me more information about that.

    Take care,
    Josh

  4. Val Says:

    Josh,
    I already tried and it did not work.
    The proof: just set your comp timezone to Adelaide, open your test page
    and your HTML will show the first item: (-12:00)Iternatioal Date Line West.
    (Adelaide is +9:30,1 by the way according to your JS values).
    If you check the HTML source, you will see, that none of the items in the combo are selected.
    If you put an alerts in JS, you will see, that TZ detected is: ‘+10:30,1′. This value does not exist in HTML, so JS can not select the combo value.
    If you change the JS script and swap the values of variables how I described before, it will work for Adelaide.
    Cheers,
    Val.

  5. Erica Says:

    Hi! Good site respect! Visit welivetogether.com and addictinggames.com Thanks!

  6. Neil Says:

    Thanks for putting up this script! It was really helpful and saved me a lot of time.

  7. ThomasMobley Says:

    I’m looking for something similar for my comments section, so I can show the user the time something was posted in their own time reference. I should think just saving the time of post in UTC, then at the client side use the difference between local time and utc would give me the proper offset to use when I pull the comments from the db. No need to worry about dst or hemispheres that way. Sound correct?

  8. Josh Fraser Says:

    Thomas,
    No, you will still need to worry about both DST and hemispheres. Your offset from GMT would vary by 1 hour depending on whether or not you are in DST. You also need to worry about hemispheres since DST occurs during different times of year for each hemisphere. The good news is that my code should give you a nice head start on getting your times right on your comments.

  9. ThomasMobley Says:

    I actually needed a way for people loading my page to see the times that comments were posted in their own time. My server is west coast and I’m east coast, so I noticed I would post and it was -3 hours off. I’ve written some ajax now that gets the cleints current time, finds the difference betwent that and the utc time, and loads the div that shows comments to my page and uses that to offset to show the time a post was made. The offset is hardcoded to -240 right now, but I’m working on the difference between utc and current client time right now. I think that should make all neccessary corrections, though I may be missing something. If utc is X and my current time is Y, I think I should be able to use that difference to offset the time a post was saved (in utc) in order to show the time that post was saved in the clients time frame. Please correct me if I’m mistaken.

  10. Josh Fraser Says:

    Thomas,

    I think you’re still missing the issue here.

    It is the offset between the client time and UTC/GMT that changes with DST. The hemisphere determines when that change will occur. (DST is always observed in the summer, but Christmas is in the summer in the lower hemisphere).

    A good case to think about is Arizona. Arizona is in the same timezone as I am (-07:00 GMT), but they don’t observe DST. That means as I am writing this comment at 6:30pm it is 5:30pm in Arizona. Basically, you need to consider more than just the raw offset from GMT. You can’t just ignore DST if you want your script to work consistently no matter where you are.

    Change the clock on your computer to test various timezones. If you can get your script to work correctly with Arizona, California and Australia, you’re probably okay.

  11. Swobo Says:

    Great script. Works like a champ! I’m trying to get it to write out the actual timezoneName when you submit it to a formMailer. It only submits the value for the array. Any suggestions?

    Thanks!

  12. Josh Fraser Says:

    Swobo,

    The form is currently submitting the offset from GMT and a 0 or 1 for whether it supports DST or not. So Denver, CO is “-07:00,1″. (-7 for the offset, 1 for DST boolean)

    You have a couple options:

    - Include the name of the timezone in the dropdown. For example:

    OR (probably a better solution)

    - Map each of the select options back to their names on the server side. For this, you would need to create an array for each possible selection and map it back to its respective name. In PHP you would do something like:

    $timezones[’-07:00,1′] = “Mountain Time (US & Canada)”;
    etc…

    I hope that helps.

  13. Bob Says:

    Hey Josh. Heck of a script. Thanks for sharing. What’s the licensing? Can I use this as part of a commercial site? Also, I’m trying to map these back to abbreviations, but I’m having a heck of a time finding the correct abbreviations for these. Do you happen to have any mapping like that?

  14. Josh Fraser Says:

    Bob,
    Feel free to use this script however you like. There are no limits on it. Just don’t blame me if it breaks. :)

    I wish I could help you with the mapping. That would definitely be a good thing to have. Unfortunately, I’ve not seen anything like that around. If you manage to find it, let me know and I’ll update the post to help some other people out.

  15. Rama Says:

    First of all thanks for your script.
    One thing for -10:00 ,-11:00 ,-12:00 the convert function is returning +-10:00,
    +-11:00,+-12:00
    to rectify that one i added one line of code in the convert function as below:

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    if(hours > 0) {
    display_hours = (hours 0) ? “+0″+hours : “+”+hours; // positive
    }
    ————————————————————————————————————

    Thanks Josh Fraser once again for you script.

  16. Jason Says:

    It really cool! thanks!
    I do have a question which is - does it detect the summer time for EU / Asian countries as well?

  17. Josh Fraser Says:

    Jason,
    Yes, as long as the time is set correctly on the local computer.

  18. Richard Says:

    Hi, I have a question:
    Because javascript is a client side script, this timezone detection actually occurs after the first request and response from the server, when the browser loads this script and executes it. My problem is I want to send the first request with timezone info, guess there’s no way to do that, huh?

  19. Josh Fraser Says:

    Richard,

    A couple tricks to be able to automatically use their timezone on the server side:
    - get the timezone on a page that is visited earlier and save it into a session cookie
    - save the timezone and force a refresh on a page
    - save the data to the server via AJAX

    What are you trying to do exactly? I may be able to suggest a better fitting solution to your problem.

  20. Raj Says:

    Thanks bunches!
    Have you or anyone found a mapping to the abbreviations? I am having a hard time getting it from the internet.

  21. Josh Fraser Says:

    Raj,

    The best resource I know of is:
    http://www.twinsun.com/tz/tz-link.htm

    There’s also a lot of useful information at:
    http://us.php.net/manual/en/function.timezone-identifiers-list.php

    Hope that helps!

  22. Tas Says:

    “As I started reading up on the getTimezoneOffset code I realized it was too buggy to be used in any critical application. The function returned inconsistent results in different browsers and it never seemed to account for daylight savings time correctly. It quickly became clear that I was going to have to write my own script if I wanted this to work.”

    Sorry but I think you are re-inventig the wheel. I tested this code in IE and FIREFOX they seem to return the same result for where I live 420, that’s PDT. what browsers did you use?

  23. Josh Fraser Says:

    Tas, change the clock on your computer to Arizona time and see if you still feel that way. :)

  24. Tas Says:

    Did change the clock to Arizona time and it’s still consistent results. 420 offsets in both IE 7 and FIREFOX Mozilla 5.0. win xp.

    considering vancouver, bc is on PDT, it should match the time in Arizona. that’s why I get 420 offset each way which is correct.

    are you suggesting Javascript has a bug that is not documented?

  25. Josh Fraser Says:

    Tas,
    So PDT and Arizona are both 420 minutes (7hrs) from GMT? I think we both know that’s not true. The reason you got the same value for 2 very different timezones is that the most browsers (older versions of IE don’t) go ahead and factor DST into the offset. This also means that you get different results depending on the time of year. My goal with writing this function was to make something that works in all browsers and returns consistent results regardless of the time of year. It also separates timezone offset and DST into separate variables — something that isn’t possible using only gettimezoneoffset().

  26. Mike Says:

    downloaded the index.html & detect_timezone.js today (06/01/2008)
    ==

    bug?…
    In the calculate_time_zone function…
    “if (hemisphere >= 0) ” ….missing the IF’s starting {
    and then also added } before the function end to properly end the prior ELSE

  27. Mike Says:

    looks like my above entries…screwed up other stuff…
    dealing with the DST calcs…backed them out.
    Why tie Hemisphere to whether the system is currently on DST?
    and if not curently on DST my -6 CST-US would report as -6 CST-Central Am ???
    ===
    my system (WIN-XP) has 5: (GMT -6:00 CST) entries
    Central America
    Central Time (US & Canada)
    Central Time Guadalajara, Mexico city, Monterrey - New
    Central Time Guadalajara, Mexico city, Monterrey - Old
    Central Time Saskatchewan
    ===
    If change my system to any - all go to CST US
    ===
    also have bunches of other TZ’s in list, that are not in the OPTION list.
    So this has not been updated, since all of the TZ changes from MS in 2007?

  28. Josh Fraser Says:

    Mike,

    No, that’s not a bug. It’s just an if-statement without braces.

    You do bring up a good point that people should understand. This script works under the presumption that you are only wanting to store the GMT offset and the DST boolean.

    This script condenses multiple timezones in order to have only 1 primary key on GMT offset/DST. While this usually works in practice, you do loose some accuracy in knowing an exact TZ.

  29. Justin Says:

    Josh,

    Great script. Is there anyway to modify the script to only use US timezones? I have the following timezones in my database, and I want to match the client to one of these timezones. The exceptions, Indiana and Arizona do not have their own timezone in my database, they simply fall into a standard zone. Thanks.

    AKST ALASKAN STANDARD TIME -9
    AST ATLANTIC STANDARD TIME -4
    CST CENTRAL STANDARD TIME -6
    EST EASTERN STANDARD TIME -5
    HST HAWAII-ALEUTIAN STANDARD TIME -10
    MST MOUNTAIN STANDARD TIME -7
    PST PACIFIC STANDARD TIME -8
    AKDT ALASKAN DAYLIGHT SAVING TIME -8
    ADT ATLANTIC DAYLIGHT SAVING TIME -3
    CDT CENTRAL DAYLIGHT SAVING TIME -5
    EDT EASTERN DAYLIGHT SAVING TIME -4
    PDT PACIFIC DAYLIGHT SAVING TIME -7
    MDT MOUNTAIN DAYLIGHT SAVING TIME -6

Leave a Reply