UTC considered harmful
Published: 2023-07-26 15:56:58

I decided to launch [TimeTime.in](https://www.timetime.in/) because, contrary to popular belief, working with dates is still terribly complicated for developers. (It's no coincidence that the [Datepicker is often paid](https://mdbootstrap.com/docs/angular/forms/datepicker/) in many UI libraries).

Not long ago, I was on Twitter and came across [a post by Ben Nadel](https://twitter.com/BenNadel/status/1684171835657662464/photo/1), a developer not suspected of being a junior, discussing a problem he faced with dates and linking to [a post explaining his solution](https://www.bennadel.com/blog/4492-considering-utc-and-recording-activity-streak-data-in-coldfusion.htm).

To my surprise, his solution isn't entirely correct, so I was inspired to write this post to prevent more developers from making the same mistake.

## First things first!

Not wanting to make this post too long, I'll start by introducing the basic concepts required to understand it.

### Civil Time vs UTC

As many people know, on the Internet most dates are represented using UTC time (actually UNIX time is used, which isn't UTC and has significant issues if we want to be serious, but that's material for another post). Simplifying, we can say that UTC time represents the number of seconds from a reference time.

Practically, instead of continuously talking in seconds, humans use a different system to represent dates called civil time. We don't say “I was born at 89891283”, we say “I was born on July 4, 1992, in Pontevedra, Spain”.

The crucial point here is to understand this difference. **Humans speak in civil time and machines in standardized time**, and if we want a functioning computer system, we need to effectively transform one format into the other.

### Time Zones, Area Zones, and GMT Offset

In simple terms, the 1884 meridian conference was held where it was agreed to divide the earth into 24 time zones, each separated by 15º.

<u>Time zones are different from area zones.</u> An area zone is a geographical region that shares the same official time. It's essential to understand that **an area zone is a civil time concept whose rules can change arbitrarily.**

![Area Zones vs. Time Zones](https://upload.wikimedia.org/wikipedia/commons/thumb/8/88/World_Time_Zones_Map.png/800px-World_Time_Zones_Map.png)

Lastly, we should discuss the GMT offset. The GMT offset is the difference in hours and minutes between the reference time (GMT) and a specific time.

_(People often talk about the “UTC offset”, even though it's important to remember that GMT is a time zone, whereas UTC is a time standard.)_

### ISO 8601

It's a standard regulation specifying the notation to represent dates, times, and more. This standard indicates that the format for representing a date with hours, minutes, seconds, and milliseconds is:

`yyyy-mm-ddThh:mm:ss.mmm`

Furthermore, this format allows specifying time using the local time zone, adding how much offset there is from GMT. If the offset is 0, a Z is added at the end.

`yyyy-mm-ddThh:mm:ss.mmmZ`

Meaning, the same moment in time (UTC) in Spain will be called "26/07/2023 15:51:19 in Spain" and in Portugal, which is in a prior time zone, it'll be called "26/07/2023 14:51:19 in Portugal".

| ISO                           | GMT                      | UTC (ms)      | Civil Time                       |
| ----------------------------- | ------------------------ | ------------- | -------------------------------  |
| 2023-07-26T13:51:19.724Z      | 2023-07-26T13:51:19.724Z | 1690379479724 | 26/07/2023 15:51:19 in Spain     |
| 2023-07-26T14:51:19.724-01:00 | 2023-07-26T13:51:19.724Z | 1690379479724 | 26/07/2023 14:51:19 in Portugal  |

# Developers

Now that we've covered this, what implications does it have for us as developers?

### Level 0: Timestamps

Many people use timestamps to represent dates. As we've seen, timestamps are an absolute time concept that doesn't account for the offset or time zone.

This is the problem Ben faced and explained on his blog. He has a sports app where he saves training data. It has a “training streak” feature which essentially shows which days the user trained.

Initially, he saved workouts as timestamps. The problem is for a user in the Eastern US, which is in GMT-4 offset. This means if they train at 5 in the morning and 10 at night, they've trained on two different days in GMT time, but the same day in GMT-4.

Examples like this show that saving timestamps is often inadequate if we want to preserve date semantics.

### Level 1: GMT Offset

A common solution is to store dates, including the GMT offset. This way, knowing a user's offset, we know whether to classify workouts on different days or not. However, this approach has one problem: Assuming that time zones are static.

As previously discussed, **a time zone differs from a GMT offset**. The classic example we all know is the switch between daylight saving time and standard time. Moreover, time zones themselves can change due to political decisions. For instance, [Spain changed its time zone in 1940](https://www.washingtonpost.com/news/worldviews/wp/2016/12/14/fascism-helped-create-a-time-zone-oddity-in-spain-70-years-later-it-may-finally-be-undone/#:~:text=It%20was%20only%20during%20World,clocks%20were%20never%20changed%20back.).

## Level 2: ISO + Time Zone

Without delving into many tedious details, I can confidently say that **the correct way to store and transmit dates is usually by using the ISO format + Time Zone.**

Let's take an example. Suppose I have an app that allows booking medical appointments. Since healthcare in Spain isn't as good as it should be, they schedule my appointment for months later.

> Your appointment is scheduled for Saturday, July 20, 2024, at 09:00 AM, Spanish mainland time.

This date and time are expressed in civil time.

Imagine that we save this date in my database, storing the date and GMT offset in ISO format.

```
2024-07-20T09:00:00.000+02:00
```


This date corresponds to a certain UTC moment:


```
1721458800000
```


Which in turn corresponds to this GMT date:

```
Sat, 20 Jul 2024 07:00:00 GMT
```

Now let's imagine that in the meantime, [some countries in Europe, including Spain, decide to abolish daylight saving time](https://www.europarl.europa.eu/legislative-train/theme-union-of-democratic-change/file-discontinuing-seasonal-changes-of-time#:~:text=The%20Parliament%20adopted%20its%20position,wishing%20to%20keep%20summer%20time.). By the time the day comes in our database, we still have:

```
2024-07-20T09:00:00.000+02:00 (1721458800000 UTC)
```

Transformed to the hypothetical Spanish civil time after the time change will be:

> Saturday, July 20, 2024, at **08:00 in the morning**, Peninsular Spanish time.

However, is this what we want? Do we want to persist the original UTC moment to which the civil date corresponded? Or do we want to preserve the initial time when the patient requested the medical appointment?

In my opinion, when a person schedules a medical appointment for 9 in the morning, they don't care about UTC or GMT or any daylight saving time changes that occur in their country in the meantime. They care about their appointment being at their local civil time.

In my case, when I say "Saturday, July 20, 2024, at 09:00 in the morning, Peninsular Spanish time," I don't care about anything that happens in between—I want my appointment at 09:00 in the morning!

## Conclusions

In this text, we have only scratched the surface of all the implications and pitfalls you can encounter when dealing with dates, just to name a few:

- Until 1908, Russia used the Julian calendar,[ causing them to arrive 12 days late to the Olympics that year.](https://www.si.com/extra-mustard/2013/12/30/the-extra-mustard-trivia-hour-when-a-calendar-defeated-russia-in-the-1908-olympics)
- [There was a February 30th.](https://www.timeanddate.com/date/february-30.html#:~:text=February%2030%20existed%20from%201930,days%20were%20%E2%80%9Cmonthless%E2%80%9D%20holidays)
- [The UNIX time (used in JavaScript dates) is not exactly the UTC time](https://unix.stackexchange.com/questions/333179/what-harm-does-a-leap-second-cause-on-a-unix-system/334029#334029).

For now, whenever you handle dates, I recommend keeping this text in mind, and if necessary, persist the time zone along with the date to preserve as much information as possible.