Chrome 144 shipped the Temporal API last week. JavaScript finally has a date/time system that works. Immutable objects, 1-indexed months, native timezone support, nanosecond precision.
I spent the weekend migrating a production dashboard from date-fns to Temporal. Removed 13KB from the bundle and deleted 140 lines of timezone utility code. Here are the seven patterns I replaced.
1. Timezone Conversion Without Moment Timezone
Before (Moment Timezone, 35KB extra):
import moment from 'moment-timezone';
const ny = moment.tz('2026-03-15 14:00', 'America/New_York');
const tokyo = ny.clone().tz('Asia/Tokyo');
After (zero dependencies):
const ny = Temporal.ZonedDateTime.from({
year: 2026, month: 3, day: 15, hour: 14,
timeZone: 'America/New_York'
});
const tokyo = ny.withTimeZone('Asia/Tokyo');
// "2026-03-16T04:00:00+09:00[Asia/Tokyo]"
One method. Handles DST transitions automatically. No timezone database bundled in your JavaScript.
2. Immutable Date Arithmetic
The mutation bug that every team hits eventually:
// Moment.js — mutates the original
const date = moment('2026-03-15');
formatHeader(date); // this calls date.add(1, 'day') internally
console.log(date); // now March 16. surprise.
// Temporal — impossible to mutate
const date = Temporal.PlainDate.from('2026-03-15');
const tomorrow = date.add({ days: 1 }); // returns new object
console.log(date.toString()); // still March 15. always.
3. Month Indexing That Makes Sense
// Old Date object
new Date(2026, 2, 15) // March 15. Because 2 = March. Obviously.
// Temporal
Temporal.PlainDate.from({ year: 2026, month: 3, day: 15 }) // March 15.
January is 1. December is 12. Thirty years of month + 1 hacks are over.
4. Date Validation That Actually Rejects Invalid Dates
// Old Date — silently gives you wrong data
new Date('2026-02-29') // March 1, 2026. No error. 2026 is not a leap year.
// Temporal — throws immediately
Temporal.PlainDate.from('2026-02-29') // RangeError: invalid date
This one change alone would have prevented bugs I have spent hours debugging in production.
5. Relative Time Without a Library
function relativeTime(isoString) {
const diff = Temporal.Instant.from(isoString)
.until(Temporal.Now.instant());
const sec = Math.abs(diff.total('seconds'));
const sign = diff.total('seconds') > 0 ? -1 : 1;
const fmt = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });
if (sec < 60) return fmt.format(sign * Math.round(sec), 'second');
if (sec < 3600) return fmt.format(sign * Math.round(sec / 60), 'minute');
if (sec < 86400) return fmt.format(sign * Math.round(sec / 3600), 'hour');
return fmt.format(sign * Math.round(sec / 86400), 'day');
}
relativeTime('2026-02-19T10:00:00Z'); // "2 hours ago"
Works in any locale. Change 'en' to 'ja' and it outputs Japanese. Zero bundle cost.
6. DST-Safe Scheduling
// US clocks spring forward March 8, 2026. 2:30 AM does not exist.
// Old Date — silently gives wrong result
new Date('2026-03-08T02:30:00') // some arbitrary result, browser-dependent
// Temporal — explicit control
Temporal.ZonedDateTime.from({
year: 2026, month: 3, day: 8, hour: 2, minute: 30,
timeZone: 'America/New_York'
}, { disambiguation: 'reject' });
// RangeError: this time does not exist
You choose how to handle ambiguous times: 'reject', 'earlier', 'later', or 'compatible'. The old Date chose for you and never told you.
7. Duration Math
const start = Temporal.PlainDate.from('2026-01-01');
const end = Temporal.PlainDate.from('2026-09-15');
const diff = start.until(end, { largestUnit: 'month' });
console.log(`${diff.months} months, ${diff.days} days`);
// "8 months, 14 days"
// Compare durations
const a = Temporal.Duration.from({ hours: 1, minutes: 30 });
const b = Temporal.Duration.from({ minutes: 100 });
Temporal.Duration.compare(a, b); // -1 (90min < 100min)
No more manual calculations with millisecond timestamps.
Cross-Browser Support Today
Chrome 144 has it natively. For Firefox and Safari, use the polyfill:
npm install @js-temporal/polyfill
import { Temporal } from '@js-temporal/polyfill';
20KB gzipped. Still smaller than Moment.js (47KB). Drop it when browsers catch up. Your code stays the same.
The Quick Migration
1. npm install @js-temporal/polyfill
2. Write all new date code with Temporal.
3. grep -r "moment\|date-fns\|dayjs\|luxon" src/ --include="*.ts" --include="*.js" -l to find migration targets.
4. Replace utility functions one at a time.
5. npm uninstall moment date-fns when done.
JavaScript had broken dates for 30 years. The fix just shipped. Full guide with React/Next.js integration, database patterns, and performance benchmarks at jsgurujobs.com.
Top comments (0)