Multipage preference

Stage 1 Draft / July 24, 2026

Intl.DateTimeFormat Alignment With Other Standards

Introduction

An explainer for this proposal is available at github.com/tc39/proposal-intl-datetime-alignment.

11 DateTimeFormat Objects

11.1 The Intl.DateTimeFormat Constructor

11.1.2 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 specialOptions be the Record { [[Hour12]]: undefined }.
  3. Let modifyResolutionOptions be a new Abstract Closure with parameters (options) that captures specialOptions and performs the following steps when called:
    1. Set specialOptions.[[Hour12]] to options.[[hour12]].
    2. Remove field [[hour12]] from options.
    3. If specialOptions.[[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. Let hour12 be specialOptions.[[Hour12]].
  6. Set options to optionsResolution.[[Options]].
  7. Let resolvedLocale be optionsResolution.[[ResolvedLocale]].
  8. Set dateTimeFormat.[[Locale]] to resolvedLocale.[[Locale]].
  9. Let resolvedCalendar be resolvedLocale.[[ca]].
  10. Set dateTimeFormat.[[Calendar]] to resolvedCalendar.
  11. Set dateTimeFormat.[[NumberingSystem]] to resolvedLocale.[[nu]].
  12. Let resolvedLocaleData be resolvedLocale.[[LocaleData]].
  13. 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 resolvedLocale.[[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 12, except the header row, in table order, do
    1. Let propertyKey be the name given in the Property column of the current row.
    2. If propertyKey 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, propertyKey, string, values, undefined).
    4. Set formatOptions.[[<propertyKey>]] 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 propertyKey of « "weekday", "year", "month", "day" », do
        1. Let value be formatOptions.[[<propertyKey>]].
        2. If value is not undefined, set needDefaults to false.
    3. If required is time or any, then
      1. For each property name propertyKey of « "dayPeriod", "hour", "minute", "second", "fractionalSecondDigits" », do
        1. Let value be formatOptions.[[<propertyKey>]].
        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 propertyKey of « "year", "month", "day" », do
        1. Set formatOptions.[[<propertyKey>]] to "numeric".
    5. If needDefaults is true and defaults is either time or all, then
      1. For each property name propertyKey of « "hour", "minute", "second" », do
        1. Set formatOptions.[[<propertyKey>]] 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 1
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 Strings "h11", "h12", "h23", or "h24".
  • [[LocaleData]].[[<locale>]].[[hourCycle12]] must be one of the Strings "h11" or "h12".
  • [[LocaleData]].[[<locale>]].[[hourCycle24]] must be one of the Strings "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.

11.2.3.1 DateTime Format Records

Each DateTime Format Record has the fields defined in Table 1.

Table 1: DateTime Format Record
Field Name Value Type Description
[[weekday]] [[Weekday]] values in the Values column of Table 12 Optional field. Present if [[pattern]] contains the substring "{weekday}".
[[era]] [[Era]] values in the Values column of Table 12 Optional field. Present if [[pattern]] contains the substring "{era}".
[[year]] [[Year]] values in the Values column of Table 12 Optional field. Present if [[pattern]] contains at least one of the substrings "{year}", "{yearName}", or "{relatedYear}".
[[month]] [[Month]] values in the Values column of Table 12 Optional field. Present if [[pattern]] contains the substring "{month}".
[[day]] [[Day]] values in the Values column of Table 12 Optional field. Present if [[pattern]] contains the substring "{day}".
[[dayPeriod]] [[DayPeriod]] values in the Values column of Table 12 Optional field. Present if [[pattern]] contains the substring "{dayPeriod}".
[[hour]] [[Hour]] values in the Values column of Table 12 Optional field. Present if [[pattern]] contains the substring "{hour}".
[[minute]] [[Minute]] values in the Values column of Table 12 Optional field. Present if [[pattern]] contains the substring "{minute}".
[[second]] [[Second]] values in the Values column of Table 12 Optional field. Present if [[pattern]] contains the substring "{second}".
[[fractionalSecondDigits]] [[FractionalSecondDigits]] values in the Values column of Table 12 Optional field. Present if [[pattern]] contains the substring "{fractionalSecondDigits}".
[[timeZoneName]] [[TimeZoneName]] values in the Values column of Table 12 Optional field. Present if [[pattern]] contains the substring "{timeZoneName}".
[[pattern]] a Pattern String Contains for each of the date and time format component fields of the record a substring starting with "{", followed by the name of the field, followed by "}". If the record has a [[year]] field, the string may contain the substrings "{yearName}" and "{relatedYear}".
[[pattern12]] a Pattern String Optional field. Present if the [[hour]] field is present. In addition to the substrings of the [[pattern]] field, contains at least one of the substrings "{ampm}" or "{dayPeriod}".
[[rangePatterns]] a DateTime Range Pattern Record Pattern strings in this field are similar to [[pattern]].
[[rangePatterns12]] a DateTime Range Pattern Record Optional field. Present if the [[hour]] field is present. Pattern strings in this field are similar to [[pattern12]].

11.2.3.2 DateTime Range Pattern Records

Each DateTime Range Pattern Record has the fields defined in Table 2.

Table 2: DateTime Range Pattern Record
Field Name Value Type Description
[[Default]] a DateTime Range Pattern Format Record It contains the default range pattern used when a more specific range pattern is not available.
[[Era]] a DateTime Range Pattern Format Record Optional field. Used when era is the largest calendar element that is different between the start and end dates.
[[Year]] a DateTime Range Pattern Format Record Optional field. Used when year is the largest calendar element that is different between the start and end dates.
[[Month]] a DateTime Range Pattern Format Record Optional field. Used when month is the largest calendar element that is different between the start and end dates.
[[Day]] a DateTime Range Pattern Format Record Optional field. Used when day is the largest calendar element that is different between the start and end dates.
[[AmPm]] a DateTime Range Pattern Format Record Optional field. Used when ante or post meridiem is the largest calendar element that is different between the start and end dates.
[[DayPeriod]] a DateTime Range Pattern Format Record Optional field. Used when day period is the largest calendar element that is different between the start and end dates.
[[Hour]] a DateTime Range Pattern Format Record Optional field. Used when hour is the largest calendar element that is different between the start and end dates.
[[Minute]] a DateTime Range Pattern Format Record Optional field. Used when minute is the largest calendar element that is different between the start and end dates.
[[Second]] a DateTime Range Pattern Format Record Optional field. Used when second is the largest calendar element that is different between the start and end dates.
[[FractionalSecondDigits]] a DateTime Range Pattern Format Record Optional field. Used when fractional seconds are the largest calendar element that is different between the start and end dates.

11.2.3.3 DateTime Range Pattern Format Records

Each DateTime Range Pattern Format Record has the fields defined in Table 3.

Table 3: DateTime Range Pattern Format Record
Field Name Value Type Description
[[weekday]] [[Weekday]] values in the Values column of Table 12 Optional field. Present if a Pattern String in [[PatternParts]] contains the substring "{weekday}".
[[era]] [[Era]] values in the Values column of Table 12 Optional field. Present if a Pattern String in [[PatternParts]] contains the substring "{era}".
[[year]] [[Year]] values in the Values column of Table 12 Optional field. Present if a Pattern String in [[PatternParts]] contains at least one of the substrings "{year}", "{yearName}", or "{relatedYear}".
[[month]] [[Month]] values in the Values column of Table 12 Optional field. Present if a Pattern String in [[PatternParts]] contains the substring "{month}".
[[day]] [[Day]] values in the Values column of Table 12 Optional field. Present if a Pattern String in [[PatternParts]] contains the substring "{day}".
[[dayPeriod]] [[DayPeriod]] values in the Values column of Table 12 Optional field. Present if a Pattern String in [[PatternParts]] contains the substring "{dayPeriod}".
[[hour]] [[Hour]] values in the Values column of Table 12 Optional field. Present if a Pattern String in [[PatternParts]] contains the substring "{hour}".
[[minute]] [[Minute]] values in the Values column of Table 12 Optional field. Present if a Pattern String in [[PatternParts]] contains the substring "{minute}".
[[second]] [[Second]] values in the Values column of Table 12 Optional field. Present if a Pattern String in [[PatternParts]] contains the substring "{second}".
[[fractionalSecondDigits]] [[FractionalSecondDigits]] values in the Values column of Table 12 Optional field. Present if a Pattern String in [[PatternParts]] contains the substring "{fractionalSecondDigits}".
[[timeZoneName]] [[TimeZoneName]] values in the Values column of Table 12 Optional field. Present if a Pattern String in [[PatternParts]] contains the substring "{timeZoneName}".
[[PatternParts]] a List of DateTime Range Pattern Part Records Each record represents a part of the range pattern.

11.2.3.4 DateTime Range Pattern Part Records

Each DateTime Range Pattern Part Record has the fields defined in Table 4.

Table 4: DateTime Range Pattern Part Record
Field Name Value Type Description
[[Source]] "shared", "startRange", or "endRange" It indicates which of the range's dates should be formatted using the value of the [[Pattern]] field.
[[Pattern]] a Pattern String A String of the same format as the regular date pattern String.

11.2.3.5 DateTime Styles Records

Each DateTime Styles Record has the fields defined in Table 5.

Table 5: DateTime Styles Record
Field Name Value Type
[[Date]] a DateTime Style Record
[[Time]] a DateTime Style Record
[[Connector]] a DateTime Connector Record
[[DateTimeRangeFormat]] a DateTime Date Range Record

11.2.3.6 DateTime Style Records

Each DateTime Style Record has the fields defined in Table 6.

Table 6: DateTime Style Record
Field Name Value Type Description
[[full]] a DateTime Format Record Format record for the "full" style.
[[long]] a DateTime Format Record Format record for the "long" style.
[[medium]] a DateTime Format Record Format record for the "medium" style.
[[short]] a DateTime Format Record Format record for the "short" style.

11.2.3.7 DateTime Connector Records

Each DateTime Connector Record has the fields defined in Table 7. All connector pattern strings must contain the strings "{0}" and "{1}".

Table 7: DateTime Connector Record
Field Name Value Type Description
[[full]] a Pattern String Connector pattern when the date style is "full".
[[long]] a Pattern String Connector pattern when the date style is "long".
[[medium]] a Pattern String Connector pattern when the date style is "medium".
[[short]] a Pattern String Connector pattern when the date style is "short".

11.2.3.8 DateTime Date Range Records

Each DateTime Date Range Record has the fields defined in Table 8.

Table 8: DateTime Date Range Record
Field Name Value Type Description
[[full]] a DateTime Time Range Record Used when date style is "full".
[[long]] a DateTime Time Range Record Used when date style is "long".
[[medium]] a DateTime Time Range Record Used when date style is "medium".
[[short]] a DateTime Time Range Record Used when date style is "short".

11.2.3.9 DateTime Time Range Records

Each DateTime Time Range Record has the fields defined in Table 9.

Table 9: DateTime Time Range Record
Field Name Value Type Description
[[full]] a DateTime Style Range Record Used when time style is "full".
[[long]] a DateTime Style Range Record Used when time style is "long".
[[medium]] a DateTime Style Range Record Used when time style is "medium".
[[short]] a DateTime Style Range Record Used when time style is "short".

11.2.3.10 DateTime Style Range Records

Each DateTime Style Range Record has the fields defined in Table 10.

Table 10: DateTime Style Range Record
Field Name Value Type Description
[[rangePatterns]] a DateTime Range Pattern Record Range patterns to combine date and time styles.
[[rangePatterns12]] a DateTime Range Pattern Record Optional Field. Range patterns to combine date and time styles for 12-hour formats.
Note 2
For example, an implementation might include the following Record as part of its English locale data:
  • [[hour]]: "numeric"
  • [[minute]]: "numeric"
  • [[pattern]]: "{hour}:{minute}"
  • [[pattern12]]: "{hour}:{minute} {ampm}"
  • [[rangePatterns]]:
    • [[Hour]]:
      • [[hour]]: "numeric"
      • [[minute]]: "numeric"
      • [[PatternParts]]:
        • {[[Source]]: "startRange", [[Pattern]]: "{hour}:{minute}"}
        • {[[Source]]: "shared", [[Pattern]]: " – "}
        • {[[Source]]: "endRange", [[Pattern]]: "{hour}:{minute}"}
    • [[Minute]]:
      • [[hour]]: "numeric"
      • [[minute]]: "numeric"
      • [[PatternParts]]:
        • {[[Source]]: "startRange", [[Pattern]]: "{hour}:{minute}"}
        • {[[Source]]: "shared", [[Pattern]]: " – "}
        • {[[Source]]: "endRange", [[Pattern]]: "{hour}:{minute}"}
    • [[Default]]:
      • [[year]]: "2-digit"
      • [[month]]: "numeric"
      • [[day]]: "numeric"
      • [[hour]]: "numeric"
      • [[minute]]: "numeric"
      • [[PatternParts]]:
        • {[[Source]]: "startRange", [[Pattern]]: "{day}/{month}/{year}, {hour}:{minute}"}
        • {[[Source]]: "shared", [[Pattern]]: " – "}
        • {[[Source]]: "endRange", [[Pattern]]: "{day}/{month}/{year}, {hour}:{minute}"}
  • [[rangePatterns12]]:
    • [[Hour]]:
      • [[hour]]: "numeric"
      • [[minute]]: "numeric"
      • [[PatternParts]]:
        • {[[Source]]: "startRange", [[Pattern]]: "{hour}:{minute}"}
        • {[[Source]]: "shared", [[Pattern]]: " – "}
        • {[[Source]]: "endRange", [[Pattern]]: "{hour}:{minute}"}
        • {[[Source]]: "shared", [[Pattern]]: " {ampm}"}
    • [[Minute]]:
      • [[hour]]: "numeric"
      • [[minute]]: "numeric"
      • [[PatternParts]]:
        • {[[Source]]: "startRange", [[Pattern]]: "{hour}:{minute}"}
        • {[[Source]]: "shared", [[Pattern]]: " – "}
        • {[[Source]]: "endRange", [[Pattern]]: "{hour}:{minute}"}
        • {[[Source]]: "shared", [[Pattern]]: " {ampm}"}
    • [[Default]]:
      • [[year]]: "2-digit"
      • [[month]]: "numeric"
      • [[day]]: "numeric"
      • [[hour]]: "numeric"
      • [[minute]]: "numeric"
      • [[PatternParts]]:
        • {[[Source]]: "startRange", [[Pattern]]: "{day}/{month}/{year}, {hour}:{minute} {ampm}"}
        • {[[Source]]: "shared", [[Pattern]]: " – "}
        • {[[Source]]: "endRange", [[Pattern]]: "{day}/{month}/{year}, {hour}:{minute} {ampm}"}
Note 3
It is recommended that implementations use the locale data provided by the Common Locale Data Repository (available at https://cldr.unicode.org/).

11.3 Properties of the Intl.DateTimeFormat Prototype Object

11.3.2 Intl.DateTimeFormat.prototype.resolvedOptions ( )

This function provides access to the locale and options computed during initialization of the object.

  1. Let dtf be the this value.
  2. If the implementation supports the normative optional constructor mode of 4.3 Note 1, then
    1. Set dtf to ? UnwrapDateTimeFormat(dtf).
  3. Perform ? RequireInternalSlot(dtf, [[InitializedDateTimeFormat]]).
  4. Let options be OrdinaryObjectCreate(%Object.prototype%).
  5. For each row of Table 11, except the header row, in table order, do
    1. Let propertyKey be the Property value of the current row.
    2. If there is an Internal Slot value in the current row, then
      1. Let value be the value of dtf's internal slot whose name is the Internal Slot value of the current row.
    3. Else,
      1. Let format be dtf.[[DateTimeFormat]].
      2. If format has a field [[<propertyKey>]] and dtf.[[DateStyle]] is undefined and dtf.[[TimeStyle]] is undefined, then
        1. Let value be format.[[<propertyKey>]].
      3. Else,
        1. Let value be undefined.
    4. If value is not undefined, then
      1. If there is a Conversion value in the current row, then
        1. Let conversion be the Conversion value of the current row.
        2. If conversion is hour12, then
          1. If value is "h11" or "h12", set value to true. Otherwise, set value to false.
        3. Else,
          1. Assert: conversion is number.
          2. Set value to 𝔽(value).
      2. Perform ! CreateDataPropertyOrThrow(options, propertyKey, value).
  6. Return options.
Table 11: Resolved Options of DateTimeFormat Instances
Internal Slot Property Conversion
[[Locale]] "locale"
[[Calendar]] "calendar"
[[NumberingSystem]] "numberingSystem"
[[TimeZone]] "timeZone"
[[HourCycle]] "hourCycle"
[[HourCycle]] "hour12" hour12
"weekday"
"era"
"year"
"month"
"day"
"dayPeriod"
"hour"
"minute"
"second"
"fractionalSecondDigits" number
"timeZoneName"
[[DateStyle]] "dateStyle"
[[TimeStyle]] "timeStyle"

For web compatibility reasons, if the property "hourCycle" is set, the "hour12" property should be set to true when "hourCycle" is "h11" or "h12", or to false when "hourCycle" is "h23" or "h24".

Note 1
In this version of the API, the "timeZone" property will be the identifier of the host environment's time zone if no "timeZone" property was provided in the options object provided to the Intl.DateTimeFormat constructor. The first edition left the "timeZone" property undefined in this case.
Note 2
For compatibility with versions prior to the fifth edition, the "hour12" property is set in addition to the "hourCycle" property.

11.4 Properties of Intl.DateTimeFormat Instances

Intl.DateTimeFormat instances are ordinary objects that inherit properties from %Intl.DateTimeFormat.prototype%.

Intl.DateTimeFormat instances have an [[InitializedDateTimeFormat]] internal slot.

Intl.DateTimeFormat instances also have several internal slots that are computed by The Intl.DateTimeFormat Constructor:

Finally, Intl.DateTimeFormat instances have a [[BoundFormat]] internal slot that caches the function returned by the format accessor (11.3.3).

11.5 Abstract Operations for DateTimeFormat Objects

Several DateTimeFormat algorithms use values from the following table, which provides internal slots, property names and allowable values for the components of date and time formats:

Table 12: Components of date and time formats
Field Name Property Values
[[Weekday]] "weekday" "narrow", "short", "long"
[[Era]] "era" "narrow", "short", "long"
[[Year]] "year" "2-digit", "numeric"
[[Month]] "month" "2-digit", "numeric", "narrow", "short", "long"
[[Day]] "day" "2-digit", "numeric"
[[DayPeriod]] "dayPeriod" "narrow", "short", "long"
[[Hour]] "hour" "2-digit", "numeric"
[[Minute]] "minute" "2-digit", "numeric"
[[Second]] "second" "2-digit", "numeric"
[[FractionalSecondDigits]] "fractionalSecondDigits" 1, 2, 3
[[TimeZoneName]] "timeZoneName" "short", "long", "shortOffset", "longOffset", "shortGeneric", "longGeneric"

11.5.1 DateTimeStyleFormat ( dateStyle, timeStyle, styles )

The abstract operation DateTimeStyleFormat takes arguments dateStyle ("full", "long", "medium", "short", or undefined), timeStyle ("full", "long", "medium", "short", or undefined), and styles (a DateTime Styles Record) and returns a DateTime Format Record. styles is a Record from %Intl.DateTimeFormat%.[[LocaleData]].[[<locale>]].[[styles]].[[<calendar>]] for some locale locale and calendar calendar. It returns the appropriate format Record for date time formatting based on the parameters. It performs the following steps when called:

  1. Assert: dateStyle is not undefined or timeStyle is not undefined.
  2. If timeStyle is not undefined, then
    1. Assert: timeStyle is one of "full", "long", "medium", or "short".
    2. Let timeFormat be styles.[[Time]].[[<timeStyle>]].
  3. If dateStyle is not undefined, then
    1. Assert: dateStyle is one of "full", "long", "medium", or "short".
    2. Let dateFormat be styles.[[Date]].[[<dateStyle>]].
  4. If dateStyle is not undefined and timeStyle is not undefined, then
    1. Let format be a new DateTime Format Record.
    2. Add to format all fields from dateFormat except [[pattern]] and [[rangePatterns]].
    3. Add to format all fields from timeFormat except [[pattern]], [[rangePatterns]], [[pattern12]], and [[rangePatterns12]], if present.
    4. Let connector be styles.[[Connector]].[[<dateStyle>]].
    5. Let pattern be the string connector with the substring "{0}" replaced with timeFormat.[[pattern]] and the substring "{1}" replaced with dateFormat.[[pattern]].
    6. Set format.[[pattern]] to pattern.
    7. If timeFormat has a [[pattern12]] field, then
      1. Let pattern12 be the string connector with the substring "{0}" replaced with timeFormat.[[pattern12]] and the substring "{1}" replaced with dateFormat.[[pattern]].
      2. Set format.[[pattern12]] to pattern12.
    8. Let dateTimeRangeFormat be styles.[[DateTimeRangeFormat]].[[<dateStyle>]].[[<timeStyle>]].
    9. Set format.[[rangePatterns]] to dateTimeRangeFormat.[[rangePatterns]].
    10. If dateTimeRangeFormat has a [[rangePatterns12]] field, then
      1. Set format.[[rangePatterns12]] to dateTimeRangeFormat.[[rangePatterns12]].
    11. Return format.
  5. If timeStyle is not undefined, then
    1. Return timeFormat.
  6. Assert: dateStyle is not undefined.
  7. Return dateFormat.

11.5.2 BasicFormatMatcher ( options, formats )

The abstract operation BasicFormatMatcher takes arguments options (a Record) and formats (a List of DateTime Format Records) and returns a DateTime Format Record. It performs the following steps when called:

  1. Let removalPenalty be 120.
  2. Let additionPenalty be 20.
  3. Let longLessPenalty be 8.
  4. Let longMorePenalty be 6.
  5. Let shortLessPenalty be 6.
  6. Let shortMorePenalty be 3.
  7. Let offsetPenalty be 1.
  8. Let bestScore be -∞.
  9. Let bestFormat be undefined.
  10. For each element format of formats, do
    1. Let score be 0.
    2. For each row of Table 12, except the header row, in table order, do
      1. Let property be the name given in the Property column of the current row.
      2. If options has a field [[<property>]], let optionsProp be options.[[<property>]]; else let optionsProp be undefined.
      3. If format has a field [[<property>]], let formatProp be format.[[<property>]]; else let formatProp be undefined.
      4. If optionsProp is undefined and formatProp is not undefined, then
        1. Set score to score - additionPenalty.
      5. Else if optionsProp is not undefined and formatProp is undefined, then
        1. Set score to score - removalPenalty.
      6. Else if property is "timeZoneName", then
        1. If optionsProp is "short" or "shortGeneric", then
          1. If formatProp is "shortOffset", set score to score - offsetPenalty.
          2. Else if formatProp is "longOffset", set score to score - (offsetPenalty + shortMorePenalty).
          3. Else if optionsProp is "short" and formatProp is "long", set score to score - shortMorePenalty.
          4. Else if optionsProp is "shortGeneric" and formatProp is "longGeneric", set score to score - shortMorePenalty.
          5. Else if optionsPropformatProp, set score to score - removalPenalty.
        2. Else if optionsProp is "shortOffset" and formatProp is "longOffset", then
          1. Set score to score - shortMorePenalty.
        3. Else if optionsProp is "long" or "longGeneric", then
          1. If formatProp is "longOffset", set score to score - offsetPenalty.
          2. Else if formatProp is "shortOffset", set score to score - (offsetPenalty + longLessPenalty).
          3. Else if optionsProp is "long" and formatProp is "short", set score to score - longLessPenalty.
          4. Else if optionsProp is "longGeneric" and formatProp is "shortGeneric", set score to score - longLessPenalty.
          5. Else if optionsPropformatProp, set score to score - removalPenalty.
        4. Else if optionsProp is "longOffset" and formatProp is "shortOffset", then
          1. Set score to score - longLessPenalty.
        5. Else if optionsPropformatProp, then
          1. Set score to score - removalPenalty.
      7. Else if optionsPropformatProp, then
        1. If property is "fractionalSecondDigits", then
          1. Let values be « 1, 2, 3 ».
        2. Else,
          1. Let values be « "2-digit", "numeric", "narrow", "short", "long" ».
        3. Let optionsPropIndex be the index of optionsProp within values.
        4. Let formatPropIndex be the index of formatProp within values.
        5. Let delta be max(min(formatPropIndex - optionsPropIndex, 2), -2).
        6. If delta = 2, set score to score - longMorePenalty.
        7. Else if delta = 1, set score to score - shortMorePenalty.
        8. Else if delta = -1, set score to score - shortLessPenalty.
        9. Else if delta = -2, set score to score - longLessPenalty.
    3. If score > bestScore, then
      1. Set bestScore to score.
      2. Set bestFormat to format.
  11. Return bestFormat.

11.5.5 FormatDateTimePattern ( dateTimeFormat, format, pattern, epochNanoseconds )

The abstract operation FormatDateTimePattern takes arguments dateTimeFormat (an Intl.DateTimeFormat), format (a DateTime Format Record or a DateTime Range Pattern Format Record), pattern (a Pattern String), and epochNanoseconds (a BigInt) and returns a List of Records with fields [[Type]] (a String) and [[Value]] (a String). It creates the corresponding parts for the epoch time epochNanoseconds according to pattern and to the effective locale and the formatting options of dateTimeFormat and format. It performs the following steps when called:

  1. Let locale be dateTimeFormat.[[Locale]].
  2. Let nfOptions be OrdinaryObjectCreate(null).
  3. Perform ! CreateDataPropertyOrThrow(nfOptions, "numberingSystem", dateTimeFormat.[[NumberingSystem]]).
  4. Perform ! CreateDataPropertyOrThrow(nfOptions, "useGrouping", false).
  5. Let nf be ! Construct(%Intl.NumberFormat%, « locale, nfOptions »).
  6. Let nf2Options be OrdinaryObjectCreate(null).
  7. Perform ! CreateDataPropertyOrThrow(nf2Options, "minimumIntegerDigits", 2𝔽).
  8. Perform ! CreateDataPropertyOrThrow(nf2Options, "numberingSystem", dateTimeFormat.[[NumberingSystem]]).
  9. Perform ! CreateDataPropertyOrThrow(nf2Options, "useGrouping", false).
  10. Let nf2 be ! Construct(%Intl.NumberFormat%, « locale, nf2Options »).
  11. If format has a field [[fractionalSecondDigits]], then
    1. Let fractionalSecondDigits be format.[[fractionalSecondDigits]].
    2. Let nf3Options be OrdinaryObjectCreate(null).
    3. Perform ! CreateDataPropertyOrThrow(nf3Options, "minimumIntegerDigits", 𝔽(fractionalSecondDigits)).
    4. Perform ! CreateDataPropertyOrThrow(nf3Options, "numberingSystem", dateTimeFormat.[[NumberingSystem]]).
    5. Perform ! CreateDataPropertyOrThrow(nf3Options, "useGrouping", false).
    6. Let nf3 be ! Construct(%Intl.NumberFormat%, « locale, nf3Options »).
  12. Let localTime be ToLocalTime(epochNanoseconds, dateTimeFormat.[[Calendar]], dateTimeFormat.[[TimeZone]]).
  13. Let patternParts be PartitionPattern(pattern).
  14. Let result be a new empty List.
  15. For each Record { [[Type]], [[Value]] } patternPart of patternParts, do
    1. Let partType be patternPart.[[Type]].
    2. If partType is "literal", then
      1. Append the Record { [[Type]]: "literal", [[Value]]: patternPart.[[Value]] } to result.
    3. Else if partType is "fractionalSecondDigits", then
      1. Assert: format has a field [[fractionalSecondDigits]].
      2. Let value be localTime.[[Millisecond]].
      3. Set value to floor(value × 10( fractionalSecondDigits - 3 )).
      4. Let formattedValue be FormatNumeric(nf3, value).
      5. Append the Record { [[Type]]: "fractionalSecond", [[Value]]: formattedValue } to result.
    4. Else if partType is "dayPeriod", then
      1. Assert: format has a field [[dayPeriod]].
      2. Let fieldFormat be format.[[dayPeriod]].
      3. Let formattedValue be an ILD String representing the day period of localTime in the form given by fieldFormat.
      4. Append the Record { [[Type]]: partType, [[Value]]: formattedValue } to result.
    5. Else if partType is "timeZoneName", then
      1. Assert: format has a field [[timeZoneName]].
      2. Let fieldFormat be format.[[timeZoneName]].
      3. Let value be dateTimeFormat.[[TimeZone]].
      4. Let formattedValue be an ILD String representing value in the form given by fieldFormat. Its value may depend on the value of the [[InDST]] field of localTime if fieldFormat is "short", "long", "shortOffset", or "longOffset". If the implementation does not have such a localized representation of fieldFormat, then use value itself.
      5. Append the Record { [[Type]]: partType, [[Value]]: formattedValue } to result.
    6. Else if partType matches a Property column of the row in Table 12, then
      1. Assert: format has a field [[<partType>]].
      2. Let fieldFormat be format.[[<partType>]].
      3. Let value be the value of localTime's field whose name is the Internal Slot column of the matching row.
      4. If partType is "year" and value ≤ 0, set value to 1 - value.
      5. If partType is "month", set value to value + 1.
      6. If partType is "hour" and dateTimeFormat.[[HourCycle]] is "h11" or "h12", then
        1. Set value to value modulo 12.
        2. If value = 0 and dateTimeFormat.[[HourCycle]] is "h12", set value to 12.
      7. If partType is "hour" and dateTimeFormat.[[HourCycle]] is "h24", then
        1. If value = 0, set value to 24.
      8. If fieldFormat is "numeric", then
        1. Let formattedValue be FormatNumeric(nf, value).
      9. Else if fieldFormat is "2-digit", then
        1. Let formattedValue be FormatNumeric(nf2, value).
        2. Let codePoints be StringToCodePoints(formattedValue).
        3. Let count be the number of elements in codePoints.
        4. If count > 2, then
          1. Let tens be codePoints[count - 2].
          2. Let ones be codePoints[count - 1].
          3. Set formattedValue to CodePointsToStringtens, ones »).
      10. Else if fieldFormat is "narrow", "short", or "long", then
        1. Let formattedValue be an ILD String representing value in the form given by fieldFormat. If partType is "month", then its value may depend on whether format has a [[day]] field. If the implementation does not have a localized representation of fieldFormat, then use value itself.
      11. Append the Record { [[Type]]: partType, [[Value]]: formattedValue } to result.
    7. Else if partType is "ampm", then
      1. Let value be localTime.[[Hour]].
      2. If value > 11, let formattedValue be an ILD String representing "post meridiem"; else let formattedValue be an ILD String representing "ante meridiem".
      3. Append the Record { [[Type]]: "dayPeriod", [[Value]]: formattedValue } to result.
    8. Else if partType is "relatedYear", then
      1. Let value be localTime.[[RelatedYear]].
      2. Let formattedValue be FormatNumeric(nf, value).
      3. Append the Record { [[Type]]: "relatedYear", [[Value]]: formattedValue } to result.
    9. Else if partType is "yearName", then
      1. Let value be localTime.[[YearName]].
      2. Let formattedValue be an ILD String representing value.
      3. Append the Record { [[Type]]: "yearName", [[Value]]: formattedValue } to result.
    10. Else,
      1. Let unknown be an ILND String based on epochNanoseconds and partType.
      2. Append the Record { [[Type]]: "unknown", [[Value]]: unknown } to result.
  16. Return result.
Note
It is recommended that implementations use the locale and calendar dependent strings provided by the Common Locale Data Repository (available at https://cldr.unicode.org/), and use CLDR "abbreviated" strings for DateTimeFormat "short" strings, and CLDR "wide" strings for DateTimeFormat "long" strings.

11.5.9 PartitionDateTimeRangePattern ( dateTimeFormat, x, y )

The abstract operation PartitionDateTimeRangePattern takes arguments dateTimeFormat (an Intl.DateTimeFormat), x (a Number), and y (a Number) 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 interprets x and y as time values as specified in ECMA-262, 21.4.1.1, and creates the corresponding parts according to the effective locale and the formatting options of dateTimeFormat. It performs the following steps when called:

  1. Set x to TimeClip(x).
  2. If x is NaN, throw a RangeError exception.
  3. Set y to TimeClip(y).
  4. If y is NaN, throw a RangeError exception.
  5. Let xEpochNanoseconds be ((x) × 106).
  6. Let yEpochNanoseconds be ((y) × 106).
  7. Let localTime1 be ToLocalTime(xEpochNanoseconds, dateTimeFormat.[[Calendar]], dateTimeFormat.[[TimeZone]]).
  8. Let localTime2 be ToLocalTime(yEpochNanoseconds, dateTimeFormat.[[Calendar]], dateTimeFormat.[[TimeZone]]).
  9. Let format be dateTimeFormat.[[DateTimeFormat]].
  10. If dateTimeFormat.[[HourCycle]] is "h11" or "h12", then
    1. Let pattern be format.[[pattern12]].
    2. Let rangePatterns be format.[[rangePatterns12]].
  11. Else,
    1. Let pattern be format.[[pattern]].
    2. Let rangePatterns be format.[[rangePatterns]].
  12. Let selectedRangePattern be undefined.
  13. Let relevantFieldsEqual be true.
  14. Let checkMoreFields be true.
  15. For each row of Table 2, except the header row, in table order, do
    1. Let fieldName be the name given in the Field Name column of the row.
    2. If rangePatterns has a field whose name is fieldName, let rangePattern be rangePatterns' field whose name is fieldName; else let rangePattern be undefined.
    3. If selectedRangePattern is not undefined and rangePattern is undefined, then
      1. NOTE: Because there is no range pattern for differences at or below this field, no further checks will be performed.
      2. Set checkMoreFields to false.
    4. If fieldName is not equal to [[Default]] and relevantFieldsEqual is true and checkMoreFields is true, then
      1. Set selectedRangePattern to rangePattern.
      2. If fieldName is [[AmPm]], then
        1. If localTime1.[[Hour]] is less than 12, let v1 be "am"; else let v1 be "pm".
        2. If localTime2.[[Hour]] is less than 12, let v2 be "am"; else let v2 be "pm".
      3. Else if fieldName is [[DayPeriod]], then
        1. Let v1 be an ILD String representing the day period of localTime1.
        2. Let v2 be an ILD String representing the day period of localTime2.
      4. Else if fieldName is [[FractionalSecondDigits]], then
        1. If format has a [[fractionalSecondDigits]] field, then
          1. Let fractionalSecondDigits be format.[[fractionalSecondDigits]].
        2. Else,
          1. Let fractionalSecondDigits be 3.
        3. Let exp be fractionalSecondDigits - 3.
        4. Let v1 be floor(localTime1.[[Millisecond]] × 10exp).
        5. Let v2 be floor(localTime2.[[Millisecond]] × 10exp).
      5. Else,
        1. Let v1 be localTime1's field whose name is fieldName.
        2. Let v2 be localTime2's field whose name is fieldName.
      6. If v1 is not equal to v2, then
        1. Set relevantFieldsEqual to false.
  16. If relevantFieldsEqual is true, then
    1. Let collapsedResult be a new empty List.
    2. Let resultParts be FormatDateTimePattern(dateTimeFormat, format, pattern, xEpochNanoseconds).
    3. For each Record { [[Type]], [[Value]] } part of resultParts, do
      1. Append the Record { [[Type]]: part.[[Type]], [[Value]]: part.[[Value]], [[Source]]: "shared" } to collapsedResult.
    4. Return collapsedResult.
  17. Let rangeResult be a new empty List.
  18. If selectedRangePattern is undefined, then
    1. Set selectedRangePattern to rangePatterns.[[Default]].
  19. For each Record { [[Pattern]], [[Source]] } rangePatternPart of selectedRangePattern.[[PatternParts]], do
    1. Let pattern be rangePatternPart.[[Pattern]].
    2. Let source be rangePatternPart.[[Source]].
    3. If source is "startRange" or "shared", then
      1. Let z be xEpochNanoseconds.
    4. Else,
      1. Let z be yEpochNanoseconds.
    5. Let resultParts be FormatDateTimePattern(dateTimeFormat, selectedRangePattern, pattern, z).
    6. For each Record { [[Type]], [[Value]] } part of resultParts, do
      1. Append the Record { [[Type]]: part.[[Type]], [[Value]]: part.[[Value]], [[Source]]: source } to rangeResult.
  20. Return rangeResult.

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.