The Temporal API provides modern date/time handling with proper timezone support, replacing the problematic Date object. Here's how to use it.
Core Concepts#
1// Temporal has several types for different use cases
2
3// Temporal.Instant - exact moment in time (like a timestamp)
4const instant = Temporal.Instant.from('2024-03-15T10:30:00Z');
5
6// Temporal.ZonedDateTime - date/time with timezone
7const zoned = Temporal.ZonedDateTime.from('2024-03-15T10:30:00[America/New_York]');
8
9// Temporal.PlainDateTime - date/time without timezone
10const dateTime = Temporal.PlainDateTime.from('2024-03-15T10:30:00');
11
12// Temporal.PlainDate - just the date
13const date = Temporal.PlainDate.from('2024-03-15');
14
15// Temporal.PlainTime - just the time
16const time = Temporal.PlainTime.from('10:30:00');
17
18// Temporal.Duration - a length of time
19const duration = Temporal.Duration.from({ hours: 2, minutes: 30 });Creating Dates#
1// Current date/time
2const now = Temporal.Now.instant();
3const nowZoned = Temporal.Now.zonedDateTimeISO('America/New_York');
4const today = Temporal.Now.plainDateISO();
5
6// From string
7const date1 = Temporal.PlainDate.from('2024-03-15');
8const time1 = Temporal.PlainTime.from('14:30:00');
9const dateTime1 = Temporal.PlainDateTime.from('2024-03-15T14:30:00');
10
11// From components
12const date2 = Temporal.PlainDate.from({
13 year: 2024,
14 month: 3,
15 day: 15,
16});
17
18const time2 = Temporal.PlainTime.from({
19 hour: 14,
20 minute: 30,
21 second: 0,
22});
23
24// From existing date
25const legacyDate = new Date();
26const instant = Temporal.Instant.fromEpochMilliseconds(legacyDate.getTime());Timezones#
1// Create zoned date/time
2const meeting = Temporal.ZonedDateTime.from({
3 timeZone: 'America/New_York',
4 year: 2024,
5 month: 3,
6 day: 15,
7 hour: 10,
8 minute: 0,
9});
10
11console.log(meeting.toString());
12// 2024-03-15T10:00:00-04:00[America/New_York]
13
14// Convert timezone
15const meetingInTokyo = meeting.withTimeZone('Asia/Tokyo');
16console.log(meetingInTokyo.toString());
17// 2024-03-15T23:00:00+09:00[Asia/Tokyo]
18
19// Get offset
20console.log(meeting.offset); // '-04:00'
21
22// Available timezones
23const timezones = Temporal.TimeZone.from('America/New_York');Arithmetic#
1const date = Temporal.PlainDate.from('2024-03-15');
2
3// Add duration
4const nextWeek = date.add({ days: 7 });
5const nextMonth = date.add({ months: 1 });
6const nextYear = date.add({ years: 1 });
7
8// Subtract duration
9const lastWeek = date.subtract({ days: 7 });
10
11// Multiple units
12const future = date.add({
13 years: 1,
14 months: 2,
15 days: 15,
16});
17
18// With time
19const dateTime = Temporal.PlainDateTime.from('2024-03-15T10:30:00');
20const later = dateTime.add({ hours: 2, minutes: 30 });Comparing Dates#
1const date1 = Temporal.PlainDate.from('2024-03-15');
2const date2 = Temporal.PlainDate.from('2024-03-20');
3
4// Comparison methods
5console.log(Temporal.PlainDate.compare(date1, date2)); // -1 (before)
6console.log(date1.equals(date2)); // false
7
8// Calculate difference
9const diff = date1.until(date2);
10console.log(diff.days); // 5
11
12// Different units
13const diff2 = date1.until(date2, { largestUnit: 'weeks' });
14console.log(diff2.weeks, diff2.days); // 0, 5
15
16// Since vs until
17const daysSince = date2.since(date1);
18console.log(daysSince.days); // 5
19
20// With time precision
21const dt1 = Temporal.PlainDateTime.from('2024-03-15T10:00:00');
22const dt2 = Temporal.PlainDateTime.from('2024-03-15T14:30:00');
23const timeDiff = dt1.until(dt2);
24console.log(timeDiff.hours, timeDiff.minutes); // 4, 30Duration#
1// Create duration
2const duration = Temporal.Duration.from({
3 hours: 2,
4 minutes: 30,
5 seconds: 45,
6});
7
8// From string (ISO 8601)
9const dur2 = Temporal.Duration.from('PT2H30M45S');
10
11// Properties
12console.log(duration.hours); // 2
13console.log(duration.minutes); // 30
14console.log(duration.total('minutes')); // 150.75
15
16// Negate
17const negative = duration.negated();
18
19// Absolute value
20const abs = negative.abs();
21
22// Add durations
23const total = duration.add({ hours: 1 });
24
25// Round duration
26const rounded = duration.round({ smallestUnit: 'minutes' });Formatting#
1const date = Temporal.PlainDate.from('2024-03-15');
2const dateTime = Temporal.PlainDateTime.from('2024-03-15T14:30:00');
3
4// ISO strings
5console.log(date.toString()); // '2024-03-15'
6console.log(dateTime.toString()); // '2024-03-15T14:30:00'
7
8// With Intl.DateTimeFormat
9const formatter = new Intl.DateTimeFormat('en-US', {
10 weekday: 'long',
11 year: 'numeric',
12 month: 'long',
13 day: 'numeric',
14});
15
16console.log(formatter.format(date));
17// 'Friday, March 15, 2024'
18
19// Custom formatting
20function formatDate(date) {
21 return `${date.year}-${String(date.month).padStart(2, '0')}-${String(date.day).padStart(2, '0')}`;
22}Calendar Support#
1// Different calendar systems
2const hebrewDate = Temporal.PlainDate.from({
3 year: 5784,
4 month: 6,
5 day: 4,
6 calendar: 'hebrew',
7});
8
9const islamicDate = Temporal.PlainDate.from({
10 year: 1445,
11 month: 9,
12 day: 4,
13 calendar: 'islamic',
14});
15
16// Convert between calendars
17const gregorianFromHebrew = hebrewDate.withCalendar('gregory');
18
19// Get calendar info
20const date = Temporal.PlainDate.from('2024-03-15');
21console.log(date.calendar.id); // 'iso8601'
22console.log(date.daysInMonth); // 31
23console.log(date.daysInYear); // 366 (leap year)
24console.log(date.monthsInYear); // 12
25console.log(date.inLeapYear); // truePractical Examples#
1// Age calculation
2function calculateAge(birthDate) {
3 const today = Temporal.Now.plainDateISO();
4 const birth = Temporal.PlainDate.from(birthDate);
5 const diff = birth.until(today, { largestUnit: 'years' });
6 return diff.years;
7}
8
9console.log(calculateAge('1990-05-15')); // 33 (in 2024)
10
11// Business days between dates
12function businessDays(start, end) {
13 let count = 0;
14 let current = Temporal.PlainDate.from(start);
15 const endDate = Temporal.PlainDate.from(end);
16
17 while (Temporal.PlainDate.compare(current, endDate) < 0) {
18 const dayOfWeek = current.dayOfWeek;
19 if (dayOfWeek !== 6 && dayOfWeek !== 7) {
20 count++;
21 }
22 current = current.add({ days: 1 });
23 }
24
25 return count;
26}
27
28// Meeting scheduler
29function scheduleRecurring(startDate, intervalDays, count) {
30 const meetings = [];
31 let current = Temporal.PlainDateTime.from(startDate);
32
33 for (let i = 0; i < count; i++) {
34 meetings.push(current.toString());
35 current = current.add({ days: intervalDays });
36 }
37
38 return meetings;
39}Time Zones Handling#
1// Schedule across timezones
2function scheduleGlobalMeeting(baseTime, attendeeTimezones) {
3 const base = Temporal.ZonedDateTime.from(baseTime);
4
5 return attendeeTimezones.map((tz) => ({
6 timezone: tz,
7 localTime: base.withTimeZone(tz).toString(),
8 }));
9}
10
11const times = scheduleGlobalMeeting(
12 '2024-03-15T10:00:00[America/New_York]',
13 ['America/Los_Angeles', 'Europe/London', 'Asia/Tokyo']
14);
15
16// DST-safe scheduling
17function addWeeks(zonedDateTime, weeks) {
18 // This handles DST transitions correctly
19 return zonedDateTime.add({ weeks });
20}Migration from Date#
1// Convert Date to Temporal
2function dateToTemporal(date) {
3 return Temporal.Instant.fromEpochMilliseconds(date.getTime());
4}
5
6// Convert Temporal to Date
7function temporalToDate(instant) {
8 return new Date(instant.epochMilliseconds);
9}
10
11// Wrapper for gradual migration
12class DateWrapper {
13 constructor(input) {
14 if (input instanceof Date) {
15 this.temporal = Temporal.Instant.fromEpochMilliseconds(input.getTime());
16 } else {
17 this.temporal = Temporal.Instant.from(input);
18 }
19 }
20
21 toDate() {
22 return new Date(this.temporal.epochMilliseconds);
23 }
24
25 toZonedDateTime(timezone) {
26 return this.temporal.toZonedDateTimeISO(timezone);
27 }
28}Best Practices#
Choose the Right Type:
✓ Instant for timestamps
✓ ZonedDateTime for user-facing times
✓ PlainDateTime for local events
✓ PlainDate for dates without time
✓ Duration for time spans
Timezone Handling:
✓ Always store as UTC/Instant
✓ Convert to local for display
✓ Use named timezones, not offsets
✓ Handle DST transitions
Comparison:
✓ Use compare() for sorting
✓ Use equals() for equality
✓ Use until()/since() for differences
✓ Specify largestUnit for clarity
Avoid:
✗ Mixing Temporal and Date
✗ Storing local times as UTC
✗ Ignoring calendar systems
✗ Manual string formatting
Conclusion#
The Temporal API provides comprehensive date/time handling with proper timezone support, duration arithmetic, and calendar systems. Use Instant for timestamps, ZonedDateTime for timezone-aware times, and Plain* types for calendar dates and times. The API handles DST transitions, leap years, and calendar conversions correctly, making it far superior to the legacy Date object for modern JavaScript applications.