You might want to read this post regarding money libraries (I am the author of one of them).
A couple of basic thoughts on money handling:
-
Unless you are completely in control of the currencies in use and you are very familiar with different currency rules (number of decimal places for example - currencies have any of 0, 1, 2, 3 or four places) use
Decimal
. Using integers means you still need to track decimal places unless you can guarantee all currencies you are using use the same decimal digits. -
Always tag the money amount with its currency. A tagged tuple like
{:AUD, 1234}
is fine, or a struct (which is what libraries usually use) and only ever do operations on the structure. Over time you’ll want to trace how money amounts are transformed and create some guarantees - for example you want to guarantee you don’t add two money amounts together in different currencies. -
Use ISO4217 currency codes so that you can interchange with other apps and users easily and have no confusion on what is meant. Tag your document with the ISO4217 code per your described use case.
-
Always do money calculations at maximum precision and round only when you need a final result. This is how financial apps work, typically at a precision of at least 7 digits. Another reason to use
Decimal
is to allow arbitrary arithmetic calculations. -
Use Banker’s rounding which in the
Decimal
library is:half_even
. -
Be aware that different currencies have rounding rules different for cash amounts than accounting amounts. For example, the Australia dollar cash amount rounds to the nearest 5c whereas the accounting amount rounds to the cent.
-
If you need to serialize money amounts (for example to a database), I recommend using a composite type in Postgres so that the currency is always associated with the amount.