Stage 1 Draft / May 8, 2026

Stable Formatting

Introduction

This proposal seeks to modify the ECMA-402 specification.

See the explainer for more information.

4 Overview

4.4.1 Compatibility across implementations

ECMA 402 describes the schema of the data used by its functions. The data contained inside is implementation-dependent, and expected to change over time and vary between implementations. The variation is visible by programmers, and it is possible to construct programs which will depend on a particular output. However, this specification attempts to describe reasonable constraints which will allow well-written programs to function across implementations. Implementations are encouraged to continue their efforts to harmonize linguistic data.

As some use cases (most notably, automated testing) have a need for stability, the behaviour of the "zxx" locale (code for "no linguistic content") is defined within this specification. Formatting with this locale will match across implementations, and will not vary with time.

6 Identification of Locales, Currencies, Time Zones, Measurement Units, Numbering Systems, Collations, and Calendars

6.2.4 IsStableLocale ( locale )

The abstract operation IsStableLocale takes argument locale (a well-formed language tag String) and returns a Boolean. It determines whether locale represents the "zxx" locale. It performs the following steps when called:

  1. Assert: IsWellFormedLanguageTag(locale) is true.
  2. Let lowerLocale be the ASCII-lowercase of locale.
  3. Let baseName be GetLocaleBaseName(lowerLocale).
  4. Let language be GetLocaleLanguage(baseName).
  5. If language is "zxx", return true; else return false.

8 Value Properties of the Intl Object

8.1.2 Intl.STABLE

The String value "zxx", the language tag for "no linguistic content". Used to elicit stable behaviour in formatters.

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }.

9 Locale and Parameter Negotiation

9.1 Internal slots of Service Constructors

Each service constructor has the following internal slots:

  • [[AvailableLocales]] is an Available Locales List. It must include the value returned by DefaultLocale as well as the value "zxx". Additionally, for each element with more than one subtag, it must also include a less narrow language tag with the same language subtag and a strict subset of the same following subtags (i.e., omitting one or more) to serve as a potential fallback from ResolveLocale. In particular, each element with a language subtag and a script subtag and a region subtag must be accompanied by another element consisting of only the same language subtag and region subtag but missing the script subtag. For example,
    • If [[AvailableLocales]] contains "de-DE", then it must also contain "de" (which might be selected to satisfy requested locales such as "de-AT" and "de-CH").
    • If [[AvailableLocales]] contains "az-Latn-AZ", then it must also contain "az-AZ" (which might be selected to satisfy requested locales such as "az-Cyrl-AZ" if "az-Cyrl" is unavailable).
  • ...

11 DateTimeFormat Objects

11.1 The Intl.DateTimeFormat Constructor

11.1.1 CreateDateTimeFormat ( newTarget, locales, options, required, defaults )

The abstract operation CreateDateTimeFormat takes arguments newTarget (a constructor), locales (an ECMAScript language value), options (an ECMAScript language value), required (date, time, or any), and defaults (date, time, or all) and returns either a normal completion containing a DateTimeFormat object or a throw completion. It performs the following steps when called:

  1. Let dateTimeFormat be ? OrdinaryCreateFromConstructor(newTarget, "%Intl.DateTimeFormat.prototype%", « [[InitializedDateTimeFormat]], [[Locale]], [[Calendar]], [[NumberingSystem]], [[TimeZone]], [[HourCycle]], [[DateStyle]], [[TimeStyle]], [[DateTimeFormat]], [[BoundFormat]] »).
  2. Let hour12 be undefined.
  3. Let modifyResolutionOptions be a new Abstract Closure with parameters (options) that captures hour12 and performs the following steps when called:
    1. Set hour12 to options.[[hour12]].
    2. Remove field [[hour12]] from options.
    3. If hour12 is not undefined, set options.[[hc]] to null.
  4. Let optionsResolution be ? ResolveOptions(%Intl.DateTimeFormat%, %Intl.DateTimeFormat%.[[LocaleData]], locales, options, « coerce-options », modifyResolutionOptions).
  5. Set options to optionsResolution.[[Options]].
  6. Let r be optionsResolution.[[ResolvedLocale]].
  7. Set dateTimeFormat.[[Locale]] to r.[[Locale]].
  8. Let resolvedCalendar be r.[[ca]].
  9. Set dateTimeFormat.[[Calendar]] to resolvedCalendar.
  10. Set dateTimeFormat.[[NumberingSystem]] to r.[[nu]].
  11. Let resolvedLocaleData be r.[[LocaleData]].
  12. If IsStableLocale(r.[[Locale]]) is true, then
    1. Let hc be resolvedLocaleData.[[hourCycle]].
  13. IfElse if hour12 is true, then
    1. Let hc be resolvedLocaleData.[[hourCycle12]].
  14. Else if hour12 is false, then
    1. Let hc be resolvedLocaleData.[[hourCycle24]].
  15. Else,
    1. Assert: hour12 is undefined.
    2. Let hc be r.[[hc]].
    3. If hc is null, set hc to resolvedLocaleData.[[hourCycle]].
  16. Let timeZone be ? Get(options, "timeZone").
  17. If timeZone is undefined, then
    1. Set timeZone to SystemTimeZoneIdentifier().
  18. Else,
    1. Set timeZone to ? ToString(timeZone).
  19. If IsTimeZoneOffsetString(timeZone) is true, then
    1. Let parseResult be ParseText(StringToCodePoints(timeZone), UTCOffset).
    2. Assert: parseResult is a Parse Node.
    3. If parseResult contains more than one MinuteSecond Parse Node, throw a RangeError exception.
    4. Let offsetNanoseconds be ParseTimeZoneOffsetString(timeZone).
    5. Let offsetMinutes be offsetNanoseconds / (6 × 1010).
    6. Assert: offsetMinutes is an integer.
    7. Set timeZone to FormatOffsetTimeZoneIdentifier(offsetMinutes).
  20. Else,
    1. Let timeZoneIdentifierRecord be GetAvailableNamedTimeZoneIdentifier(timeZone).
    2. If timeZoneIdentifierRecord is empty, throw a RangeError exception.
    3. Set timeZone to timeZoneIdentifierRecord.[[PrimaryIdentifier]].
  21. Set dateTimeFormat.[[TimeZone]] to timeZone.
  22. Let formatOptions be a new Record.
  23. Set formatOptions.[[hourCycle]] to hc.
  24. Let hasExplicitFormatComponents be false.
  25. For each row of Table 16, except the header row, in table order, do
    1. Let prop be the name given in the Property column of the current row.
    2. If prop is "fractionalSecondDigits", then
      1. Let value be ? GetNumberOption(options, "fractionalSecondDigits", 1, 3, undefined).
    3. Else,
      1. Let values be a List whose elements are the strings given in the Values column of the current row.
      2. Let value be ? GetOption(options, prop, string, values, undefined).
    4. Set formatOptions.[[<prop>]] to value.
    5. If value is not undefined, then
      1. Set hasExplicitFormatComponents to true.
  26. Let formatMatcher be ? GetOption(options, "formatMatcher", string, « "basic", "best fit" », "best fit").
  27. Let dateStyle be ? GetOption(options, "dateStyle", string, « "full", "long", "medium", "short" », undefined).
  28. Set dateTimeFormat.[[DateStyle]] to dateStyle.
  29. Let timeStyle be ? GetOption(options, "timeStyle", string, « "full", "long", "medium", "short" », undefined).
  30. Set dateTimeFormat.[[TimeStyle]] to timeStyle.
  31. If dateStyle is not undefined or timeStyle is not undefined, then
    1. If hasExplicitFormatComponents is true, then
      1. Throw a TypeError exception.
    2. If required is date and timeStyle is not undefined, then
      1. Throw a TypeError exception.
    3. If required is time and dateStyle is not undefined, then
      1. Throw a TypeError exception.
    4. Let styles be resolvedLocaleData.[[styles]].[[<resolvedCalendar>]].
    5. Let bestFormat be DateTimeStyleFormat(dateStyle, timeStyle, styles).
  32. Else,
    1. Let needDefaults be true.
    2. If required is date or any, then
      1. For each property name prop of « "weekday", "year", "month", "day" », do
        1. Let value be formatOptions.[[<prop>]].
        2. If value is not undefined, set needDefaults to false.
    3. If required is time or any, then
      1. For each property name prop of « "dayPeriod", "hour", "minute", "second", "fractionalSecondDigits" », do
        1. Let value be formatOptions.[[<prop>]].
        2. If value is not undefined, set needDefaults to false.
    4. If needDefaults is true and defaults is either date or all, then
      1. For each property name prop of « "year", "month", "day" », do
        1. Set formatOptions.[[<prop>]] to "numeric".
    5. If needDefaults is true and defaults is either time or all, then
      1. For each property name prop of « "hour", "minute", "second" », do
        1. Set formatOptions.[[<prop>]] to "numeric".
    6. Let formats be resolvedLocaleData.[[formats]].[[<resolvedCalendar>]].
    7. If formatMatcher is "basic", then
      1. Let bestFormat be BasicFormatMatcher(formatOptions, formats).
    8. Else,
      1. Let bestFormat be BestFitFormatMatcher(formatOptions, formats).
  33. Set dateTimeFormat.[[DateTimeFormat]] to bestFormat.
  34. If bestFormat has a field [[hour]], then
    1. Set dateTimeFormat.[[HourCycle]] to hc.
  35. Return dateTimeFormat.

11.2 Properties of the Intl.DateTimeFormat Constructor

11.2.3 Internal slots

The value of the [[AvailableLocales]] internal slot is implementation-defined within the constraints described in 9.1.

The value of the [[RelevantExtensionKeys]] internal slot is « "ca", "hc", "nu" ».

Note
Unicode Technical Standard #35 Part 1 Core, Section 3.6.1 Key and Type Definitions describes four locale extension keys that are relevant to date and time formatting: "ca" for calendar, "hc" for hour cycle, "nu" for numbering system (of formatted numbers), and "tz" for time zone. DateTimeFormat, however, requires that the time zone is specified through the "timeZone" property in the options objects.

The value of the [[ResolutionOptionDescriptors]] internal slot is « { [[Key]]: "ca", [[Property]]: "calendar" }, { [[Key]]: "nu", [[Property]]: "numberingSystem" }, { [[Key]]: "hour12", [[Property]]: "hour12", [[Type]]: boolean }, { [[Key]]: "hc", [[Property]]: "hourCycle", [[Values]]: « "h11", "h12", "h23", "h24" » } ».

The value of the [[LocaleData]] internal slot is implementation-defined within the constraints described in 9.1 and the following additional constraints, for all locale values locale:

  • [[LocaleData]].[[<locale>]].[[nu]] must be a List that does not include the values "native", "traditio", or "finance".
  • [[LocaleData]].[[<locale>]].[[hc]] must be « null, "h11", "h12", "h23", "h24" ».
  • [[LocaleData]].[[<locale>]].[[hourCycle]] must be one of the String values "h11", "h12", "h23", or "h24".
  • [[LocaleData]].[[<locale>]].[[hourCycle12]] must be one of the String values "h11" or "h12".
  • [[LocaleData]].[[<locale>]].[[hourCycle24]] must be one of the String values "h23" or "h24".
  • [[LocaleData]].[[<locale>]] must have a [[formats]] field. The value of this [[formats]] field must be a Record with a [[<calendar>]] field for each calendar value calendar. The value of each [[<calendar>]] field must be a List of DateTime Format Records. Multiple Records in such a List may use the same subset of the fields as long as the corresponding values differ for at least one field. The following subsets must be available for each locale:
    • weekday, year, month, day, hour, minute, second, fractionalSecondDigits
    • weekday, year, month, day, hour, minute, second
    • weekday, year, month, day
    • year, month, day
    • year, month
    • month, day
    • month
    • hour, minute, second, fractionalSecondDigits
    • hour, minute, second
    • hour, minute
    • dayPeriod, hour, minute, second, fractionalSecondDigits
    • dayPeriod, hour, minute, second
    • dayPeriod, hour, minute
    • dayPeriod, hour
  • [[LocaleData]].[[<locale>]] must have a [[styles]] field. The value of this [[styles]] field must be a Record with a [[<calendar>]] field for each calendar value calendar. The value of each [[<calendar>]] field must be a DateTime Styles Record.
  • For the locale "zxx", the [[LocaleData]].[[<locale>]] Record must have the following values:
    • [[nu]]: « "latn" »
    • [[hourCycle]]: "h23"
    • [[hourCycle24]]: "h23"
    • [[formats]]: TODO
    • [[styles]]: TODO

12 DisplayNames Objects

12.2.3 Internal slots

The value of the [[AvailableLocales]] internal slot is implementation-defined within the constraints described in 9.1.

The value of the [[RelevantExtensionKeys]] internal slot is « ».

The value of the [[ResolutionOptionDescriptors]] internal slot is « ».

The value of the [[LocaleData]] internal slot is implementation-defined within the constraints described in 9.1 and the following additional constraints:

  • [[LocaleData]].[[<locale>]] must have a [[types]] field for all locale values locale. The value of this field must be a Record, which must have fields with the names of all display name types: "language", "region", "script", "currency", "calendar", and "dateTimeField".
  • The value of the field "language" must be a Record which must have fields with the names of one of the valid language displays: "dialect" and "standard".
  • The language display fields under display name type "language" should contain Records which must have fields with the names of one of the valid display name styles: "narrow", "short", and "long".
  • The value of the fields "region", "script", "currency", "calendar", and "dateTimeField" must be Records, which must have fields with the names of all display name styles: "narrow", "short", and "long".
  • The display name style fields under display name type "language" should contain Records with keys corresponding to language codes that can be matched by the unicode_language_id Unicode locale nonterminal. The value of these fields must be string values.
  • The display name style fields under display name type "region" should contain Records with keys corresponding to region codes. The value of these fields must be string values.
  • The display name style fields under display name type "script" should contain Records with keys corresponding to script codes. The value of these fields must be string values.
  • The display name style fields under display name type "currency" should contain Records with keys corresponding to currency codes. The value of these fields must be string values.
  • The display name style fields under display name type "calendar" should contain Records with keys corresponding to calendar identifiers that can be matched by the type Unicode locale nonterminal. The value of these fields must be string values.
  • The display name style fields under display name type "dateTimeField" should contain Records with keys corresponding to codes listed in Table 19. The value of these fields must be string values.
  • For the locale "zxx", the display name style fields under all display name types must contain empty Records.
Note
It is recommended that implementations use the locale data provided by the Common Locale Data Repository (available at https://cldr.unicode.org/).

13 DurationFormat Objects

13.2.3 Internal slots

The value of the [[AvailableLocales]] internal slot is implementation defined within the constraints described in 9.1.

The value of the [[RelevantExtensionKeys]] internal slot is « "nu" ».

The value of the [[ResolutionOptionDescriptors]] internal slot is « { [[Key]]: "nu", [[Property]]: "numberingSystem" } ».

The value of the [[LocaleData]] internal slot is implementation-defined within the constraints described in 9.1 and the following additional constraints for all locale values locale:

  • [[LocaleData]].[[<locale>]] must be a Record with fields [[nu]] and [[DigitalFormat]].
  • [[LocaleData]].[[<locale>]].[[nu]] must be a List as specified in 16.2.3 and must not include the values "native", "traditio", or "finance".
  • [[LocaleData]].[[<locale>]].[[DigitalFormat]] must be a Record with keys corresponding to each numbering system available for locale. Each value associated with one of those keys must be a Record containing the following fields:
    • [[HourMinuteSeparator]] must be a String value that is the appropriate separator between hours and minutes for that combination of locale and numbering system when using style "numeric" or "2-digit".
    • [[MinuteSecondSeparator]] must be a String value that is the appropriate separator between minutes and seconds for that combination of locale and numbering system when using style "numeric" or "2-digit".
    • [[TwoDigitHours]] must be a Boolean value indicating whether hours are always displayed using two digits when using style "numeric".
  • For the locale "zxx" and the calendar "latn", the [[LocaleData]].[[<locale>]].[[DigitalFormat]].[[<calendar>]] Record must have the following values:
    • [[HourMinuteSeparator]]: ":"
    • [[MinuteSecondSeparator]]: ":"
    • [[TwoDigitHours]]: true
Note
It is recommended that implementations use the locale data provided by the Common Locale Data Repository (available at http://cldr.unicode.org/).

14 ListFormat Objects

14.2.3 Internal slots

The value of the [[AvailableLocales]] internal slot is implementation-defined within the constraints described in 9.1.

The value of the [[RelevantExtensionKeys]] internal slot is « ».

The value of the [[ResolutionOptionDescriptors]] internal slot is « ».

Note 1
Intl.ListFormat does not have any relevant extension keys.

The value of the [[LocaleData]] internal slot is implementation-defined within the constraints described in 9.1 and the following additional constraints, for each locale value locale in %Intl.ListFormat%.[[AvailableLocales]]:

  • [[LocaleData]].[[<locale>]] is a Record which has three fields [[conjunction]], [[disjunction]], and [[unit]]. Each of these is a Record which must have fields with the names of three formatting styles: [[long]], [[short]], and [[narrow]].
  • Each of those fields is considered a ListFormat template set, which must be a List of Records with fields named: [[Pair]], [[Start]], [[Middle]], and [[End]]. Each of those fields must be a template string as specified in LDML List Format Rules. Each template string must contain the substrings "{0}" and "{1}" exactly once. The substring "{0}" should occur before the substring "{1}".
  • For the locale "zxx", each of the [[LocaleData]].[[<locale>]] Record fields must be a Record that has the following values:
    • [[long]]: a List containing a single Record with the following values:
      • [[Pair]]: "{0}, {1}"
      • [[Start]]: "{0}, {1}"
      • [[Middle]]: "{0}, {1}"
      • [[End]]: "{0}, {1}"
    • [[short]]: a List containing a single Record with the following values:
      • [[Pair]]: "{0}, {1}"
      • [[Start]]: "{0}, {1}"
      • [[Middle]]: "{0}, {1}"
      • [[End]]: "{0}, {1}"
    • [[narrow]]: a List containing a single Record with the following values:
      • [[Pair]]: "{0} {1}"
      • [[Start]]: "{0} {1}"
      • [[Middle]]: "{0} {1}"
      • [[End]]: "{0} {1}"
Note 2
It is recommended that implementations use the locale data provided by the Common Locale Data Repository (available at https://cldr.unicode.org/). In LDML's listPattern, conjunction corresponds to "standard", disjunction corresponds to "or", and unit corresponds to "unit".
Note 3
Among the list types, conjunction stands for "and"-based lists (e.g., "A, B, and C"), disjunction stands for "or"-based lists (e.g., "A, B, or C"), and unit stands for lists of values with units (e.g., "5 pounds, 12 ounces").

15 Locale Objects

15.5.9 CalendarsOfLocale ( loc )

The implementation-defined abstract operation CalendarsOfLocale takes argument loc (an Intl.Locale) and returns an Array. The following algorithm refers to Locale data specified in Unicode Technical Standard #35 Part 4 Dates, Calendar Preference Data. It performs the following steps when called:

  1. If loc.[[Calendar]] is not undefined, then
    1. Return CreateArrayFromListloc.[[Calendar]] »).
  2. Let preference be RegionPreference(loc.[[Locale]]).
  3. Let region be preference.[[Region]].
  4. Let regionOverride be preference.[[RegionOverride]].
  5. If regionOverride is not undefined and calendar preference data for regionOverride are available, then
    1. Let lookupRegion be regionOverride.
  6. Else,
    1. Let lookupRegion be region.
  7. If IsStableLocale(loc.[[Locale]]) is true, then
    1. Let list be « "iso8601" ».
  8. Else,
    1. Let list be a List of unique calendar types in canonical form (6.9), sorted in descending preference of those in common use for date and time formatting in lookupRegion. The list is empty if no calendar preference data for lookupRegion is available.
    2. If list is empty, set list to « "gregory" ».
  9. Return CreateArrayFromList(list).

16 NumberFormat Objects

16.1 Intl.NumberFormat ( [ locales [ , options ] ] )

When the Intl.NumberFormat function is called with optional arguments locales and options, the following steps are taken:

  1. If NewTarget is undefined, let newTarget be the active function object, else let newTarget be NewTarget.
  2. Let numberFormat be ? OrdinaryCreateFromConstructor(newTarget, "%Intl.NumberFormat.prototype%", « [[InitializedNumberFormat]], [[Locale]], [[LocaleData]], [[NumberingSystem]], [[Style]], [[Unit]], [[UnitDisplay]], [[Currency]], [[CurrencyDisplay]], [[CurrencySign]], [[MinimumIntegerDigits]], [[MinimumFractionDigits]], [[MaximumFractionDigits]], [[MinimumSignificantDigits]], [[MaximumSignificantDigits]], [[RoundingType]], [[Notation]], [[CompactDisplay]], [[UseGrouping]], [[SignDisplay]], [[RoundingIncrement]], [[RoundingMode]], [[ComputedRoundingPriority]], [[TrailingZeroDisplay]], [[BoundFormat]] »).
  3. Let optionsResolution be ? ResolveOptions(%Intl.NumberFormat%, %Intl.NumberFormat%.[[LocaleData]], locales, options, « coerce-options »).
  4. Set options to optionsResolution.[[Options]].
  5. Let r be optionsResolution.[[ResolvedLocale]].
  6. Set numberFormat.[[Locale]] to r.[[Locale]].
  7. Set numberFormat.[[LocaleData]] to r.[[LocaleData]].
  8. Set numberFormat.[[NumberingSystem]] to r.[[nu]].
  9. Perform ? SetNumberFormatUnitOptions(numberFormat, options).
  10. Let style be numberFormat.[[Style]].
  11. Let notation be ? GetOption(options, "notation", string, « "standard", "scientific", "engineering", "compact" », "standard").
  12. Set numberFormat.[[Notation]] to notation.
  13. If style is "currency" and notation is "standard", then
    1. Let currency be numberFormat.[[Currency]].
    2. Let cDigits be CurrencyDigits(currency).
    3. Let mnfdDefault be cDigits.
    4. Let mxfdDefault be cDigits.
  14. Else,
    1. Let mnfdDefault be 0.
    2. If style is "percent", then
      1. Let mxfdDefault be 0.
    3. Else,
      1. Let mxfdDefault be 3.
  15. Perform ? SetNumberFormatDigitOptions(numberFormat, options, mnfdDefault, mxfdDefault, notation).
  16. Let compactDisplay be ? GetOption(options, "compactDisplay", string, « "short", "long" », "short").
  17. Let defaultUseGrouping be "auto".
  18. If notation is "compact", then
    1. Set numberFormat.[[CompactDisplay]] to compactDisplay.
    2. Set defaultUseGrouping to "min2".
  19. NOTE: For historical reasons, the strings "true" and "false" are accepted and replaced with the default value.
  20. Let useGrouping be ? GetBooleanOrStringNumberFormatOption(options, "useGrouping", « "min2", "auto", "always", "true", "false" », defaultUseGrouping).
  21. If useGrouping is "true" or useGrouping is "false", set useGrouping to defaultUseGrouping.
  22. If useGrouping is true, set useGrouping to "always".
  23. If IsStableLocale(numberFormat.[[Locale]]), set useGrouping to false.
  24. Set numberFormat.[[UseGrouping]] to useGrouping.
  25. Let signDisplay be ? GetOption(options, "signDisplay", string, « "auto", "never", "always", "exceptZero", "negative" », "auto").
  26. Set numberFormat.[[SignDisplay]] to signDisplay.
  27. If the implementation supports the normative optional constructor mode of 4.3 Note 1, then
    1. Let this be the this value.
    2. Return ? ChainNumberFormat(numberFormat, NewTarget, this).
  28. Return numberFormat.

16.2 Properties of the Intl.NumberFormat Constructor

16.2.3 Internal slots

The value of the [[AvailableLocales]] internal slot is implementation-defined within the constraints described in 9.1.

The value of the [[RelevantExtensionKeys]] internal slot is « "nu" ».

The value of the [[ResolutionOptionDescriptors]] internal slot is « { [[Key]]: "nu", [[Property]]: "numberingSystem" } ».

Note 1
Unicode Technical Standard #35 Part 1 Core, Section 3.6.1 Key and Type Definitions describes three locale extension keys that are relevant to number formatting: "cu" for currency, "cf" for currency format style, and "nu" for numbering system. Intl.NumberFormat, however, requires that the currency of a currency format is specified through the currency property in the options objects, and the currency format style of a currency format is specified through the currencySign property in the options objects.

The value of the [[LocaleData]] internal slot is implementation-defined within the constraints described in 9.1 and the following additional constraints:

  • The List that is the value of the "nu" field of any locale field of [[LocaleData]] must not include the values "native", "traditio", or "finance".
  • [[LocaleData]].[[<locale>]] must have a [[patterns]] field for all locale values locale. The value of this field must be a Record, which must have fields with the names of the four number format styles: "decimal", "percent", "currency", and "unit".
  • The two fields "currency" and "unit" noted above must be Records with at least one field, "fallback". The "currency" may have additional fields with keys corresponding to currency codes according to 6.3. Each field of "currency" must be a Record with fields corresponding to the possible currencyDisplay values: "code", "symbol", "narrowSymbol", and "name". Each of those fields must contain a Record with fields corresponding to the possible currencySign values: "standard" or "accounting". The "unit" field (of [[LocaleData]].[[<locale>]]) may have additional fields beyond the required field "fallback" with keys corresponding to core measurement unit identifiers corresponding to 6.6. Each field of "unit" must be a Record with fields corresponding to the possible unitDisplay values: "narrow", "short", and "long".
  • All of the leaf fields so far described for the patterns tree ("decimal", "percent", great-grandchildren of "currency", and grandchildren of "unit") must be Records with the keys "positivePattern", "zeroPattern", and "negativePattern".
  • The value of the aforementioned fields (the sign-dependent pattern fields) must be string values that must contain the substring "{number}". "positivePattern" must contain the substring "{plusSign}" but not "{minusSign}"; "negativePattern" must contain the substring "{minusSign}" but not "{plusSign}"; and "zeroPattern" must not contain either "{plusSign}" or "{minusSign}". Additionally, the values within the "percent" field must also contain the substring "{percentSign}"; the values within the "currency" field must also contain one or more of the following substrings: "{currencyCode}", "{currencyPrefix}", or "{currencySuffix}"; and the values within the "unit" field must also contain one or more of the following substrings: "{unitPrefix}" or "{unitSuffix}". The pattern strings, when interpreted as a sequence of UTF-16 encoded code points as described in ECMA-262, 6.1.4, must not contain any code points in the General Category "Number, decimal digit" as specified by the Unicode Standard.
  • [[LocaleData]].[[<locale>]] must also have a [[notationSubPatterns]] field for all locale values locale. The value of this field must be a Record, which must have two fields: [[scientific]] and [[compact]]. The [[scientific]] field must be a string value containing the substrings "{number}", "{scientificSeparator}", and "{scientificExponent}". The [[compact]] field must be a Record with two fields: "short" and "long". Each of these fields must be a Record with integer keys corresponding to all discrete magnitudes the implementation supports for compact notation. Each of these fields must be a string value which may contain the substring "{number}". Strings descended from "short" must contain the substring "{compactSymbol}", and strings descended from "long" must contain the substring "{compactName}".
  • For the locale "zxx", the [[LocaleData]].[[<locale>]] Record must have the following values:
    • "decimal":
      • "positivePattern": "{plusSign}{number}"
      • "zeroPattern": "{number}"
      • "negativePattern": "{minusSign}{number}"
    • "percent":
      • "positivePattern": "{plusSign}{number}{percentSign}"
      • "zeroPattern": "{number}{percentSign}"
      • "negativePattern": "{minusSign}{number}{percentSign}"
    • "currency":
      • "fallback":
        • "code":
          • "standard":
            • "positivePattern": "{plusSign}{number} {currencyCode}"
            • "zeroPattern": "{number} {currencyCode}"
            • "negativePattern": "{minusSign}{number} {currencyCode}"
          • "accounting":
            • "positivePattern": "{plusSign}{number} {currencyCode}"
            • "zeroPattern": "{number} {currencyCode}"
            • "negativePattern": "{minusSign}{number} {currencyCode}"
        • "symbol":
          • "standard":
            • "positivePattern": "{plusSign}{number} {currencyCode}"
            • "zeroPattern": "{number} {currencyCode}"
            • "negativePattern": "{minusSign}{number} {currencyCode}"
          • "accounting":
            • "positivePattern": "{plusSign}{number} {currencyCode}"
            • "zeroPattern": "{number} {currencyCode}"
            • "negativePattern": "{minusSign}{number} {currencyCode}"
        • "narrowSymbol":
          • "standard":
            • "positivePattern": "{plusSign}{number} {currencyCode}"
            • "zeroPattern": "{number} {currencyCode}"
            • "negativePattern": "{minusSign}{number} {currencyCode}"
          • "accounting":
            • "positivePattern": "{plusSign}{number} {currencyCode}"
            • "zeroPattern": "{number} {currencyCode}"
            • "negativePattern": "{minusSign}{number} {currencyCode}"
        • "name":
          • "standard":
            • "positivePattern": "{plusSign}{number} {currencyCode}"
            • "zeroPattern": "{number} {currencyCode}"
            • "negativePattern": "{minusSign}{number} {currencyCode}"
          • "accounting":
            • "positivePattern": "{plusSign}{number} {currencyCode}"
            • "zeroPattern": "{number} {currencyCode}"
            • "negativePattern": "{minusSign}{number} {currencyCode}"
    • "unit":
      • "fallback":
        • "narrow":
          • "positivePattern": "{plusSign}{number}{unitSuffix}"
          • "zeroPattern": "{number}{unitSuffix}"
          • "negativePattern": "{minusSign}{number}{unitSuffix}"
        • "short":
          • "positivePattern": "{plusSign}{number} {unitSuffix}"
          • "zeroPattern": "{number} {unitSuffix}"
          • "negativePattern": "{minusSign}{number} {unitSuffix}"
        • "long":
          • "positivePattern": "{plusSign}{number} {unitSuffix}"
          • "zeroPattern": "{number} {unitSuffix}"
          • "negativePattern": "{minusSign}{number} {unitSuffix}"
    • [[notationSubPatterns]]:
      • [[scientific]]: "{number}{scientificSeparator}{scientificExponent}"
      • [[compact]]:
        • "short":
          • 3: "{number}{compactSymbol}"
          • 6: "{number}{compactSymbol}"
          • 9: "{number}{compactSymbol}"
          • 12: "{number}{compactSymbol}"
        • "long":
          • 3: "{number}{compactName}"
          • 6: "{number}{compactName}"
          • 9: "{number}{compactName}"
          • 12: "{number}{compactName}"
Note 2
It is recommended that implementations use the locale data provided by the Common Locale Data Repository (available at https://cldr.unicode.org/).

16.5 Abstract Operations for NumberFormat Objects

16.5.4 PartitionNumberPattern ( numberFormat, x )

The abstract operation PartitionNumberPattern takes arguments numberFormat (an object initialized as a NumberFormat) and x (an Intl mathematical value) and returns a List of Records with fields [[Type]] (a String) and [[Value]] (a String). It creates the parts representing the mathematical value of x according to the effective locale and the formatting options of numberFormat. It performs the following steps when called:

  1. Let exponent be 0.
  2. If x is not-a-number, then
    1. Let n be an ILD String value indicating the NaN value. For the "zxx" locale, this is "NaN".
  3. Else if x is positive-infinity, then
    1. Let n be an ILD String value indicating positive infinity. For the "zxx" locale, this is "Infinity".
  4. Else if x is negative-infinity, then
    1. Let n be an ILD String value indicating negative infinity. For the "zxx" locale, this is "-Infinity".
  5. Else,
    1. If x is not negative-zero, then
      1. Assert: x is a mathematical value.
      2. If numberFormat.[[Style]] is "percent", set x be 100 × x.
      3. Set exponent to ComputeExponent(numberFormat, x).
      4. Set x to x × 10-exponent.
    2. Let formatNumberResult be FormatNumericToString(numberFormat, x).
    3. Let n be formatNumberResult.[[FormattedString]].
    4. Set x to formatNumberResult.[[RoundedNumber]].
  6. Let pattern be GetNumberFormatPattern(numberFormat, x).
  7. Let result be a new empty List.
  8. Let patternParts be PartitionPattern(pattern).
  9. For each Record { [[Type]], [[Value]] } patternPart of patternParts, do
    1. Let p be patternPart.[[Type]].
    2. If p is "literal", then
      1. Append the Record { [[Type]]: "literal", [[Value]]: patternPart.[[Value]] } to result.
    3. Else if p is "number", then
      1. Let notationSubParts be PartitionNotationSubPattern(numberFormat, x, n, exponent).
      2. Set result to the list-concatenation of result and notationSubParts.
    4. Else if p is "plusSign", then
      1. Let plusSignSymbol be the ILND String representing the plus sign. For the "zxx" locale, this is "+".
      2. Append the Record { [[Type]]: "plusSign", [[Value]]: plusSignSymbol } to result.
    5. Else if p is "minusSign", then
      1. Let minusSignSymbol be the ILND String representing the minus sign. For the "zxx" locale, this is "-".
      2. Append the Record { [[Type]]: "minusSign", [[Value]]: minusSignSymbol } to result.
    6. Else if p is "percentSign" and numberFormat.[[Style]] is "percent", then
      1. Let percentSignSymbol be the ILND String representing the percent sign. For the "zxx" locale, this is "%".
      2. Append the Record { [[Type]]: "percentSign", [[Value]]: percentSignSymbol } to result.
    7. Else if p is "unitPrefix" and numberFormat.[[Style]] is "unit", then
      1. Let unit be numberFormat.[[Unit]].
      2. Let unitDisplay be numberFormat.[[UnitDisplay]].
      3. Let mu be an ILD String value representing unit before x in unitDisplay form, which may depend on x in languages having different plural forms.
      4. Append the Record { [[Type]]: "unit", [[Value]]: mu } to result.
    8. Else if p is "unitSuffix" and numberFormat.[[Style]] is "unit", then
      1. Let unit be numberFormat.[[Unit]].
      2. Let unitDisplay be numberFormat.[[UnitDisplay]].
      3. Let mu be an ILD String value representing unit after x in unitDisplay form, which may depend on x in languages having different plural forms. For the "zxx" locale, this is the unit String with any "-per-" infix replaced by "/".
      4. Append the Record { [[Type]]: "unit", [[Value]]: mu } to result.
    9. Else if p is "currencyCode" and numberFormat.[[Style]] is "currency", then
      1. Let currency be numberFormat.[[Currency]].
      2. Let cd be currency.
      3. Append the Record { [[Type]]: "currency", [[Value]]: cd } to result.
    10. Else if p is "currencyPrefix" and numberFormat.[[Style]] is "currency", then
      1. Let currency be numberFormat.[[Currency]].
      2. Let currencyDisplay be numberFormat.[[CurrencyDisplay]].
      3. Let cd be an ILD String value representing currency before x in currencyDisplay form, which may depend on x in languages having different plural forms.
      4. Append the Record { [[Type]]: "currency", [[Value]]: cd } to result.
    11. Else if p is "currencySuffix" and numberFormat.[[Style]] is "currency", then
      1. Let currency be numberFormat.[[Currency]].
      2. Let currencyDisplay be numberFormat.[[CurrencyDisplay]].
      3. Let cd be an ILD String value representing currency after x in currencyDisplay form, which may depend on x in languages having different plural forms. If the implementation does not have such a representation of currency, use currency itself.
      4. Append the Record { [[Type]]: "currency", [[Value]]: cd } to result.
    12. Else,
      1. Let unknown be an ILND String based on x and p.
      2. Append the Record { [[Type]]: "unknown", [[Value]]: unknown } to result.
  10. Return result.

16.5.5 PartitionNotationSubPattern ( numberFormat, x, n, exponent )

The abstract operation PartitionNotationSubPattern takes arguments numberFormat (an Intl.NumberFormat), x (an Intl mathematical value), n (a String), and exponent (an integer) and returns a List of Records with fields [[Type]] (a String) and [[Value]] (a String). x is an Intl mathematical value after rounding is applied and n is an intermediate formatted string. It creates the corresponding parts for the number and notation according to the effective locale and the formatting options of numberFormat. It performs the following steps when called:

  1. Let result be a new empty List.
  2. If x is not-a-number, then
    1. Append the Record { [[Type]]: "nan", [[Value]]: n } to result.
  3. Else if x is positive-infinity or negative-infinity, then
    1. Append the Record { [[Type]]: "infinity", [[Value]]: n } to result.
  4. Else,
    1. Let notationSubPattern be GetNotationSubPattern(numberFormat, exponent).
    2. Let patternParts be PartitionPattern(notationSubPattern).
    3. For each Record { [[Type]], [[Value]] } patternPart of patternParts, do
      1. Let p be patternPart.[[Type]].
      2. If p is "literal", then
        1. Append the Record { [[Type]]: "literal", [[Value]]: patternPart.[[Value]] } to result.
      3. Else if p is "number", then
        1. If the numberFormat.[[NumberingSystem]] matches one of the values in the Numbering System column of Table 30 below, then
          1. Let digits be a List whose elements are the code points specified in the Digits column of the matching row in Table 30.
          2. Assert: The length of digits is 10.
          3. Let transliterated be the empty String.
          4. Let len be the length of n.
          5. Let position be 0.
          6. Repeat, while position < len,
            1. Let c be the code unit at index position within n.
            2. If 0x0030 ≤ c ≤ 0x0039, then
              1. NOTE: c is an ASCII digit.
              2. Let i be c - 0x0030.
              3. Set c to CodePointsToStringdigits[i] »).
            3. Set transliterated to the string-concatenation of transliterated and c.
            4. Set position to position + 1.
          7. Set n to transliterated.
        2. Else,
          1. Use an implementation dependent algorithm to map n to the appropriate representation of n in the given numbering system.
        3. Let decimalSepIndex be StringIndexOf(n, ".", 0).
        4. If decimalSepIndex is not not-found and decimalSepIndex > 0, then
          1. Let integer be the substring of n from 0 to decimalSepIndex.
          2. Let fraction be the substring of n from decimalSepIndex + 1.
        5. Else,
          1. Let integer be n.
          2. Let fraction be undefined.
        6. If the numberFormat.[[UseGrouping]] is false, then
          1. Append the Record { [[Type]]: "integer", [[Value]]: integer } to result.
        7. Else,
          1. Let groupSepSymbol be the ILND String representing the grouping separator.
          2. Let groups be a List whose elements are, in left to right order, the substrings defined by ILND set of locations within the integer, which may depend on the value of numberFormat.[[UseGrouping]].
          3. Assert: The number of elements in groups List is greater than 0.
          4. Repeat, while groups List is not empty,
            1. Remove the first element from groups and let integerGroup be the value of that element.
            2. Append the Record { [[Type]]: "integer", [[Value]]: integerGroup } to result.
            3. If groups List is not empty, then
              1. Append the Record { [[Type]]: "group", [[Value]]: groupSepSymbol } to result.
        8. If fraction is not undefined, then
          1. Let decimalSepSymbol be the ILND String representing the decimal separator. For the "zxx" locale, this is ".".
          2. Append the Record { [[Type]]: "decimal", [[Value]]: decimalSepSymbol } to result.
          3. Append the Record { [[Type]]: "fraction", [[Value]]: fraction } to result.
      4. Else if p is "compactSymbol", then
        1. Let compactSymbol be an ILD string representing exponent in short form, which may depend on x in languages having different plural forms. The implementation must be able to provide this string, or else the pattern would not have a "{compactSymbol}" placeholder. For the "zxx" locale, this is "k" if exponent is 3, "M" if exponent is 6, "G" if exponent is 9, and "T" if exponent is 12.
        2. Append the Record { [[Type]]: "compact", [[Value]]: compactSymbol } to result.
      5. Else if p is "compactName", then
        1. Let compactName be an ILD string representing exponent in long form, which may depend on x in languages having different plural forms. The implementation must be able to provide this string, or else the pattern would not have a "{compactName}" placeholder. For the "zxx" locale, this is "k" if exponent is 3, "M" if exponent is 6, "G" if exponent is 9, and "T" if exponent is 12.
        2. Append the Record { [[Type]]: "compact", [[Value]]: compactName } to result.
      6. Else if p is "scientificSeparator", then
        1. Let scientificSeparator be the ILND String representing the exponent separator. For the "zxx" locale, this is "E".
        2. Append the Record { [[Type]]: "exponentSeparator", [[Value]]: scientificSeparator } to result.
      7. Else if p is "scientificExponent", then
        1. If exponent < 0, then
          1. Let minusSignSymbol be the ILND String representing the minus sign. For the "zxx" locale, this is "-".
          2. Append the Record { [[Type]]: "exponentMinusSign", [[Value]]: minusSignSymbol } to result.
          3. Let exponent beSet exponent to -exponent.
        2. Let exponentResult be ToRawFixed(exponent, 0, 0, 1, undefined).
        3. Append the Record { [[Type]]: "exponentInteger", [[Value]]: exponentResult.[[FormattedString]] } to result.
      8. Else,
        1. Let unknown be an ILND String based on x and p.
        2. Append the Record { [[Type]]: "unknown", [[Value]]: unknown } to result.
  5. Return result.

16.5.14 ComputeExponentForMagnitude ( numberFormat, magnitude )

The abstract operation ComputeExponentForMagnitude takes arguments numberFormat (an Intl.NumberFormat) and magnitude (an integer) and returns an integer. It computes an exponent by which to scale a number of the given magnitude (power of ten of the most significant digit) according to the locale and the desired notation (scientific, engineering, or compact). It performs the following steps when called:

  1. Let notation be numberFormat.[[Notation]].
  2. If notation is "standard", then
    1. Return 0.
  3. Else if notation is "scientific", then
    1. Return magnitude.
  4. Else if notation is "engineering", then
    1. Let thousands be the greatest integer that is not greater than magnitude / 3.
    2. Return thousands × 3.
  5. Else,
    1. Assert: notation is "compact".
    2. If IsStableLocale(numberFormat.[[Locale]]), then
      1. If magnitude ≥ 12, return 12.
      2. Else if magnitude ≥ 9, return 9.
      3. Else if magnitude ≥ 6, return 6.
      4. Else if magnitude ≥ 3, return 3.
      5. Else return 0.
    3. Let exponent be an ILD integer by which to scale a number of the given magnitude in compact notation for the current locale.
    4. Return exponent.

16.5.19 PartitionNumberRangePattern ( numberFormat, x, y )

The abstract operation PartitionNumberRangePattern takes arguments numberFormat (an Intl.NumberFormat), x (an Intl mathematical value), and y (an Intl mathematical value) and returns either a normal completion containing a List of Records with fields [[Type]] (a String), [[Value]] (a String), and [[Source]] (a String), or a throw completion. It creates the parts for a localized number range according to x, y, and the formatting options of numberFormat. It performs the following steps when called:

  1. If x is not-a-number or y is not-a-number, throw a RangeError exception.
  2. Let xResult be PartitionNumberPattern(numberFormat, x).
  3. Let yResult be PartitionNumberPattern(numberFormat, y).
  4. If FormatNumeric(numberFormat, x) is FormatNumeric(numberFormat, y), then
    1. Let appxResult be FormatApproximately(numberFormat, xResult).
    2. For each element r of appxResult, do
      1. Set r.[[Source]] to "shared".
    3. Return appxResult.
  5. Let result be a new empty List.
  6. For each element r of xResult, do
    1. Append the Record { [[Type]]: r.[[Type]], [[Value]]: r.[[Value]], [[Source]]: "startRange" } to result.
  7. Let rangeSeparator be an ILND String value used to separate two numbers. For the "zxx" locale, this is "-".
  8. Append the Record { [[Type]]: "literal", [[Value]]: rangeSeparator, [[Source]]: "shared" } to result.
  9. For each element r of yResult, do
    1. Append the Record { [[Type]]: r.[[Type]], [[Value]]: r.[[Value]], [[Source]]: "endRange" } to result.
  10. Return CollapseNumberRange(numberFormat, result).

16.5.20 FormatApproximately ( numberFormat, result )

The abstract operation FormatApproximately takes arguments numberFormat (an Intl.NumberFormat) and result (a List of Records with fields [[Type]] (a String) and [[Value]] (a String)) and returns a List of Records with fields [[Type]] (a String) and [[Value]] (a String). It modifies result, which must be a List of Record values as described in PartitionNumberPattern, by adding a new Record for the approximately sign, which may depend on numberFormat. It performs the following steps when called:

  1. Let approximatelySign be an ILND String value used to signify that a number is approximate. For the "zxx" locale, this is "~".
  2. If approximatelySign is not empty, insert the Record { [[Type]]: "approximatelySign", [[Value]]: approximatelySign } at an ILND index in result. For example, if numberFormat has [[Locale]] "en-US" and [[NumberingSystem]] "latn" and [[Style]] "decimal", the new Record might be inserted before the first element of result. For the "zxx" locale, the new Record is inserted before the first element of result.
  3. Return result.

17 PluralRules Objects

17.5.1 PluralRuleSelect ( locale, type, notation, compactDisplay, s )

The implementation-defined abstract operation PluralRuleSelect takes arguments locale (a language tag), type ("cardinal" or "ordinal"), notation (a String), compactDisplay ("short" or "long"), and s (a decimal String) and returns "zero", "one", "two", "few", "many", or "other". The returned String characterizes the plural category of s according to type, notation, and compactDisplay for the corresponding locale. If IsStableLocale(locale) is true, the string "other" is returned.

17.5.2 ResolvePlural ( pluralRules, n )

The abstract operation ResolvePlural takes arguments pluralRules (an Intl.PluralRules) and n (an Intl mathematical value) and returns a Record with fields [[PluralCategory]] ("zero", "one", "two", "few", "many", or "other") and [[FormattedString]] (a String). The returned Record contains two string-valued fields describing n according to the effective locale and the internal slots of pluralRules: [[PluralCategory]] characterizing its plural category, and [[FormattedString]] containing its formatted representation. It performs the following steps when called:

  1. If n is not-a-number, then
    1. Let s be an ILD String value indicating the NaN value. For the "zxx" locale, this is "NaN".
    2. Return the Record { [[PluralCategory]]: "other", [[FormattedString]]: s }.
  2. If n is positive-infinity, then
    1. Let s be an ILD String value indicating positive infinity. For the "zxx" locale, this is "Infinity".
    2. Return the Record { [[PluralCategory]]: "other", [[FormattedString]]: s }.
  3. If n is negative-infinity, then
    1. Let s be an ILD String value indicating negative infinity. For the "zxx" locale, this is "-Infinity".
    2. Return the Record { [[PluralCategory]]: "other", [[FormattedString]]: s }.
  4. Let res be FormatNumericToString(pluralRules, n).
  5. Let s be res.[[FormattedString]].
  6. Let locale be pluralRules.[[Locale]].
  7. Let type be pluralRules.[[Type]].
  8. Let notation be pluralRules.[[Notation]].
  9. Let compactDisplay be pluralRules.[[CompactDisplay]].
  10. Let p be PluralRuleSelect(locale, type, notation, compactDisplay, s).
  11. Return the Record { [[PluralCategory]]: p, [[FormattedString]]: s }.

17.5.3 PluralRuleSelectRange ( locale, type, notation, compactDisplay, xp, yp )

The implementation-defined abstract operation PluralRuleSelectRange takes arguments locale (a language tag), type ("cardinal" or "ordinal"), notation (a String), compactDisplay ("short" or "long"), xp ("zero", "one", "two", "few", "many", or "other"), and yp ("zero", "one", "two", "few", "many", or "other") and returns "zero", "one", "two", "few", "many", or "other". It performs an implementation-dependent algorithm to map the plural category String values xp and yp, respectively characterizing the start and end of a range, to a resolved String value for the plural form of the range as a whole denoted by type, notation, and compactDisplay for the corresponding locale, or the String value "other". If IsStableLocale(locale) is true, the string "other" is returned.

18 RelativeTimeFormat Objects

18.2.3 Internal slots

The value of the [[AvailableLocales]] internal slot is implementation-defined within the constraints described in 9.1.

The value of the [[RelevantExtensionKeys]] internal slot is « "nu" ».

The value of the [[ResolutionOptionDescriptors]] internal slot is « { [[Key]]: "nu", [[Property]]: "numberingSystem" } ».

Note 1
Unicode Technical Standard #35 Part 1 Core, Section 3.6.1 Key and Type Definitions describes one locale extension key that is relevant to relative time formatting: "nu" for numbering system (of formatted numbers).

The value of the [[LocaleData]] internal slot is implementation-defined within the constraints described in 9.1 and the following additional constraints, for all locale values locale:

  • [[LocaleData]].[[<locale>]] has fields "second", "minute", "hour", "day", "week", "month", "quarter", and "year". Additional fields may exist with the previous names concatenated with the strings "-narrow" or "-short". The values corresponding to these fields are Records which contain these two categories of fields:
    • "future" and "past" fields, which are Records with a field for each of the plural categories relevant for locale. The value corresponding to those fields is a pattern which may contain "{0}" to be replaced by a formatted number.
    • Optionally, additional fields whose key is the result of ToString of a Number, and whose values are literal Strings which are not treated as templates.
  • The List that is the value of the "nu" field of any locale field of [[LocaleData]] must not include the values "native", "traditio", or "finance".
  • For the locale "zxx", the [[LocaleData]].[[<locale>]] Record must have the following values:
    • "second":
      • "future":
        • "other": "+PT{0}S"
      • "past":
        • "other": "-PT{0}S"
    • "minute":
      • "future":
        • "other": "+PT{0}M"
      • "past":
        • "other": "-PT{0}M"
    • "hour":
      • "future":
        • "other": "+PT{0}H"
      • "past":
        • "other": "-PT{0}H"
    • "day":
      • "future":
        • "other": "+P{0}D"
      • "past":
        • "other": "-P{0}D"
    • "week":
      • "future":
        • "other": "+P{0}W"
      • "past":
        • "other": "-P{0}W"
    • "month":
      • "future":
        • "other": "+P{0}M"
      • "past":
        • "other": "-P{0}M"
    • "quarter":
      • "future":
        • "other": "+{0}Q"
      • "past":
        • "other": "-{0}Q"
    • "year":
      • "future":
        • "other": "+P{0}Y"
      • "past":
        • "other": "-P{0}Y"
Note 2
It is recommended that implementations use the locale data provided by the Common Locale Data Repository (available at https://cldr.unicode.org/).

20 Locale Sensitive Functions of the ECMAScript Language Specification

20.5.1 Array.prototype.toLocaleString ( [ locales [ , options ] ] )

This definition supersedes the definition provided in Array.prototype.toLocaleString ( [ reserved1 [ , reserved2 ] ] ).

When the toLocaleString method is called with optional arguments locales and options, the following steps are taken:

  1. Let array be ? ToObject(this value).
  2. Let len be ? LengthOfArrayLike(array).
  3. Let separator be the implementation-defined list-separator String value appropriate for the host environment's current locale (such as ", "). For the "zxx" locale, this is ",".
  4. Let R be the empty String.
  5. Let k be 0.
  6. Repeat, while k < len,
    1. If k > 0, then
      1. Set R to the string-concatenation of R and separator.
    2. Let nextElement be ? Get(array, ! ToString(𝔽(k))).
    3. If nextElement is not undefined or null, then
      1. Let S be ? ToString(? Invoke(nextElement, "toLocaleString", « locales, options »)).
      2. Set R to the string-concatenation of R and S.
    4. Set k to k + 1.
  7. Return R.
Note 1
This algorithm's steps mirror the steps taken in Array.prototype.toLocaleString ( [ reserved1 [ , reserved2 ] ] ), with the exception that Invoke(nextElement, "toLocaleString") now takes locales and options as arguments.
Note 2
The elements of the array are converted to Strings using their toLocaleString methods, and these Strings are then concatenated, separated by occurrences of an implementation-defined locale-sensitive separator String. This function is analogous to toString except that it is intended to yield a locale-sensitive result corresponding with conventions of the host environment's current locale.
Note 3
The toLocaleString function is intentionally generic; it does not require that its this value be an Array object. Therefore it can be transferred to other kinds of objects for use as a method.

Copyright & Software License

Software License

All Software contained in this document ("Software") is protected by copyright and is being made available under the "BSD License", included below. This Software may be subject to third party rights (rights from parties other than Ecma International), including patent rights, and no licenses under such third party rights are granted under this license even if the third party concerned is a member of Ecma International. SEE THE ECMA CODE OF CONDUCT IN PATENT MATTERS AVAILABLE AT https://ecma-international.org/memento/codeofconduct.htm FOR INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO IMPLEMENT ECMA INTERNATIONAL STANDARDS.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of the authors nor Ecma International may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.