JavaScript Temporal API: The End of Date and Moment.js Is Near
Hello HaWkers, after years of development, the Temporal API is finally arriving in major browsers. This new native API promises to solve all the historical problems of JavaScript's Date object.
Let's explore how to use the Temporal API and prepare your projects for this change.
Why We Need the Temporal API
Current Date Problems
JavaScript's Date object was created in 10 days in 1995, copied from Java, and was never fixed.
Classic Date problems:
// Problem 1: Months start at 0
const date = new Date(2026, 0, 20); // January, not February
console.log(date.getMonth()); // 0, not 1
// Problem 2: 2-digit years
const y2k = new Date(99, 0, 1);
console.log(y2k.getFullYear()); // 1999, not 99 or 2099
// Problem 3: Mutability
const original = new Date(2026, 0, 20);
const modified = original;
modified.setMonth(5);
console.log(original.getMonth()); // 5 - original was changed!
// Problem 4: Inconsistent parsing
new Date('2026-01-20'); // UTC
new Date('2026/01/20'); // Local
new Date('01-20-2026'); // Invalid in some browsers
// Problem 5: No timezone support
// No native way to work with time zones
// Problem 6: No duration support
// No way to represent "2 hours and 30 minutes"What Temporal Solves
The Temporal API was designed to fix all these problems:
Temporal principles:
- Immutability: All objects are immutable
- Clarity: Explicit APIs without ambiguity
- Timezones: Complete timezone support
- Precision: Nanosecond precision
- Separate types: Different types for different needs
Main Temporal Types
Type Overview
Temporal introduces several specialized types:
// Temporal.Instant - exact moment in time (UTC)
const instant = Temporal.Instant.from('2026-01-20T15:30:00Z');
// Temporal.ZonedDateTime - date/time with timezone
const zonedDateTime = Temporal.ZonedDateTime.from({
year: 2026,
month: 1,
day: 20,
hour: 15,
minute: 30,
timeZone: 'America/New_York'
});
// Temporal.PlainDateTime - date/time without timezone
const plainDateTime = Temporal.PlainDateTime.from({
year: 2026,
month: 1,
day: 20,
hour: 15,
minute: 30
});
// Temporal.PlainDate - date only
const plainDate = Temporal.PlainDate.from({
year: 2026,
month: 1,
day: 20
});
// Temporal.PlainTime - time only
const plainTime = Temporal.PlainTime.from({
hour: 15,
minute: 30,
second: 0
});
// Temporal.Duration - time duration
const duration = Temporal.Duration.from({
hours: 2,
minutes: 30
});When to Use Each Type
| Type | Use Case | Example |
|---|---|---|
| Instant | Event timestamps | Logs, auditing |
| ZonedDateTime | Local events | Meetings, flights |
| PlainDateTime | Timezone-free events | Templates |
| PlainDate | Dates only | Birthdays, holidays |
| PlainTime | Times only | Business hours |
| Duration | Intervals | Execution time |
Using Temporal in Practice
Creating Dates
// From ISO string
const date1 = Temporal.PlainDate.from('2026-01-20');
// From object
const date2 = Temporal.PlainDate.from({
year: 2026,
month: 1,
day: 20
});
// Current date
const today = Temporal.Now.plainDateISO();
console.log(today.toString()); // "2026-01-20"
// Current DateTime with timezone
const now = Temporal.Now.zonedDateTimeISO('America/New_York');Manipulating Dates
const date = Temporal.PlainDate.from('2026-01-20');
// Add time (returns new instance)
const nextWeek = date.add({ days: 7 });
console.log(nextWeek.toString()); // "2026-01-27"
// Subtract time
const lastMonth = date.subtract({ months: 1 });
console.log(lastMonth.toString()); // "2025-12-20"
// Modify specific fields
const newYear = date.with({ month: 12, day: 31 });
console.log(newYear.toString()); // "2026-12-31"
// Original remains unchanged (immutability)
console.log(date.toString()); // "2026-01-20"Comparing Dates
const date1 = Temporal.PlainDate.from('2026-01-20');
const date2 = Temporal.PlainDate.from('2026-02-15');
// Comparison
console.log(Temporal.PlainDate.compare(date1, date2)); // -1
// Equality
console.log(date1.equals(date2)); // false
// Difference between dates
const diff = date1.until(date2);
console.log(diff.days); // 26
Working with Timezones
ZonedDateTime
// Create datetime with timezone
const meeting = Temporal.ZonedDateTime.from({
year: 2026,
month: 1,
day: 20,
hour: 15,
minute: 0,
timeZone: 'America/New_York'
});
// Convert to another timezone
const meetingInTokyo = meeting.withTimeZone('Asia/Tokyo');
// The moment is the same, only representation changes
console.log(meeting.toInstant().equals(meetingInTokyo.toInstant())); // trueHandling Daylight Saving Time
Temporal correctly handles DST transitions.
Migrating from Existing Libraries
Replacing Moment.js
// Moment.js (old)
import moment from 'moment';
const m = moment('2026-01-20');
const added = m.add(7, 'days');
// Temporal (new)
const t = Temporal.PlainDate.from('2026-01-20');
const addedT = t.add({ days: 7 });
// Bundle size comparison
// Moment.js: ~70KB minified
// Temporal: 0KB (native browser)Equivalence Table
| Operation | Moment/date-fns | Temporal |
|---|---|---|
| Create date | moment() |
Temporal.Now.plainDateISO() |
| Add days | .add(7, 'days') |
.add({ days: 7 }) |
| Subtract months | .subtract(1, 'month') |
.subtract({ months: 1 }) |
| Format | .format('DD/MM/YYYY') |
Intl.DateTimeFormat |
| Difference | differenceInDays() |
.until().days |
| Compare | .isBefore() |
Temporal.PlainDate.compare() |
| Timezone | moment.tz() |
Temporal.ZonedDateTime |
Current Support and Polyfills
Implementation Status
As of January 2026:
| Browser | Status |
|---|---|
| Chrome | Experimental flag |
| Firefox | In development |
| Safari | In development |
| Node.js | --harmony-temporal flag |
| Deno | Supported |
| Bun | Supported |
Using Polyfill
While native support arrives, use the official polyfill:
npm install @js-temporal/polyfillimport { Temporal } from '@js-temporal/polyfill';
const now = Temporal.Now.plainDateISO();
console.log(now.toString());
Conclusion
The Temporal API represents the biggest evolution in JavaScript date handling since its creation. We finally have a native solution that solves historical Date problems.
Key points:
- Immutable objects prevent common bugs
- Separate types for different needs
- Complete timezone support
- Nanosecond precision
- Clear and unambiguous API
Recommendations:
- Start using the polyfill in new projects
- Plan gradual migration from Moment.js/date-fns
- Learn the different types and when to use each
- Follow browser implementation progress
The transition will take time, but it's worth getting familiar with the Temporal API now.

