[philiptellis] /bb|[^b]{2}/
Never stop Grokking


Thursday, August 08, 2013

Don't guess at TimeZones in JavaScript

I spent quite some time a couple of months ago working on timezone support for mPulse and thought I should document the insanity, but never quite got around to it. Then there was this post on hacker news about reading a user's timezone in JavaScript and using that to display the right time. That post brought back a flood of horrific memories, prompting me to put my thoughts down.

First, while Trevor's post has a good hack to display a time in the user's current timezone, that hack works in only one case -- displaying the current time to the user in their device's timezone.

If you've worked with timezones and front end development for a while, this is probably the first hack you'll think up.  It turns out that in most cases, this is insufficient.

We'll first look at the problems with this approach, and then look at the requirements for proper timezone support.

Problems

  • The user's device timezone is not always correct. Some users fix their device timezone to their home time even when they're travelling, however the information you need to display may be pertinent for the location where they are right now.
  • On the other hand, the user may have their device set to automatically update timezone, but they actually want to see times in their home time (because, for example, that's when they call home, or have their calendar app configured).
  • The timezone offset (which is what you actually get from JavaScript), only tells you the offset from UTC for "right now". This information is irrelevant if you need to display a time that is not now, because daylight saving rules may come into effect.
  • You cannot use a lookup table for offset to timezone, because there isn't a one-to-one mapping between offset and timezone. It's a many-to-many mapping, and it changes.

Second attempt

A second attempt might be to figure out the timezone name by parsing the JavaScript Date.toString() output. This was my second attempt when writing the strftime function for the YUI Library.

I did this study in 2008, and it turns out that browsers are pretty inconsistent wrt Date.toString() output.

Requirements

Ok, before going into this, read this post on stackoverflow about daylight saving time and timezones.

So, what we need is the ability to do the following:

  1. store any date or range of dates.
  2. display a date in any timezone that makes sense for the user, and/or the event(s) being displayed, and/or the environment.
  3. display date ranges that may cross a timezone boundary.
  4. display a historic date in a historic timezone that may have changed due to political decisions.

The first requirement should be pretty straightforward. We'd like to store dates, and the best way is really a unix timestamp or an ISO8601 date. I prefer the latter because it takes into account leap seconds as well (unix timestamps are leap second agnostic [1],[2]). I also always use Zulu time for an ISO8601 date.

This is not sufficient, however. We also need to store the timezone name of the event. This is so that we can display historic events in the timezone they originally occurred in, even if the definition of that timezone changes. This comes from the Olson Database.

With these two pieces of information (event date/time & event timezone name), we can render the date in several ways... the original event date/time, the event date/time relative to the user's current timezone, etc.

We also need to handle date ranges. This could be something like your spring vacation, that just happened to cross several timezones because you left San Francisco on March 8th, flew to the UK, stayed there until April 7th, and then flew back. Your flight departure from SFO is in Pacific Standard Time and your arrival at LHR is in British Standard Time. Your departure from LHR is in British Daylight Time, and your arrival at SFO is in Pacific Daylight Time.

What's most important is that you display these dates in their specific timezones regardless of where the user actually is.

So should we guess or ask the user what they want?

By all means guess at what the user's timezone might be. Use a combination of GeoIP + JavaScript timezone offset to figure out where they might be (note that both of these could be wrong), but give them the option to specify the timezone that they care about.

Also, when displaying event dates, use a date local to the event, but use JavaScript to allow the user an easy way to flip it to their local timezone if they like. That's progressive enhancement.

What else shouldn't we do?

Don't try and guess the user's language or preferred currency from their current location. Always ask and store their response.

Click to help me test boomerang (opens google.com in a new window).

...===...