Temporal

Temporal: the Successor to Date (ES2027)

Temporal reached Stage 4 in March 2026 and joins ES2027. It ships in Chrome 144 1 , Firefox 139 555 , Deno 2.7 60,577 and Node.js 26 2,131 ; Safari 10 has it only in Technology Preview, so load temporal-polyfill 775 (github.com/fullcalendar/temporal-polyfill (https://github.com/fullcalendar/temporal-polyfill 775 )) there. Its objects are immutable, months count from 1, parsing accepts only ISO 8601 (plus RFC 9557 zone annotations such as [Europe/Paris]), and separate types say what a value means: Instant (an exact moment), ZonedDateTime (moment plus time zone), PlainDate, PlainTime and PlainDateTime (wall-clock values with no zone) and Duration. Node.js 25 lacks Temporal, so this listing ran in headless Chrome 152.

Month-end clamping, DST-aware arithmetic and durations (Chrome 152)JavaScriptLive
const jan31 = Temporal.PlainDate.from('2026-01-31');
console.log(`${jan31.add({ months: 1 })}`, jan31.dayOfWeek, jan31.daysInMonth);  // clamps to Feb 28
const call = Temporal.ZonedDateTime.from('2026-03-07T09:00[America/New_York]');
const nextDay = call.add({ days: 1 });                 // crosses the DST change on 8 March
console.log(`${nextDay}`, `${nextDay.since(call, { largestUnit: 'hours' })}`);
console.log(`${call.withTimeZone('Asia/Kuala_Lumpur').toPlainDateTime()}`);
const wait = Temporal.PlainDate.from('2026-09-15').until('2026-12-25', { largestUnit: 'months' });
console.log(`${wait}`, wait.months, wait.days, `${new Date(0).toTemporalInstant()}`);

Adding one day kept 09:00 local time even though only 23 hours passed, which Date arithmetic gets wrong. Bridge old code with date.toTemporalInstant() and new Date(instant.epochMilliseconds).