Stage 1 Draft / April 21, 2026

Amount

Introduction

This specification consists of two parts:

Editor's Note

The changes proposed here are stacked on top of the Keep Trailing Zeros ECMA-402 proposal, and include calls to ECMA-402 Abstract Operations from ECMA​-262 algorithms. Where necessary, we intend to promote those semantics to ECMA​-262.

1 The Amount Object

Introduction

An Amount is an object that wraps a numeric value—as a Number, BigInt, or String—together with an optional unit (e.g., mile, kilogram, EUR, JPY, USD-per-mile). One can intuitively understand an Amount as a value that, so to speak, knows what it is measuring.

When precision options (such as fractionDigits or significantDigits) are applied, or when unit conversion is performed, the numeric value is stored as a decimal digit string, which is a String in StrDecimalLiteral form or "NaN". Otherwise, the original JavaScript value type (Number, BigInt, or String) is retained.

Rounding a mathematical value is an important part of this spec. When we say rounding mode in this specification we simply refer to ECMA-402's definition.

1.1 Abstract Operations

1.1.1 GetOption ( options, property, type, values, default )

The abstract operation GetOption takes arguments options (an Object), property (a property key), type (boolean, string or number), values (empty or a List of ECMAScript language values), and default (required or an ECMAScript language value) and returns either a normal completion containing an ECMAScript language value or a throw completion. It extracts the value of the specified property of options, converts it to the required type, checks whether it is allowed by values if values is not empty, and substitutes default if the value is undefined. It performs the following steps when called:

  1. Let value be ? Get(options, property).
  2. If value is undefined, then
    1. If default is required, throw a RangeError exception.
    2. Return default.
  3. If type is boolean, then
    1. Set value to ToBoolean(value).
  4. Else if type is number, then
    1. Set value to ? ToNumber(value).
  5. Else,
    1. Assert: type is string.
    2. Set value to ? ToString(value).
  6. If values is not empty and values does not contain value, throw a RangeError exception.
  7. Return value.

1.1.2 GetAmountOptions ( opts )

The abstract operation GetAmountOptions takes argument opts (an Object) and returns either a normal completion containing a Record with fields [[FractionDigits]] (a non-negative integer or undefined), [[RoundingMode]] (a rounding mode), [[SignificantDigits]] (a positive integer or undefined), and [[Unit]] (a String or undefined) or a throw completion. It validates the given options (an ECMAScript object) for creating an Amount and returns a Record with slots set to appropriate marthematical values (or undefined). It performs the following steps when called:

  1. Let opts be ? GetOptionsObject(opts).
  2. Let fractionDigits be ? GetOption(opts, "fractionDigits", number, empty, undefined).
  3. Let roundingMode be ? GetOption(opts, "roundingMode", string, « "ceil", "floor", "expand", "trunc", "halfCeil", "halfFloor", "halfExpand", "halfTrunc", "halfEven" », "halfEven").
  4. Let significantDigits be ? GetOption(opts, "significantDigits", number, empty, undefined).
  5. Let unit be ? GetOption(opts, "unit", string, empty, undefined).
  6. If fractionDigits is not undefined, then
    1. If significantDigits is not undefined, throw a RangeError exception.
    2. If fractionDigits is not an integral Number, throw a RangeError exception.
    3. Set fractionDigits to (fractionDigits).
    4. If fractionDigits is not in the inclusive interval from 0 to 100, throw a RangeError exception.
  7. Else if significantDigits is not undefined, then
    1. If significantDigits is not an integral Number, throw a RangeError exception.
    2. Set significantDigits to (significantDigits).
    3. If significantDigits is not in the inclusive interval from 1 to 21, throw a RangeError exception.
  8. If unit is the empty String, throw a RangeError exception.
  9. Return the Record { [[FractionDigits]]: fractionDigits, [[RoundingMode]]: roundingMode, [[SignificantDigits]]: significantDigits, [[Unit]]: unit }.

1.1.3 GetAmountConvertToOptions ( opts )

The abstract operation GetAmountConvertToOptions takes argument opts (an Object) and returns either a normal completion containing a Record with fields [[MinimumFractionDigits]] (a non-negative integer or undefined), [[MaximumFractionDigits]] (a non-negative integer or undefined), [[RoundingMode]] (a rounding mode), [[RoundingPriority]] (a String), [[MinimumSignificantDigits]] (a positive integer or undefined), [[MaximumSignificantDigits]] (a positive integer or undefined), [[Locale]] (a String or undefined), [[Usage]] (a String or undefined), and [[Unit]] (a String or undefined) or a throw completion. It validates the given options (an ECMAScript object) for converting an Amount to another Amount and returns a Record with slots set to appropriate marthematical values (or undefined). It performs the following steps when called:

  1. Let opts be ? GetOptionsObject(opts).
  2. Let minFractionDigits be ? GetOption(opts, "minimumFractionDigits", number, empty, undefined).
  3. Let maxFractionDigits be ? GetOption(opts, "maximumFractionDigits", number, empty, undefined).
  4. Let roundingMode be ? GetOption(opts, "roundingMode", string, « "ceil", "floor", "expand", "trunc", "halfCeil", "halfFloor", "halfExpand", "halfTrunc", "halfEven" », "halfEven").
  5. Let roundingPriority be ? GetOption(opts, "roundingPriority", string, empty, undefined).
  6. Let minSignificantDigits be ? GetOption(opts, "minimumSignificantDigits", number, empty, undefined).
  7. Let maxSignificantDigits be ? GetOption(opts, "maximumSignificantDigits", number, empty, undefined).
  8. Let unit be ? GetOption(opts, "unit", string, empty, undefined).
  9. If minFractionDigits is not undefined, then
    1. If minFractionDigits is not an integral Number, throw a RangeError exception.
    2. Set minFractionDigits to (minFractionDigits).
    3. If minFractionDigits is not in the inclusive interval from 0 to 100, throw a RangeError exception.
  10. If maxFractionDigits is not undefined, then
    1. If maxFractionDigits is not an integral Number, throw a RangeError exception.
    2. Set maxFractionDigits to (maxFractionDigits).
    3. If maxFractionDigits is not in the inclusive interval from 0 to 100, throw a RangeError exception.
  11. If minFractionDigits is not undefined and maxFractionDigits is not undefined and minFractionDigits > maxFractionDigits, throw a RangeError exception.
  12. If minSignificantDigits is not undefined, then
    1. If minSignificantDigits is not an integral Number, throw a RangeError exception.
    2. Set minSignificantDigits to (minSignificantDigits).
    3. If minSignificantDigits is not in the inclusive interval from 1 to 21, throw a RangeError exception.
  13. If maxSignificantDigits is not undefined, then
    1. If maxSignificantDigits is not an integral Number, throw a RangeError exception.
    2. Set maxSignificantDigits to (maxSignificantDigits).
    3. If maxSignificantDigits is not in the inclusive interval from 1 to 21, throw a RangeError exception.
  14. If minSignificantDigits is not undefined and maxSignificantDigits is not undefined and minSignificantDigits > maxSignificantDigits, throw a RangeError exception.
  15. If unit is the empty String, throw a RangeError exception.
  16. Return the Record { [[MinimumFractionDigits]]: minFractionDigits, [[MaximumFractionDigits]]: maxFractionDigits, [[MinimumSignificantDigits]]: minSignificantDigits, [[MaximumSignificantDigits]]: maxSignificantDigits, [[RoundingMode]]: roundingMode, [[RoundingPriority]]: roundingPriority, [[Unit]]: unit }.

1.1.4 CreateFormatterObject ( roundingMode, minFractionDigits, maxFractionDigits, minSignificantDigits, maxSignificantDigits, roundingPriority )

The abstract operation CreateFormatterObject takes arguments roundingMode (a String), minFractionDigits (a non-negative integer or undefined), maxFractionDigits (a non-negative integer or undefined), minSignificantDigits (a positive integer or undefined), maxSignificantDigits (a positive integer or undefined), and roundingPriority (a String or undefined) and returns an Object. It creates an object with the internal slots required by FormatNumericToString, configured according to the given rounding and digit options. It performs the following steps when called:

  1. Let formatter be OrdinaryObjectCreate(null, « [[MinimumFractionDigits]], [[MinimumIntegerDigits]], [[MinimumSignificantDigits]], [[MaximumFractionDigits]], [[MaximumSignificantDigits]], [[RoundingIncrement]], [[RoundingMode]], [[RoundingType]], [[TrailingZeroDisplay]] »).
  2. Set formatter.[[RoundingMode]] to roundingMode.
  3. Set formatter.[[MinimumIntegerDigits]] to 1.
  4. Set formatter.[[RoundingIncrement]] to 1.
  5. Set formatter.[[TrailingZeroDisplay]] to "auto".
  6. If minSignificantDigits is not undefined or maxSignificantDigits is not undefined, let hasSD be true; else let hasSD be false.
  7. If minFractionDigits is not undefined or maxFractionDigits is not undefined, let hasFD be true; else let hasFD be false.
  8. If hasSD is true, then
    1. If minSignificantDigits is not undefined, let resolvedMinSD be minSignificantDigits; else let resolvedMinSD be 1.
    2. If maxSignificantDigits is not undefined, let resolvedMaxSD be maxSignificantDigits; else let resolvedMaxSD be 21.
    3. Set formatter.[[MinimumSignificantDigits]] to resolvedMinSD.
    4. Set formatter.[[MaximumSignificantDigits]] to resolvedMaxSD.
  9. Else,
    1. Set formatter.[[MinimumSignificantDigits]] to 1.
    2. Set formatter.[[MaximumSignificantDigits]] to 21.
  10. If hasFD is true, then
    1. If minFractionDigits is not undefined, let resolvedMinFD be minFractionDigits; else let resolvedMinFD be 0.
    2. If maxFractionDigits is not undefined, let resolvedMaxFD be maxFractionDigits; else let resolvedMaxFD be 100.
    3. Set formatter.[[MinimumFractionDigits]] to resolvedMinFD.
    4. Set formatter.[[MaximumFractionDigits]] to resolvedMaxFD.
  11. Else,
    1. Set formatter.[[MinimumFractionDigits]] to 0.
    2. Set formatter.[[MaximumFractionDigits]] to 100.
  12. If hasSD is true and hasFD is true, then
    1. If roundingPriority is "morePrecision", set formatter.[[RoundingType]] to more-precision; else set formatter.[[RoundingType]] to less-precision.
  13. Else if hasSD is true, then
    1. Set formatter.[[RoundingType]] to significant-digits.
  14. Else,
    1. Set formatter.[[RoundingType]] to fraction-digits.
  15. Return formatter.

1.1.5 Unit Conversion Data

Unit conversion data is derived from CLDR file units.xml. As described in Unicode Technical Standard #35 Part 6 Supplemental, Conversion Data, each <convertUnit> element defines how to convert a source unit into a compatible baseUnit. An ECMAScript implementation must ignore all special conversions and support all conversions based on factor and/or offset, interpreting the value for each as an arithmetic expression with mathematical value operands (noting the respective defaults of 1 and 0 and the implicit presence of an identity mapping for each unit identified as the value of a baseUnit).

Two units are convertible if and only if they share the same baseUnit value in CLDR. A unit that appears as a baseUnit value has an implicit identity conversion (factor 1, offset 0).

Note

In factor and offset expressions, * multiplication binds more tightly than / division, and constants defined by <unitConstant> elements are valid operands.

For example:

  • <convertUnit source='celsius' baseUnit='kelvin' offset='273.15' systems="si metric"/> specifies that conversion from unit "celsius" to unit "kelvin" requires addition of 273.15.
  • <convertUnit source='fahrenheit' baseUnit='kelvin' factor='5/9' offset='2298.35/9' systems="ussystem uksystem"/> specifies that conversion from unit "fahrenheit" to unit "kelvin" requires multiplication by (5 / 9) followed by addition of (2298.35 / 9).
  • <convertUnit source='radian' baseUnit='revolution' factor='1/2*PI' systems="si metric"/> specifies that conversion from unit "radian" to unit "revolution" requires multiplication by (1 / (2 × PI)), which references <unitConstant constant="PI" value="411557987 / 131002976" status='approximate'/> and is thus equivalent to multiplication by (1 / (2 × (411557987 / 131002976))) = (131002976 / 823115974).
  • <convertUnit source='solar-mass' baseUnit='kilogram' factor='1.98847E+30' systems="astronomical"/> specifies that conversion from unit "solar-mass" to unit "kilogram" requires multiplication by (1.98847 × 1030).

1.1.6 GetUnitConversionFactor ( unit )

The abstract operation GetUnitConversionFactor takes argument unit (a String) and returns either a normal completion containing a Record with fields [[BaseUnit]] (a String), [[Factor]] (a mathematical value), and [[Offset]] (a mathematical value) or a throw completion. It returns the conversion data for converting unit to its base unit. It performs the following steps when called:

  1. If unit is the source of a <convertUnit> element in the unit conversion data, then
    1. Let element be that <convertUnit> element.
    2. If element has an attribute special, throw a TypeError exception.
    3. Let baseUnit be the baseUnit of element.
    4. Let factor be the mathematical value of the factor attribute of element if present, or 1 otherwise.
    5. Let offset be the mathematical value of the offset attribute of element if present, or 0 otherwise.
  2. Else if unit is a baseUnit value in the unit conversion data, then
    1. Let baseUnit be unit.
    2. Let factor be 1.
    3. Let offset be 0.
  3. Else,
    1. Throw a TypeError exception.
  4. Return the Record { [[BaseUnit]]: baseUnit, [[Factor]]: factor, [[Offset]]: offset }.
Note

The formula for converting a value in unit to its base unit is: baseValue = value × [[Factor]] + [[Offset]].

1.1.7 ConvertUnitValue ( value, sourceUnit, targetUnit )

The abstract operation ConvertUnitValue takes arguments value (a Number), sourceUnit (a String), and targetUnit (a String) and returns either a normal completion containing a Number or a throw completion. It converts value from sourceUnit to targetUnit using Number arithmetic. It performs the following steps when called:

  1. If SameValue(sourceUnit, targetUnit) is true, return value.
  2. Let sourceConv be ? GetUnitConversionFactor(sourceUnit).
  3. Let targetConv be ? GetUnitConversionFactor(targetUnit).
  4. If sourceConv.[[BaseUnit]] is not targetConv.[[BaseUnit]], throw a TypeError exception.
  5. If value is NaN, return NaN.
  6. Let sourceFactor be sourceConv.[[Factor]].
  7. Let sourceOffset be sourceConv.[[Offset]].
  8. Let targetFactor be targetConv.[[Factor]].
  9. Let targetOffset be targetConv.[[Offset]].
  10. If sourceOffset is targetOffset, then
    1. NOTE: This preserves a value of -0𝔽.
    2. Return value × 𝔽(sourceFactor / targetFactor).
  11. Return value × 𝔽(sourceFactor / targetFactor) + 𝔽((sourceOffset - targetOffset) / targetFactor).
Note

The factor term sourceFactor / targetFactor and the offset term (sourceOffsettargetOffset) / targetFactor are computed as mathematical values, and then converted to Number values for the multiplication and addition. For non-offset conversions (the vast majority), the offset term is 0 and addition is skipped in order to preserve an input value of -0𝔽.

1.2 The Amount Constructor

The Amount constructor:

  • is %Amount%.
  • is the initial value of the the "Amount" property of the global object.
  • creates and initializes a new Amount object when called as a constructor
  • may be used as the value of an extends clause of a class definition.

1.2.1 Amount ( x [ , opts ] )

  1. If NewTarget is undefined, throw a TypeError exception.
  2. If x is not a Number, not a BigInt, and not a String, throw a TypeError exception.
  3. If x is a String, then
    1. Let text be StringToCodePoints(x).
    2. Let parsed be ParseText(text, StringNumericLiteral).
    3. If parsed is a List of errors, throw a RangeError exception.
  4. Let validatedOpts be ? GetAmountOptions(opts).
  5. Let roundingMode be validatedOpts.[[RoundingMode]].
  6. Let fractionDigits be validatedOpts.[[FractionDigits]].
  7. Let significantDigits be validatedOpts.[[SignificantDigits]].
  8. Let unit be validatedOpts.[[Unit]].
  9. If x is a Number or x is a BigInt, then
    1. Let value be x.
  10. Else,
    1. Assert: x is a String.
    2. Let formatter be CreateFormatterObject(roundingMode, fractionDigits, fractionDigits, significantDigits, significantDigits, undefined).
    3. Let intlMV be ! ToIntlMathematicalValue(x).
    4. Let formatted be FormatNumericToString(formatter, intlMV.[[Value]], intlMV.[[StringDigitCount]]).
    5. Let value be formatted.[[FormattedString]].
  11. Let O be OrdinaryObjectCreate(%Amount.prototype%, « [[AmountValue]], [[Unit]] »).
  12. Set O.[[AmountValue]] to value.
  13. Set O.[[Unit]] to unit.
  14. Return O.
Note

When no precision options are given, Number and BigInt arguments are stored directly in [[AmountValue]], preserving the original type. String arguments are normalized to StrDecimalLiteral form. When precision options are specified, [[AmountValue]] always holds a String.

Editor's Note

We intend to move 402's FormatNumericToString, and its dependent AOs, to 262, possibly renamed.

2 Properties of the Amount Prototype

2.1 get Amount.prototype.value

This accessor property, whose set accessor function is undefined, returns the numeric value of the Amount. Its get accessor function performs the following steps when called:

  1. Let O be the this value.
  2. Perform ? RequireInternalSlot(O, [[AmountValue]]).
  3. Return O.[[AmountValue]].
Note

The value may be a Number, BigInt, or String. It is a String when precision options were applied during construction or when the Amount is the result of unit conversion.

2.2 get Amount.prototype.unit

This accessor property, whose set accessor function is undefined, returns a String value (or undefined) indicating the unit that this Amount has. Its get accessor function performs the following steps when called:

  1. Let O be the this value.
  2. Perform ? RequireInternalSlot(O, [[AmountValue]]).
  3. Return O.[[Unit]].

2.3 Amount.prototype.toString ( )

This method returns a String representation of the Amount, including a unit indicator in bracket notation.

It performs the following steps when called:

  1. Let O be the this value.
  2. Perform ? RequireInternalSlot(O, [[AmountValue]]).
  3. Let v be O.[[AmountValue]].
  4. Let u be O.[[Unit]].
  5. If v is a String, then
    1. Let valueStr be v.
  6. Else if v is a Number, then
    1. Let valueStr be Number::toString(v, 10).
  7. Else,
    1. Assert: v is a BigInt.
    2. Let valueStr be BigInt::toString(v, 10).
  8. If u is undefined, return the string-concatenation of valueStr and "[]".
  9. Return the string-concatenation of valueStr, "[", u, and "]".

2.4 Amount.prototype.toLocaleString ( [ reserved1 [ , reserved2 ] ] )

An ECMAScript implementation that includes the ECMA-402 Internationalization API must implement this method as specified in the ECMA-402 specification. If an ECMAScript implementation does not include the ECMA-402 API the following specification of this method is used:

It performs the following steps when called:

  1. Let O be the this value.
  2. Perform ? RequireInternalSlot(O, [[AmountValue]]).
  3. Return ? Call(%Amount.prototype.toString%, O, « »).

The meanings of the optional parameters to this method are defined in the ECMA-402 specification; implementations that do not include ECMA-402 support must not use those parameter positions for anything else.

2.5 Amount.prototype.convertTo ( options )

This method returns a new Amount whose value is the result of converting this Amount’s value from its current unit to a target unit. The target unit is specified by options.

It performs the following steps when called:

  1. Let O be the this value.
  2. Perform ? RequireInternalSlot(O, [[AmountValue]]).
  3. Let sourceUnit be O.[[Unit]].
  4. If sourceUnit is undefined, throw a TypeError exception.
  5. Let validatedOpts be ? GetAmountConvertToOptions(options).
  6. Let targetUnit be validatedOpts.[[Unit]].
  7. If targetUnit is undefined, throw a TypeError exception.
  8. Let roundingMode be validatedOpts.[[RoundingMode]].
  9. Let roundingPriority be validatedOpts.[[RoundingPriority]].
  10. Let minFractionDigits be validatedOpts.[[MinimumFractionDigits]].
  11. Let maxFractionDigits be validatedOpts.[[MaximumFractionDigits]].
  12. Let minSignificantDigits be validatedOpts.[[MinimumSignificantDigits]].
  13. Let maxSignificantDigits be validatedOpts.[[MaximumSignificantDigits]].
  14. Let v be O.[[AmountValue]].
  15. If v is a Number, then
    1. Let sourceValue be v.
  16. Else if v is a BigInt, then
    1. Let sourceValue be 𝔽((v)).
  17. Else,
    1. Assert: v is a String.
    2. Let sourceValue be StringToNumber(v).
  18. Let convertedValue be ? ConvertUnitValue(sourceValue, sourceUnit, targetUnit).
  19. Let formatter be CreateFormatterObject(roundingMode, minFractionDigits, maxFractionDigits, minSignificantDigits, maxSignificantDigits, roundingPriority).
  20. Let formatted be FormatNumericToString(formatter, (convertedValue), 0).
  21. Let result be OrdinaryObjectCreate(%Amount.prototype%, « [[AmountValue]], [[Unit]] »).
  22. Set result.[[AmountValue]] to formatted.[[FormattedString]].
  23. Set result.[[Unit]] to targetUnit.
  24. Return result.

3 Amendments to the ECMAScript® 2024 Internationalization API Specification

Editor's Note

This section lists amendments which must be made to ECMA-402, the ECMAScript® 2024 Internationalization API Specification. Text to be added is marked like this, and text to be deleted is marked like this. Blocks of unmodified text between modified sections are marked by [...].

3.1 Properties of the Amount Prototype Object

3.1.1 Amount.prototype.toLocaleString ( [ locales [ , options ] ] )

This definition supersedes the definition provided in es2025, 2.4.

This function performs the following steps when called:

  1. Let O be the this value.
  2. Perform ? RequireInternalSlot(O, [[AmountValue]]).
  3. Let v be O.[[AmountValue]].
  4. If v is a String, then
    1. Let numValue be v.
  5. Else if v is a BigInt, then
    1. Let numValue be BigInt::toString(v, 10).
  6. Else,
    1. Assert: v is a Number.
    2. Let numValue be v.
  7. Let unit be O.[[Unit]].
  8. Let mergedOptions be OrdinaryObjectCreate(null).
  9. If options is not undefined, then
    1. Let optionsObj be ? GetOptionsObject(options).
    2. Perform ? CopyDataProperties(mergedOptions, optionsObj, « »).
  10. If unit is not undefined, then
    1. If ? HasProperty(mergedOptions, "style") is false, then
      1. If IsWellFormedCurrencyCode(unit) is true, then
        1. Perform ! CreateDataPropertyOrThrow(mergedOptions, "style", "currency").
        2. If ? HasProperty(mergedOptions, "currency") is false, then
          1. Perform ! CreateDataPropertyOrThrow(mergedOptions, "currency", unit).
      2. Else,
        1. Perform ! CreateDataPropertyOrThrow(mergedOptions, "style", "unit").
        2. If ? HasProperty(mergedOptions, "unit") is false, then
          1. Perform ! CreateDataPropertyOrThrow(mergedOptions, "unit", unit).
  11. Let numberFormat be ? Construct(%Intl.NumberFormat%, « locales, mergedOptions »).
  12. Return FormatNumeric(numberFormat, numValue).

3.2 Amendment to the Normative References of ECMA-402

Editor's Note

The following entry is to be added to ECMA-402's list of referenced parts of Unicode Technical Standard #35.

4 NumberFormat Objects

4.1 Abstract Operations for NumberFormat Objects

4.1.1 GetNumberFormatPattern ( numberFormat, x )

The abstract operation GetNumberFormatPattern takes arguments numberFormat (an Intl.NumberFormat) and x (an Intl mathematical value) and returns either a normal completion containing a String or a throw completion. It considers the resolved unit-related options in the number format object along with the final scaled and rounded number being formatted (an Intl mathematical value) and returns a pattern, a String value as described in 16.2.3. It performs the following steps when called:

  1. Let resolvedLocaleData be numberFormat.[[LocaleData]].
  2. Let patterns be resolvedLocaleData.[[patterns]].
  3. Assert: patterns is a Record (see 16.2.3).
  4. Let style be numberFormat.[[Style]].
  5. If style is "percent", then
    1. Set patterns to patterns.[[percent]].
  6. Else if style is "unit", then
    1. Let unit be numberFormat.[[Unit]].
    2. Let fmtUnit be x.[[Unit]].
    3. If fmtUnit is not undefined and SameValueNonNumber(unit, fmtUnit) is false, then
      1. If unit is not undefined, throw a TypeError exception.
      2. Set unit to fmtUnit.
    4. Else if unit is undefined, then
      1. Throw a TypeError exception.
    5. Let unitDisplay be numberFormat.[[UnitDisplay]].
    6. Set patterns to patterns.[[unit]].
    7. If patterns doesn't have a field [[<unit>]], then
      1. Set unit to "fallback".
    8. Set patterns to patterns.[[<unit>]].
    9. Set patterns to patterns.[[<unitDisplay>]].
  7. Else if style is "currency", then
    1. Let currency be numberFormat.[[Currency]].
    2. Let fmtCurrency be x.[[Currency]].
    3. If fmtCurrency is not undefined and SameValueNonNumber(currency, fmtCurrency) is false, then
      1. If currency is not undefined, throw a TypeError exception.
      2. Set currency to fmtCurrency.
    4. Else if currency is undefined, then
      1. Throw a TypeError exception.
    5. Let currencyDisplay be numberFormat.[[CurrencyDisplay]].
    6. Let currencySign be numberFormat.[[CurrencySign]].
    7. Set patterns to patterns.[[currency]].
    8. If patterns doesn't have a field [[<currency>]], then
      1. Set currency to "fallback".
    9. Set patterns to patterns.[[<currency>]].
    10. Set patterns to patterns.[[<currencyDisplay>]].
    11. Set patterns to patterns.[[<currencySign>]].
  8. Else,
    1. Assert: style is "decimal".
    2. Set patterns to patterns.[[decimal]].
  9. If x is negative-infinity, then
    1. Let category be negative-non-zero.
  10. Else if x is negative-zero, then
    1. Let category be negative-zero.
  11. Else if x is not-a-number, then
    1. Let category be positive-zero.
  12. Else if x is positive-infinity, then
    1. Let category be positive-non-zero.
  13. Else,
    1. Assert: x is a mathematical value.
    2. If x < 0, then
      1. Let category be negative-non-zero.
    3. Else if x > 0, then
      1. Let category be positive-non-zero.
    4. Else,
      1. Let category be positive-zero.
  14. Let signDisplay be numberFormat.[[SignDisplay]].
  15. If signDisplay is "never", then
    1. Let pattern be patterns.[[zeroPattern]].
  16. Else if signDisplay is "auto", then
    1. If category is positive-non-zero or positive-zero, then
      1. Let pattern be patterns.[[zeroPattern]].
    2. Else,
      1. Let pattern be patterns.[[negativePattern]].
  17. Else if signDisplay is "always", then
    1. If category is positive-non-zero or positive-zero, then
      1. Let pattern be patterns.[[positivePattern]].
    2. Else,
      1. Let pattern be patterns.[[negativePattern]].
  18. Else if signDisplay is "exceptZero", then
    1. If category is positive-zero or negative-zero, then
      1. Let pattern be patterns.[[zeroPattern]].
    2. Else if category is positive-non-zero, then
      1. Let pattern be patterns.[[positivePattern]].
    3. Else,
      1. Let pattern be patterns.[[negativePattern]].
  19. Else,
    1. Assert: signDisplay is "negative".
    2. If category is negative-non-zero, then
      1. Let pattern be patterns.[[negativePattern]].
    3. Else,
      1. Let pattern be patterns.[[zeroPattern]].
  20. Return pattern.

4.1.2 SetNumberFormatUnitOptions ( intlObj, options )

The abstract operation SetNumberFormatUnitOptions takes arguments intlObj (an Intl.NumberFormat) and options (an Object) and returns either a normal completion containing unused or a throw completion. It resolves the user-specified options relating to units onto intlObj. It performs the following steps when called:

  1. Let style be ? GetOption(options, "style", string, « "decimal", "percent", "currency", "unit" », "decimal").
  2. Set intlObj.[[Style]] to style.
  3. Let currency be ? GetOption(options, "currency", string, empty, undefined).
  4. If currency is undefined, then
    1. If style is "currency", throw a TypeError exception.
  5. Else,
    1. If IsWellFormedCurrencyCode(currency) is false, throw a RangeError exception.
  6. If currency is not undefined and IsWellFormedCurrencyCode(currency) is false, throw a RangeError exception.
  7. Let currencyDisplay be ? GetOption(options, "currencyDisplay", string, « "code", "symbol", "narrowSymbol", "name" », "symbol").
  8. Let currencySign be ? GetOption(options, "currencySign", string, « "standard", "accounting" », "standard").
  9. Let unit be ? GetOption(options, "unit", string, empty, undefined).
  10. If unit is undefined, then
    1. If style is "unit", throw a TypeError exception.
  11. Else,
    1. If IsWellFormedUnitIdentifier(unit) is false, throw a RangeError exception.
  12. If unit is not undefined and IsWellFormedUnitIdentifier(unit) is false, throw a RangeError exception.
  13. Let unitDisplay be ? GetOption(options, "unitDisplay", string, « "short", "narrow", "long" », "short").
  14. If style is "currency", then
    1. If currency is not undefined, set Set intlObj.[[Currency]] to the ASCII-uppercase of currency.
    2. Set intlObj.[[CurrencyDisplay]] to currencyDisplay.
    3. Set intlObj.[[CurrencySign]] to currencySign.
  15. If style is "unit", then
    1. If unit is not undefined, Set set intlObj.[[Unit]] to unit.
    2. Set intlObj.[[UnitDisplay]] to unitDisplay.
  16. Return unused.

5 Normative References

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.