In April 2021, our China-based team working on an Australian project discovered that the E2E test deployed in AWS Sydney was giving out a lot of time calculation errors. Day.js, the Datetime Utils calculation tool that had been stable for six months, had started behaving abnormally overnight. Turns out that Day.js had stopped working when time changed to AEST (Australian Eastern Standard Time). Strict time format requirements only compounded our problems. To solve this, we looked into the common time calculation libraries in the TypeScript ecosystem.
A battle of wits with datetime
Representation of datetime
First, we need to explain how time representation works. Long before the advent of computers, humans had a general and well-established method of describing time.
This is a standard press release, where the time is indicated as follows:
March 14, 2022 at 11:00 PM EDT
We can get a more precise point in time:
March 14, 2022, 11 o’clock PM, 0 minutes and 0 seconds in Eastern Daylight Time
Then make it more international:
2022-03-14 23:00:00 GMT -04:00 (internationalized representation)
2022-03-14T23:00:00.000-04:00 (ISO format representation)
2022-03-15T03:00:00.000Z (Converted to UTC time and expressed in ISO format)
In order for a point in time to be perfectly represented in a computer, we calculate the number of milliseconds between the current time and 0:0:0 on January 1, 1970 in Universal Standard Time and store it. This value is called a timestamp. It’s parsed by the computer according to the machine's time representation, time zone, and other settings.
1647313200000
GMT and UTC
While GMT and UTC are often used interchangeably, they actually point to two different concepts.
GMT stands for Greenwich Mean Time. It’s the local time observed by the Greenwich Observatory in London, located on the 0 degree longitude line. It was used as Universal Standard Time from 1925 to 1972.
UTC was established in 1972 to compensate for the slowing down of the Earth's rotation. It’s based on International Atomic Time, which uses the atomic frequency of cesium to set the time standard. In other words, UTC is a more accurate alternative to GMT.
Offset and Timezone
The last part of time representation is called offset, meaning the offset of local time from UTC. -04:00 means 4 hours behind UTC time. Based on the local time and the local offset, we can easily calculate UTC time as follows:
Offset ≠ timezone. What we call UTC +8 etc. isn’t a timezone, but a set of timezones with offset of +08:00:
UTC +8 = {
CST (China Standard Time),
SGT (Singapore Time),
AWST (Australian Western Standard Time),
…
}
Things have been straightforward up to now. DST complicates matters.
DST
DST (Daylight Saving Time), also known as summer time/winter time, means setting the clock back one hour on a certain day in spring and forward one hour on a certain day in autumn every year.
Because of DST, a timezone corresponds to different offsets at different times of the year.
In Sydney, after 2:59:59 AM on April 4, 2021, the hour hand will roll back and point to 2:00 again.
Then, on October 3, 2021, after 1:59:59 am, the hour hand will skip 2:00 am and point directly to 3:00 am.
The result is that:
Sydneysiders will experience 2am to 3am twice on April 4, 2021!
On October 3, 2021, 2am to 3am doesn’t exist in Sydney!
This happens every year!
Can it get even scarier?
The date of the switch between DST and ST can change every year!
In fact, each country can adjust the DST date according to recent sunshine conditions. The IANA (Internet Assigned Numbers Authority) website keeps a database of each country’s DST. Here’s Sydney’s database in 2022:
Before 2008, the date of DST in eastern Australia changed every 3 or 5 years. Fortunately, it was temporarily fixed after 2008, switching to DST on the first Sunday of October every year and switching back to ST (standard time) on the first Sunday of April every year.
In the next part, we'll discuss how we solved the issues introduced by DST.
Disclaimer: The statements and opinions expressed in this article are those of the author(s) and do not necessarily reflect the positions of Thoughtworks.