Temporal API: JavaScript Dates Done Right
new Date() is broken. Time zones are wrong, arithmetic is painful, and DST transitions silently corrupt data. The Temporal API (Stage 3 proposal, polyfill available) fixes all of it.
The Problems with Date
// Date is mutable — easy to corrupt shared state
const d = new Date();
d.setDate(d.getDate() + 1); // Mutates d in place
// Month is 0-indexed — Jan = 0, Dec = 11
new Date(2026, 0, 1); // January 1, not month 0
// No timezone support
new Date('2026-04-08T08:00:00'); // Interpreted as LOCAL time
new Date('2026-04-08T08:00:00Z'); // UTC — inconsistent behavior
// Arithmetic is manual and error-prone
const tomorrow = new Date(Date.now() + 24 * 60 * 60 * 1000);
// Breaks during DST — some days are 23 or 25 hours
Temporal Basics
import { Temporal } from '@js-temporal/polyfill';
// PlainDate — calendar date without time
const today = Temporal.Now.plainDateISO();
console.log(today.toString()); // '2026-04-07'
// PlainDateTime — date + time without timezone
const meeting = Temporal.PlainDateTime.from('2026-04-08T09:00:00');
// ZonedDateTime — date + time + timezone (the full picture)
const launch = Temporal.ZonedDateTime.from({
year: 2026, month: 4, day: 8,
hour: 8, minute: 0,
timeZone: 'America/Denver',
});
Immutable Arithmetic
const today = Temporal.Now.plainDateISO();
// Returns new instance — original unchanged
const tomorrow = today.add({ days: 1 });
const nextMonth = today.add({ months: 1 });
const lastYear = today.subtract({ years: 1 });
// Correctly handles month lengths
const jan31 = Temporal.PlainDate.from('2026-01-31');
const feb = jan31.add({ months: 1 }); // '2026-02-28' — not March!
Duration
const start = Temporal.PlainDateTime.from('2026-04-01T09:00:00');
const end = Temporal.PlainDateTime.from('2026-04-08T17:30:00');
const duration = end.since(start);
console.log(duration.days); // 7
console.log(duration.hours); // 8
console.log(duration.minutes); // 30
// Human readable
const days = Math.floor(duration.total({ unit: 'days' }));
Comparison
const a = Temporal.PlainDate.from('2026-04-07');
const b = Temporal.PlainDate.from('2026-04-08');
Temporal.PlainDate.compare(a, b); // -1 (a < b)
a.equals(b); // false
// Sort an array of dates
dates.sort((a, b) => Temporal.PlainDate.compare(a, b));
Time Zone Conversion
// Convert between time zones
const utc = Temporal.Now.zonedDateTimeISO('UTC');
const denver = utc.withTimeZone('America/Denver');
const tokyo = utc.withTimeZone('Asia/Tokyo');
console.log(utc.toString()); // 2026-04-07T15:00:00+00:00[UTC]
console.log(denver.toString()); // 2026-04-07T09:00:00-06:00[America/Denver]
console.log(tokyo.toString()); // 2026-04-08T00:00:00+09:00[Asia/Tokyo]
Install Polyfill
npm install @js-temporal/polyfill
import { Temporal, Intl, toTemporalInstant } from '@js-temporal/polyfill';
// Temporal is available natively in Chrome 121+ and Firefox 139+
TypeScript utilities including date helpers ship in the AI SaaS Starter Kit. $99 at whoffagents.com.
Top comments (0)