Archive for March, 2013

A funny story – featuring UTC offset

March 28, 2013

I don’t normally write about mistakes I make.

You know mistakes! You’re supposed to accept them, learn from them and never talk about them, especially online where your customers can read about them. No! You’re supposed to project an image of self-confidence, invulnerability and super human coding abilities.

Well, this mistake is funny and relatively harmless. I just have to write about it.

I’ve been writing before about the implementation of our CRM sync service. With every refresh, that sync service sends two things to the server: the timestamp of the last sync (to only get the delta from there) and the utc offset of the client (provided by the browser). This UTC offset is only reliable for getting the utc offset for that session, not to be reused as the UTC offset in general, and that’s because:

  1. The browser’s UTC offset is a naive offset, it’s not a timezone. In particular, it doesn’t know about daylight saving (although it applies it if in effect at the time of the request)
  2. The user might be travelling and using the service from a hotel in a totally different timezone

Anyways. We only use it in order to associate the dates and times with words like Today, Yesterday, etc. in the current session.

On the server, which uses python by the way, I use to have this naive handling of the UTC offset.

        utcoffset = int( request.GET.get('utcoffset', 0) )
        utcoffset = 0

The defaulting to 0 should never happen, as this parameter is always sent and the UTC offset, populated in javascript, should always be available in the browser. The try/except was more of a “just in case”.

So one day, I’ve decided that try/except doesn’t make sense, for the reasons highlighted above. Further more, I didn’t want the exception to be swallowed, I wanted to know about it. Django has a nice feature where you get an email every time an exception is thrown and not handled.

So I took that out, and my code now looked like this:

    utcoffset = int( request.GET.get('utcoffset', 0) )

Great, I thought. However, in my ignorance, I totally forgot about half hour timezones. India for example has a 6.5 UTC offset and there are half-hour timezones in Canada and Australia.

I caught this one pretty quickly when someone from India used the website and passed in a 6.5 offset. That line started throwing and flooding me with emails for every failure. Now this sync service actually polls for updates, so you can imagine I got quite a few emails.

Luckily for me, the fix was straightforward:

    utcoffset = float( request.GET.get('utcoffset', 0) )

Using a float instead of an int.

I suppose the moral of the story is twofold:

  1. Never swallow exceptions as the code might end up doing something you have not intended (using UTC offset 0 for half-hour timezones) and you will not know about it to fix it
  2. Learn about timezones