If you’ve ever built a web application, you’ve dealt with JavaScript’s Date object. Everyone has.
Parsing a date string and getting a different result depending on which browser runs it. Adding two days to a variable and accidentally mutating the original. Trying to figure out what time it is in Tokyo when your server is in London. The Date object was born in 1995 during Brendan Eich’s ten-day sprint to create JavaScript (then called Mocha). But Eich didn’t write the Date code himself. Ken Smith at Netscape ported Java’s java.util.Date directly into the language, bugs and all. It was the only code in Mocha that Eich didn’t write. Changing the API to differ from Java wasn’t an option: Sun would have objected, and the internal philosophy at Netscape was literally called MILLJ (Make It Look Like Java).
That shortcut has caused bugs for over three decades.
After roughly eight years in the TC39 standardization process (the proposal reached Stage 1 in 2018), JavaScript now has a proper replacement: The Temporal API.
What was wrong with Date?
Everything. But specifically:
- Mutable by default. Modify a
Dateand you change the original object. A helper function that’s supposed to return the next day can silently corrupt the date you passed into it. - No real timezone support.
Dateunderstands UTC and the user’s local time. That’s it. Anything else requires manual offset math or a library. - No date-only or time-only types. You can’t represent “March 12th, 2026” without also specifying a time and timezone. Everything is a full timestamp under the hood.
- 0-indexed months. January is 0, but days start at 1. This is inherited from
java.util.Date. Java deprecated that class in 1997 and replaced it withjava.timein 2014. JavaScript kept the original design for 30 years. - Ambiguous parsing. The string
"2026-06-25 15:15:00"produces different results across browsers. Some treat it as local time, some as UTC, and some throw an error. The spec left “almost ISO” strings as undefined behavior. - Silent overflow. Setting a date to February 31st doesn’t throw an error. It rolls over to March 3rd.
new Date("Sat Jan 31 2026").setMonth(1)gives you March 3rd, not February 28th.
Because of all this, the ecosystem leaned on third-party libraries: moment.js, date-fns, luxon, dayjs. Moment.js alone still gets over 12 million downloads per week, even though the team put it in maintenance mode in September 2020. They’ll patch security issues, but there won’t be new features or fixes for long-standing quirks.
Enter Temporal
The Temporal API is a new global Temporal object, similar to Math or Intl. It’s the biggest addition to the ECMAScript spec since ES2015, with roughly 4,500 tests in the official test suite.
1. Immutability
All Temporal objects are immutable. Adding a day to a date returns a new object. The original stays untouched.
const today = Temporal.PlainDate.from('2026-03-12');const tomorrow = today.add({ days: 1 });
console.log(today.toString()); // '2026-03-12'console.log(tomorrow.toString()); // '2026-03-13'2. Separate types for separate things
Instead of stuffing everything into one Date object, Temporal gives you distinct types:
Temporal.Instant— a fixed point in time at nanosecond precision. No timezone, no calendar. Just a timestamp.Temporal.PlainDate— a date with no time or timezone. Your birthday.Temporal.PlainTime— a time with no date. “3:00 PM.”Temporal.PlainDateTime— date and time, no timezone. “The meeting is at 3 PM” when the timezone is implied.Temporal.ZonedDateTime— the full package: timezone-aware, DST-aware. The closest replacement fornew Date().Temporal.Duration— a length of time (5 hours and 30 minutes), for arithmetic and measuring differences.Temporal.PlainYearMonth/Temporal.PlainMonthDay— partial dates like “October 2026” or “July 14th.”
3. Timezone handling that works
Timezones use IANA identifiers and are DST-aware out of the box.
// What time is it in Tokyo right now?const tokyoTime = Temporal.Now.zonedDateTimeISO('Asia/Tokyo');console.log(tokyoTime.toString());// e.g., '2026-03-12T16:40:00+09:00[Asia/Tokyo]'4. Readable date math
No more multiplying by 1000 * 60 * 60 * 24.
const meeting = Temporal.PlainDateTime.from('2026-03-12T15:00:00');const delayedMeeting = meeting.add({ hours: 1, minutes: 30 });
console.log(delayedMeeting.toString()); // '2026-03-12T16:30:00'5. Duration and comparison
Temporal has Duration objects and built-in comparison. Sorting a list of durations is one line:
const d1 = Temporal.Duration.from({ hours: 1, minutes: 30 });const d2 = Temporal.Duration.from({ hours: 2 });const d3 = Temporal.Duration.from({ hours: 1, minutes: 45 });
const sorted = [d2, d3, d1].sort(Temporal.Duration.compare);console.log(sorted.map(d => d.toString()));// ['PT1H30M', 'PT1H45M', 'PT2H']6. Non-Gregorian calendars
Adding “one month” in the Hebrew or Chinese calendar actually uses that calendar’s month structure, instead of adding a Gregorian month and hoping for the best:
const hebrewDate = Temporal.PlainDate.from('2026-03-11[u-ca=hebrew]');hebrewDate.toLocaleString('en', { calendar: 'hebrew' }); // '22 Adar 5786'const nextMonth = hebrewDate.add({ months: 1 });nextMonth.toLocaleString('en', { calendar: 'hebrew' }); // '22 Nisan 5786'Browser support (March 2026)
Before you refactor everything, check where things stand:
- Firefox 139+ — shipped May 2025. Firefox was first, thanks to André Bargull’s work on SpiderMonkey.
- Chrome 144+ — shipped January 2026, using the Rust-based
temporal_rslibrary. - Edge 144+ — supported, same Chromium engine as Chrome.
- Safari — not yet. Behind a flag in Technology Preview, but not available to end users.
- Node.js — in progress.
Global browser support is around 49% according to caniuse.com/temporal. If you need it in production now, there are polyfills: temporal-polyfill and @js-temporal/polyfill.
What this means
Date-manipulation libraries like Moment.js, date-fns, and dayjs collectively get over 100 million npm downloads per week. With Temporal landing in browsers, those libraries will probably shift from patching language-level gaps to providing convenience wrappers and formatting opinions.
Date isn’t going away. Too much code depends on it. But Temporal is at TC39 Stage 3, and with Firefox and Chrome both shipping implementations, Stage 4 (full standardization) needs just one more thing: passing the acceptance tests. That’s within reach.
Next time you start a new project, skip Date.
(For the full history, including the challenges of aligning with IANA timezones, RFC 9557, and ISO 8601, read Bloomberg’s write-up. Bloomberg was one of the main champions of the proposal, since their trading terminals span every timezone on earth.)