ChronousDocumentation

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
}
FieldTypeDescription
localeLocaleIdAny BCP 47 tag, passed straight to Intl.
timeZoneTimeZoneIdThe zone a date-time is shown in. Defaults to the offset the string already carries, and is ignored for a bare date.
optionsDateTimeFormatOptionsIntl.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.