Reference · Decimals and money

money.of

signature
money.of(dec | int | str, str, str=) -> map | error(str)

What it does

An amount of money: a plain map { amount: dec, currency: "USD" }, the amount with exactly the currency's minor units (ISO 4217: USD 2, JPY 0, KWD 3). The amount is a decimal, an int or text as a program writes one ("1234.50"), the currency a code; text as a person writes it in a locale, "1.234,50 €", is for money.parse. An amount with more decimals than the currency has is an error value, unless a rounding mode (those of round) says how to round it. Bad text, an unknown currency and an amount too large to count in minor units are error values too, so text from a form can be checked with ??. The map is plain, so JSON, the database and the browser take it as it is.

Examples

print(money.of(dec("19.99"), "USD"))print(money.of(42, "USD"), money.of("12.50", "EUR"))print(money.of(1250, "JPY"), money.of("1.234", "KWD"))print(money.of("12.345", "USD"), money.of("12.345", "USD", "half_up"))
output
{ amount: 19.99m, currency: "USD" }{ amount: 42.00m, currency: "USD" } { amount: 12.50m, currency: "EUR" }{ amount: 1250m, currency: "JPY" } { amount: 1.234m, currency: "KWD" }err("12.345 has more decimals than USD has (2); give a rounding mode to round it") { amount: 12.35m, currency: "USD" }

Edge cases

print(money.of(dec("1.5"), "JPY"), money.of(dec("2.5"), "JPY", "half_even"), money.of(dec("2.5"), "JPY", "half_up"))print(money.of(" 12.5 ", "usd"), money.of("1e3", "USD"), money.of("abc", "USD"))print(money.of(10, "XYZ"), money.of(10, "XAU"))print(money.of("12.5", "BGN"), money.of(3, " hrk "))print(money.of("92233720368547758.07", "USD").amount, money.of("92233720368547758.08", "USD"))print(money.of("-5.5", "USD"), money.of(0, "EUR"))
output
err("1.5 has more decimals than JPY has (0); give a rounding mode to round it") { amount: 2m, currency: "JPY" } { amount: 3m, currency: "JPY" }{ amount: 12.50m, currency: "USD" } err("not an amount: \"1e3\"") err("not an amount: \"abc\"")err("unknown currency \"XYZ\"") err("unknown currency \"XAU\""){ amount: 12.50m, currency: "BGN" } { amount: 3.00m, currency: "HRK" }92233720368547758.07 err("92233720368547758.08 USD is too large an amount"){ amount: -5.50m, currency: "USD" } { amount: 0.00m, currency: "EUR" }

Errors

What comes from data is an error value: bad text, too many decimals, an unknown currency, too large an amount. What is the program's mistake is a runtime error: a float amount (convert it with dec), a whole float such as 2.0 too, in the browser as on the server, so an amount never goes through a float; a currency that is not text; a rounding mode that is not one of the seven.

let m = money.of("x", "USD")print(is_err(m), m.error)print(money.of("x", "USD") ?? money.zero("USD"))
output
true not an amount: "x"{ amount: 0.00m, currency: "USD" }
this one fails
print(money.of(1.5, "USD"))
output
line 1: `money.of` takes a dec, an int or text, not a float: convert it with dec(x)
this one fails
print(money.of("1", "USD", "nearest"))
output
line 1: `money.of`: unknown rounding "nearest" (one of half_even, half_up, half_down, up, down, ceiling or floor)
in a program
route POST /pay { form: { amount: str } } {    let total = money.of(form.amount, "EUR") ?? reply 400 "not an amount"    charge(total)}

Chaining

In a pipeline the amount comes first, so "19.99" | money.of("USD") reads as text made money, and the result goes on to the other money functions:

print("19.99" | money.of("USD") | money.format)print(["1.50", "x", "2"] | map((t) => money.of(t, "USD")) | filter((m) => !is_err(m)) | len)
output
$19.992

See also

money.from_minor, money.zero, money.round, money.minor_units, money.parse, money.format, dec, is_err

Thread
8Useful? Like it, or add to its thread below.

Thread 0 posts

On money.of(): questions, tips, corrections, and code that uses it.

No posts yet. The first one opens the thread.

    Edit this page on GitHub · every example's output was made by running it (tools/refcheck.mjs) · questions on Discord or r/quillo