A spec-compliant polyfill for Intl.DurationFormat

npm Version size

ECMA-402 Spec Compliance

This package implements the Stage 4 Intl.DurationFormat specification, which is included in ECMA-402 12th Edition (June 2025). The implementation is fully spec-compliant with all features.

Specification Details

  • TC39 Proposal: Intl.DurationFormat
  • Stage: Stage 4 (Finalized)
  • ECMA-402 Edition: 12th Edition (June 2025)
  • Spec Pages: 57-62

✅ All Features Implemented

Core Methods

  • format(duration) - Format a duration object to a localized string
  • formatToParts(duration) - Format a duration and return an array of parts
  • resolvedOptions() - Return resolved formatting options
  • supportedLocalesOf(locales) - Check which locales are supported

Style Options

All 4 style values are supported:

  • 'long' (default) - Full format (e.g., "3 hours, 25 minutes")
  • 'short' - Abbreviated format (e.g., "3 hr, 25 min")
  • 'narrow' - Most compact format (e.g., "3h 25m")
  • 'digital' - Digital clock format (e.g., "3:25:00")

Duration Units

All 10 duration fields are fully supported:

  • Years (years)
  • Months (months)
  • Weeks (weeks)
  • Days (days)
  • Hours (hours)
  • Minutes (minutes)
  • Seconds (seconds)
  • Milliseconds (milliseconds)
  • Microseconds (microseconds)
  • Nanoseconds (nanoseconds)

Each unit supports multiple format styles:

  • 'long', 'short', 'narrow' - Text-based formats
  • 'numeric' - Numeric format
  • '2-digit' - Two-digit numeric format (for hours, minutes, seconds)

Display Control

Per-unit display options with values 'always' | 'auto':

  • yearsDisplay, monthsDisplay, weeksDisplay, daysDisplay
  • hoursDisplay, minutesDisplay, secondsDisplay
  • millisecondsDisplay, microsecondsDisplay, nanosecondsDisplay

When set to 'auto', zero values are omitted. When set to 'always', zero values are included.

Additional Options

  • fractionalDigits - Control decimal precision (0-9 digits)
  • numberingSystem - Alternative numbering systems (50+ supported)
  • localeMatcher - Locale resolution algorithm ('best fit' or 'lookup')

Example Usage

Global import

import '@formatjs/intl-durationformat/polyfill.js'

const formatter = new Intl.DurationFormat('en', {
  style: 'long',
  hours: 'numeric',
  minutes: 'numeric',
  seconds: 'numeric',
})

formatter.format({hours: 3, minutes: 25, seconds: 7})
// "3 hours, 25 minutes, 7 seconds"

// Digital format
const digital = new Intl.DurationFormat('en', {style: 'digital'})
digital.format({hours: 1, minutes: 30, seconds: 45})
// "1:30:45"

// formatToParts
const parts = formatter.formatToParts({hours: 2, minutes: 30})
// [
//   {type: "integer", value: "2", unit: "hour"},
//   {type: "literal", value: " hours, "},
//   {type: "integer", value: "30", unit: "minute"},
//   {type: "literal", value: " minutes"}
// ]

ES Modules

import {DurationFormat} from '@formatjs/intl-durationformat'

const formatter = new DurationFormat('en', {
  style: 'long',
  hours: 'numeric',
  minutes: 'numeric',
  seconds: 'numeric',
})

formatter.format({hours: 3, minutes: 25, seconds: 7})
// "3 hours, 25 minutes, 7 seconds"

Installation

npm i @formatjs/intl-durationformat

Requirements

Usage

Simple

import '@formatjs/intl-durationformat/polyfill.js'

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-durationformat/polyfill-force.js')
}

Numbering system validation

A well-formed but unsupported numberingSystem option falls back to the locale's supported numbering system. Only malformed Unicode type identifiers throw RangeError.

Duration record validation

Each duration field is read once in the ECMA-402 order. Fields must convert to finite integers of a common sign. Invalid numeric fields throw RangeError; an empty record throws TypeError. Absolute years, months, and weeks must be less than 2 ** 32; absolute normalized seconds must be less than 2 ** 53. Subsecond contributions participate in the bound comparison exactly.