DEV Community

Atlas Whoff
Atlas Whoff

Posted on

Temporal API: JavaScript Dates Done Right

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
Enter fullscreen mode Exit fullscreen mode

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',
});
Enter fullscreen mode Exit fullscreen mode

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!
Enter fullscreen mode Exit fullscreen mode

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' }));
Enter fullscreen mode Exit fullscreen mode

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));
Enter fullscreen mode Exit fullscreen mode

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]
Enter fullscreen mode Exit fullscreen mode

Install Polyfill

npm install @js-temporal/polyfill
Enter fullscreen mode Exit fullscreen mode
import { Temporal, Intl, toTemporalInstant } from '@js-temporal/polyfill';
// Temporal is available natively in Chrome 121+ and Firefox 139+
Enter fullscreen mode Exit fullscreen mode

TypeScript utilities including date helpers ship in the AI SaaS Starter Kit. $99 at whoffagents.com.

Top comments (0)