DEV Community

Cover image for Dates in JS
Florian Lackner for 365Talents

Posted on

Dates in JS

Date and time handling is arguably one of the most complicated things in computer science. It seems simple, since everybody knows how to read a clock or how to use a calendar. But the devil is in the details, as always. Since so many people seem to get it wrong over and over, we should talk about it.

In this blog post I want to offer a mental model to you. It created this famous click moment for me. Maybe it helps you too. Let me know, I'd be delighted.

Terminology

Let's give clearly defined names to the things we'll talk about. The topic is already complicated enough without confusion induced by the ambiguous nature of human language.

  1. A Date is the information you can find on a physical calendar. It's a day, month and year.
  2. A Time is the information you can find on a wall clock. It's an hour, minute and second. You can of course go finer by giving milliseconds etc.
  3. A DateTime is a Date and a Time.
  4. An Instant is a point in time on the planet. If two Instants are the same, this means that they happened at the same moment, physically speaking.
  5. A Timezone is an algorithm to convert an Instant to a DateTime.

The key takeaway

A DateTime is NOT an Instant.

If you take one thing home today, it should be this. A DateTime is NOT an Instant. Neither can you convert between the two losslessly. They are fundamentally different concepts. In my opinion the confusion between the two is the cause of most bugs in date and time handling.

The mental model I'm offering is that these are different things that can't be converted without loss of information. You need to ask yourself every time which of the two you're working with and you can't mix and match them.

Let's use an example to show the difference. Say you're speaking on the phone with a friend who lives on the other side of the planet. Where you live it's maybe the evening, while your friend's about to start their day. Your DateTime is very different from your friend's DateTime. Yet, you're having a conversation at the same Instant in time. Of course, because you're saying something and your friend responds immediately (ignoring the slight delay imposed by the speed of light).

So let's repeat this again. A DateTime is NOT an Instant.

Timezones

Let's take the example further. Say you didn't have your conversation yet. Since you and your friend are both busy, you schedule it. Easy, you agree on an Instant in the future and be done with it. While it's true that you must agree on an Instant, it's unfortunately also true that people don't work on Instants. They work on DateTimes. How impractical. And since your friend lives far away, the DateTimes for the Instant of your call won't be the same.

You need to convert the Instant to a DateTime for each one of you. The algorithm to do so is called a Timezone. I'm saying algorithm, because Timezones are more than just a simple offset. There are complications like daylight saving time, leap seconds, and historical changes in time zones. I'd consider them black box algorithms, because they're complex and there's no shortcut around this fact.

Say you're living in France. Your Timezone is called "Central European Time" (CET) or Europe/Paris. Your friend lives in India. Their Timezone is called "Indian Standard Time" (IST) or Asia/Kolkata. You both agree on an Instant in the future. Then, you need to apply the respective Timezones to the same Instant to get your DateTimes. I've used India as an example, because its Timezone doesn't experience daylight saving time. In France, however, it does. So the way to calculate the DateTimes in each case are very different.

Universal Time Code (UTC)

The keyword "UTC" comes up a lot in discussions around time management. It is the name of a Timezone called "Universal Time Code". It is very often used to communicate Instants between actors in different Timezones. It has a special property that makes it very useful for storing Instants. It doesn't experience daylight saving time. This means that the conversion between Instants and DateTimes becomes reversible. Or in other words: A DateTime in UTC is equivalent to an Instant. You can convert between the two without loss of information.

Storage

So how do you store Instant, DateTime and Timezone ?

Instants can be stored as offset from a known Instant (epoch) in seconds. This is also called a timestamp. A common choice of the epoch is the Instant that corresponds to the DateTime Jan 1st 1970 at midnight in the Timezone UTC. The offset can be in seconds, milliseconds, etc. You can choose the granularity. This storage method is space efficient, since you only need to store one number.

DateTimes can be stored as strings or as Instant in UTC. There are several formats for the string representation. The most common format is the ISO 8601 format. It looks like this: 2023-03-15T12:34:56. This corresponds to March 15th, 2023 at 12:34:56. The Timezone is not specified in this example.

The second storage method is to store DateTimes as Instants in UTC. As already discussed, Instants in UTC map uniquely to DateTimes and vice-versa. This storage method is space efficient, since you only need to store one number. However, it is important to note that it is easy to make mistakes when using this method. You have to be very careful with your conversions.

Timezone values are usually stored as strings. There are standardized names for timezones. You should use these names. They are supported by libraries implementing Timezone.

DateTime or Instant?

Let's do some examples of when to use which for your information.

The time information of a log entry in a computer system: Instant, because it happens at a specific point in time.

Showing an Instant to a user: DateTime (obtained by applying the users Timezone).

A users birthdate: Date / DateTime , because that's what's written on their official documents.

The timing information of a one-off calendar event in a shared calendar: Instant, because it happens at a specific point in time. The Timezone of one user does not influence the Instant.

The timing information of a recurring calendar event. That's a tricky one. Think of every Monday at 2AM. What happens if the user changes their timezone? What happens on the day the clocks are reset for daylight saving time? Does the event happen twice? In my opinion there's no absolute answer here. It depends on how you want your system to behave. I'd store a DateTime + Timezone. I'd add code to handle the edge cases of the Timezone (using a library of course). And then I'd start praying.

The JS Date class

So what does the JS Date class represent? It's JS, so let's not be surprised by the answer: an Instant. Yes, that's the hard truth. And I want to be very clear: There is no Timezone information stored in the Date class. No UTC. It's an Instant. End of story.

But why does it have getters and setters for years, months, days, hours, minutes, and seconds? Because it's badly designed. And what do these return? They convert the Instant to a DateTime in the local Timezone of your user (frontend) or your server (backend). And then they extract the year, month, etc. and return them as numbers.

And here's another hard truth: Your users Timezone might be anything. You can't assume that:

  1. it's correct.
  2. it does / doesn't experience daylight saving time
  3. its offset to UTC is positive / negative
  4. it won't change

You need to code with this in mind.

I think the JS Date class should be avoided for anything related to DateTime. Instead, use one of the established libraries: Moment.js or Day.js. And in the near future, use the successor of Date, the new Temporal API.

Top comments (1)

Collapse
 
alexmustiere profile image
Alex Mustiere

Don't use Moment JS as stated on their homepage (momentjs.com/) or here (momentjs.com/docs/#/-project-status/).