JavaScript Temporal API - Finally a Proper Date Replacement
Problem
JavaScript’s Date object has frustrated developers for over two decades.
// Create January 15, 2026
const date = new Date(2026, 0, 15); // month starts from 0?!
console.log(date.getMonth()); // 0 ← It's January, but returns 0
// Mutating a reference changes the original
const original = new Date(2026, 0, 15);
const copy = original;
copy.setMonth(5);
console.log(original.getMonth()); // 5 ← original is mutated
Zero-indexed months and mutable objects have been a constant source of bugs. Most teams ended up depending on libraries like moment.js or day.js just to handle dates sanely. Now there’s a native solution.
Solution
The Temporal API ships natively in Chrome 144 (January 2026) and Firefox 139 (May 2025). No libraries needed.
Creating Dates
// PlainDate - date without time
const date = Temporal.PlainDate.from('2026-02-07');
const date2 = Temporal.PlainDate.from({ year: 2026, month: 2, day: 7 });
console.log(date.month); // 2 ← February is actually 2!
console.log(date.dayOfWeek); // 6 (Saturday)
// PlainTime - time without date
const time = Temporal.PlainTime.from('14:30:00');
console.log(time.hour); // 14
Date Arithmetic
const today = Temporal.PlainDate.from('2026-02-07');
// 30 days later
const later = today.add({ days: 30 });
console.log(later.toString()); // 2026-03-09
// Original stays unchanged (immutable!)
console.log(today.toString()); // 2026-02-07
// Duration between two dates
const start = Temporal.PlainDate.from('2026-01-01');
const end = Temporal.PlainDate.from('2026-02-07');
const diff = start.until(end);
console.log(diff.days); // 37
Timezone Conversion
// Current time in Seoul
const now = Temporal.Now.zonedDateTimeISO('Asia/Seoul');
console.log(now.toString());
// 2026-02-07T14:30:00+09:00[Asia/Seoul]
// Convert to New York time
const nyTime = now.withTimeZone('America/New_York');
console.log(nyTime.toString());
// 2026-02-07T00:30:00-05:00[America/New_York]
Timezone conversion with Date required ugly workarounds. With Temporal, it’s a single withTimeZone() call.
Key Points
- Months start from 1: January = 1, December = 12. The most common off-by-one bug source is gone
- Immutable by design: Every operation like
add()andsubtract()returns a new object. No more accidental mutations - Purpose-built types:
PlainDate(date only),PlainTime(time only),ZonedDateTime(with timezone) — use exactly what you need - Browser support: Available in Chrome 144+ and Firefox 139+. For Safari, use
@js-temporal/polyfillin production