A few tips for handling and manipulating timezones

A few tips for handling and manipulating timezones

Some issues transcend programming language, equally tripping up developers across the board...

After dealing with timezones at work last week (and for more hours than I intended this weekend), I've had enough to last a year! If you've had to deal with them, you know my pain. Otherwise, you're probably wondering what I'm talking about.

Why are timezones such a pain?

That's a good question, glad you asked. Let me present a (not so?) outrageous scenario.

An employee, from a company headquartered in California (PST -08:00) with a satellite office in Turkey (TRT +03:00), is on a business trip in Malaysia (MYT +08:00) and wants to schedule a calendar meeting with customers in Sydney (AET +10:00) and Ohio (EST -05:00).

Well that's easy! Adjust times for the employee so everything is from her perspective. But then it might be easy to schedule a meeting at 3pm and forget it's the middle of the night in Ohio. Okay, show the invitee's timezone.. oh, there's more than one invitee. Well, duh, then show everyone's timezones so she can easily compare them. Wait, she's still on the plane, half-way to Malaysia - should her timezone be Malaysia, or whatever timezone she's currently flying over? What if the timezone changes while the scheduling page is open? When she eventually selects a time and submits it, how does the server reconcile that value with the other invitees' timezones so it shows up in their calendars correctly? Screw it, just show everything in UTC and leave the users to their own devices (not really).

The real problem is keeping everyone on the same page. Even though one person's "noon" is another person's "midnight", it's our job to abstract away the weirdness for them (and it can get unexpectedly weird) while making sure nothing gets lost in translation. This week I realized it's good to keep a few things in mind to tame the timezone beast...

Don't Reinvent the Wheel

A surprising amount of work goes into dealing with timezones - by individual developers like you and me, but also by the creators of the frameworks we use, and by teams of people who release their own OSS projects to supplement those frameworks.

In C#, the .NET Framework has a crazy amount of logic for converting between timezones in the TimeZoneInfo class. There's also the independent Noda Time project, maintained primarily by Jon Skeet but also a handful of other dedicated contributors.

Java provides a java.time package, but there's also the independent Joda-Time project if you're using anything prior to Java SE 8. (Apparently, Joda-Time was incorporated are otherwise superseded in SE 8.)

Erlang has a some functions for helping with conversions and standardization, including the calendar module, a couple BIFs (built-in functions), and the independent iso8601 library. I've been using all of those to try and ease my current timezone woes.

Before you start laying down new code, see what's already been done for you. Most likely someone's already taken into account all those crazy political lines and other outliers that muddy the timezone waters. Besides, laziness is one of the three virtues of a programmer! ;)

Stick to Standards (i.e. UTC and ISO8601)

As much as possible, only pass timestamps around by UTC. That's the timezone to which all other timezones are compared when trying to synchronize locations. When the employee in the earlier example finally schedules her meeting, pass the timestamp as UTC to the server. Format the display of dates and times however you like - day of week and time, milliseconds since the epoch, or hieroglyphics - but convert everything back to UTC before passing it around.

One of the things that got me stuck this week was passing values around that were not in UTC, but then converting between UTC and the user's local timezone in multiple places. Programming is tricky enough without finding yourself with lists of values that look the same but mean different things, and not having a reliable baseline from which to compare them.

Besides UTC, there are other standards too. The ISO 8601 standard defines how the timestamp (in any timezone, not just UTC) should look. It eliminates ambiguity so we can pass a timestamp around in any timezone and won't lose our bearings. Typically, UTC looks like this in the ISO 8601 format:

  • 2017-07-09T17:29:05+00:00
  • 2017-07-09T17:29:05Z

The plus (or minus) hour/minute value at the end signifies the offset from UTC, so EST would be -05:00. The 'Z' stands for Zulu time, which is just another name for GMT or UTC.

Most likely, your particular language has a standard for passing timestamps around unambiguously too. In Erlang, it's typically a series of tuples like {{year,month,day},{hour,minute,second}}, whereas C# has its own DateTime class. This probably goes without saying, but try to use what's provided and don't (for example) pass timestamps around in C# as strings.

Decide Who's in Charge

This is probably more relevant if, for some reason, you can't deal with UTC on both sides of the wall. Or you don't want to. Maybe you want the server to deal solely with conversions and calculations and all of what's traditionally called "business logic", and the client side to get spoon fed its data.

If you go the spoon fed route, be consistent. The client should just get what it gets and display it to the user, then send the value right back to the server (if anything needs to be saved).