Fork me on GitHub

Dinero

A Dinero object is an immutable data structure representing a specific monetary value. It comes with methods for creating, parsing, manipulating, testing, transforming and formatting them.

A Dinero object has:

  • An amount, expressed in minor currency units.
  • A currency, expressed as an ISO 4217 currency code.
  • A precision, expressed as an integer, to represent the number of decimal places in the amount. This is helpful when you want to represent fractional minor currency units (e.g.: $10.4545). You can also use it to represent a currency with a different exponent than 2 (e.g.: Iraqi dinar with 1000 fils in 1 dinar (exponent of 3), Japanese yen with no sub-units (exponent of 0)).
  • An optional locale property that affects how output strings are formatted.

Here's an overview of the public API:

Parameters:
Name Type Attributes Default Description
options.amount Number <optional>
0

The amount in minor currency units (as an integer).

options.currency String <optional>
'USD'

An ISO 4217 currency code.

options.precision String <optional>
2

The number of decimal places to represent.

Source:
Throws:

If amount or precision is invalid.

Type
TypeError

Methods

(inner) getAmount() → {Number}

Returns the amount.

Source:
Example
// returns 500
Dinero({ amount: 500 }).getAmount()

(inner) getCurrency() → {String}

Returns the currency.

Source:
Example
// returns 'EUR'
Dinero({ currency: 'EUR' }).getCurrency()

(inner) getLocale() → {String}

Returns the locale.

Source:
Example
// returns 'fr-FR'
Dinero().setLocale('fr-FR').getLocale()

(inner) setLocale(newLocale) → {Dinero}

Returns a new Dinero object with an embedded locale.

Parameters:
Name Type Description
newLocale String

The new locale as an BCP 47 language tag.

Source:
Example
// Returns a Dinero object with locale 'ja-JP'
Dinero().setLocale('ja-JP')

(inner) getPrecision() → {Number}

Returns the precision.

Source:
Example
// returns 3
Dinero({ precision: 3 }).getPrecision()

(inner) convertPrecision(newPrecision) → {Dinero}

Returns a new Dinero object with a new precision and a converted amount.

Parameters:
Name Type Description
newPrecision Number

The new precision.

Source:
Throws:

If newPrecision is invalid.

Type
TypeError
Example
// Returns a Dinero object with precision 3 and amount 1000
Dinero({ amount: 100, precision: 2 }).convertPrecision(3)

(inner) add(addend) → {Dinero}

Returns a new Dinero object that represents the sum of this and an other Dinero object.

If Dinero objects have a different precision, they will be first converted to the highest.

Parameters:
Name Type Description
addend Dinero

The Dinero object to add.

Source:
Throws:

If addend has a different currency.

Type
TypeError
Examples
// returns a Dinero object with amount 600
Dinero({ amount: 400 }).add(Dinero({ amount: 200 }))
// returns a Dinero object with amount 144545 and precision 4
Dinero({ amount: 400 }).add(Dinero({ amount: 104545, precision: 4 }))

(inner) subtract(subtrahend) → {Dinero}

Returns a new Dinero object that represents the difference of this and an other Dinero object.

If Dinero objects have a different precision, they will be first converted to the highest.

Parameters:
Name Type Description
subtrahend Dinero

The Dinero object to subtract.

Source:
Throws:

If subtrahend has a different currency.

Type
TypeError
Examples
// returns a Dinero object with amount 200
Dinero({ amount: 400 }).subtract(Dinero({ amount: 200 }))
// returns a Dinero object with amount 64545 and precision 4
Dinero({ amount: 104545, precision: 4 }).subtract(Dinero({ amount: 400 }))

(inner) multiply(multiplier, roundingModeopt) → {Dinero}

Returns a new Dinero object that represents the multiplied value by the given factor.

By default, fractional minor currency units are rounded using the half to even rule (banker's rounding).

Rounding can lead to accuracy issues as you chain many times. Consider a minimal amount of subsequent calculations for safer results. You can also specify a different roundingMode to better fit your needs.

Parameters:
Name Type Attributes Default Description
multiplier Number

The factor to multiply by.

roundingMode String <optional>
'HALF_EVEN'

The rounding mode to use: 'HALF_ODD', 'HALF_EVEN', 'HALF_UP', 'HALF_DOWN', 'HALF_TOWARDS_ZERO' or 'HALF_AWAY_FROM_ZERO'.

Source:
Examples
// returns a Dinero object with amount 1600
Dinero({ amount: 400 }).multiply(4)
// returns a Dinero object with amount 800
Dinero({ amount: 400 }).multiply(2.001)
// returns a Dinero object with amount 801
Dinero({ amount: 400 }).multiply(2.00125, 'HALF_UP')

(inner) divide(divisor, roundingModeopt) → {Dinero}

Returns a new Dinero object that represents the divided value by the given factor.

By default, fractional minor currency units are rounded using the half to even rule (banker's rounding).

Rounding can lead to accuracy issues as you chain many times. Consider a minimal amount of subsequent calculations for safer results. You can also specify a different roundingMode to better fit your needs.

As rounding is applied, precision may be lost in the process. If you want to accurately split a Dinero object, use allocate instead.

Parameters:
Name Type Attributes Default Description
divisor Number

The factor to divide by.

roundingMode String <optional>
'HALF_EVEN'

The rounding mode to use: 'HALF_ODD', 'HALF_EVEN', 'HALF_UP', 'HALF_DOWN', 'HALF_TOWARDS_ZERO' or 'HALF_AWAY_FROM_ZERO'.

Source:
Examples
// returns a Dinero object with amount 100
Dinero({ amount: 400 }).divide(4)
// returns a Dinero object with amount 52
Dinero({ amount: 105 }).divide(2)
// returns a Dinero object with amount 53
Dinero({ amount: 105 }).divide(2, 'HALF_UP')

(inner) percentage(percentage) → {Dinero}

Returns a new Dinero object that represents a percentage of this.

As rounding is applied, precision may be lost in the process. If you want to accurately split a Dinero object, use allocate instead.

Parameters:
Name Type Description
percentage Number

The percentage to extract (between 0 and 100).

Source:
Throws:

If percentage is out of range.

Type
RangeError
Example
// returns a Dinero object with amount 5000
Dinero({ amount: 10000 }).percentage(50)

(inner) allocate(ratios) → {Array.<Dinero>}

Allocates the amount of a Dinero object according to a list of ratios.

Sometimes you need to split monetary values but percentages can't cut it without adding or losing pennies. A good example is invoicing: let's say you need to bill $1,000.03 and you want a 50% downpayment. If you use percentage, you'll get an accurate Dinero object but the amount won't be billable: you can't split a penny. If you round it, you'll bill a penny extra. With allocate, you can split a monetary amount then distribute the remainder as evenly as possible.

You can use percentage style or ratio style for ratios: [25, 75] and [1, 3] will do the same thing.

Parameters:
Name Type Description
ratios Array.<Number>

The ratios to allocate the money to.

Source:
Throws:

If ratios are invalid.

Type
TypeError
Examples
// returns an array of two Dinero objects
// the first one with an amount of 502
// the second one with an amount of 501
Dinero({ amount: 1003 }).allocate([50, 50])
// returns an array of two Dinero objects
// the first one with an amount of 25
// the second one with an amount of 75
Dinero({ amount: 100 }).allocate([1, 3])

(inner) convert(currency) → {Promise}

Returns a Promise containing a new Dinero object converted to another currency.

You must provide your own API to retrieve exchange rates. This method won't work if you don't set either global API parameters, or local ones for your instance.

Here are some exchange rate APIs you can use:

You will need to specify at least:

  • a destination currency: the currency in which you want to convert your Dinero object. You can specify it with currency.
  • an endpoint: the API URL to query exchange rates, with parameters. You can specify it with options.endpoint.
  • a property path: the path to access the wanted rate in your API's JSON response. For example, with a response of:
    {
      "data": {
        "base": "USD",
        "destination": "EUR",
        "rate": "0.827728919"
      }
    }
    Then the property path is 'data.rate'. You can specify it with options.propertyPath.

The base currency (the currency of your Dinero object) and the destination currency can be used as "merge tags" with the mustache syntax, respectively {{from}} and {{to}}. You can use these tags to refer to these values in options.endpoint and options.propertyPath.

For example, if you need to specify the base currency as a query parameter, you can do the following:

{
  endpoint: 'https://yourexchangerates.api/latest?base={{from}}'
}
Parameters:
Name Type Attributes Default Description
currency String

The destination currency, expressed as an ISO 4217 currency code.

options.endpoint String

The API endpoint to retrieve exchange rates.

options.propertyPath String

The property path to the rate.

options.headers Object <optional>

The HTTP headers to provide, if needed.

options.roundingMode String <optional>
'HALF_EVEN'

The rounding mode to use: 'HALF_ODD', 'HALF_EVEN', 'HALF_UP', 'HALF_DOWN', 'HALF_TOWARDS_ZERO' or 'HALF_AWAY_FROM_ZERO'.

Source:
Examples
// your global API parameters
Dinero.globalExchangeRatesApi = { ... }

// returns a Promise containing a Dinero object with the destination currency
// and the initial amount converted to the new currency.
Dinero({ amount: 500 }).convert('EUR')
// returns a Promise containing a Dinero object,
// with specific API parameters and rounding mode for this specific instance.
Dinero({ amount: 500 })
  .convert('XBT', {
    endpoint: 'https://yourexchangerates.api/latest?base={{from}}',
    propertyPath: 'data.rates.{{to}}',
    headers: {
      'user-key': 'xxxxxxxxx'
    },
    roundingMode: 'HALF_UP'
  })
// usage with Promise.prototype.then and Promise.prototype.catch
Dinero({ amount: 500 })
  .convert('EUR')
  .then(dinero => {
    dinero.getCurrency() // returns 'EUR'
  })
  .catch(err => {
    // handle errors
  })
// usage with async/await
(async () => {
  const price = await Dinero({ amount: 500 }).convert('EUR')
  price.getCurrency() // returns 'EUR'
})()

(inner) equalsTo(comparator) → {Boolean}

Checks whether the value represented by this object equals to the other.

Parameters:
Name Type Description
comparator Dinero

The Dinero object to compare to.

Source:
Examples
// returns true
Dinero({ amount: 500, currency: 'EUR' }).equalsTo(Dinero({ amount: 500, currency: 'EUR' }))
// returns false
Dinero({ amount: 500, currency: 'EUR' }).equalsTo(Dinero({ amount: 800, currency: 'EUR' }))
// returns false
Dinero({ amount: 500, currency: 'USD' }).equalsTo(Dinero({ amount: 500, currency: 'EUR' }))
// returns false
Dinero({ amount: 500, currency: 'USD' }).equalsTo(Dinero({ amount: 800, currency: 'EUR' }))
// returns true
Dinero({ amount: 1000, currency: 'EUR', precision: 2 }).equalsTo(Dinero({ amount: 10000, currency: 'EUR', precision: 3 }))
// returns false
Dinero({ amount: 10000, currency: 'EUR', precision: 2 }).equalsTo(Dinero({ amount: 10000, currency: 'EUR', precision: 3 }))

(inner) lessThan(comparator) → {Boolean}

Checks whether the value represented by this object is less than the other.

Parameters:
Name Type Description
comparator Dinero

The Dinero object to compare to.

Source:
Throws:

If comparator has a different currency.

Type
TypeError
Examples
// returns true
Dinero({ amount: 500 }).lessThan(Dinero({ amount: 800 }))
// returns false
Dinero({ amount: 800 }).lessThan(Dinero({ amount: 500 }))
// returns true
Dinero({ amount: 5000, precision: 3 }).lessThan(Dinero({ amount: 800 }))
// returns false
Dinero({ amount: 800 }).lessThan(Dinero({ amount: 5000, precision: 3 }))

(inner) lessThanOrEqual(comparator) → {Boolean}

Checks whether the value represented by this object is less than or equal to the other.

Parameters:
Name Type Description
comparator Dinero

The Dinero object to compare to.

Source:
Throws:

If comparator has a different currency.

Type
TypeError
Examples
// returns true
Dinero({ amount: 500 }).lessThanOrEqual(Dinero({ amount: 800 }))
// returns true
Dinero({ amount: 500 }).lessThanOrEqual(Dinero({ amount: 500 }))
// returns false
Dinero({ amount: 500 }).lessThanOrEqual(Dinero({ amount: 300 }))
// returns true
Dinero({ amount: 5000, precision: 3 }).lessThanOrEqual(Dinero({ amount: 800 }))
// returns true
Dinero({ amount: 5000, precision: 3 }).lessThanOrEqual(Dinero({ amount: 500 }))
// returns false
Dinero({ amount: 800 }).lessThanOrEqual(Dinero({ amount: 5000, precision: 3 }))

(inner) greaterThan(comparator) → {Boolean}

Checks whether the value represented by this object is greater than the other.

Parameters:
Name Type Description
comparator Dinero

The Dinero object to compare to.

Source:
Throws:

If comparator has a different currency.

Type
TypeError
Examples
// returns false
Dinero({ amount: 500 }).greaterThan(Dinero({ amount: 800 }))
// returns true
Dinero({ amount: 800 }).greaterThan(Dinero({ amount: 500 }))
// returns true
Dinero({ amount: 800 }).greaterThan(Dinero({ amount: 5000, precision: 3 }))
// returns false
Dinero({ amount: 5000, precision: 3 }).greaterThan(Dinero({ amount: 800 }))

(inner) greaterThanOrEqual(comparator) → {Boolean}

Checks whether the value represented by this object is greater than or equal to the other.

Parameters:
Name Type Description
comparator Dinero

The Dinero object to compare to.

Source:
Throws:

If comparator has a different currency.

Type
TypeError
Examples
// returns true
Dinero({ amount: 500 }).greaterThanOrEqual(Dinero({ amount: 300 }))
// returns true
Dinero({ amount: 500 }).greaterThanOrEqual(Dinero({ amount: 500 }))
// returns false
Dinero({ amount: 500 }).greaterThanOrEqual(Dinero({ amount: 800 }))
// returns true
Dinero({ amount: 800 }).greaterThanOrEqual(Dinero({ amount: 5000, precision: 3 }))
// returns true
Dinero({ amount: 500 }).greaterThanOrEqual(Dinero({ amount: 5000, precision: 3 }))
// returns false
Dinero({ amount: 5000, precision: 3 }).greaterThanOrEqual(Dinero({ amount: 800 }))

(inner) isZero() → {Boolean}

Checks if the value represented by this object is zero.

Source:
Examples
// returns true
Dinero({ amount: 0 }).isZero()
// returns false
Dinero({ amount: 100 }).isZero()

(inner) isPositive() → {Boolean}

Checks if the value represented by this object is positive.

Source:
Examples
// returns false
Dinero({ amount: -10 }).isPositive()
// returns true
Dinero({ amount: 10 }).isPositive()
// returns true
Dinero({ amount: 0 }).isPositive()

(inner) isNegative() → {Boolean}

Checks if the value represented by this object is negative.

Source:
Examples
// returns true
Dinero({ amount: -10 }).isNegative()
// returns false
Dinero({ amount: 10 }).isNegative()
// returns false
Dinero({ amount: 0 }).isNegative()

(inner) hasSubUnits() → {Boolean}

Checks if this has minor currency units. Deprecates hasCents.

Source:
Examples
// returns false
Dinero({ amount: 1100 }).hasSubUnits()
// returns true
Dinero({ amount: 1150 }).hasSubUnits()

(inner) hasCents() → {Boolean}

Checks if this has minor currency units.

Deprecated:
  • since version 1.4.0, will be removed in 2.0.0 Use hasSubUnits instead.

Source:
Examples
// returns false
Dinero({ amount: 1100 }).hasCents()
// returns true
Dinero({ amount: 1150 }).hasCents()

(inner) hasSameCurrency(comparator) → {Boolean}

Checks whether the currency represented by this object equals to the other.

Parameters:
Name Type Description
comparator Dinero

The Dinero object to compare to.

Source:
Examples
// returns true
Dinero({ amount: 2000, currency: 'EUR' }).hasSameCurrency(Dinero({ amount: 1000, currency: 'EUR' }))
// returns false
Dinero({ amount: 1000, currency: 'EUR' }).hasSameCurrency(Dinero({ amount: 1000, currency: 'USD' }))

(inner) hasSameAmount(comparator) → {Boolean}

Checks whether the amount represented by this object equals to the other.

Parameters:
Name Type Description
comparator Dinero

The Dinero object to compare to.

Source:
Examples
// returns true
Dinero({ amount: 1000, currency: 'EUR' }).hasSameAmount(Dinero({ amount: 1000 }))
// returns false
Dinero({ amount: 2000, currency: 'EUR' }).hasSameAmount(Dinero({ amount: 1000, currency: 'EUR' }))
// returns true
Dinero({ amount: 1000, currency: 'EUR', precision: 2 }).hasSameAmount(Dinero({ amount: 10000, precision: 3 }))
// returns false
Dinero({ amount: 10000, currency: 'EUR', precision: 2 }).hasSameAmount(Dinero({ amount: 10000, precision: 3 }))

(inner) toFormat(formatopt, roundingModeopt) → {String}

Returns this object formatted as a string.

The format is a mask which defines how the output string will be formatted. It defines whether to display a currency, in what format, how many fraction digits to display and whether to use grouping separators. The output is formatted according to the applying locale.

Object Format String
Dinero({ amount: 500050 }) '$0,0.00' $5,000.50
Dinero({ amount: 500050 }) '$0,0' $5,001
Dinero({ amount: 500050 }) '$0' $5001
Dinero({ amount: 500050 }) '$0.0' $5000.5
Dinero({ amount: 500050 }) 'USD0,0.0' USD5,000.5
Dinero({ amount: 500050 }) '0,0.0 dollar' 5,000.5 dollars

Don't try to substitute the $ sign or the USD code with your target currency, nor adapt the format string to the exact format you want. The format is a mask which defines a pattern and returns a valid, localized currency string. If you want to display the object in a custom way, either use getAmount, toUnit or toRoundedUnit and manipulate the output string as you wish.

toFormat wraps around Number.prototype.toLocaleString. For that reason, format will vary depending on how it's implemented in the end user's environment.

You can also use toLocaleString directly: Dinero().toRoundedUnit(digits, roundingMode).toLocaleString(locale, options).

By default, amounts are rounded using the half away from zero rule (commercial rounding). You can also specify a different roundingMode to better fit your needs.

Parameters:
Name Type Attributes Default Description
format String <optional>
'$0,0.00'

The format mask to format to.

roundingMode String <optional>
'HALF_AWAY_FROM_ZERO'

The rounding mode to use: 'HALF_ODD', 'HALF_EVEN', 'HALF_UP', 'HALF_DOWN', 'HALF_TOWARDS_ZERO' or 'HALF_AWAY_FROM_ZERO'.

Source:
Examples
// returns $2,000
Dinero({ amount: 200000 }).toFormat('$0,0')
// returns €50.5
Dinero({ amount: 5050, currency: 'EUR' }).toFormat('$0,0.0')
// returns 100 euros
Dinero({ amount: 10000, currency: 'EUR' }).setLocale('fr-FR').toFormat('0,0 dollar')
// returns 2000
Dinero({ amount: 200000, currency: 'EUR' }).toFormat()
// returns $10
Dinero({ amount: 1050 }).toFormat('$0', 'HALF_EVEN')

(inner) toUnit() → {Number}

Returns the amount represented by this object in units.

Source:
Examples
// returns 10.5
Dinero({ amount: 1050 }).toUnit()
// returns 10.545
Dinero({ amount: 10545, precision: 3 }).toUnit()

(inner) toRoundedUnit(digits, roundingModeopt) → {Number}

Returns the amount represented by this object in rounded units.

By default, the method uses the half away from zero rule (commercial rounding). You can also specify a different roundingMode to better fit your needs.

Parameters:
Name Type Attributes Default Description
digits Number

The number of fraction digits to round to.

roundingMode String <optional>
'HALF_AWAY_FROM_ZERO'

The rounding mode to use: 'HALF_ODD', 'HALF_EVEN', 'HALF_UP', 'HALF_DOWN', 'HALF_TOWARDS_ZERO' or 'HALF_AWAY_FROM_ZERO'.

Source:
Examples
// returns 10.6
Dinero({ amount: 1055 }).toRoundedUnit(1)
// returns 10
Dinero({ amount: 1050 }).toRoundedUnit(0, 'HALF_EVEN')

(inner) toObject() → {Object}

Return the object's data as an object literal.

Source:
Example
// returns { amount: 500, currency: 'EUR', precision: 2 }
Dinero({ amount: 500, currency: 'EUR', precision: 2 }).toObject()

(static) normalizePrecision(objects) → {Array.<Dinero>}

Returns an array of Dinero objects, normalized to the same precision (the highest).

Parameters:
Name Type Description
objects Array.<Dinero>

An array of Dinero objects

Source:
Example
// returns an array of Dinero objects
// both with a precision of 3
// and an amount of 1000
Dinero.normalizePrecision([
  Dinero({ amount: 100, precision: 2 }),
  Dinero({ amount: 1000, precision: 3 })
])