The other side of the moon

[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).

Monday, March 18, 2013

Reducing checkboxes

Alex Limi has an excellent post on the overuse of checkboxes in Firefox's preferences screen. It reminded me of something Nat mentioned during his talk with Miguel de Icaza back at Linux Bangalore 2003 about Gnome. They mentioned several UI idioms including checkboxes and disabled menu items, but the gist of it was, every time you give the user a decision to make, you're making their lives harder. As the domain expert for this product, it's your job to pick sane defaults and not bother the user with these choices.

We took this to heart on the Ayttm project. At the time ayttm probably had over 200 user modifiable configuration options in the preferences screen, and each plugin could add its own. It was way past the point of violating one of our primary design requirements, that it should be easy enough for Colin's mum to use. We had a bit of a dilemma though. While our target audience was definitely non technical, we had a significant number of geeky early adopters who really wanted the ability to modify everything.

Over the next few days we stripped out almost every configurable option from the Preferences screen, however, we left them all in the config file on disk. Any user that really wanted to modify the options could edit the config file in their favourite text editor and make the changes themselves. This made everyone happier. Our technical users were happy that they didn't have to click through too many screens to change all their options, and our non technical users had a preferences screen where the most they'd have to do was enter their account information, and the type of smileys they wanted.

The Gnome Human Interface Guidelines cover a lot about designing intuitive interfaces, so go read that.

Friday, February 01, 2013

Nexus 4 — First impressions

Just got a Nexus 4. Started it up, and tried to sign in to my gmail account. I have two-factor auth set up for extra security, and you'd expect a google device to work well with google auth, but here's a list of bugs I've found within minutes of opening the package.

  1. It first asks you to sign in to your gmail account. Type in your username and password.
  2. It then tells you you need to sign in on the web to continue, so it opens the browser for you to sign in.
  3. Focus is on the username field, but there's no keyboard available. You need to tap on the username field (which already has focus) to bring up the keyboard. This is counter-intuitive.
  4. Type in your username and password and submit. It then takes you to the 2FA page (at least in my case) where you enter your security code.
  5. Again, tap on the field to bring up the keyboard. This field is a numeric field, but the keyboard starts out in alphabetic mode. This is probably a bug with all mobile devices, but you'd think that something this new would have fixed it.
  6. Type in the code, and now try to click on the checkbox that says "Remember this device". Except the keyboard goes away and you now end up clicking a link that explains what 2FA is.
  7. Ok, cool, I just want to go back and hit submit... except there's no back button on this browser. There's no toolbar that normally pops up at the bottom of the browser. No, this is a special browser that does not allow you to navigate through the browser history. FAIL.
  8. The only way forward is to shut down the phone and then start it up again. Except at this point you start from scratch, including selecting your language.

A few other things I've noticed...

  • The timezone by default appears to be UTC. You'd think that it'd localise this based on my location, which it knows and is configured to use.
  • If a transient alert message pops up, and you try to tap on it, you'll actually tap on the item below the message.
  • The icons are a bit too small for someone with normal sized fingers like me. It's easy to tap on the wrong item.
  • The position of the power button and volume control buttons means that when you press the power button with your thumb, your forefinger will inadvertently hit the volume control (or vice-versa). This happens because of Newton's third law of motion. Google/LG engineers should know this since it's a 300 year old basic law of motion.
  • You cannot move a widget from one screen to another by dragging it. You have to remove it from the old screen and then go through the process of adding and configuring it again for the new screen.
  • When you select punctuation on the keyboard, entering an apostrophe should switch back to alphabetic mode. It doesn't.
  • It just reboots at times.

Will post more as I use it.