Time and Dates
Why do we need to talk about this?
I have seen it time and again (pun intended) that developers used times and dates in sub-optimal ways. It's not that hard if you understand some basic principles related to time zones.
Even if an application is only dealing with now
or some time that is really close to it, time zones might matter. If a system is talking about dates and times in the past or in the future, even more so. Likewise, if the geographical time zone is always the same as there are still the seasonal time zones a.k.a. Daylight Saving Time (DST). Different time zones and different DST settings shall be regarded as the same problem for this discussion.
Common Problems
Using local time poses multiple problems. The application might be fine with the local time internally, but users might want to display it in their own time zone. I had the "opportunity" to debug time zone problems in a system where the developers, the servers, and the customer were all in different time zones and only local time was used.
Time calculations will be unreasonably difficult if the times are local, but for different time zones. If you book a flight, you will usually be presented with the departure and arrival time in the respective local time. Flights from London to Paris will present the departure as the local time of London and arrival as the local time of Paris. While the flight will take something like 1:20h, but the departure might be at 8:00 and the arrival at 10:20, because the two locations are in different geographical time zones. Calculating the duration from the local times is not possible without knowing the respective time zones.
This gets even more interesting if the flight happens across a change to or from Daylight Savings Time (DST). The fun increases if the two locations do this change at different times of the year. Some countries do not even have DST at all. If you want to take all of this into account when doing such calculations, you will find yourself in a world of pain.
Coordinated Universal Time
A common way to deal with time zones is to use some kind of local DateTime (e.g. LocalDateTime
in Java) or timestamps (e.g. Instant
) assuming UTC internally for everything. When a time enters your system, it is translated to UTC. This works fine if you don't need to know the original time zone later or need to translate the time to a specific user's time zone, anyway.
Geo-Political Time Zones
A second option is to use DateTime with time zones attached (e.g. ZonedDateTime
in Java). The time zones should not be stored as mere static offsets, but as dynamic objects identified by their geographical and political location. Example: The timezone for Paris should neither be described as an offset (“+1”) nor with the traditional Timezone name (Central European Time/CET), because during summer France changes the timezone to “+2” and Central European Summer Time/CEST. Not only is a change of the time zone necessary, the name is also misleading because other countries share the same time zone but might not have DST or have different transition dates. That’s why there are “geo-political” time zone identifiers like “Europe/Paris”, "Asia/Tokyo", and “America/New_York” (see List of tz database time zones for a list). Date and Time libraries "know" when each political region changes to DST and take that into account when doing calculations.
Example
var departureInputTime = "2021-03-28T00:00:00";
var departureInputTimeZone = "Europe/London";
var arrivalInputTime = "2021-03-28T03:20:00";
var arrivalInputTimeZone = "Europe/Paris";
var departure = ZonedDateTime.of(
LocalDateTime.parse(departureInputTime),
ZoneId.of(departureInputTimeZone)
);
var arrival = ZonedDateTime.of(
LocalDateTime.parse(arrivalInputTime),
ZoneId.of(arrivalInputTimeZone)
);
var flightDuration = Duration.between(departure, arrival);
var oneHourTwentyMinutes = Duration.of(80, ChronoUnit.MINUTES);
assertEquals(oneHourTwentyMinutes, flightDuration);
The departure in London is at midnight local time and the arrival in Paris is at 3:20 local time. How long do you fly? If you guessed 1 hour and 20 minutes, you are right. The UK is changing to DST at 1 o'clock in the morning on March 28th in 2021. France is doing it at the same time, which is at 2 in their time zone. If you take 3:20h and subtract one hour for the DST change and another hour for the different time zone, you get 1:20h. Don't try to do this without the support from your favorite DateTime library or whatever your programming language and platform use for that kind of thing. I have done the above with Java as well as C# and PHP.
Inherently Local Time
There are many cases where you have to deal with times that are inherently local. The airline example is one of those. The departure time always refers to the place of departure and the arrival time always refers to the destination. In such cases, it might make sense to use a local time (i.e. without attached time zone). If you need to do calculations with these times, you can always transform the local times into a time zone aware format or UTC.
In most cases, I would still transform the times into either time zone aware types or UTC for internal use and only convert back to local time when needed. The local time is only interesting when showing it to the user and you don't want to do the transformation every time you need to do calculations or trigger actions based on them.
Databases
How do you store time and date in the database? If you go the UTC route, it is fairly easy. Just store it as a timestamp, which is something all types of databases should support.
ZonedDateTime, or whatever the equivalent is in your programming language and platform, is possibly a bit more difficult. For one, this depends on the actual database used, the database driver, and possibly the ORM if you use one. If you store it as a bare timestamp, you lose the time zone information, so you might have to store it separately. How to map that also depends on the actual technology used and is out of scope for this article.
Story Time (haha)
In the early 2000s, I had to debug a problem in a content management system (CMS) of a news site. Sometimes, the editors would receive restricted press releases from companies that must not be published before a set point in time. The CMS allowed to schedule publishing of articles, and this was used to prepare the press release and make sure it would not be published before the retention time. There was a case where a company complained that the editors published an article one hour early. It turned out that the article was prepared on a Friday for publishing on Monday with a DST-Sunday in between. The article was really published one hour early, because the CMS did not account for the DST switch. The CMS was changed so that it would properly deal with time zones and store the scheduled publishing time as the correct UTC value. The bug was fixed.
One year later, we had the same situation. A company complained that a press release was published one hour early. We were stumped. How could that happen? Well, the bug was fixed and the CMS did it correctly this time. The complaining company did not check for adherence to the publishing restriction for each press release, but only did random sampling at different times of the year. In the offending case, the article was published during DST, but the check was done after DST ended. The article was published correctly, but the publishing time on the article was shown incorrectly, using the current non-DST time zone offset.
Conclusion
Knowing how times and dates are used and stored in your system is essential. It is not rocket science to get it right if you use the proper types and formats provided by your programming languages standard library. If in doubt, use time zone aware types and formats with geo-political time zones.