JavaScript Time Zone Conversion with Walltime

Time is important.  Keeping accurate time has been one of the major challenges of technology throughout all of history.  Here’s a little history lesson from the US Navy:

Naval Observatory

In 1845, at the request of the Secretary of the Navy, the Observatory installed a time ball atop the 9.6-inch telescope dome. The time ball was dropped every day precisely at Noon, enabling the inhabitants of Washington to set their timepieces. Ships in the Potomac River could also set their clocks before putting to sea. The Observatory’s Time Service was initiated in 1865. A time signal was transmitted via telegraph lines to the Navy Department, and also activated the Washington fire bells at 0700, 1200, and 1800.

For the Navy, time is important for navigating all those ships around the globe.  For Sprout Social, time is important because we have some pretty cool technology that determines the optimal time to send a tweet or Facebook post to get the most reach for our customers.

Time in the Browser

Right now, browsers can give you pretty accurate time information for the time zone currently configured on your computer.  The problem comes in when you need to know what time it is in another time zone than your own.  For instance, if I’m a user in Australia, and I want to post something at 3:00 AM Chicago time, where the majority of my followers are, how do I calculate that accurately with JavaScript and send it up to the server?

Daylight Savings and Olson Files

It turns out, the hard part of these equations is determining the daylight savings offset for a given time zone.  We already have a really easy way to get UTC for any time in JavaScript; the problem is determining if another time zone than our own currently has a daylight savings rule applied.  Otherwise, we could just keep a map of all the time zone offsets and apply the different offsets to our UTC – back and forth.

It turns out, there is a group of files that keep a record of all the daylight savings rules across the world just for this kind of thing:

The tz database, also called the zoneinfo database or IANA Time Zone Database, is a collaborative compilation of information about the world’s time zones, primarily intended for use with computer programs and operating systems. It is sometimes referred to as the Olson database after the founding contributor Arthur David Olson.

The problem is that no one has really implemented using them in JavaScript yet (there is another library called timezone-js, but it turns out they are not applying the rules properly).

Introducing Walltime-js

Walltime makes it easy to convert from one UTC date to the “wall time” of just about any time zone:

In addition, what if we need to convert from a local time zone time in another time zone than your own to a UTC time?  We’ve got you covered there too:

Make sure to check out the source on Github and file any issues you may find.

11 thoughts on “JavaScript Time Zone Conversion with Walltime

  1. Hi, thanks for your JS libray, I’m currently trying to use it in a project I’m working on but I’m tearing my hair out trying to get a UTC date to display correctly based on a passed timezone. I can’t seem to understand what’s going wrong, is it something to do with my understanding of dates or the implementation in WallTime!?

    For example when I try this:
    new Date(1333116000000).toUTCString()

    I get “Fri, 30 Mar 2012 14:00:00 GMT” which is as expected.

    However when I try:
    WallTime.UTCToWallTime(1333116000000, ‘Europe/London’).toUTCString()

    I get “Fri, 30 Mar 2012 15:00:00 GMT” which seems incorrect.

    Note, the clocks in London UK went forward at 1am 31st March 2013 so up until then GMT was the same as UTC.

    I’ve tried this in FireFox 18 and IE 7

    Any ideas? Your help would be extremely appreciated

    Thanks!

    • > WallTime.UTCToWallTime(1333116000000, ‘Europe/London’).toUTCString()

      WallTime “wraps” a native date object and only uses UTC methods to set and hold the values so that browser time settings won’t affect it. If you inspect the returned object you’ll see both a `utc` and `wallTime` object that hold the original utc time passed in, and the wallTime date object we are wrapping.

      If you want the original UTC string, try `WallTime.UTCToWallTime(1333116000000, ‘Europe/London’).utc.toUTCString()`, if you want the walltime (actual wall time string) you’ll also want toUTCString but on the wallTime object; `WallTime.UTCToWallTime(1333116000000, ‘Europe/London’).wallTime.toUTCString()`

      Hopefully that is not too confusing. Just remember that the wallTime object is only relevant when reading the UTC values of it. You can check the source at https://github.com/sproutsocial/walltime-js/blob/master/lib/olson/timezonetime.coffee#L10-L28 to see how we pass through most of the functions to those values.

      • Thanks Jacob for the (extremely) prompt reply.

        I made an error in my examples – the value given is for 2012 and not for 2013 but the issue is still there for 2013.

        I think something’s wrong possibly with my environment, although my regional settings are all set to UK (I am based in London), the date routines all seem to be ‘think’ that BST started before the correct date for London, I’m thinking they all seem to think I am in the US, where the clocks went forward a few weeks earlier than the UK. For example:

        new Date(1364652000000).toLocaleString() shows as “30 March 2013 15:00:00″, which is wrong

        but if I execute the same code on another machine I get “30 March 2013 14:00:00″, which is correct!

        Very frustrating, as I say my regional settings are all set to UK and time zone in Windows is set to GMT. Anyway looks nothing to do with the your library, as your say you wrap the JS library.

        Thanks for your help, looks like back to the drawing board.

  2. You library helped me a lot.
    Maybe you can document it a little. For developers it will be good help.

    You put only one example of usage. But there is no hint how to get converted date (wallTime). So I found only one way:

    $OsloTime = new Date(WallTime.UTCToWallTime(new Date(“April 26, 2013 09:00:00″), “Europe/Oslo”).toUTCString()).format(‘U’)

    • A couple things about that code.

      new Date(“April 26, 2013 09:00:00″) is going to cause you problems in the future. The browser will always parse that in the machines time zone, you won’t have any control over that. It’s better to always instantiate date objects with time stamps, a la new Date(12412473141), or new Date(Date.UTC(2013, 3, 26, 9)).

      Two, what’s returned from WallTime.UTCToWallTime is already a wrapped Date object. You can call the normal Date object functions like getMonth, getFullYear.

      Native Date objects cannot be used to keep accurate cross time zone time. Which means that you probably are going to lose the format(“U”) function because it’s probably on the Date.prototype. We have some new features planned for WallTime that will make the returned date inherit from the Date object, but I have no definitive timeline on when that will happen.

      • So you mean that there is no way to get correct `timestamp` on JS side for Mexico if my browser time zone is Oslo ?

        • Not sure what you mean by `timestamp`. The `timestamp` as in the milliseconds since epoch is always the same, no matter what timezone you are in. The displaying of the current wall time as a string for a specific timezone can change.

          Here is an example of showing two timezones with the same date to see the differences in WallTime. Note that you cannot use the format(“U”) on a WallTime returned date because it’s not really a Date object.

          https://gist.github.com/jgable/5468402

  3. I installed all dependence and get an exception

    “Error: Must call init with rules and zones before setting time zone”

    • Did you put your walltime-data script before the walltime script?

      If that doesn’t work, file an issue on the project over at github to get more help: github.com/sproutsocial/walltime-js

  4. Pingback: Rounded Corners 398 — I made a few adjustments … | Labnotes