How to print formatted BigDecimal values?
Asked Answered
R

7

141

I have a BigDecimal field amount which represents money, and I need to print its value in the browser in a format like $123.00, $15.50, $0.33.

How can I do that?

(The only simple solution which I see myself is getting floatValue from BigDecimal and then using NumberFormat to make two-digit precision for the fraction part).

Rozella answered 3/8, 2010 at 10:57 Comment(6)
I know this is an old question, but I just wanted to point out that it's usually not a good idea to use an arbitrary-precision data type to hold currency values. Currency is fixed-point. It can even be represented by an integer.Digression
@TrippKinetics Except that not all currencies have the same number of fraction digits. Euros have two fraction digits, while Japanese yen have zero. The Maltese lira, until it was replaced by the euro, had three, although the thousands were no longer used in practice. This would mean that, in addition to keeping the value as an integer, you would also need to keep track of the divider. That's going to be a major headache with currency conversions.Ligniform
@Ligniform None of these options are enough to warrant the use of floating point. All of these can be accomplished with fixed point. The number of the digits after the point is largely irrelevant to the problem.Digression
@TrippKinetics Yes, of course, but fixed point is equally unsuited. What you want is a Money type, which has the amount, the currency, and the precision. Then, you only need a ratio (which would probably be a BigDecimal or something similar) to convert from one currency to the other. Within the Money type, you would of course use fixed point. Using fixed point sounds too much like doing your own time calculations for my liking.Ligniform
@Ligniform Your money type ends as an encapsulated fixed-point value on some level. You only have two choices. Fixed-point is essentially the same thing as integer. Floating-point is inherently inexact. You do not want to be inexact when dealing with currency.Digression
@Ligniform And a BigDecimal is not floating-point. It is decidedly fixed-point. float is floating-point. It is rarely a good idea to convert between them.Digression
M
168
public static String currencyFormat(BigDecimal n) {
    return NumberFormat.getCurrencyInstance().format(n);
}

It will use your JVM’s current default Locale to choose your currency symbol. Or you can specify a Locale.

NumberFormat.getInstance(Locale.US)

For more info, see NumberFormat class.

Maroc answered 3/8, 2010 at 11:1 Comment(1)
Is it possible to specify a pattern just as DecimalFormat does?Dost
M
100

To set thousand separator, say 123,456.78 you have to use DecimalFormat:

DecimalFormat df = new DecimalFormat("#,###.00");
System.out.println(df.format(new BigDecimal(123456.75)));
System.out.println(df.format(new BigDecimal(123456.00)));
System.out.println(df.format(new BigDecimal(123456123456.78)));

Here is the result:

123,456.75
123,456.00
123,456,123,456.78

Although I set #,###.00 mask, it successfully formats the longer values too. Note that the comma(,) separator in result depends on your locale. It may be just space( ) for Russian locale.

Maple answered 21/7, 2015 at 5:45 Comment(1)
If you prefer zero to be displayed as 0.00 (instead of .00), use the pattern "#,##0.00" instead.Garman
T
44

Another way which could make sense for the given situation is

BigDecimal newBD = oldBD.setScale(2);

I just say this because in some cases when it comes to money going beyond 2 decimal places does not make sense. Taking this a step further, this could lead to

String displayString = oldBD.setScale(2).toPlainString();

but I merely wanted to highlight the setScale method (which can also take a second rounding mode argument to control how that last decimal place is handled. In some situations, Java forces you to specify this rounding method).

Thereat answered 20/12, 2011 at 21:2 Comment(1)
I think java enforces it in all cases, but the point is that some number comply with the scale, like 1.55, some don't like 1.555 and need a hit on how to round the x.xx5 part.Claudication
B
22
 BigDecimal pi = new BigDecimal(3.14);
 BigDecimal pi4 = new BigDecimal(12.56);

 System.out.printf("%.2f",pi);

// prints 3.14

System.out.printf("%.0f",pi4);

// prints 13

Barbey answered 20/9, 2017 at 3:46 Comment(0)
H
14

Similar to answer by @Jeff_Alieffson, but not relying on default Locale:

Use DecimalFormatSymbols for explicit locale:

DecimalFormatSymbols decimalFormatSymbols  = DecimalFormatSymbols.getInstance(new Locale("ru", "RU"));

Or explicit separator symbols:

DecimalFormatSymbols decimalFormatSymbols = new DecimalFormatSymbols();
decimalFormatSymbols.setDecimalSeparator('.');
decimalFormatSymbols.setGroupingSeparator(' ');

Then:

new DecimalFormat("#,##0.00", decimalFormatSymbols).format(new BigDecimal("12345"));

Result:

12 345.00
Heavierthanair answered 6/5, 2019 at 11:54 Comment(0)
O
1
BigDecimal("19.0001").setScale(2, BigDecimal.RoundingMode.DOWN)
Odele answered 26/6, 2016 at 6:51 Comment(3)
Should be BigDecimal(19.001).setScale(2, BigDecimal.ROUND_HALF_UP).toString()Migrant
setScale is deprecatedArmyn
You should never instance BigDecimal from float or double. You should use a String: new BigDecimal( "19.0001" )Fencer
O
1

I know this question is very old, but I was making similar thing in my kotlin app recently. So here is an example if anyone needs it:

val dfs = DecimalFormatSymbols.getInstance(Locale.getDefault())
val bigD = BigDecimal("1e+30")
val formattedBigD = DecimalFormat("#,##0.#",dfs).format(bigD)

Result displaying $formattedBigD:

1,000,000,000,000,000,000,000,000,000,000
Ovariotomy answered 27/1, 2021 at 16:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.