A spec-compliant polyfill for Intl.DateTimeFormat fully tested by the official ECMAScript Conformance test suite
Caution
Right now we only support Gregorian calendar in this polyfill. Therefore we
recommend setting calendar: 'gregory' in your options to be safe.
Caution
Right now this polyfill supports daylight transition until 2100 to reduce the dataset size
ECMA-402 Spec Compliance#
This package is fully compliant with the ECMA-402 specification for Intl.DateTimeFormat, including all finalized proposals.
Implemented Features#
✅ Core Methods#
format(date)- Format a single date/timeformatToParts(date)- Format a date/time and return parts arrayformatRange(startDate, endDate)- Format a date range (Proposal)formatRangeToParts(startDate, endDate)- Format a date range and return parts array with source attributionresolvedOptions()- Return resolved formatting options
✅ dateStyle & timeStyle Options#
- Proposal: Intl.DateTimeFormat dateStyle & timeStyle
- Values:
'full','long','medium','short' - Usage: Can be used individually or together for quick date/time formatting
- Example:
Global import#
new Intl.DateTimeFormat('en', {dateStyle: 'long', timeStyle: 'short'})
// "January 1, 2024 at 12:00 PM"
Info
The global import does not include TypeScript type declarations. For TypeScript projects, we recommend using ES module imports instead.
If you choose to use the global import, in order to prevent type errors, you must manually include the corresponding type declaration files (.d.ts) in your project.
ES Modules#
import {DateTimeFormat} from '@formatjs/intl-datetimeformat'
new DateTimeFormat('en', {dateStyle: 'long', timeStyle: 'short'})
// "January 1, 2024 at 12:00 PM"
✅ Extended timeZoneName Options#
All 6 timeZoneName values are supported:
'short'- Short standard format (e.g., "EST", "PST")'long'- Long standard format (e.g., "Eastern Standard Time")'shortOffset'- Short format with UTC offset (e.g., "GMT-5")'longOffset'- Long format with UTC offset (e.g., "GMT-05:00")'shortGeneric'- Short generic non-location format (e.g., "ET", "PT")'longGeneric'- Long generic non-location format (e.g., "Eastern Time")
✅ Additional Features#
- dayPeriod - Format day periods (
'narrow','short','long') - fractionalSecondDigits - Control decimal precision for seconds (1-3 digits)
- era - Format era information (
'narrow','short','long') - hour12 and hourCycle - 12/24 hour format control
- Full IANA timezone support - 600+ timezones with accurate DST transitions
- UTC offset timezones - Direct offset support (e.g.,
'+01:00','-05:30')
Not Implemented (Stage 2.7 Proposals - Not Yet Finalized)#
- eraDisplay option - Control era visibility (
'always','never','auto') - monthCode support - ISO 8601 month codes for non-Gregorian calendars
Features#
Installation#
npm i @formatjs/intl-datetimeformat
Requirements#
This package requires the following capabilities:
Usage#
Via polyfill-fastly.io#
You can use polyfill-fastly.io URL Builder to create a polyfill script tag for Intl.DateTimeFormat. By default the created URL does not come with any locale data. In order to add locale data, append Intl.DateTimeFormat.~locale.<locale>, as well as locale data for any required polyfills, to your list of features. For example:
<!-- Polyfill Intl.DateTimeFormat, its dependencies & `en` locale data -->
<script src="https://polyfill-fastly.io/v3/polyfill.min.js?features=Intl.DateTimeFormat,Intl.DateTimeFormat.~locale.en,Intl.NumberFormat.~locale.en"></script>
Simple#
import '@formatjs/intl-datetimeformat/polyfill.js'
import '@formatjs/intl-datetimeformat/locale-data/en.js' // locale-data for en
import '@formatjs/intl-datetimeformat/add-all-tz.js' // Add ALL tz data
Dynamic import + capability detection#
async function polyfill(locale: string) {
const unsupportedLocale = shouldPolyfill(locale)
// This locale is supported
if (!unsupportedLocale) {
return
}
// Load the polyfill 1st BEFORE loading data
await import('@formatjs/intl-datetimeformat/polyfill-force.js')
// Parallelize CLDR data loading
const dataPolyfills = [
import('@formatjs/intl-datetimeformat/add-all-tz.js'),
import(`@formatjs/intl-datetimeformat/locale-data/${unsupportedLocale}.js`),
]
await Promise.all(dataPolyfills)
}
Adding IANA Timezone Database#
We provide 2 pre-processed IANA Timezone:
Full: contains ALL Timezone from IANA database#
import '@formatjs/intl-datetimeformat/polyfill.js'
import '@formatjs/intl-datetimeformat/add-all-tz.js'
Golden: contains popular set of timezones from IANA database#
import '@formatjs/intl-datetimeformat/polyfill.js'
import '@formatjs/intl-datetimeformat/add-golden-tz.js'
UTC Offset Timezones#
This polyfill supports UTC offset timezone identifiers as specified in ECMA-402 (ES2026). You can use offset-based timezone strings in addition to IANA timezone names.
Supported Formats#
The following UTC offset formats are supported:
±HH:MM- e.g.,"+01:00","-05:00"(recommended format)±HHMM- e.g.,"+0100","-0500"±HH- e.g.,"+01","-05"±HH:MM:SS- e.g.,"+01:30:45"(with seconds)±HH:MM:SS.sss- e.g.,"+01:30:45.123"(with fractional seconds)
All offset formats are automatically canonicalized to ±HH:MM format (with seconds/fractional seconds preserved if non-zero).
Usage Example#
import '@formatjs/intl-datetimeformat/polyfill.js'
import '@formatjs/intl-datetimeformat/locale-data/en.js'
// Using UTC offset timezone
const formatter = new Intl.DateTimeFormat('en-GB', {
timeZone: '+01:00',
year: 'numeric',
month: 'numeric',
day: 'numeric',
hour: 'numeric',
minute: 'numeric',
})
console.log(formatter.format(new Date('2024-01-01T00:00:00Z')))
// Output: "01/01/2024, 01:00"
// Works with @date-fns/tz and other libraries
const dtf = new Intl.DateTimeFormat('en-GB', {
timeZone: '+01:00',
hour: 'numeric',
timeZoneName: 'longOffset',
})
Compatibility#
- UTC offset timezones work without loading any timezone data (
add-all-tz.jsoradd-golden-tz.js) - Compatible with libraries like
@date-fns/tzin React Native/Hermes environments - Follows the same behavior as Chrome and Node.js 22+ native implementations
Default Timezone#
Since JS Engines do not expose default timezone, there's currently no way for us to detect local timezone that a browser is in. Therefore, the default timezone in this polyfill is UTC.
You can change this by either calling __setDefaultTimeZone or always explicitly pass in timeZone option for accurate date time calculation.
Since __setDefaultTimeZone is not in the spec, you should make sure to check for its existence before calling it & after tz data has been loaded, e.g:
import '@formatjs/intl-datetimeformat/polyfill.js'
import '@formatjs/intl-datetimeformat/add-all-tz.js'
if ('__setDefaultTimeZone' in Intl.DateTimeFormat) {
Intl.DateTimeFormat.__setDefaultTimeZone('America/Los_Angeles')
}
Tests#
This library is fully test262-compliant.