Stage 3 Draft / November 13, 2024

Intl.DurationFormat

1 DurationFormat Objects

1.1 Abstract Operations for DurationFormat Objects

1.1.1 Duration Records

A Duration Record is a Record value used to represent a Duration.

Duration Records have the fields listed in Table 1

Table 1: Duration Record Fields
Field Meaning
[[Years]] The number of years in the duration.
[[Months]] The number of months in the duration.
[[Weeks]] The number of weeks in the duration.
[[Days]] The number of days in the duration.
[[Hours]] The number of hours in the duration.
[[Minutes]] The number of minutes in the duration.
[[Seconds]] The number of seconds in the duration.
[[Milliseconds]] The number of milliseconds in the duration.
[[Microseconds]] The number of microseconds in the duration.
[[Nanoseconds]] The number of nanoseconds in the duration.

1.1.2 ToIntegerIfIntegral ( argument )

The abstract operation ToIntegerIfIntegral takes argument argument (an ECMAScript language value) and returns either a normal completion containing an integer, or an abrupt completion. It converts argument to an integer representing its Number value, or throws a RangeError when that value is not integral. It performs the following steps when called:

  1. Let number be ? ToNumber(argument).
  2. If number is not an integral Number, throw a RangeError exception.
  3. Return (number).

1.1.3 ToDurationRecord ( input )

The abstract operation ToDurationRecord takes argument input (an ECMAScript language value) and returns either a normal completion containing a Duration Record, or an abrupt completion. It converts a given object that represents a Duration into a Duration Record. It performs the following steps when called:

  1. If input is not an Object, then
    1. If input is a String, throw a RangeError exception.
    2. Throw a TypeError exception.
  2. Let result be a new Duration Record with each field set to 0.
  3. Let days be ? Get(input, "days").
  4. If days is not undefined, set result.[[Days]] to ? ToIntegerIfIntegral(days).
  5. Let hours be ? Get(input, "hours").
  6. If hours is not undefined, set result.[[Hours]] to ? ToIntegerIfIntegral(hours).
  7. Let microseconds be ? Get(input, "microseconds").
  8. If microseconds is not undefined, set result.[[Microseconds]] to ? ToIntegerIfIntegral(microseconds).
  9. Let milliseconds be ? Get(input, "milliseconds").
  10. If milliseconds is not undefined, set result.[[Milliseconds]] to ? ToIntegerIfIntegral(milliseconds).
  11. Let minutes be ? Get(input, "minutes").
  12. If minutes is not undefined, set result.[[Minutes]] to ? ToIntegerIfIntegral(minutes).
  13. Let months be ? Get(input, "months").
  14. If months is not undefined, set result.[[Months]] to ? ToIntegerIfIntegral(months).
  15. Let nanoseconds be ? Get(input, "nanoseconds").
  16. If nanoseconds is not undefined, set result.[[Nanoseconds]] to ? ToIntegerIfIntegral(nanoseconds).
  17. Let seconds be ? Get(input, "seconds").
  18. If seconds is not undefined, set result.[[Seconds]] to ? ToIntegerIfIntegral(seconds).
  19. Let weeks be ? Get(input, "weeks").
  20. If weeks is not undefined, set result.[[Weeks]] to ? ToIntegerIfIntegral(weeks).
  21. Let years be ? Get(input, "years").
  22. If years is not undefined, set result.[[Years]] to ? ToIntegerIfIntegral(years).
  23. If years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, and nanoseconds are all undefined, throw a TypeError exception.
  24. If IsValidDuration( result.[[Years]], result.[[Months]], result.[[Weeks]], result.[[Days]], result.[[Hours]], result.[[Minutes]], result.[[Seconds]], result.[[Milliseconds]], result.[[Microseconds]], result.[[Nanoseconds]]) is false, then
    1. Throw a RangeError exception.
  25. Return result.

1.1.4 DurationSign ( duration )

The abstract operation DurationSign takes argument duration (a Duration Record) and returns -1, 0, or 1. It returns 1 if the most significant non-zero element in its arguments is positive, and -1 if the most significant non-zero element is negative. If all of its arguments are zero, it returns 0. It performs the following steps when called:

  1. For each value v of « duration.[[Years]], duration.[[Months]], duration.[[Weeks]], duration.[[Days]], duration.[[Hours]], duration.[[Minutes]], duration.[[Seconds]], duration.[[Milliseconds]], duration.[[Microseconds]], duration.[[Nanoseconds]] », do
    1. If v < 0, return -1.
    2. If v > 0, return 1.
  2. Return 0.

1.1.5 IsValidDuration ( years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds )

The abstract operation IsValidDuration takes arguments years (an integer), months (an integer), weeks (an integer), days (an integer), hours (an integer), minutes (an integer), seconds (an integer), milliseconds (an integer), microseconds (an integer), and nanoseconds (an integer) and returns a Boolean. It returns true if its arguments form valid input from which to construct a Duration Record, and false otherwise. It performs the following steps when called:

  1. Let sign be 0.
  2. For each value v of « years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds », do
    1. If 𝔽(v) is not finite, return false.
    2. If v < 0, then
      1. If sign > 0, return false.
      2. Set sign to -1.
    3. Else if v > 0, then
      1. If sign < 0, return false.
      2. Set sign to 1.
  3. If abs(years) ≥ 232, return false.
  4. If abs(months) ≥ 232, return false.
  5. If abs(weeks) ≥ 232, return false.
  6. Let normalizedSeconds be days × 86,400 + hours × 3600 + minutes × 60 + seconds + (𝔽(milliseconds)) × 10-3 + (𝔽(microseconds)) × 10-6 + (𝔽(nanoseconds)) × 10-9.
  7. NOTE: The above step cannot be implemented directly using floating-point arithmetic. Multiplying by 10-3, 10-6, and 10-9 respectively may be imprecise when milliseconds, microseconds, or nanoseconds is an unsafe integer. This multiplication can be implemented in C++ with an implementation of std::remquo() with sufficient bits in the quotient. String manipulation will also give an exact result, since the multiplication is by a power of 10.
  8. If abs(normalizedSeconds) ≥ 253, return false.
  9. Return true.
Note
The abstract operations ToIntegerIfIntegral, DurationSign, and IsValidDuration take the same parameters as the abstract operations of the same name in the Temporal proposal's specification, aside from the use of a Duration Record instead of a Temporal.Duration instance. They will be removed in favor of the equivalent Temporal abstract operations if the Temporal proposal becomes part of ECMAScript before this proposal does.

1.1.6 GetDurationUnitOptions ( unit, options, baseStyle, stylesList, digitalBase, prevStyle, twoDigitHours )

The abstract operation GetDurationUnitOptions takes arguments unit (a String), options (an Object), baseStyle (a String), stylesList (a List of Strings), digitalBase (a String), prevStyle (a String), and twoDigitHours (a Boolean) and returns either a normal completion containing a Record with [[Style]] and [[Display]] fields, or an abrupt completion. It extracts the relevant options for any given unit from an Object and returns them as a Record. It performs the following steps when called:

  1. Let style be ? GetOption(options, unit, string, stylesList, undefined).
  2. Let displayDefault be "always".
  3. If style is undefined, then
    1. If baseStyle is "digital", then
      1. If unit is not one of "hours", "minutes", or "seconds", then
        1. Set displayDefault to "auto".
      2. Set style to digitalBase.
    2. Else,
      1. If prevStyle is "fractional", "numeric" or "2-digit", then
        1. If unit is not one of "minutes" or "seconds", then
          1. Set displayDefault to "auto".
        2. Set style to "numeric".
      2. Else,
        1. Set displayDefault to "auto".
        2. Set style to baseStyle.
  4. If style is "numeric", then
    1. If unit is one of "milliseconds", "microseconds", or "nanoseconds", then
      1. Set style to "fractional".
      2. Set displayDefault to "auto".
  5. Let displayField be the string-concatenation of unit and "Display".
  6. Let display be ? GetOption(options, displayField, string, « "auto", "always" », displayDefault).
  7. If display is "always" and style is "fractional", then
    1. Throw a RangeError exception.
  8. If prevStyle is "fractional", then
    1. If style is not "fractional", then
      1. Throw a RangeError exception.
  9. If prevStyle is "numeric" or "2-digit", then
    1. If style is not "fractional", "numeric" or "2-digit", then
      1. Throw a RangeError exception.
    2. If unit is "minutes" or "seconds", then
      1. Set style to "2-digit".
  10. If unit is "hours" and twoDigitHours is true, then
    1. Set style to "2-digit".
  11. Return the Record { [[Style]]: style, [[Display]]: display  }.

1.1.7 ComputeFractionalDigits ( durationFormat, duration )

The abstract operation ComputeFractionalDigits takes arguments durationFormat (a DurationFormat Object) and duration (a Duration Record) and returns a mathematical value. It computes the sum of all values in durationFormat units with "fractional" style, expressed as a fraction of the smallest unit of durationFormat that does not use "fractional" style. It performs the following steps when called:

  1. Let result be 0.
  2. Let exponent be 3.
  3. For each row of Table 2, except the header row, in table order, do
    1. Let style be the value of durationFormat's internal slot whose name is the Style Slot value of the current row.
    2. If style is "fractional", then
      1. Assert: The Unit value of the current row is "milliseconds", "microseconds", or "nanoseconds".
      2. Let value be the value of duration's field whose name is the Value Field value of the current row.
      3. Set value to value / 10exponent.
      4. Set result to result + value.
      5. Set exponent to exponent + 3.
  4. Return result.

1.1.8 NextUnitFractional ( durationFormat, unit )

The abstract operation NextUnitFractional takes arguments durationFormat (a DurationFormat Object) and unit (a String) and returns a Boolean. It returns true if the next smallest unit uses the "fractional" style. It performs the following steps when called:

  1. Assert: unit is "seconds", "milliseconds", or "microseconds".
  2. If unit is "seconds" and durationFormat.[[MillisecondsStyle]] is "fractional", return true.
  3. Else if unit is "milliseconds" and durationFormat.[[MicrosecondsStyle]] is "fractional", return true.
  4. Else if unit is "microseconds" and durationFormat.[[NanosecondsStyle]] is "fractional", return true.
  5. Return false.

1.1.9 FormatNumericHours ( durationFormat, hoursValue, signDisplayed )

The abstract operation FormatNumericHours takes arguments durationFormat (a DurationFormat object), hoursValue (an integer), and signDisplayed (a Boolean) and returns a List of Records. hoursValue is an integer indicating a number of hours. It creates the parts for hoursValue according to the effective locale and the formatting options of durationFormat. It performs the following steps when called:

  1. Let result be a new empty List.
  2. Let hoursStyle be durationFormat.[[HoursStyle]].
  3. Assert: hoursStyle is "numeric" or hoursStyle is "2-digit".
  4. Let nfOpts be OrdinaryObjectCreate(null).
  5. Let numberingSystem be durationFormat.[[NumberingSystem]].
  6. Perform ! CreateDataPropertyOrThrow(nfOpts, "numberingSystem", numberingSystem).
  7. If hoursStyle is "2-digit", then
    1. Perform ! CreateDataPropertyOrThrow(nfOpts, "minimumIntegerDigits", 2𝔽).
  8. If signDisplayed is false, then
    1. Perform ! CreateDataPropertyOrThrow(nfOpts, "signDisplay", "never").
  9. Perform ! CreateDataPropertyOrThrow(nfOpts, "useGrouping", false).
  10. Let nf be ! Construct(%Intl.NumberFormat%, « durationFormat.[[Locale]], nfOpts »).
  11. Let hoursParts be PartitionNumberPattern(nf, hoursValue).
  12. For each Record { [[Type]], [[Value]] } part of hoursParts, do
    1. Append the Record { [[Type]]: part.[[Type]], [[Value]]: part.[[Value]], [[Unit]]: "hour" } to result.
  13. Return result.

1.1.10 FormatNumericMinutes ( durationFormat, minutesValue, hoursDisplayed, signDisplayed )

The abstract operation FormatNumericMinutes takes arguments durationFormat (a DurationFormat Object), minutesValue (an integer), hoursDisplayed (a Boolean), and signDisplayed (a Boolean) and returns a List of Records. minutesValue is an integer indicating a number of minutes. It creates the parts for minutesValue according to the effective locale and the formatting options of durationFormat. It performs the following steps when called:

  1. Let result be a new empty List.
  2. If hoursDisplayed is true, then
    1. Let separator be durationFormat.[[HourMinuteSeparator]].
    2. Append the Record { [[Type]]: "literal", [[Value]]: separator, [[Unit]]: empty } to result.
  3. Let minutesStyle be durationFormat.[[MinutesStyle]].
  4. Assert: minutesStyle is "numeric" or minutesStyle is "2-digit".
  5. Let nfOpts be OrdinaryObjectCreate(null).
  6. Let numberingSystem be durationFormat.[[NumberingSystem]].
  7. Perform ! CreateDataPropertyOrThrow(nfOpts, "numberingSystem", numberingSystem).
  8. If minutesStyle is "2-digit", then
    1. Perform ! CreateDataPropertyOrThrow(nfOpts, "minimumIntegerDigits", 2𝔽).
  9. If signDisplayed is false, then
    1. Perform ! CreateDataPropertyOrThrow(nfOpts, "signDisplay", "never").
  10. Perform ! CreateDataPropertyOrThrow(nfOpts, "useGrouping", false).
  11. Let nf be ! Construct(%Intl.NumberFormat%, « durationFormat.[[Locale]], nfOpts »).
  12. Let minutesParts be PartitionNumberPattern(nf, minutesValue).
  13. For each Record { [[Type]], [[Value]] } part of minutesParts, do
    1. Append the Record { [[Type]]: part.[[Type]], [[Value]]: part.[[Value]], [[Unit]]: "minute" } to result.
  14. Return result.

1.1.11 FormatNumericSeconds ( durationFormat, secondsValue, minutesDisplayed, signDisplayed )

The abstract operation FormatNumericSeconds takes arguments durationFormat (a DurationFormat Object), secondsValue (a mathematical value), minutesDisplayed (a Boolean), and signDisplayed (a Boolean) and returns a List of Records. secondsValue is a mathematical value indicating a number of seconds. It creates the parts for secondsValue according to the effective locale and the formatting options of durationFormat. It performs the following steps when called:

  1. Let result be a new empty List.
  2. If minutesDisplayed is true, then
    1. Let separator be durationFormat.[[MinuteSecondSeparator]].
    2. Append the Record { [[Type]]: "literal", [[Value]]: separator, [[Unit]]: empty } to result.
  3. Let secondsStyle be durationFormat.[[SecondsStyle]].
  4. Assert: secondsStyle is "numeric" or secondsStyle is "2-digit".
  5. Let nfOpts be OrdinaryObjectCreate(null).
  6. Let numberingSystem be durationFormat.[[NumberingSystem]].
  7. Perform ! CreateDataPropertyOrThrow(nfOpts, "numberingSystem", numberingSystem).
  8. If secondsStyle is "2-digit", then
    1. Perform ! CreateDataPropertyOrThrow(nfOpts, "minimumIntegerDigits", 2𝔽).
  9. If signDisplayed is false, then
    1. Perform ! CreateDataPropertyOrThrow(nfOpts, "signDisplay", "never").
  10. Perform ! CreateDataPropertyOrThrow(nfOpts, "useGrouping", false).
  11. If durationFormat.[[FractionalDigits]] is undefined, then
    1. Let maximumFractionDigits be 9𝔽.
    2. Let minimumFractionDigits be +0𝔽.
  12. Else,
    1. Let maximumFractionDigits be durationFormat.[[FractionalDigits]].
    2. Let minimumFractionDigits be durationFormat.[[FractionalDigits]].
  13. Perform ! CreateDataPropertyOrThrow(nfOpts, "maximumFractionDigits", maximumFractionDigits).
  14. Perform ! CreateDataPropertyOrThrow(nfOpts, "minimumFractionDigits", minimumFractionDigits).
  15. Perform ! CreateDataPropertyOrThrow(nfOpts, "roundingMode", "trunc").
  16. Let nf be ! Construct(%Intl.NumberFormat%, « durationFormat.[[Locale]], nfOpts »).
  17. Let secondsParts be PartitionNumberPattern(nf, secondsValue).
  18. For each Record { [[Type]], [[Value]] } part of secondsParts, do
    1. Append the Record { [[Type]]: part.[[Type]], [[Value]]: part.[[Value]], [[Unit]]: "second" } to result.
  19. Return result.

1.1.12 FormatNumericUnits ( durationFormat, duration, firstNumericUnit, signDisplayed )

The abstract operation FormatNumericUnits takes arguments durationFormat (a DurationFormat Object), duration (a Duration Record), firstNumericUnit (a String), and signDisplayed (a Boolean) and returns a List of Records. It creates the parts representing the elements of duration that use "numeric" or "2-digit" style according to the effective locale and the formatting options of durationFormat. It performs the following steps when called:

  1. Assert: firstNumericUnit is "hours", "minutes", or "seconds".
  2. Let numericPartsList be a new empty List.
  3. Let hoursValue be duration.[[Hours]].
  4. Let hoursDisplay be durationFormat.[[HoursDisplay]].
  5. Let minutesValue be duration.[[Minutes]].
  6. Let minutesDisplay be durationFormat.[[MinutesDisplay]].
  7. Let secondsValue be duration.[[Seconds]].
  8. If duration.[[Milliseconds]] is not 0 or duration.[[Microseconds]] is not 0 or duration.[[Nanoseconds]] is not 0, then
    1. Set secondsValue to secondsValue + ComputeFractionalDigits(durationFormat, duration).
  9. Let secondsDisplay be durationFormat.[[SecondsDisplay]].
  10. Let hoursFormatted be false.
  11. If firstNumericUnit is "hours", then
    1. If hoursValue is not 0 or hoursDisplay is "always", then
      1. Set hoursFormatted to true.
  12. If secondsValue is not 0 or secondsDisplay is "always", then
    1. Let secondsFormatted be true.
  13. Else,
    1. Let secondsFormatted be false.
  14. Let minutesFormatted be false.
  15. If firstNumericUnit is "hours" or firstNumericUnit is "minutes", then
    1. If hoursFormatted is true and secondsFormatted is true, then
      1. Set minutesFormatted to true.
    2. Else if minutesValue is not 0 or minutesDisplay is "always", then
      1. Set minutesFormatted to true.
  16. If hoursFormatted is true, then
    1. If signDisplayed is true, then
      1. If hoursValue is 0 and DurationSign(duration) is -1, then
        1. Set hoursValue to negative-zero.
    2. Let hoursParts be FormatNumericHours(durationFormat, hoursValue, signDisplayed).
    3. Set numericPartsList to the list-concatenation of numericPartsList and hoursParts.
    4. Set signDisplayed to false.
  17. If minutesFormatted is true, then
    1. If signDisplayed is true, then
      1. If minutesValue is 0 and DurationSign(duration) is -1, then
        1. Set minutesValue to negative-zero.
    2. Let minutesParts be FormatNumericMinutes(durationFormat, minutesValue, hoursFormatted, signDisplayed).
    3. Set numericPartsList to the list-concatenation of numericPartsList and minutesParts.
    4. Set signDisplayed to false.
  18. If secondsFormatted is true, then
    1. Let secondsParts be FormatNumericSeconds(durationFormat, secondsValue, minutesFormatted, signDisplayed).
    2. Set numericPartsList to the list-concatenation of numericPartsList and secondsParts.
  19. Return numericPartsList.

1.1.13 ListFormatParts ( durationFormat, partitionedPartsList )

The abstract operation ListFormatParts takes arguments durationFormat (a DurationFormat Object) and partitionedPartsList (a List of Lists of Records) and returns a List. It creates a List corresponding to the parts within the Lists in partitionedPartsList according to the effective locale and the formatting options of durationFormat. It performs the following steps when called:

  1. Let lfOpts be OrdinaryObjectCreate(null).
  2. Perform ! CreateDataPropertyOrThrow(lfOpts, "type", "unit").
  3. Let listStyle be durationFormat.[[Style]].
  4. If listStyle is "digital", then
    1. Set listStyle to "short".
  5. Perform ! CreateDataPropertyOrThrow(lfOpts, "style", listStyle).
  6. Let lf be ! Construct(%Intl.ListFormat%, « durationFormat.[[Locale]], lfOpts »).
  7. Let strings be a new empty List.
  8. For each element parts of partitionedPartsList, do
    1. Let string be the empty String.
    2. For each Record { [[Type]], [[Value]], [[Unit]] } part in parts, do
      1. Set string to the string-concatenation of string and part.[[Value]].
    3. Append string to strings.
  9. Let formattedPartsList be CreatePartsFromList(lf, strings).
  10. Let partitionedPartsIndex be 0.
  11. Let partitionedLength be the number of elements in partitionedPartsList.
  12. Let flattenedPartsList be a new empty List.
  13. For each Record { [[Type]], [[Value]] } listPart in formattedPartsList, do
    1. If listPart.[[Type]] is "element", then
      1. Assert: partitionedPartsIndex < partitionedLength.
      2. Let parts be partitionedPartsList[partitionedPartsIndex].
      3. For each Record { [[Type]], [[Value]], [[Unit]] } part in parts, do
        1. Append part to flattenedPartsList.
      4. Set partitionedPartsIndex to partitionedPartsIndex + 1.
    2. Else,
      1. Assert: listPart.[[Type]] is "literal".
      2. Append the Record { [[Type]]: "literal", [[Value]]: listPart.[[Value]], [[Unit]]: empty } to flattenedPartsList.
  14. Return flattenedPartsList.

1.1.14 PartitionDurationFormatPattern ( durationFormat, duration )

The abstract operation PartitionDurationFormatPattern takes arguments durationFormat (a DurationFormat) and duration (a Duration Record) and returns a List. It creates the corresponding parts for duration according to the effective locale and the formatting options of durationFormat. It performs the following steps when called:

  1. Let result be a new empty List.
  2. Let signDisplayed be true.
  3. Let numericUnitFound be false.
  4. While numericUnitFound is false, repeat for each row in Table 2 in table order, except the header row:
    1. Let value be the value of duration's field whose name is the Value Field value of the current row.
    2. Let style be the value of durationFormat's internal slot whose name is the Style Slot value of the current row.
    3. Let display be the value of durationFormat's internal slot whose name is the Display Slot value of the current row.
    4. Let unit be the Unit value of the current row.
    5. If style is "numeric" or "2-digit", then
      1. Append FormatNumericUnits(durationFormat, duration, unit, signDisplayed) to result.
      2. Let numericPartsList be FormatNumericUnits(durationFormat, duration, unit, signDisplayed).
      3. If numericPartsList is not empty, append numericPartsList to result.
      4. Set numericUnitFound to true.
    6. Else,
      1. Let nfOpts be OrdinaryObjectCreate(null).
      2. If unit is "seconds", "milliseconds", or "microseconds", then
        1. If NextUnitFractional(durationFormat, unit) is true, then
          1. Set value to value + ComputeFractionalDigits(durationFormat, duration).
          2. If durationFormat.[[FractionalDigits]] is undefined, then
            1. Let maximumFractionDigits be 9𝔽.
            2. Let minimumFractionDigits be +0𝔽.
          3. Else,
            1. Let maximumFractionDigits be durationFormat.[[FractionalDigits]].
            2. Let minimumFractionDigits be durationFormat.[[FractionalDigits]].
          4. Perform ! CreateDataPropertyOrThrow(nfOpts, "maximumFractionDigits", maximumFractionDigits).
          5. Perform ! CreateDataPropertyOrThrow(nfOpts, "minimumFractionDigits", minimumFractionDigits).
          6. Perform ! CreateDataPropertyOrThrow(nfOpts, "roundingMode", "trunc").
          7. Set numericUnitFound to true.
      3. If value is not 0 or display is "always", then
        1. Let numberingSystem be durationFormat.[[NumberingSystem]].
        2. Perform ! CreateDataPropertyOrThrow(nfOpts, "numberingSystem", numberingSystem).
        3. If signDisplayed is true, then
          1. Set signDisplayed to false.
          2. If value is 0 and DurationSign(duration) is -1, then
            1. Set value to negative-zero.
        4. Else,
          1. Perform ! CreateDataPropertyOrThrow(nfOpts, "signDisplay", "never").
        5. Let numberFormatUnit be the NumberFormat Unit value of the current row.
        6. Perform ! CreateDataPropertyOrThrow(nfOpts, "style", "unit").
        7. Perform ! CreateDataPropertyOrThrow(nfOpts, "unit", numberFormatUnit).
        8. Perform ! CreateDataPropertyOrThrow(nfOpts, "unitDisplay", style).
        9. Let nf be ! Construct(%Intl.NumberFormat%, « durationFormat.[[Locale]], nfOpts »).
        10. Let parts be PartitionNumberPattern(nf, value).
        11. Let list be a new empty List.
        12. For each Record { [[Type]], [[Value]] } part of parts, do
          1. Append the Record { [[Type]]: part.[[Type]], [[Value]]: part.[[Value]], [[Unit]]: numberFormatUnit } to list.
        13. Append list to result.
  5. Return ListFormatParts(durationFormat, result).
Table 2: DurationFormat instance internal slots and properties relevant to PartitionDurationFormatPattern
Value Field Style Slot Display Slot Unit NumberFormat Unit
[[Years]] [[YearsStyle]] [[YearsDisplay]] "years" "year"
[[Months]] [[MonthsStyle]] [[MonthsDisplay]] "months" "month"
[[Weeks]] [[WeeksStyle]] [[WeeksDisplay]] "weeks" "week"
[[Days]] [[DaysStyle]] [[DaysDisplay]] "days" "day"
[[Hours]] [[HoursStyle]] [[HoursDisplay]] "hours" "hour"
[[Minutes]] [[MinutesStyle]] [[MinutesDisplay]] "minutes" "minute"
[[Seconds]] [[SecondsStyle]] [[SecondsDisplay]] "seconds" "second"
[[Milliseconds]] [[MillisecondsStyle]] [[MillisecondsDisplay]] "milliseconds" "millisecond"
[[Microseconds]] [[MicrosecondsStyle]] [[MicrosecondsDisplay]] "microseconds" "microsecond"
[[Nanoseconds]] [[NanosecondsStyle]] [[NanosecondsDisplay]] "nanoseconds" "nanosecond"

1.2 The Intl.DurationFormat Constructor

The DurationFormat constructor is the %Intl.DurationFormat% intrinsic object and a standard built-in property of the Intl object. Behaviour common to all service constructor properties of the Intl object is specified in 9.1.

1.2.1 Intl.DurationFormat ( [ locales [ , options ] ] )

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

  1. If NewTarget is undefined, throw a TypeError exception.
  2. Let durationFormat be ? OrdinaryCreateFromConstructor(NewTarget, "%Intl.DurationFormatPrototype%", « [[InitializedDurationFormat]], [[Locale]], [[DataLocale]], [[NumberingSystem]], [[Style]], [[YearsStyle]], [[YearsDisplay]], [[MonthsStyle]], [[MonthsDisplay]], [[WeeksStyle]], [[WeeksDisplay]], [[DaysStyle]], [[DaysDisplay]], [[HoursStyle]], [[HoursDisplay]], [[MinutesStyle]], [[MinutesDisplay]], [[SecondsStyle]], [[SecondsDisplay]], [[MillisecondsStyle]], [[MillisecondsDisplay]], [[MicrosecondsStyle]], [[MicrosecondsDisplay]], [[NanosecondsStyle]], [[NanosecondsDisplay]], [[HourMinuteSeparator]], [[MinuteSecondSeparator]], [[FractionalDigits]] »).
  3. Let requestedLocales be ? CanonicalizeLocaleList(locales).
  4. Let options be ? GetOptionsObject(options).
  5. Let matcher be ? GetOption(options, "localeMatcher", string, « "lookup", "best fit" », "best fit").
  6. Let numberingSystem be ? GetOption(options, "numberingSystem", string, empty, undefined).
  7. If numberingSystem is not undefined, then
    1. If numberingSystem does not match the Unicode Locale Identifier type nonterminal, throw a RangeError exception.
  8. Let opt be the Record { [[localeMatcher]]: matcher, [[nu]]: numberingSystem }.
  9. Let r be ResolveLocale(%Intl.DurationFormat%.[[AvailableLocales]], requestedLocales, opt, %Intl.DurationFormat%.[[RelevantExtensionKeys]], %Intl.DurationFormat%.[[LocaleData]]).
  10. Let locale be r.[[locale]].
  11. Set durationFormat.[[Locale]] to locale.
  12. Set durationFormat.[[DataLocale]] to r.[[dataLocale]].
  13. Let dataLocale be durationFormat.[[DataLocale]].
  14. Let dataLocaleData be durationFormat.[[LocaleData]].[[<dataLocale>]].
  15. Let digitalFormat be dataLocaleData.[[DigitalFormat]].
  16. Let twoDigitHours be digitalFormat.[[TwoDigitHours]].
  17. Let hourMinuteSeparator be digitalFormat.[[HourMinuteSeparator]].
  18. Set durationFormat.[[HourMinuteSeparator]] to hourMinuteSeparator.
  19. Let minuteSecondSeparator be digitalFormat.[[MinuteSecondSeparator]].
  20. Set durationFormat.[[MinuteSecondSeparator]] to minuteSecondSeparator.
  21. Set durationFormat.[[NumberingSystem]] to r.[[nu]].
  22. Let style be ? GetOption(options, "style", string, « "long", "short", "narrow", "digital" », "short").
  23. Set durationFormat.[[Style]] to style.
  24. Let prevStyle be the empty String.
  25. For each row of Table 3, except the header row, in table order, do
    1. Let styleSlot be the Style Slot value of the current row.
    2. Let displaySlot be the Display Slot value of the current row.
    3. Let unit be the Unit value of the current row.
    4. Let valueList be the Values value of the current row.
    5. Let digitalBase be the Digital Default value of the current row.
    6. Let unitOptions be ? GetDurationUnitOptions(unit, options, style, valueList, digitalBase, prevStyle, twoDigitHours).
    7. Set the value of the styleSlot slot of durationFormat to unitOptions.[[Style]].
    8. Set the value of the displaySlot slot of durationFormat to unitOptions.[[Display]].
    9. If unit is one of "hours", "minutes", "seconds", "milliseconds", or "microseconds", then
      1. Set prevStyle to unitOptions.[[Style]].
  26. Set durationFormat.[[FractionalDigits]] to ? GetNumberOption(options, "fractionalDigits", 0, 9, undefined).
  27. Return durationFormat.
Table 3: Internal slots and property names of DurationFormat instances relevant to Intl.DurationFormat constructor
Style Slot Display Slot Unit Values Digital Default
[[YearsStyle]] [[YearsDisplay]] "years" « "long", "short", "narrow" » "short"
[[MonthsStyle]] [[MonthsDisplay]] "months" « "long", "short", "narrow" » "short"
[[WeeksStyle]] [[WeeksDisplay]] "weeks" « "long", "short", "narrow" » "short"
[[DaysStyle]] [[DaysDisplay]] "days" « "long", "short", "narrow" » "short"
[[HoursStyle]] [[HoursDisplay]] "hours" « "long", "short", "narrow",
"numeric", "2-digit" »
"numeric"
[[MinutesStyle]] [[MinutesDisplay]] "minutes" « "long", "short", "narrow",
"numeric", "2-digit" »
"numeric"
[[SecondsStyle]] [[SecondsDisplay]] "seconds" « "long", "short", "narrow",
"numeric", "2-digit" »
"numeric"
[[MillisecondsStyle]] [[MillisecondsDisplay]] "milliseconds" « "long", "short", "narrow",
"numeric" »
"numeric"
[[MicrosecondsStyle]] [[MicrosecondsDisplay]] "microseconds" « "long", "short", "narrow",
"numeric" »
"numeric"
[[NanosecondsStyle]] [[NanosecondsDisplay]] "nanoseconds" « "long", "short", "narrow",
"numeric" »
"numeric"

1.3 Properties of the Intl.DurationFormat Constructor

The Intl.DurationFormat constructor has the following properties:

1.3.1 Intl.DurationFormat.prototype

The value of Intl.DurationFormat.prototype is %Intl.DurationFormat.prototype%.

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

1.3.2 Intl.DurationFormat.supportedLocalesOf ( locales [ , options ] )

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

  1. Let availableLocales be %Intl.DurationFormat%.[[AvailableLocales]].
  2. Let requestedLocales be ? CanonicalizeLocaleList(locales).
  3. Return ? FilterLocales(availableLocales, requestedLocales, options).

1.3.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 [[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 as specified in 15.2.3.
  • [[LocaleData]].[[<locale>]].[[DigitalFormat]] must be a Record with keys corresponding to each numbering system available for the given locale, with Record values containing the following fields:
    • [[HourMinuteSeparator]] is a String value that is the appropriate separator between hours and minutes for that combination of locale, numbering system, and unit when using "numeric" or "2-digit" styles
    • [[MinuteSecondSeparator]] is a String value that is the appropriate separator between minutes and seconds for that combination of locale, numbering system, and unit when using "numeric" or "2-digit" styles.
    • [[TwoDigitHours]] is a Boolean value indicating whether hours are always displayed using two digits when the "numeric" style is used.
Note
It is recommended that implementations use the locale data provided by the Common Locale Data Repository (available at http://cldr.unicode.org/).

1.4 Properties of the Intl.DurationFormat Prototype Object

The Intl.DurationFormat prototype object is itself an ordinary object. %Intl.DurationFormat.prototype% is not an Intl.DurationFormat instance and does not have an [[InitializedDurationFormat]] internal slot or any of the other internal slots of Intl.DurationFormat instance objects.

1.4.1 Intl.DurationFormat.prototype.constructor

The initial value of Intl.DurationFormat.prototype.constructor is the intrinsic object %Intl.DurationFormat%.

1.4.2 Intl.DurationFormat.prototype [ @@toStringTag ]

The initial value of the @@toStringTag property is the string value "Intl.DurationFormat".

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

1.4.3 Intl.DurationFormat.prototype.format ( duration )

When the format method is called with an argument duration, the following steps are taken:

  1. Let df be the this value.
  2. Perform ? RequireInternalSlot(df, [[InitializedDurationFormat]]).
  3. Let record be ? ToDurationRecord(duration).
  4. Let parts be PartitionDurationFormatPattern(df, record).
  5. Let result be the empty String.
  6. For each Record { [[Type]], [[Value]], [[Unit]] } part in parts, do
    1. Set result to the string-concatenation of result and part.[[Value]].
  7. Return result.

1.4.4 Intl.DurationFormat.prototype.formatToParts ( duration )

When the formatToParts method is called with an argument duration, the following steps are taken:

  1. Let df be the this value.
  2. Perform ? RequireInternalSlot(df, [[InitializedDurationFormat]]).
  3. Let record be ? ToDurationRecord(duration).
  4. Let parts be PartitionDurationFormatPattern(df, record).
  5. Let result be ! ArrayCreate(0).
  6. Let n be 0.
  7. For each Record { [[Type]], [[Value]], [[Unit]] } part in parts, do
    1. Let obj be OrdinaryObjectCreate(%Object.prototype%).
    2. Perform ! CreateDataPropertyOrThrow(obj, "type", part.[[Type]]).
    3. Perform ! CreateDataPropertyOrThrow(obj, "value", part.[[Value]]).
    4. If part.[[Unit]] is not empty, perform ! CreateDataPropertyOrThrow(obj, "unit", part.[[Unit]]).
    5. Perform ! CreateDataPropertyOrThrow(result, ! ToString(n), obj).
    6. Set n to n + 1.
  8. Return result.

1.4.5 Intl.DurationFormat.prototype.resolvedOptions ( )

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

  1. Let df be the this value.
  2. Perform ? RequireInternalSlot(df, [[InitializedDurationFormat]]).
  3. Let options be OrdinaryObjectCreate(%Object.prototype%).
  4. For each row of Table 4, except the header row, in table order, do
    1. Let p be the Property value of the current row.
    2. Let v be the value of df's internal slot whose name is the Internal Slot value of the current row.
    3. If p is "fractionalDigits", then
      1. If v is not undefined, set v to 𝔽(v).
    4. Else,
      1. Assert: v is not undefined.
    5. If v is "fractional", then
      1. Assert: The Internal Slot value of the current row is [[MillisecondsStyle]], [[MicrosecondsStyle]], or [[NanosecondsStyle]] .
      2. Set v to "numeric".
    6. If v is not undefined, then
      1. Perform ! CreateDataPropertyOrThrow(options, p, v).
  5. Return options.
Table 4: Resolved Options of DurationFormat Instances
Internal Slot Property
[[Locale]] "locale"
[[NumberingSystem]] "numberingSystem"
[[Style]] "style"
[[YearsStyle]] "years"
[[YearsDisplay]] "yearsDisplay"
[[MonthsStyle]] "months"
[[MonthsDisplay]] "monthsDisplay"
[[WeeksStyle]] "weeks"
[[WeeksDisplay]] "weeksDisplay"
[[DaysStyle]] "days"
[[DaysDisplay]] "daysDisplay"
[[HoursStyle]] "hours"
[[HoursDisplay]] "hoursDisplay"
[[MinutesStyle]] "minutes"
[[MinutesDisplay]] "minutesDisplay"
[[SecondsStyle]] "seconds"
[[SecondsDisplay]] "secondsDisplay"
[[MillisecondsStyle]] "milliseconds"
[[MillisecondsDisplay]] "millisecondsDisplay"
[[MicrosecondsStyle]] "microseconds"
[[MicrosecondsDisplay]] "microsecondsDisplay"
[[NanosecondsStyle]] "nanoseconds"
[[NanosecondsDisplay]] "nanosecondsDisplay"
[[FractionalDigits]] "fractionalDigits"

1.5 Properties of Intl.DurationFormat Instances

Intl.DurationFormat instances inherit properties from %Intl.DurationFormat.prototype%.

Intl.DurationFormat instances have an [[InitializedDurationFormat]] internal slot.

Intl.DurationFormat instances also have several internal slots that are computed by the constructor:

  • [[Locale]] is a String value with the language tag of the locale whose localization is used for formatting.
  • [[DataLocale]] is a String value with the language tag of the nearest locale for which the implementation has data to perform the formatting operation. It will be a parent locale of [[Locale]].
  • [[NumberingSystem]] is a String value with the "type" given in Unicode Technical Standard 35 for the numbering system used for formatting.
  • [[Style]] is one of the String values "long", "short", "narrow", or "digital" identifying the duration formatting style used.
  • [[YearsStyle]] is one of the String values "long", "short", or "narrow" identifying the formatting style used for the years field.
  • [[YearsDisplay]] is one of the String values "auto" or "always" identifying when to display the years field.
  • [[MonthsStyle]] is one of the String values "long", "short", or "narrow" identifying the formatting style used for the months field.
  • [[MonthsDisplay]] is one of the String values "auto" or "always" identifying when to display the months field.
  • [[WeeksStyle]] is one of the String values "long", "short", or "narrow" identifying the formatting style used for the weeks field.
  • [[WeeksDisplay]] is one of the String values "auto" or "always" identifying when to display the weeks field.
  • [[DaysStyle]] is one of the String values "long", "short", or "narrow" identifying the formatting style used for the days field.
  • [[DaysDisplay]] is one of the String values "auto" or "always" identifying when to display the days field.
  • [[HoursStyle]] is one of the String values "long", "short", "narrow", "2-digit", or "numeric" identifying the formatting style used for the hours field.
  • [[HoursDisplay]] is one of the String values "auto" or "always" identifying when to display the hours field.
  • [[MinutesStyle]] is one of the String values "long", "short", "narrow", "2-digit", or "numeric" identifying the formatting style used for the minutes field.
  • [[MinutesDisplay]] is one of the String values "auto" or "always" identifying when to display the minutes field.
  • [[SecondsStyle]] is one of the String values "long", "short", "narrow", "2-digit", or "numeric" identifying the formatting style used for the seconds field.
  • [[SecondsDisplay]] is one of the String values "auto" or "always" identifying when to display the seconds field.
  • [[MillisecondsStyle]] is one of the String values "long", "short", "narrow", or "fractional" identifying the formatting style used for the milliseconds field.
  • [[MillisecondsDisplay]] is one of the String values "auto" or "always" identifying when to display the milliseconds field.
  • [[MicrosecondsStyle]] is one of the String values "long", "short", "narrow", or "fractional" identifying the formatting style used for the microseconds field.
  • [[MicrosecondsDisplay]] is one of the String values "auto" or "always" identifying when to display the microseconds field.
  • [[NanosecondsStyle]] is one of the String values "long", "short", "narrow", or "fractional" identifying the formatting style used for the nanoseconds field.
  • [[NanosecondsDisplay]] is one of the String values "auto" or "always" identifying when to display the nanoseconds field.
  • [[HourMinuteSeparator]] is a String value identifying the separator to be used between hours and minutes when both fields are displayed and both fields are formatted using numeric styles.
  • [[MinuteSecondSeparator]] is a String value identifying the separator to be used between minutes and seconds when both fields are displayed and both fields are formatted using numeric styles.
  • [[FractionalDigits]] is a non-negative integer, identifying the number of fractional digits to be used with numeric styles, or is undefined.

A Copyright & Software License

Copyright Notice

© 2024 Ujjwal Sharma, Younies Mahmoud

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.