- Published on
Working with Time and Timezones
- Authors
- Name
- Yair Mark
- @yairmark
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.
- Look at the specifics for the language/framework you are using but generally if you specify the desired TZ as the
- 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.
- Look at the specifics for the language/framework you are using but generally if you specify the desired TZ as the
- 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
- Software Engineering question on Saving Timezones
- Stackoverflow question on best practices for dealing with daylight savings and timezones
- The W3 Timezone Standards Doc where it defines what TZIDs are
- A Baeldung Article Discussing Different Approaches for validating datetimes in Java
- The Wikipedia page on the Timezone's DB
- The values defined under
TZ database name
should be used as described in this answer- This further points to this GitHub repo
- The values defined under
- Short Article giving some examples for working with TZs with Java 8's datetime API