Skip to Content
GuidesIntl Options

Intl Options

The adapter at rosetta-date/intl bridges token strings and the native Intl.DateTimeFormat API. It is the path from a hardcoded pattern to native, locale-aware formatting.

import { toIntlOptions } from 'rosetta-date/intl' import { moment } from 'rosetta-date/dialects' const options = toIntlOptions('YYYY-MM-DD HH:mm', { from: moment }) // { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', hourCycle: 'h23' } new Intl.DateTimeFormat('pt-BR', options).format(new Date())

Why a separate surface

Every other endpoint is a token string. Intl.DateTimeFormat is not — it takes an unordered options bag and lets the locale decide layout at format time:

ModelCarries order?Carries separators / literals?Examples
PatternyesyesDD/MM/YYYY, every dialect and library
Field bagnonoIntl options

Crossing that boundary is a deliberate, lossy projection — so the adapter is its own pair of functions rather than another endpoint for convert.

toIntlOptions — pattern → options

toIntlOptions(format, { from }) reads the locale-agnostic intent out of a format string.

import { toIntlOptions } from 'rosetta-date/intl' import { moment } from 'rosetta-date/dialects' toIntlOptions('h:mm A', { from: moment }) // { hour: 'numeric', minute: '2-digit', hourCycle: 'h12' }

Literals and field order are dropped by design — the locale, not the format, decides where the slashes go and whether the day leads. 'DD/MM/YYYY' and 'YYYY-MM-DD' produce the same options; hand them to a pt-BR formatter and you get the Brazilian layout back, to an en-US one the American layout.

The AM/PM markers — uppercase A and lowercase a — have no Intl option, so on their own they are dropped (or throw under 'throw'). In practice the marker is redundant: an h11 / h12 hour already carries the 12-hour cycle via hourCycle, so dropping it loses nothing.

fromIntlOptions — options → pattern

fromIntlOptions(intlOptions, { to }) goes the other way. Its locale-correct path is the style axis: dateStyle / timeStyle map to the target’s localized presets, which the library resolves per locale at format time — so no locale argument is needed.

import { fromIntlOptions } from 'rosetta-date/intl' import { dayjs } from 'rosetta-date/libraries' fromIntlOptions({ dateStyle: 'short' }, { to: dayjs }) // 'L' fromIntlOptions({ dateStyle: 'long', timeStyle: 'long' }, { to: dayjs }) // 'LLL'

Targeting a library returns its preset (e.g. L for Moment.js / Day.js, P for date-fns) precisely because that preset stays locale-aware — freezing it to a fixed pattern would defeat the library’s own locale machinery. See Localized presets.

Components reconstruct a skeleton

When the options are a component bag rather than a style, there is no order or separator to recover without a locale, so the output is a skeleton — the fields in CLDR canonical order, no separators:

fromIntlOptions({ year: 'numeric', month: '2-digit', day: '2-digit' }, { to: ldml }) // 'yyyyMMdd'

A round trip preserves the field set, not the layout: toIntlOptions then fromIntlOptions recovers the components, but the slashes and ordering are gone — they live in the locale, not the format.

Unsupported fields

The canonical vocabulary is a strict superset of what Intl.DateTimeFormat can express. Fields with no equivalent are routed to onUnsupportedToken:

  • toIntlOptions — quarter, week-numbering year, week of year, day-of-year, ordinals, epoch, the AM/PM marker, stand-alone names, and the numeric / short weekday forms.
  • fromIntlOptions — a preset against a pure dialect that has no preset token, a dateStyle / timeStyle mismatch with no single fused preset, an Intl-only zone style (long, *Generic), and the flexible dayPeriod.

The policy is narrower than the dialect-to-dialect one: only 'throw' and 'drop' (the default) apply, since there is no output string to literalize and no target dialect for a handler.

toIntlOptions('[Q]Q YYYY', { from: moment }) // { year: 'numeric' } — quarter dropped toIntlOptions('Q', { from: moment, onUnsupportedToken: 'throw' }) // throws UnsupportedTokenError

toIntlOptions is a human-display tool: it yields options for Intl.DateTimeFormat, which renders a GMT-prefixed offset (GMT+05:00), not a bare ISO +05:00. The ISO offsets that emit Z at zero have no Intl equivalent at all. Keep machine-readable ISO timestamps as a plain convert between dialects.

Last updated on