Locale Formatting
Problem
Displaying dates and times for international users requires locale-specific formats, calendar systems, and timezone offsets. Intl.DateTimeFormat handles this but requires verbose configuration and careful key management for caching.
Solution
Use format() with the pattern shorthand for common layouts, or pass intl directly for a custom Intl.DateTimeFormatOptions. Tempo manages formatter caching internally.
ts
import { format, formatInstant, formatRange, formatRelative, parseInstant } from '@vielzeug/tempo';
const time = parseInstant('2026-03-21T10:15:30Z');
// Preset patterns
format(time, { pattern: 'short', locale: 'en-US', tz: 'UTC' }); // '3/21/2026, 10:15 AM'
format(time, { pattern: 'short', locale: 'de-DE', tz: 'Europe/Berlin' }); // '21.3.2026, 11:15'
format(time, { pattern: 'short', locale: 'ja-JP', tz: 'Asia/Tokyo' }); // '2026/3/21 19:15'
// All preset patterns
format(time, { pattern: 'medium', locale: 'en-GB', tz: 'UTC' }); // '21 Mar 2026, 10:15'
format(time, { pattern: 'long', locale: 'en-GB', tz: 'UTC' }); // 'Saturday, 21 March 2026 at 10:15:30'
format(time, { pattern: 'date-only', locale: 'en-GB', tz: 'UTC' }); // '21/03/2026'
format(time, { pattern: 'time-only', locale: 'en-GB', tz: 'UTC' }); // '10:15'
// Stable UTC instant string (for APIs and logs)
formatInstant(time); // '2026-03-21T10:15:30Z'Escape Hatch: Full Intl Spec
When presets do not fit, pass intl directly. The intl option takes full precedence over pattern.
ts
format(time, {
locale: 'de-DE',
tz: 'Europe/Berlin',
intl: { dateStyle: 'short', timeStyle: 'short', weekday: 'long', hour12: false },
});
// → 'Samstag, 21.3.2026, 11:15'Range Formatting
ts
import { formatRange, parseInstant } from '@vielzeug/tempo';
formatRange(parseInstant('2026-03-21T10:00:00Z'), parseInstant('2026-03-21T12:00:00Z'), {
pattern: 'short',
locale: 'en-US',
tz: 'America/New_York',
});
// → '3/21/2026, 6:00 AM – 8:00 AM'Relative Formatting
ts
import { formatRelative, parseInstant } from '@vielzeug/tempo';
const base = parseInstant('2026-03-21T10:00:00Z');
formatRelative(parseInstant('2026-03-21T12:00:00Z'), { base, locale: 'en-US', numeric: 'always' });
// → 'in 2 hours'
formatRelative(parseInstant('2026-03-19T10:00:00Z'), { base, locale: 'en-US' });
// → '2 days ago'
formatRelative(parseInstant('2026-03-21T10:00:45Z'), { base, locale: 'de-DE', numeric: 'auto' });
// → 'in 45 Sekunden'Pitfalls
patternandintlare mutually exclusive at the TypeScript type level (FormatOptionsis a discriminated union). TypeScript will report an error if you attempt to pass both — do not rely on one overriding the other.formatRelative()only acceptsTemporal.InstantorTemporal.ZonedDateTimeinputs. Passing aPlainDateTimeorPlainDatethrows aTypeError.- Locale strings must be valid BCP 47 tags. An invalid locale (e.g.,
'english') may silently fall back to the system locale or throw depending on the runtime.