JavaScript Temporal API: Modern Date and Time Handling

The JavaScript Temporal API is the long-awaited replacement for the broken Date object — it provides immutable date/time objects, correct timezone handling, calendar arithmetic, and duration comparisons that are impossible to get right with Date.

Problem: JavaScript's Date object is mutable, has inconsistent month indexing (0-based), unreliable timezone handling, and no built-in support for duration arithmetic or calendar systems — making date logic in WordPress admin SPAs error-prone.

Solution: Use the TC39 Temporal API (stage 3) — available behind a polyfill today via @js-temporal/polyfill. Use Temporal.PlainDate for calendar dates, Temporal.ZonedDateTime for timezone-aware instants, and Temporal.Duration for arithmetic. All objects are immutable and operations are explicit about calendar and timezone.

The examples below use Temporal.PlainDate for date-only operations, Temporal.ZonedDateTime for timezone-aware scheduling, and Temporal.Duration for relative time display in WordPress admin JavaScript.

// Temporal API — available natively in Chrome 127+ (behind flag earlier)
// Polyfill: npm install @js-temporal/polyfill

// PlainDate — date only, no time, no timezone
const today     = Temporal.Now.plainDateISO();          // e.g., 2025-01-08
const published = Temporal.PlainDate.from('2024-12-15');
const daysSince = published.until(today).days;          // exact day count
console.log(`Published ${daysSince} days ago`);

// Add/subtract durations (no DST surprises — pure calendar arithmetic)
const nextMonth = today.add({ months: 1 });
const weekAgo   = today.subtract({ weeks: 1 });

// Compare dates
if ( Temporal.PlainDate.compare(published, today) < 0 ) {
    console.log('Post is in the past');
}

// PlainDateTime — date + time, no timezone
const scheduledAt = Temporal.PlainDateTime.from('2025-01-15T14:30:00');
const formatted   = scheduledAt.toLocaleString('en-US', {
    dateStyle: 'medium',
    timeStyle: 'short',
});

// ZonedDateTime — full timezone-aware datetime
const wpPostDate = Temporal.ZonedDateTime.from({
    year: 2025, month: 1, day: 15,
    hour: 14, minute: 30,
    timeZone: 'America/New_York',
});

// Convert to UTC for API calls
const utcInstant = wpPostDate.toInstant();
console.log(utcInstant.toString());  // 2025-01-15T19:30:00Z

// Convert between timezones
const londonTime = wpPostDate.withTimeZone('Europe/London');
console.log(londonTime.toString());

Duration and relative time for WordPress admin UI:

// Duration — represents a span of time
const duration = Temporal.Duration.from({ hours: 2, minutes: 30 });
const inMinutes = duration.total('minutes');  // 150

// Calculate post age for "X time ago" display
function getRelativeTime( isoString ) {
    const postDate = Temporal.Instant.from( isoString );
    const now      = Temporal.Now.instant();
    const diff     = now.since( postDate );

    // Intl.RelativeTimeFormat gives human-readable output
    const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });

    const totalSeconds = Math.abs( diff.total('seconds') );
    if ( totalSeconds < 60 )   return rtf.format( -Math.round(totalSeconds), 'second');
    if ( totalSeconds < 3600 ) return rtf.format( -Math.round(totalSeconds / 60), 'minute');
    if ( totalSeconds < 86400) return rtf.format( -Math.round(totalSeconds / 3600), 'hour');
    return rtf.format( -Math.round(totalSeconds / 86400), 'day');
}

// Use in Gutenberg block
import { useSelect } from '@wordpress/data';
import { store as coreDataStore } from '@wordpress/core-data';

function PostAge({ postId }) {
    const post = useSelect( select =>
        select( coreDataStore ).getEntityRecord('postType', 'post', postId)
    );
    if ( !post?.date ) return null;
    return { getRelativeTime(post.date) };
}

NOTE: The Temporal API polyfill (@js-temporal/polyfill) is production-ready and matches the Stage 3 spec. Avoid mixing Date and Temporal in the same module — convert at boundaries using Temporal.Instant.fromEpochMilliseconds(date.getTime()). The Temporal API is the first major JavaScript date library baked into the language itself.

Leave Comment

Your email address will not be published. Required fields are marked *