JavaScript Dates were never really about Dates

Consider this blog post to be a quick catch-up on what Temporal is, why we need it, and why you might already want to consider using it today, even though (at the time of writing) it is not yet available in all major browsers. If you’ve been hurt by timezones before and did not enjoy the experience, this might be what you are looking for.

Dates are nastier than they look

The JavaScript Date has always just been a fancy Unix timestamp with a couple of tools attached to get some human-readable data out of it.

As developers, we tend to think of dates as if they can easily be represented by numbers. In reality, they're much more complex than that.

Dates and times are one of those problems that seem trivial until you have to deal with them in a real application. Most of us think of time as "just a timestamp", but users rarely do.

Users care about concepts like:

  • Tomorrow at 9 AM

  • The last day of the month

  • Every Monday

  • The same time in another timezone

  • A birthday, regardless of timezone

Those concepts are fundamentally different from a single point in time represented by milliseconds since January 1st, 1970.

In fact, time handling has historically been responsible for an impressive number of software bugs. If you're interested in going down that rabbit hole, there's even a whole list of notable date and time-related failures on Wikipedia:

Unfortunately, JavaScript's own DateAPI has had its fair share of quirks as well. Many of these issues are somewhat confusing and, due to JavaScript's strong commitment to backwards compatibility, will likely never be fixed.

If you've never looked into the weirdness and fun of Date, feel free to check out jsdate.wtf

It's both educational and mildly terrifying.

What's actually wrong with Date?

The biggest issue with Date is that it tries to represent several different concepts at once:

  • A timestamp

  • A calendar date

  • A local date/time

  • A UTC date/time

As a result, the same object exposes methods like:

date.getMonth(); date.getUTCMonth(); date.toLocaleString(); date.toISOString();

Accidentally mixing local and UTC operations is one of the most common sources of date-related bugs.

A good example is this:

new Date("2025-01-01");

At first glance, this looks like "January 1st, 2025".

In reality, you've created a specific point in time. Depending on the user's timezone, displaying that value may even show up as December 31st, 2024.

That behavior is technically correct, but rarely what developers expect.

The problem isn't necessarily that Date is broken. The problem is that a single object is trying to solve too many different problems at once.

We've tried fixing this before

Over the years there have been plenty of attempts to improve the situation through community-maintained libraries.

The most notable example was probably Moment.js. When I first started programming, I pretty much assumed Moment was the gold standard for date handling.

Of course, these libraries all had their own tradeoffs, but they were generally far superior to relying exclusively on the native Date API.

Other libraries such as Luxon and date-fns continued pushing the ecosystem forward and collectively taught the community a lot about what a good date API should actually look like.

Fortunately, those lessons eventually found their way into the language itself.

Enter Temporal

Temporal is a new standardized date and time API for JavaScript and a worthy successor to Date.

What's particularly interesting is that Temporal doesn't primarily add new capabilities. Instead, it fixes a design mistake that has existed since the earliest days of JavaScript.

Rather than trying to represent every concept using a single object, Temporal splits responsibilities into dedicated types.

A few examples:

Temporal.Instant

Represents a precise moment in time.

Temporal.Instant.from("2025-01-01T12:00:00Z");

This is what many developers currently use Date for.

Temporal.PlainDate

Represents a calendar date without time or timezone information.

Temporal.PlainDate.from("2025-01-01");

Perfect for birthdays, holidays, due dates, and similar concepts.

Temporal.PlainTime

Represents a time without a date.

Temporal.PlainTime.from("09:30");

Useful for recurring schedules or opening hours.

Temporal.ZonedDateTime

Represents a date and time tied to a specific timezone.

Temporal.ZonedDateTime.from( "2025-01-01T09:30:00[Europe/Berlin]" );

This makes timezone-aware calculations significantly safer and easier to reason about.

More than just better types

Temporal also comes with several quality-of-life improvements.

For example, Temporal objects are immutable.

With Date, operations often mutate the original object:

const date = new Date(); date.setMonth(12);

With Temporal, operations return a new value instead:

const nextMonth = date.add({ months: 1 });

This aligns much better with modern JavaScript APIs and eliminates an entire category of accidental mutations.

Date arithmetic is also somewhat more pleasant.

const tomorrow = date.add({ days: 1 }); const nextYear = date.add({ years: 1 });

Compare that to traditional Date arithmetic involving timestamp calculations and edge cases around daylight saving time transitions.

Temporal also introduces proper calendar support, whereas Date only supports the Gregorian calendar.

If you'd like to explore the API in more detail, the MDN documentation provides an excellent overview:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal

Can I use Temporal today?

(That is what caniuse is for)

Temporal is not Baseline just yet, mostly because Safari is still catching up.

That said, browser support is already surprisingly good.

At the time of writing, roughly 67% of browsers used by end users already support Temporal:

In practice, we're mostly waiting for Safari support before Temporal becomes an easy recommendation for virtually every project.

If you'd like to start using it today, there's a polyfill available:

https://www.npmjs.com/package/temporal-polyfill

For greenfield projects, adopting Temporal through a polyfill is already a perfectly reasonable option. For existing applications, introducing it incrementally is probably the most realistic path.

My personal feelings toward Temporal

I was introduced to Temporal by a colleague after I ran into some timezone-related issues and suggested adding Moment.js to an existing project.

And yes, that happened in 2025. Silly me.

Ever since then I've begun to appreciate what Temporal brings to the table.

I hadn't really noticed just how difficult date and time handling was until I encountered some genuinely nasty timezone bugs in production. Temporal's biggest achievement may simply be making those bugs much harder to create in the first place.

To me, Temporal feels like the culmination of years of lessons learned from Moment.js, Luxon, date-fns, and the wider JavaScript ecosystem. Getting all of those lessons standardized into the language itself is quite an impressive achievement.

I don't think Date is going away anytime soon (we have to stay backwards compatible after all), but for new applications I can absolutely see Temporal becoming the default choice once browser support catches up.