DEV Community

JSGuruJobs
JSGuruJobs

Posted on

Chrome 144 Just Shipped the Temporal API. Here Are 7 Date Library Patterns It Replaces With Native Code.

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

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

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

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

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

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

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

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

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
Enter fullscreen mode Exit fullscreen mode
import { Temporal } from '@js-temporal/polyfill';
Enter fullscreen mode Exit fullscreen mode

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)