Active Foundation

Search documentation

Search all pages, headings and text, in the current package or topic or in all documentation.

Dates and time zones

Calendar days, instants, presets, time zones, relative time and machine forms.

@workspace/active-format 1.0.0Developmentunreleased, in development in Foundationbaseline ce081dc3

Two kinds of dates#

The package keeps two things apart that look alike:

  • A calendar day (YYYY-MM-DD): a birthday, a due date, a holiday. It has no time and no zone, and it reads the same everywhere. Format it with formatDateOnly.

  • An instant: a moment in time, written with Z or an offset (2026-03-09T23:30:00Z), a Date, or epoch milliseconds. It reads differently per zone. Format it with formatDate or formatDateTime, in the presentation's time zone.

A date-time without a zone (2026-03-09T23:30:00) is neither: it gives '', never a guess.

Calendar day versus instantClient

ZoneThe instantIts day thereThe calendar day
UTC9 Mar 2026, 23:302026-03-099 March 2026
Europe/Amsterdam10 Mar 2026, 00:302026-03-109 March 2026
America/New_York9 Mar 2026, 19:302026-03-099 March 2026
Asia/Tokyo10 Mar 2026, 08:302026-03-109 March 2026

calendarDayOf(instant, timeZone) gives the calendar day of an instant in a zone. An instant without a zone argument throws, so the zone is never the runtime's by accident.

Time zones#

Time zones are IanaTimeZone values: a validated IANA identity such as 'Europe/Amsterdam', never an offset. Make one with toIanaTimeZone (throws for an unknown zone) or test a string with isIanaTimeZone. UTC_TIME_ZONE is 'UTC'.

The zone belongs in the presentation: composePresentationContext(language, profile, timeZone). Without a zone, instants are formatted in the runtime zone.

Presets#

A preset names a form; the language and profile decide its exact pattern.

  • Calendar-day presets (DateOnlyPreset): numeric, short, long, full, day-month, day-month-numeric, day-month-year-short, month-year, quarter-year, month, month-long, weekday-long, year.

  • Time and date-time presets (DatePreset adds): time, time-seconds, time-millis, numeric-datetime, numeric-datetime-seconds, numeric-datetime-millis, datetime, datetime-long, time-day.

Without a preset, the form follows the presentation's date shape (normalDateOnlyPreset, normalDateTimePreset). Language-derived notations are day-month-year with a 24-hour clock; a month-first or 12-hour form only comes from a profile (MDY_NUMERIC, H12).

formatDateWithPattern(value, pattern, presentation, reason) is the escape hatch for a date-fns pattern. The reason argument is required, so every use explains itself.

Today#

todayIsoDate(timeZone) gives today's calendar day in an explicit zone, never the runtime's day. It is one of only two functions that read the clock.

Relative time#

resolveRecency(value, presentation, {now?, thresholdDays?, absolutePreset?}) is the only route to relative time. Within the threshold (seven days by default, in both directions) it is relative ("2 minutes ago", "in 3 days"), beyond it absolute. Pass now and it reads no clock.

Relative timeClient

Valuemodetext
2026-03-09T11:58:00Zrelative2 minutes ago
2026-03-08T09:00:00Zrelative1 day ago
2026-03-12T12:00:00Zrelativein 3 days
2026-02-01T08:00:00Zabsolute1 Feb 2026, 08:00
2026-03-09unavailable(none)

Machine forms#

For files, APIs and URLs, never for text a person reads:

  • formatMachineDate(value): yyyy-MM-dd.

  • formatMachineDateTime(value): YYYY-MM-DDTHH:mm:ss.sssZ, for an instant only.

  • formatMachineNumber(value, decimals?): a plain dot decimal, never an exponent.

Absence gives ''; an invalid value throws, unlike the human formatters.

This page as Markdown