JavaScript Finally Fixed Dates (And It Only Took 30 Years)
Enter the new Temporal API
The Temporal API just shipped in Chrome 144 and Firefox 139. If you’ve ever fought with Date objects, this is the moment you’ve been waiting for.
The Date Object Was Always Broken
Let me tell you a story. In 1995, Brendan Eich had 10 days to build JavaScript. He was told to “make it like Java,” so he copied Java’s Date object.
Java fixed their Date in 1997. JavaScript? We’ve been stuck with it for 30 years.
// This is JavaScript in 2025
const date = new Date('2025-02-06');
date.getMonth(); // Returns 1 (February is month 1?!)
// Try to add a month
date.setMonth(date.getMonth() + 1);
// Hope you didn't need that original date value
// Also hope you didn't try this with January 31st
Zero-indexed months. Mutable objects that change when you pass them around. Time zone handling that’s basically “good luck.” The Date object is a masterclass in how not to design an API.
And we’ve been living with it because... backward compatibility. Can’t fix it without breaking the entire web.
Enter Temporal: JavaScript’s Second Chance
After years in TC39 proposal hell, Temporal is finally here. Firefox shipped it in May 2025. Chrome shipped it in January 2026. It’s real, it’s stable, and it’s actually good.
Here’s the same code with Temporal:
const date = Temporal.PlainDate.from('2025-02-06');
date.month; // Returns 2 (because February is the 2nd month, obviously)
// Add a month - returns a NEW date
const nextMonth = date.add({ months: 1 });
// Original date is unchanged, no surprisesSimple. Predictable. Immutable. This is what we should have had from day one.
Why This Actually Matters
Time zones that work: Remember fighting with DST bugs? Or trying to figure out what time “9 AM tomorrow” means across time zones?
// Old way - pray it works
const meeting = new Date('2025-03-10T09:00:00');
meeting.setDate(meeting.getDate() + 1);
// Did DST just break your meeting time? Who knows!
// Temporal way - explicit and correct
const meeting = Temporal.ZonedDateTime.from({
year: 2025,
month: 3,
day: 10,
hour: 9,
timeZone: 'America/New_York'
});
const tomorrow = meeting.add({ days: 1 });
// DST transitions handled correctly, no surprises
Durations that make sense: Ever tried to calculate “2 weeks and 3 days from now”? With Date you’re doing manual math with milliseconds. With Temporal:
const now = Temporal.Now.plainDateISO();
const deadline = now.add({ weeks: 2, days: 3 });
Different types for different needs: This is the real genius. Date tried to be everything and ended up being terrible at everything. Temporal gives you:
Temporal.Instant- A point in time (like Unix timestamp)Temporal.PlainDate- Just a date, no timeTemporal.PlainTime- Just a time, no dateTemporal.PlainDateTime- Date + time, no timezoneTemporal.ZonedDateTime- The whole package with timezoneTemporal.Duration- Time spans
Use what you need. No more “is this date UTC or local?” confusion.
The Performance Question
“But is it fast?” Yeah, I had the same question.
Early benchmarks showed Date was faster. That makes sense - it’s been optimized for 30 years. But here’s the thing: Temporal’s performance has been catching up fast now that it’s shipping in browsers.
For most apps, the performance difference doesn’t matter. You’re probably not doing thousands of date calculations in a hot loop. And if you are, you’re probably already using a library like date-fns anyway.
What matters more: not shipping bugs. DST bugs. Timezone bugs. Off-by-one bugs because months are zero-indexed. Temporal eliminates entire categories of mistakes.
Should You Use It?
In production? Not yet. Safari doesn’t ship it yet (though it’s in Technical Preview). Node.js has it behind a flag. The polyfill works, but it’s big (~160kb).
In new projects? Absolutely plan for it. Use the polyfill now, switch to native when Safari ships. Write your code with Temporal from day one.
In legacy codebases? Migrate gradually. Temporal and Date can coexist:
// Convert between them when you need to
const legacyDate = new Date();
const temporal = Temporal.Instant.fromEpochMilliseconds(
legacyDate.getTime()
);
The Real Win
Here’s what gets me excited: we’re finally moving past band-aid solutions.
Moment.js existed because Date sucked. Then date-fns existed because Moment was too big. Then Day.js existed because date-fns was too big. Then Luxon existed because we needed better timezone support.
All of these libraries exist to paper over JavaScript’s fundamental date problem. Temporal fixes it at the platform level.
Will people still use date libraries? Sure. But now they’ll be doing it for convenience and syntax sugar, not because the platform is fundamentally broken.
My Take
I’ve been burned by Date too many times. The zero-indexed months. The mutable objects that get changed three functions deep. The time zone bugs that only show up in production when users are in different regions.
Temporal isn’t just “nice to have.” It’s what JavaScript should have shipped with in 1995. Better late than never.
The API is a bit verbose - sure, Temporal.PlainDate.from() is longer than new Date(). But verbosity that prevents bugs beats brevity that causes them.
And honestly? After 30 years of Date pain, I’m just happy we’re finally getting something that works.
Browser Support:
✅ Firefox 139+ (May 2025)
✅ Chrome 144+ (January 2026)
⏳ Safari (in Technical Preview)
⏳ Node.js (behind flag, coming in next major)
Try it now: Use the @js-temporal/polyfill package
Have you tried Temporal yet? Hit reply and let me know what you think.


