JavaScript’s Temporal API officially reached TC39 Stage 4 on March 11, 2026, making it part of the ES2026 specification. Chrome 144 and Firefox 139 already ship it natively. After nine years of standardization work and three decades of new Date() bugs, JavaScript now has a proper date-and-time primitive—immutable, timezone-aware, and nanosecond-precise.
What Is the Temporal API?
Temporal is a new set of built-in JavaScript objects for representing and manipulating dates, times, and durations. It does not patch the existing Date object—it replaces it with a purpose-built family of types that address every major failure mode of Date at the language level.1
Where Date is a single mutable object that conflates calendar dates, wall-clock times, UTC instants, and timezone offsets into one confused blob, Temporal offers distinct types for each semantic concept. You reach for the right type and the API prevents the class of bugs that follow from picking the wrong one.
The core types are:
| Type | What It Represents | Typical Use Case |
|---|---|---|
Temporal.PlainDate | Calendar date (no time, no zone) | Birthdays, deadlines, holidays |
Temporal.PlainTime | Wall-clock time (no date, no zone) | Business hours, alarm times |
Temporal.PlainDateTime | Date + time, no timezone | Log entries, local schedules |
Temporal.ZonedDateTime | Date + time + IANA timezone | Calendar events, user-facing timestamps |
Temporal.Instant | Exact moment (nanoseconds since epoch) | Metrics, event ordering, serialization |
Temporal.Duration | Span of time | Countdowns, elapsed time |
Temporal.Now | Utilities for current time | Replacements for Date.now() |
Why Did JavaScript’s Date Object Need Replacing?
The Date object was written by Brendan Eich in 1995 in approximately 10 days, copied almost directly from Java’s java.util.Date class. Java itself had copied the design from C, which traces the zero-indexed month convention back to Research Unix V4 in 1973.2
That lineage explains every maddening quirk of Date:
Zero-indexed months. January is 0, December is 11. Days of the month are one-indexed. Years are normal. The inconsistency has no rational justification and has burned developers for 30 years.
// Date: January is 0const date = new Date(2026, 0, 15); // January 15thdate.getMonth(); // → 0
// Temporal: January is 1const tDate = Temporal.PlainDate.from({ year: 2026, month: 1, day: 15 });tDate.month; // → 1Mutability. Date methods like setDate(), setMonth(), and setFullYear() modify the object in place, making functions that accept dates unpredictable. Pass a Date into a function; that function can silently alter it.
// Date: mutable, side-effect proneconst deadline = new Date(2026, 2, 31);deadline.setDate(deadline.getDate() + 7); // mutates deadlineconsole.log(deadline); // April 7 — the original date is gone
// Temporal: immutable, returns a new objectconst tDeadline = Temporal.PlainDate.from('2026-03-31');const extended = tDeadline.add({ days: 7 });console.log(tDeadline.toString()); // '2026-03-31' — unchangedconsole.log(extended.toString()); // '2026-04-07'No real timezone support. Date stores a UTC millisecond timestamp and renders it in the host machine’s local timezone. It does not understand IANA timezone names like America/New_York. It tracks offsets—integers like -05:00—not the rules that govern them. When DST transitions occur, Date arithmetic can produce results that are off by an hour, and the behavior has differed across browsers.3
Browser inconsistencies. Feeding new Date('2026-01-15') a date-only string returns midnight UTC in most browsers but midnight local time in others. The spec was underspecified for parsing, and implementations diverged accordingly.
Millisecond ceiling. Date.now() maxes out at millisecond precision. Temporal.Instant stores nanoseconds since the Unix epoch—6 orders of magnitude more granular—without requiring performance.now() gymnastics.4
How the Temporal API Solves These Problems
Type Safety Through Separation
The explicit separation between PlainDate, PlainDateTime, and ZonedDateTime forces developers to declare whether timezone matters—at the type level, not as documentation or convention.
// A date-only value: no accidental timezone arithmeticconst birthday = Temporal.PlainDate.from('1991-06-15');
// A precise, timezone-aware eventconst meeting = Temporal.ZonedDateTime.from( '2026-03-20T14:00:00[America/New_York]');
// Current moment with full nanosecond precisionconst now = Temporal.Now.instant();console.log(now.epochNanoseconds); // e.g., 1742000000000000000nArithmetic That Respects Reality
Duration-based arithmetic in Temporal understands DST. Adding one day to a ZonedDateTime gives you the next calendar day at the same wall-clock time—not 24 hours later, which might land in the wrong hour after a DST transition.
const beforeDST = Temporal.ZonedDateTime.from( '2026-03-07T10:00:00[America/New_York]'); // Day before spring forward
// Add 1 day: lands at 10:00 AM even though 25 hours pass in UTCconst afterDST = beforeDST.add({ days: 1 });console.log(afterDST.toString());// 2026-03-08T10:00:00-04:00[America/New_York]Deterministic Parsing
Temporal.PlainDate.from() throws a RangeError on invalid input rather than silently returning Invalid Date or guessing. There is no ambiguity: the string format is ISO 8601, strictly enforced.
// Date: silent failurenew Date('not-a-date'); // Invalid Date — no error thrown
// Temporal: strict validationTemporal.PlainDate.from('not-a-date'); // throws RangeErrorCalendar System Support
Temporal ships with support for non-Gregorian calendar systems as a first-class concern—Islamic, Hebrew, Japanese, Chinese calendars among them. Internationalization no longer requires external libraries for calendar-aware date arithmetic.5
Nine Years: How Web Standards Actually Get Made
The Temporal proposal entered TC39 at Stage 1 in 2017, championed by Maggie Johnson-Pint, who had spent years maintaining Moment.js and knew the ecosystem’s pain intimately.6 The problem was not controversial—the committee recognized Date was broken immediately. The difficulty was design.
Date-and-time is one of the most semantically complex domains in computing. Timezones change. Calendars differ across cultures. DST rules are revised by governments with little notice. A design adequate for 2017 web apps needed to remain coherent for the next 20 years of JavaScript.
Bloomberg became a significant force in moving the proposal forward. Bloomberg engineers already worked with value-semantic datetime types internally. When Bloomberg’s Andrew Paprocki connected with Igalia and Daniel Ehrenberg at TC39, it created a bridge between production engineering needs and standards infrastructure.7 Bloomberg and Igalia funded sustained implementation work in browser engines—the unglamorous work of turning a spec into shipping code across V8, SpiderMonkey, and JavaScriptCore.
Progress stalled repeatedly. Stage 3 was reached in 2021 but the proposal sat there for four years while implementations were written, edge cases identified, and spec text refined. Firefox 139 was the first browser to ship Temporal by default, in May 2025. Chrome 144 followed in January 2026.8
On March 11, 2026, at TC39’s 113th plenary meeting in New York, Temporal advanced to Stage 4—the final stage, meaning ratification into ES2026.9
What This Means for the Ecosystem
The Date Library Era Is Ending
Moment.js declared itself in maintenance mode years ago, explicitly citing Temporal as the long-term successor.10 Luxon, date-fns, and Day.js remain relevant for applications supporting browsers without native Temporal—primarily Safari, which has not yet shipped a stable release (as of March 2026, Safari supports Temporal only in Technology Preview).
For new projects targeting Chrome and Firefox, Temporal covers what these libraries provided without the bundle weight. Moment.js adds 67KB minified to a bundle; Temporal costs nothing.
Polyfill for the Transition Period
The @js-temporal/polyfill npm package provides compatibility for environments without native support. It adds meaningfully less bundle size than Moment or moment-timezone, though the polyfill team notes it should be treated as beta-quality for production use.11
npm install @js-temporal/polyfillimport { Temporal } from '@js-temporal/polyfill';
const today = Temporal.Now.plainDateISO();console.log(today.toString()); // '2026-03-15'TypeScript 6.0 Ships Native Types
TypeScript 6.0 RC, released March 6, 2026, includes built-in type definitions for the entire Temporal API. Enable them with "lib": ["esnext"] or the granular "temporal.esnext" lib entry—no @types/ package required.12
Node.js and Deno
Node.js 22+ exposes Temporal via V8 once the flag is enabled; Node 23 is expected to ship it unflagged. Deno already includes full Temporal support through its web-standard-first approach.
The Comparison: Old Patterns vs. New
| Concern | Legacy Date | Temporal |
|---|---|---|
| Month indexing | 0–11 (January = 0) | 1–12 (January = 1) |
| Mutability | Mutable in place | Immutable, returns new objects |
| Timezone support | Offset only (-05:00) | Full IANA names (America/New_York) |
| Precision | Milliseconds | Nanoseconds |
| Parsing | Ambiguous, browser-dependent | Strict ISO 8601, throws on error |
| Calendar systems | Gregorian only | 12+ calendars including Hebrew, Islamic, Japanese |
| Duration arithmetic | Manual millisecond math | add({ months: 1 }), DST-aware |
| Comparison | date1 - date2 (numeric coercion) | Temporal.PlainDate.compare(a, b) |
| Type separation | One object for everything | Distinct types per semantic concept |
Frequently Asked Questions
Q: Is Date being removed from JavaScript?
A: No. Date remains in the language permanently for backward compatibility. Temporal is an addition, not a replacement at the removal level—but it is the API you should use going forward.
Q: Can I use Temporal in production today?
A: In Chrome 144+ and Firefox 139+, yes—it ships natively. For Safari support you need the @js-temporal/polyfill, which the team considers beta-quality. If your user base is primarily Chrome/Firefox, native Temporal is production-ready as of March 2026.
Q: Does Temporal replace performance.now() for timing?
A: Not exactly. Temporal.Now.instant() provides nanosecond precision for timestamps, but performance.now() remains the standard for high-resolution relative timing within a session. They serve different purposes: Temporal for absolute time points and durations; performance.now() for benchmarking and animation frames.
Q: How do I migrate existing code that uses Moment.js?
A: Smashing Magazine published a migration guide in March 2026 covering the Moment-to-Temporal path. The key shift is conceptual: stop thinking in mutable Date wrappers and start thinking in typed, immutable value objects. Most moment(date).add(7, 'days') calls map directly to temporalDate.add({ days: 7 }).
Q: What happens to TypeScript users before TypeScript 6.0?
A: Install @js-temporal/polyfill, which ships its own TypeScript definitions. Alternatively, the @types/temporal-polyfill community package provides type coverage. TypeScript 6.0 stable (expected March 2026) resolves the question for everyone on the current toolchain.
Sources:
- JavaScript Temporal in 2026 - is it finally here? - Bryntum
- Temporal - JavaScript | MDN
- Chrome 144 Ships Temporal API - InfoQ
- Temporal: The 9-Year Journey to Fix Time in JavaScript | Bloomberg JS Blog
- Temporal Reaches Stage 4 | Igalia
- TC39 Proposal Temporal | GitHub
- ES2026 Solves JavaScript Headaches - The New Stack
- Announcing TypeScript 6.0 RC - TypeScript Blog
- Moving From Moment.js To The JS Temporal API - Smashing Magazine
- @js-temporal/polyfill - npm
- JavaScript Date type is horribly broken - codeofmatt.com
- History of Zero-based Months? - jefftk.com
Footnotes
-
MDN Web Docs. “Temporal - JavaScript.” Mozilla, March 2026. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal ↩
-
Jeff Kaufman. “History of Zero-based Months?” jefftk.com. https://www.jefftk.com/p/history-of-zero-based-months ↩
-
Matt Johnson-Pint. “JavaScript Date type is horribly broken.” codeofmatt.com. https://codeofmatt.com/javascript-date-type-is-horribly-broken/ ↩
-
MDN Web Docs. “Temporal.Instant.” Mozilla, 2026. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant ↩
-
TC39 Proposal. “Temporal Documentation.” tc39.es. https://tc39.es/proposal-temporal/docs/ ↩
-
Bloomberg Engineering. “Temporal: The 9-Year Journey to Fix Time in JavaScript.” Bloomberg JS Blog. https://bloomberg.github.io/js-blog/post/temporal/ ↩
-
Igalia. “Temporal Reaches Stage 4.” March 13, 2026. https://www.igalia.com/2026/03/13/Temporal-Reaches-Stage-4.html ↩
-
InfoQ. “Chrome 144 Ships Temporal API: Advancing JavaScript Date/Time Standardisation.” February 2026. https://www.infoq.com/news/2026/02/chrome-temporal-date-api/ ↩
-
The New Stack. “ES2026 Solves JavaScript Headaches With Dates, Math and Modules.” March 2026. https://thenewstack.io/es2026-solves-javascript-headaches-with-dates-math-and-modules/ ↩
-
Moment.js. “Project Status.” momentjs.com. https://momentjs.com/docs/ ↩
-
npm. “@js-temporal/polyfill.” npmjs.com. https://www.npmjs.com/package/@js-temporal/polyfill ↩
-
Microsoft. “Announcing TypeScript 6.0 RC.” TypeScript Blog, March 6, 2026. https://devblogs.microsoft.com/typescript/announcing-typescript-6-0-rc/ ↩