maximedubourg.com

Demystifying datetime handling for frontend developers

25/07/2024

I always struggled to understand how datetimes and timezones worked. I mean, I do understand the concept well, what purposes it serves etc, but I couldn't be 100% sure about how to technically explain it to somebody. What should the database store about a datetime ? What should the API send to clients ? How does my browsers parses it ? Should I handle timezones myself, or is it handled automatically ?

So, I decided to force myself to understand it. Here's a cheatsheet about what I believe is important:

Cheat sheet / TL;DR

A bit of vocabulary

Yeah I know, boring, but trust me it will be important to understand datetimes and timezones handling well. I'll be brief.

datetime

A datetime is basically a data type that represents a date and a time OR a point in time, I'll get back to this important point a bit further. It is usually textually represented by a combination of a date, a time of day, and sometimes an offset from UTC.

2023-12-04T08:30:42+01:00

Here:

This notation is called ISO 8601 and is the most common way to represent a datetime.

You'll sometimes see a Z at the end of a datetime, like 2023-12-04T08:30:42Z. It means that the datetime is in UTC (which is the same as +00:00, Z standing for "Zulu time").

timestamp

A timestamp is also a point in time, but it is represented as the number of seconds or milliseconds since the Unix Epoch (January 1 1970 00:00:00 UTC).

Here's 2023-12-04T08:30:42+01:00 represented as a timestamp in seconds:

1701675042

timezone

A timezone is a geographical region where the same standard time is used. It is usually represented by a name, a UTC offset, and sometimes a DST offset.

For example, the timezone used in Bordeaux, France (aswell as most of central european countries) is:

CET
UTC+01:00
UTC+02:00 (DST)

UTC, GMT, DST

What does a datetime conceptually represent ?

It is, for me, the main thing to understand about dates:

Depending about what we talk about, a date can either represent an exact moment in time, OR a date and a time relative to a physical localization.

Here's an example:

The JavaScript Date object does not make this difference, and only represents dates as points in time. It is up to you to know what you're manipulating when using a datetime (note: the Temporal TC39 proposal aims to introduce a new JavaScript API that makes this difference).

What should backends store and send to frontends ?

UTC localized datetimes, almost always.

There are few exceptions to this rule as explained in this great article by Jon Skeet, but it is a good rule of thumb for most common date handling cases.

Parsing and displaying dates in JavaScript

As stated before, the JavaScript Date object only represents dates as points in time, and does not make the difference between a datetime representing an exact moment in time, and a datetime representing a date and a time relative to a physical localization, so this is your job to parse and display accordingly to what "type" of date you're manipulating.

Gotchas of parsing datetimes in JavaScript

Here's what happen when you parse an ISO 8601 datetime string in JavaScript (in your browser or in Node.js):

parsing an ISO string that DOES contain a timezone offset

If the ISO string does contain a timezone offset, then this offset will be respected. For example, with system time scheduled to CET (UTC+1):

new Date("2023-12-04T08:30:42Z").toISOString();
// => "2023-12-04T08:30:42.000Z"

parsing an ISO string that DOES NOT contain a timezone offset

If the ISO string does not contain a timezone offset, then it will be considered as a datetime for the current timezone. For example, with system time still scheduled to CET (UTC+1):

new Date("2023-12-04T08:30:42").toISOString();
// => "2023-12-04T07:30:42.000Z"

parsing a date string separated by hyphens (-) vs slashes (/)

Weird and confusing case, when parsing a date string (without time offset), the resulting Date object will get a different timezone depending on the separator used.

For example, again with system time scheduled to CET (UTC+1):

new Date("2023-12-04").toISOString();
// hyphens: current timezone (UTC+1) is respected
// => "2023-12-03T23:00:00.000Z"

new Date("2023/12/04").toISOString();
// slashes: UTC is taken as timezone
// => "2023-12-04T00:00:00.000Z"

Moreover, this behavior is not even consistent between browsers, as some older versions of browsers will do the opposite.

Parsing rule of thumb

Let's take the same examples as before of a scheduled worldwide video conference and of the Halloween celebration. My advice to parse for these two different cases would be:

→ when parsing a datetime representing an exact same moment for anybody around the world (ex: video conference): parse a string WITH a timezone offset

This way, the resulting Date object will be the same no matter where the end user will be, ex:

new Date("2023-12-04T08:30:42Z");

→ when parsing a datetime representing a date and a time relative to a physical localization (ex: Halloween celebration): parse a string WITHOUT a timezone offset

This way, the resulting Date object will be different depending on which timezone the end user physically is in, ex:

new Date(startsOn.split("T")[0]);

Displaying dates to end users

Always display dates in the timezone the end user is in, which is the default behavior in most browsers.

For rare cases where it is really needed to display a date in a specific timezone, specify the corresponding timezone:

04/12/2023 08:30:42 (CET)

→ use the <time> HTML element

The <time> HTML element is a semantic element that is really useful to display dates of times to end users as it allows specifying a date or time in a machine-readable format while keeping a human-readable format for display.

It helps screen readers and assistive technologies to better understand and make use of the date or time, search engines to better index the content, and can also be used to represent a duration using the ISO 8601 Duration Format.

<p>
  The show starts at <time datetime="2024-07-25T14:00">2:00 PM</time> and lasts
  <time datetime="PT2H00M">2 hours</time>.
</p>

Conclusion

Understanding datetimes and timezones can be challenging for developers, but mastering these concepts are essential for handling date and time data effectively. By following best practices, such as manipulating UTC localized datetimes on the backend and displaying dates in the user's timezone, you can ensure consistency and accuracy in your applications.

I hope these guidelines will help you being confident about datetimes management in the future.

Sources

Here are the several very good articles I learned from and used to write this: