API
formatIso
One formatter for both shapes, with cached Intl instances underneath.
Signature
formatIso(value, options) reads either shape a calendar hands back — a bare date or a date-time with an offset — and returns a string.
tsx
import { buildCalendar, formatIso } from '@midstem/chronous' const calendar = buildCalendar( { view: 'day', currentDate: '2026-03-18', timeZone: 'Europe/Kyiv' }, [{ id: 'standup', start: '2026-03-18T09:00', duration: 'PT30M' }], ) const [day] = calendar.days const [box] = day.boxes // a bare date: formatted as the floating date it is console.log( formatIso(day.date, { locale: 'uk-UA', options: { day: 'numeric', month: 'long' } }), ) // '18 березня' // a date-time: read in the offset it already carries console.log( formatIso(box.start, { locale: 'en-GB', options: { hour: '2-digit', minute: '2-digit' } }), ) // '09:00' // the same instant, shown somewhere else console.log( formatIso(box.start, { locale: 'en-GB', timeZone: 'America/New_York', options: { timeStyle: 'short' }, }), ) // '03:00'
Type
type FormatOptions = { locale: LocaleId timeZone?: TimeZoneId options?: DateTimeFormatOptions }
| Field | Type | Description |
|---|---|---|
locale | LocaleId | Any BCP 47 tag, passed straight to Intl. |
timeZone | TimeZoneId | The zone a date-time is shown in. Defaults to the offset the string already carries, and is ignored for a bare date. |
options | DateTimeFormatOptions | Intl.DateTimeFormatOptions, unchanged. |
Behaviour
A date is formatted as the floating date it is and is never moved into a zone. A date-time carries its offset, which fixes the instant, and one with no offset is floating too. Formatters are cached, so a month grid formatting forty-two cells builds one formatter, not forty-two.