Open kotaroyamazaki opened 1 year ago
I am having the same issue:
origPrice := float64(18.99)
cents := money.NewFromFloat(origPrice, money.USD)
int(cents.Amount()) => this is 1898
Floats are the issue:
@kotaroyamazaki https://go.dev/play/p/oNzxYVoZK4K
@kylebragger https://go.dev/play/p/j9lwBeNUllb
The idea of this package is to use the smallest unit of the currency, so cent in case of dollars and use that as int. So 136.98 becomes 13698.
This is know as Fowler's Money pattern which is what this package implements. It is designed to overcome floating point issues like the one you described.
I was starting with a string in the form of a float, so my solution was to strip non-numeric characters with regex, parse the remaining string as an int, and pass that int to the money
package, like this:
nonNumeric := regexp.MustCompile(`\D*`)
amountStr := "18.99"
numStr := nonNumeric.ReplaceAllString(amountStr, "")
num, _ := strconv.ParseInt(numStr, 10, 32) // handle err
val := money.New(num, currency)
We encountered the same issue, and decided to switch to https://github.com/shopspring/decimal.
amount := 73708.43
// money
moneyAmount := money.NewFromFloat(amount, "EUR")
fmt.Println("money cents", moneyAmount.Amount()) // decimal 7370843
// decimal
decimalAccount := decimal.NewFromFloat(amount)
decimalSubunits := decimal.New(100, 0)
decimalAmountCents := decimalAccount.Mul(decimalSubunits)
fmt.Println("decimal cents", decimalAmountCents.IntPart()) // money 7370842
@SkipHendriks @Rhymond Hey, just a thought, if floats are causing trouble, why was the NewFromFloat method included in the library to begin with? Maybe it's worth mentioning in the README so other people don't stumble over this again?
e,g) Display amount of SDG
input 136.98 expected: $136.98 actual: $136.97
seeing is believing ↓ https://go.dev/play/p/l4imxLkT70u