Globalizing APIs is hard. I’ve posted before about some of the pitfalls of dates and times in APIs in The 5 Laws of API Dates and Times, as well as content and currency localization in How to Localize Your API .
One area that I did not get into was how timezones can play a role when a specific time and location are in play.
Simply put: you cannot tell what the UTC offset of a given date+time will be, unless you know precisely where and when it will be. As such, this becomes the defining line for when we should supply timezones.
Some questions to help think through this:
- Where: Is there a latitude and longitude?
- When: Is there a specific time (versus just a date)?
Review of Standards
- ISO 8601 & 3339: these are standards which give us a well defined way to represent dates, e.g. “2013-08-16T10:30:15Z” is easily interpreted as August 8th, 2013, at 5:30:15 UTC.
- UTC: using Universal Coordinated Time is great because we don’t deal with representing timezone-specific offsets.
- Offsets from UTC: If there were a compelling reason to do so, we could add “-0500” to our date example, shifting the time to represent a timezone which is 5 hours ahead of UTC, something like the US Central time zone. For example: 2013-08-16T05:30:15-500.
Timezone calculation is hard
Deriving the timezone of any given latitude/longitude can be tricky. In the United States/North America alone, this is tremendously complicated subject, especially in places like the Southwest bordering Mexico. You could drive a few hours in any direction around Arizona and hit 8 different timezones, depending on when you are there. For a great (and pretty comical) explanation of why US timezones are such a mess, and why the algorithmic aspect of the software is so hard, here’s a great video, Daylight Saving Time Explained.
However this is not unique to the USA & North American region. Take a look at the contrast between countries which share longitudes, such as China and Russia. Since 1949, China has basically eliminated timezones, and now only has one offset, UTC+0800. This covers a range which used to run from UTC+0530 through UTC+0830. In that same range of longitudes, Russia minds UTC+0400 through UTC+0900 (although it is wider than that as a whole).
Timezone offsets can change across latitudes, longitudes, nations, and seasons. However, to make things worse, ongoing changes in legislation often mean that timezone offsets can arbitrarily change. For instance, in Russia, “On 8 February 2011, Russian President Dmitry Medvedev issued a decree that Russia would observe year-round DST. Under the decree, all clocks in Russia were advanced one hour on 27 March 2011 as usual, but are not to change back the following October, effectively making Moscow Time UTC+4 permanently.” (from: wikipedia Time in Russia)
Issues of precision
In our example, we’ll provide our API client with data regarding a time and place they need to be, for example a calendar event.
In an imprecise example, we’ll give the user an appointment object in our API response:
While this seems perfectly innocuous, the trouble is when we have to store this date (assuming there’s perhaps a POST to create this). Typically, we would convert dates to UTC, a global universal standard for storing time. While this would seem to be the right time to convey the time with an offset (e.g. 2013-08-16 10:30:15-05:00), we would not be able to derive where this event occurred.
The real problem
We cannot resolve where an event occurred based on the timezone offset. For instance, in “America/Phoenix”, Daylight Savings time is not observed. At the time this post is being written, Phoenix, AZ is -0700 offset, while Boulder, CO is observing DST, therefore it is -0600. If we provided a time as 2013-08-16T08:30:15-0700, you could potentially misinterpret that as being the Pacific timezone, such as “America/Los_Angeles”.
Explicit timezone is the right approach
To make this simple, we are best suited to continue using UTC for the time returned, but add an accompanying “timezone” field.
A few things to keep in mind
- The zoneinfo/tzdb standard is used as the standard. This is the most accurate and widely accepted global standard. While people often use abbreviations such as “EST, WST, CST”, “these are not part of the international time and date standard ISO 8601 and their use as sole designator for a time zone is not recommended”. (from wikipedia: Time Zone)
- In order to respect the physical location’s timezone, your API backend should geolocate the location/address specified. There are a wide variety of options for this, via numerous APIs. One interesting open source example is from GISgraphy, which is a REST API that you can pay to use, or download and host yourself. The service provided resolves an address to latitude/longitude as well as time zone. It is exceedingly important to record the lat+long+tz when storing data like an appointment.
- Zoneinfo does not relay Daylight Savings information. While this seems potentially deficient, virtually every operating system and programming language provides a mechanism to retrieve zoneinfo info, and even modulate the time with the DST adjusted zoneinfo offset. For instance, in Python:
As you can see, time zones can be an exhausting topic, alongside other globalization issues. In the design of your APIs, it is only scenarios with a specific time and location when time zones are an issue exposed to clients. When you are working with dates, use time sparingly (i.e. if there is no time, only use the date) and use location more sparingly. When both time and location are required, follow these guidelines to provide a consistent user experience for your API clients.
Side note: For US-based readers, please visit StandardTime.com. It is my opinion that the use of Daylight Savings Time should be abolished in the US. The historical benefits have evaporated, meanwhile our automation systems must carry the burden of these legacies. If you are not in the US, please find a cause that urges your government to eliminate DST as well.
Image credit: doomu / 123RF Stock Photo