10

I am trying to format some numbers as a currency, with commas and 2 decimal places. I've found "github.com/dustin/go-humanize" for the commas but it doesn't allow for specifying the number of decimal places. fmt.Sprintf will do the currency and decimal formatting but not the commas.

for _, fl := range []float64{123456.789, 123456.0, 123456.0100} {
    log.Println(humanize.Commaf(fl))
  }

Results:

123,456.789
123,456
123,456.01

I am expecting:

$123,456.79
$123,456.00
$123,456.01
  • 5
    Never ever ever use float's for storing currency, its such a bad idea ! - See http://play.golang.org/p/TQBd4yJe6B – LenW Jul 20 '15 at 19:49
  • 1
    I have amended my answer to propose an alternative. – VonC Jul 21 '15 at 05:42
  • You can checkout the leekchan/accounting project, using Go1.5 big.Float. See [my edited answer below](http://stackoverflow.com/a/31503800/6309). – VonC Aug 22 '15 at 09:14
  • If you want to get the job done without a third party lib, maybe this solution works for you https://stackoverflow.com/a/71142159/10435604 – Rafael Affonso Feb 16 '22 at 12:55

4 Answers4

11

That would be what the humanize.FormatFloat() does:

// FormatFloat produces a formatted number as string based on the following user-specified criteria:
// * thousands separator
// * decimal separator
// * decimal precision

In your case:

FormatFloat("$#,###.##", afloat)

That being said, as commented by LenW, float (in Go, float64) is not a good fit for currency.
See floating-point-gui.de.

Using a package like go-inf/inf (previously go/dec, used for instance in this currency implementation) is better.

See Dec.go:

// A Dec represents a signed arbitrary-precision decimal.
// It is a combination of a sign, an arbitrary-precision integer coefficient
// value, and a signed fixed-precision exponent value.
// The sign and the coefficient value are handled together as a signed value
// and referred to as the unscaled value.

That type Dec does include a Format() method.


Since July 2015, you now have leekchan/accounting from Kyoung-chan Lee (leekchan) with the same advice:

Please do not use float64 to count money. Floats can have errors when you perform operations on them.
Using big.Rat (< Go 1.5) or big.Float (>= Go 1.5) is highly recommended. (accounting supports float64, but it is just for convenience.)

fmt.Println(ac.FormatMoneyBigFloat(big.NewFloat(123456789.213123))) // "$123,456,789.21"
Community
  • 1
  • 1
VonC
  • 1,129,465
  • 480
  • 4,036
  • 4,755
  • This seems to be more practical than Commaf that the OP mentioned in https://github.com/dustin/go-humanize/issues/18#issuecomment-122625518 – VonC Jul 19 '15 at 17:17
4

There is a good blog post about why you should never use floats to represent currency here - http://engineering.shopspring.com/2015/03/03/decimal/

From their examples you can :

  d := New(-12345, -3)
  println(d.String())

Will give you :

-12.345
LenW
  • 3,014
  • 1
  • 23
  • 25
0
fmt.Printf("%.2f", 12.3456) 

-- output is 12.34

goenning
  • 6,384
  • 1
  • 33
  • 41
Drew
  • 24,556
  • 10
  • 41
  • 75
-6

Try:

ToString("#,##0.00");

or you can try this too:

int number = 1234567890;
Convert.ToDecimal(number).ToString("#,##0.00");

You will get the result like this 1,234,567,890.00.

Farah Nawaz
  • 388
  • 1
  • 2
  • 3