Published on

Working with Time and Timezones

Authors

Something seemingly as simple as time turns out to be a real headache to work with from a development perspective.

The main difficulty is caused by timezones which are determined more by political factors than scientific factors. As a result, no algorithmic and systematic approach can be used to deal with them. You need to rely on libraries which keep track of what timezone a region has and use this in your code. This library should be updated regularly to ensure that you are using up to date information.

TLDR

  • Storing Date and Time: Store datetimes with UTC+0 time
  • Storing and Working with Timezones (for users): If you need the user's TZ store the TZ database name as defined here
    • Look at the specifics for the language/framework you are using but generally if you specify the desired TZ as the TZ database name it will work.
  • Storing and Working with Timezones (for servers): If you only care about a TZ from a server's perspective then decide on a strategy. I chose the capital's TZ where the server is running.
  • Use a Library to Manipulate Time: When you want to apply a TZ's offset to time use the best library or built in standard library for that language.
    • These libraries should be updated regularly to incorporate any TZ changes like DST being added/removed to/from a region and for new TZs.
    • Examples of these libraries:
      • Java 8's time API
      • Moment.js for JavaScript

Storing Datetime Information

Now how do you store a date with a timezone for a region in a way that is consistent and that can keep up with timezone changes? Luckily in my case, I only need to care about this problem from the perspective of one server running for a given country as opposed to a user's timezone. To cater for this I decided to only consider the timezone of a country's capital.

Ok cool, I have a strategy for which timezone to use. But how do I store this now? For a time in a date let us store it as GMT/UTC+0 and somehow store the offset. The offset alone is not sufficient as this does not cater for daylight savings time in a country or that country changing the timezone due to political or other issues.

I did a bit of research and came across this answer. The point they make is very sensible:

You want to store something that doesn't change all the time (or twice a year). The time zone database https://en.wikipedia.org/wiki/List_of_tz_database_time_zones is exactly the right thing. So it seems you just store two letters.

This makes sense. Armed with this information I went and started trying to see how I could apply this to Java's new time/date API. The country's two-letter option did not work. After digging around for a bit I found that you have to use the TZ database name column from the Wikipedia timezone article mentioned previously. So you have to specify the timezone using ZoneId for example:

ZoneId.of("Africa/Gaborone")

Django's TIME_ZONE configuration also expects timezones to be specified in this format. Django adopts the approach of storing datetimes as UTC+0 as described in the official docs here:

When support for time zones is enabled, Django stores datetime information in UTC in the database uses time-zone-aware datetime objects internally, and translates them to the end user’s time zone in templates and forms.

Formatting Datetimes

Using Java/Kotlin this is fairly straightforward:

//DateTimeFormatter which includes the TZ:

private val dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm a z")

//2020-01-24 10:00 am GMT Based off of: //LocalDateTime.of(2020, Month.JANUARY, 24, 10, 0, 0, 0)

Alternatively you can also specify the TZ database name for the TZ you want:

ZonedDateTime.of(aLocalDateTime, ZoneId.of("UTC+00:00")).withZoneSameInstant(ZoneId.of("Africa/Gaborone"))

Summary / TLDR

  • Storing Date and Time: Store datetimes with UTC+0 time
  • Storing and Working with Timezones (for users): If you need the user's TZ store the TZ database name as defined here
    • Look at the specifics for the language/framework you are using but generally if you specify the desired TZ as the TZ database name it will work.
  • Storing and Working with Timezones (for servers): If you only care about a TZ from a server's perspective then decide on a strategy. I chose the capital's TZ where the server is running.
  • Use a Library to Manipulate Time: When you want to apply a TZ's offset to time use the best library or built in standard library for that language.
    • These libraries should be updated regularly to incorporate any TZ changes like DST being added/removed to/from a region and for new TZs.
    • Examples of these libraries:
      • Java 8's time API
      • Moment.js for JavaScript

References