1 The Amount Object
Introduction
An Amount is an object that wraps mathematical value and a precision, together with a unit (e.g., mile, kilogram) or currency (e.g., EUR, JPY, USD). One can intuitively understand an Amount as a number that, so to speak, knows its own precision and what it is measuring.
The notation for mathematical values used by Amount are decimal digit string, which are Strings that adhere to the DecimalLiteral production, excepting "NaN", "Infinity", and *"-Infinity".
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 Operations for Reading Options
1.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:
- Let value be ? Get(options, property).
- If value is undefined, then
- If default is required, throw a RangeError exception.
- Return default.
- If type is boolean, then
- Set value to ToBoolean(value).
- Else if type is number, then
- Set value to ? ToNumber(value).
- Else,
- Assert: type is string.
- Set value to ? ToString(value).
- If values is not empty and values does not contain value, throw a RangeError exception.
- Return value.
1.1.2 Operations on Decimal Digit Strings
1.1.2.1 CountSignificantDigits ( s )
The abstract operation CountSignificantDigits takes argument s (a decimal digit String) and returns a positive integer. It computes the number of significant digits in a given decimal digit String. It performs the following steps when called:
- Let digitsToCount be s.
- If digitsToCount contains an e character, set digitsToCount be the substring of s before the first occurence of "e".
- If digitsToCount contains a "." character, set digitsToCount to the result of replacing all occurrences of "." in digitsToCount by "".
- Let l be the length of digitsToCount.
- Return l.
1.1.2.2 CountFractionDigits ( s )
The abstract operation CountFractionDigits takes argument s (a decimal digit String) and returns a non-negative integer. It computes the number of fractional digits in a given decimal digit String. It performs the following steps when called:
- If s contains a "." character, then
- Let fractionDigits be the substring of s after the first "." character up to the first occurrence of "e" or "E" in s, if any.
- Let l be the length of fractionDigits.
- Return l.
- Otherwise:
- Return 0.
1.1.3 Abstract Operations
1.1.3.1 ApplyRoundingModeToPositive ( m, roundingMode )
The abstract operation ApplyRoundingModeToPositive takes arguments m (a positive mathematical value) and roundingMode (a rounding mode) and returns an integer. It computes the closest integer approximation to a given positive mathematical value, rounded according to the given rounding mode. It performs the following steps when called:
- Let mLow be floor(m).
- Let fraction be m – mLow.
- If fraction = 0, return mLow.
- Let mHigh be mLow + 1.
- If roundingMode is "floor" or "trunc", return mLow.
- If roundingMode is "ceil" or *"expand", return mHigh.
- If fraction < 0.5, return mLow.
- If fraction > 0.5, return mHigh.
- If roundingMode is "halfTrunc" or "halfFloor", return mLow.
- If roundingMode is "halfExpand" or *"halfCeil"*, return _mHigh_.
- If mLow is even, return mLow.
- Return mHigh.
1.1.3.2 RoundToFractionDigits ( v, n [ , roundingMode ] )
The abstract operation RoundToFractionDigits takes arguments v (a mathematical value) and n (a non-negative integer) and optional argument roundingMode (a rounding mode) and returns a mathematical value. It computes the closest approximation to a given mathematical value that has at most the given number of fractional digits, rounding (if necessary) according to the given rounding mode. It performs the following steps when called:
- If roundingMode is undefined, set roundingMode to "halfEven".
- If v = 0, return 0.
- If v < 0, then
- Let reverseRoundingMode be roundingMode.
- If roundingMode is "floor", set reverseRoundingMode to "ceil".
- If roundingMode is "ceil", set reverseRoundingMode to "floor".
- If roundingMode is "halfCeil", set reverseRoundingMode to "halfFloor".
- If roundingMode is "halfFloor", set reverseRoundingMode to "halfCeil".
- Let d be RoundToFractionDigits(–v, n, reverseRoundingMode).
- Return –d.
- Let e be the unique integer such that 10e ≤ v < 10e+1.
- Let pow be e + n.
- Let m be v × 10–pow.
- Let rounded be ApplyRoundingModeToPositive(m, roundingMode).
- Return rounded × 10e + n.
1.1.3.3 RoundToSignificantDigits ( v, n [ , roundingMode ] )
The abstract operation RoundToSignificantDigits takes arguments v (a mathematical value) and n (a non-negative integer) and optional argument roundingMode (a rounding mode) and returns a mathematical value. It computes the closest approximation to a given mathematical value that has at most the given number of significant digits, rounding (if necessary) according to the given rounding mode. It performs the following steps when called:
- If roundingMode is undefined, set roundingMode to "halfEven".
- If v = 0, return 0.
- If v < 0, then
- Let reverseRoundingMode be roundingMode.
- If roundingMode is "floor", set reverseRoundingMode to "ceil".
- If roundingMode is "ceil", set reverseRoundingMode to "floor".
- Let d be RoundToSignificantDigits(–v, n, reverseRoundingMode).
- Return –d.
- Let e be the unique integer such that 10e ≤ v < 10e+1.
- If n ≤ e, then
- Let pow be e - n.
- Let m be v × 10–pow.
- Let rounded be ApplyRoundingModeToPositive(m, roundingMode).
- Return rounded × 10n + e.
- Otherwise:
- todo.
1.1.3.4 RenderMVWithFractionDigits ( v, numDigits [ , roundingMode ] )
The abstract operation RenderMVWithFractionDigits takes arguments v (a mathematical value) and numDigits (a non-negative integer) and optional argument roundingMode (a rounding mode) and returns a String. It renders the given mathematical value with a given number of fractional digits, possibly rounding if necessary, using the given rounding mode, which, if missing, is "halfEven". It performs the following steps when called:
- If roundingMode is undefined, let mode be "halfEven", else let mode be roundingMode.
- If v < 0, let prefix be "-", else let prefix be "".
- If v < 0, set v to -v.
- Let rounded be ApplyRoundingModeToPositive(v × 10numDigits, mode).
- Set v to rounded × 10-numDigits.
- Let e be the smallest non-negative integer such that v × 10-numDigits is an integer.
- Let s be the unique decimal string representation of v without leading zeroes.
- If numDigits > e, then
- If v is an integer, return the string concatenation of _prefix, s, ".", and "0" repeated numDigits times.
- Otherwise, return the string concatenation of prefix, s and "0" repeated numDigits - e times.
- Otherwise:
- Return the string concatenation of _prefix, s and "0" repeated e - numDigits times.
1.1.3.5 GetAmountOptions ( opts )
The abstract operation GetAmountOptions takes argument opts (an Object) and returns either a normal completion containing a Record with fields [[Currency]] (a String or undefined), [[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:
- Let opts be ? GetOptionsObject(opts).
- Let currency be ? GetOption(opts, "currency", string, empty, undefined).
- Let fractionDigits be ? GetOption(opts, "fractionDigits", number, empty, undefined).
- Let roundingMode be ? GetOption(opts, "roundingMode", string, « "ceil", "floor", "expand", "trunc", "halfCeil", "halfFloor", "halfExpand", "halfTrunc", "halfEven" », "halfEven").
- Let significantDigits be ? GetOption(opts, "significantDigits", number, empty, undefined).
- Let unit be ? GetOption(opts, "unit", string, empty, undefined).
- If currency is the empty String, throw a RangeError exception.
- If fractionDigits is not undefined, then
- If significantDigits is not undefined, throw a RangeError exception.
- If fractionDigits is not a non-negative integral number, throw a RangeError exception.
- Else if significantDigits is not undefined, then
- If significantDigits is not an integral number, throw a RangeError exception.
- If ℝ(significantDigits) < 1, throw a RangeError exception.
- If unit is the empty String, throw a RangeError exception.
- If unit is not undefined and currency is not undefined, throw a *RangeError exception.
- If currency is not undefined, set currency to the ASCII-uppercase of currency.
- If unit is not undefined, set unit to the ASCII-lowercase of unit.
- Return the Record { [[Currency]]: currency, [[FractionDigits]]: fractionDigits, [[RoundingMode]]: roundingMode, [[SignificantDigits]]: _significantDigits, [[Units]]: unit }.
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 ] )
- If NewTarget is undefined, throw a TypeError exception.
- Let toParse be undefined.
- If x is a BigInt, set toParse to BigInt::toString(x, 10).
- Else if x is a Number, set toParse to Number::toString(x, 10).
- Otherwise, if x is a String, set toParse to x.
- If toParse is not a String, throw a TypeError exception.
- If toParse is in « "NaN", "Infinity", "-Infinity" », throw a RangeError exception.
- Let parseResult be ParseText(toParse, StrDecimalLiteral).
- Let validatedOpts be ? GetAmountOptions(opts).
- If parseResult is a List of errors, throw a SyntaxError exception.
- Let amountValue be ? StringDecimalValue of parseResult.
- Let currency be validatedOpts.[[Currency]].
- Let fractionDigits be validatedOpts.[[FractionDigits]].
- Let roundingMode be validatedOpts.[[RoundingMode]].
- Let significantDigits be validatedOpts.[[SignificantDigits]].
- Let unit be validatedOpts.[[Unit]].
- Let roundedValue be amountValue.
- Assert: If fractionDigits is not undefined, then significantDigits is undefined.
- Assert: If significantDigits is not undefined, then fractionDigits is undefined.
- If both significantDigits and fractionDigits are undefined, then
- Set significantDigits to CountSignificantDigits(toParse).
- Set fractionDigits to CountFractionDigits(toParse).
- Else if significantDigits is undefined, then
- Set roundedValue be RoundToFractionDigits(amountValue, fractionDigits, roundingMode).
- Let digitStr be the unique decimal string representation of roundedValue without leading zeroes.
- Set significantDigits to CountSignificantDigits(digitStr).
- Otherwise:
- Set roundedValue be RoundToSignificantDigits(amountValue, significantDigits, roundingMode).
- Let digitStr be the unique decimal string representation of roundedValue without leading zeroes.
- Set fractionDigits to CountFractionDigits(digitStr).
- Let O be OrdinaryObjectCreate(%Amount.prototype%, « [[Currency]], [[FractionDigits]], [[SignificantDigits]], [[Unit]], [[Value]] »).
- Set O.[[Value]] to roundedValue.
- Set O.[[SignificantDigits]] to significantDigits.
- Set O.[[FractionDigits]] to fractionDigits.
- If unit is not undefined, set O.[[Unit]] to unit.
- If currency is not undefined, set O.[[Currency]] to currency.
- Return O.
Note
Given a Number argument, the constructor converts it to a String using the toString method (with no arguments). In some cases, this may not be desired; consider passing in a String form of a Number using the toFixed or toPrecision methods.
1.2.1.1 Runtime Semantics: StringDecimalValue
The syntax-directed operation StringDecimalValue takes no arguments and returns either a normal completion containing a mathematical value or a throw completion. It is defined piecewise over the following productions:
StrDecimalLiteral :::
-
StrUnsignedDecimalLiteral
- Let a be ? StringAmountValue of StrUnsignedDecimalLiteral.
- Assert: a is finite.
- Return −a.
StrUnsignedDecimalLiteral ::: Infinity
- Throw a RangeError exception.
StrUnsignedDecimalLiteral :::
DecimalDigits
.
DecimalDigitsopt
ExponentPartopt
- Let a be MV of the first DecimalDigits.
- If the second DecimalDigits is present, then
- Let b be MV of the second DecimalDigits.
- Let n be the number of code points in the second DecimalDigits.
- Else,
- Let b be 0.
- Let n be 0.
- If ExponentPart is present, let e be MV of ExponentPart. Otherwise, let e be 0.
- Return (a + (b × 10−n)) × 10e.
StrUnsignedDecimalLiteral :::
.
DecimalDigits
ExponentPartopt
- Let b be MV of DecimalDigits.
- If ExponentPart is present, let e be MV of ExponentPart. Otherwise, let e be 0.
- Let n be the number of code points in DecimalDigits.
- Let newValue be b × 10e − n.
- Return newValue.
StrUnsignedDecimalLiteral :::
DecimalDigits
ExponentPartopt
- Let a be MV of DecimalDigits.
- If ExponentPart is present, let e be MV of ExponentPart. Otherwise, let e be 0.
- Return a × 10e.
2 Properties of the Amount Prototype
2.1 Amount.prototype.toString ( [ options ] )
This method returns a String value that renders the underlying mathematical value according to its precision, as well as any unit or currency indicators, if present.
It performs the following steps when called:
- Let O be the this value.
- Perform ? RequireInternalSlot(O, [[Value]]).
- Perform ? RequireInternalSlot(O, [[FractionDigits]]).
- Let processedOptions be ? GetOptionsObject(options).
- Let displayUnit be ? GetOption(processedOptions, "displayUnit", string, « "always", "auto", "never" », "auto").
- Let c be O.[[Currency]].
- Let u be O.[[Unit]].
- Let v be O.[[Value]].
- Let fractionDigits be O.[[FractionDigits]].
- Let s be RenderMVWithFractionDigits(v, fractionDigits).
- If u is undefined and c is undefined, then
- If displayUnit is "always", return the string concatenation of s, "[", "1", and "]".
- Else, return s.
- Else if u is undefined, then
- If displayUnit is "never", return s.
- Else, return the string concatenation of s, "[", c, and "]".
- Else,
- If displayUnit is "never", return s.
- Else, return the string concatenation of s, "[", u, and "]".
2.2 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:
This method produces a String value that represents this Amount object formatted according to the conventions of the host environment’s current locale. This method is implementation-defined, and it is permissible, but not encouraged, for it to return the same thing as toString
.
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.3 Amount.prototype.with ( options )
This method returns a fresh Amount object whose underlying mathematical value is equal to the mathematical value of the current Amount, but possibly with different precision as specified in the options.
It performs the following steps when called:
- Let O be the this value.
- Perform ? RequireInternalSlot(O, [[Currency]]).
- Perform ? RequireInternalSlot(O, [[Unit]]).
- Perform ? RequireInternalSlot(O, [[Value]]).
- Let processedOptions be ? GetAmountOptions(options).
- Let unit be processedOptions.[[Unit]].
- Let currency be processedOptions.[[Currency]].
- Let fractionDigits be processedOptions.[[FractionDigits]].
- Let significantDigits be processedOptions.[[SignificantDigits]].
- Let value be O.[[Value]].
- If fractionDigits is not undefined, set value to RoundToFractionDigits(value, fractionDigits).
- Else if significantDigits is not undefined, set value to RoundToSignificantDigits(value, significantDigits).
- Otherwise, throw a TypeError exception.
- Let N be OrdinaryObjectCreate("%Amount.prototype%", « [[Currency]], [[FractionDigits]], [[SignificantDigits]], [[Unit]], [[Value]] »).
- If unit is not undefined, then
- If O.[[Currency]] is not undefined, throw a TypeError exception.
- If O.[[Unit]] is undefined, throw a TypeError exception.
- If unit is not string equal to O.[[Unit]], throw a TypeError exception.
- If currency is not undefined, then
- If O.[[Unit]] is not undefined, throw a TypeError exception.
- If O.[[Currency]] is undefined, throw a TypeError exception.
- If currency is not string equal to O.[[Currency]], throw a TypeError exception.
- Set N.[[Value]] to value.
- Set N.[[Unit]] to unit.
- Set N.[[Currency]] to currency.
- Set N.[[FractionDigits]] to ℝ(fractionDigits).
- Set N.[[SignificantDigits]] to ℝ(significantDigits).
- Return N.
2.4 Amount.prototype [ %Symbol.toPrimitive% ] ( hint )
This method is called by ECMAScript language operators to convert an Amount to a primitive value. The allowed values are "default", "number", and "string". The default is "number."
It performs the following steps when called:
- Let O be the the this value.
- Perform ? RequireInternalSlot(O, [[Value]]).
- Perform ? RequireInternalSlot(O, [[FractionDigits]]).
- Perform ? RequireInternalSlot(O, [[Unit]]).
- Perform ? RequireInternalSlot(O, [[Currency]]).
- If hint is not in « "default", "number", "string" », throw a RangeError exception.
- Let mv be O.[[Value]].
- If hint is "string", then
- Let fractionDigits be O.[[FractionDigits]].
- Let str be RenderMVWithFractionDigits(mv, fractionDigits).
- If O.[[Unit]] is undefined and O.[[Currency]] is undefined, return str.
- Else if O.[[Unit]] is undefined, return the string concatenation of str, "[", O.[[Currency]], and "]".
- Otherwise, return the string concatenation of str, "[", O.[[Unit]], and "]".
- Else,
- If O.[[Unit]] is not undefined, throw a TypeError exception.
- If O.[[Currency]] is not undefined, throw a TypeError exception.
- Return the Number value for mv.
Copyright & Software License
Copyright Notice
© 2025 Ben Allen, Jesse Alama
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:
- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
- 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.
- 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.