How to format decimals in a currency format?
Asked Answered
S

22

110

Is there a way to format a decimal as following:

100   -> "100"  
100.1 -> "100.10"

If it is a round number, omit the decimal part. Otherwise format with two decimal places.

Sato answered 4/3, 2010 at 12:33 Comment(0)
P
51

I doubt it. The problem is that 100 is never 100 if it's a float, it's normally 99.9999999999 or 100.0000001 or something like that.

If you do want to format it that way, you have to define an epsilon, that is, a maximum distance from an integer number, and use integer formatting if the difference is smaller, and a float otherwise.

Something like this would do the trick:

public String formatDecimal(float number) {
  float epsilon = 0.004f; // 4 tenths of a cent
  if (Math.abs(Math.round(number) - number) < epsilon) {
     return String.format("%10.0f", number); // sdb
  } else {
     return String.format("%10.2f", number); // dj_segfault
  }
}
Plast answered 4/3, 2010 at 12:51 Comment(2)
Minor nitpick: a float can be exactly 100, with bit pattern 0x42c80000.Ardor
Yes, as was stated by Karol S, many numbers CAN be exactly matched by floats. Just not ALL numbers. 100 is one number that can be represented, you should just account for numbers that can't be.Davenport
P
182

I'd recommend using the java.text package:

double money = 100.1;
NumberFormat formatter = NumberFormat.getCurrencyInstance();
String moneyString = formatter.format(money);
System.out.println(moneyString);

This has the added benefit of being locale specific.

But, if you must, truncate the String you get back if it's a whole dollar:

if (moneyString.endsWith(".00")) {
    int centsIndex = moneyString.lastIndexOf(".00");
    if (centsIndex != -1) {
        moneyString = moneyString.substring(1, centsIndex);
    }
}
Propene answered 4/3, 2010 at 13:7 Comment(11)
You should never use a double to represent currencies. Either convert to longs and manage the decimal point yourself or use BigDecimal with a formatter. joda-money.sourceforge.net should be a nice library to use once it's done.Garble
I agree re: double != money, but that's not how the question was posed.Propene
What do you mean thats how currencies work? I can say something costs $1 not $1.00....there are different way of displaying currencies (other than the default) and this questions asks how to omit the decimal part if its a whole number.Sato
It's a rendering issue. Put the logic in your UI to accept the currency as a String and truncate the decimal and cents if it's an exact dollar.Propene
Can I use the following: if (!dolVal.endsWith(".##")) to ensure if there is NO number or decimal to attach the 00?Eckhart
also for ints only developer.android.com/reference/java/text/…Pair
This solution won't work if the locale has the decimal separator as a comma. E.g Spain: €1.234,00 (1,234.00 in U.S. Format)Sato
Have you tried it? The NumberFormatter is Locale-aware. It should know about your comma separator.Propene
@Propene DD is right - if the string ends ",00" (note the comma) instead of ".00" then the lastIndexOf check won't work. It will also fail for locales which have the currency symbol after the number, like French (e.g., "1000,00 €").Furze
Agreed - that's why I recommended using Locale when I wrote this 5.5 years ago. "But, if you must,...." is the key phrase.Propene
Why are you trimming the currency symbol only when it's a whole dollar? And why call lastIndexOf() altogether? Just get moneyString.substring(1, moneyString.length() - 3).Conspecific
A
157
double amount =200.0;
Locale locale = new Locale("en", "US");      
NumberFormat currencyFormatter = NumberFormat.getCurrencyInstance(locale);
System.out.println(currencyFormatter.format(amount));

or

double amount =200.0;
System.out.println(NumberFormat.getCurrencyInstance(new Locale("en", "US"))
        .format(amount));

The best way to display currency

Output

$200.00

Note: Locale constructors have been deprecated. See Obtaining a Locale for other options.

have

So, since Locale constructors are deprecated, we can use Locale.Builder() to construct a Locale object.

    double amount =200.0;
    Locale locale = new Locale.Builder().setLanguage("en").setRegion("US").build();
    NumberFormat currencyFormatter = NumberFormat.getCurrencyInstance(locale);
    System.out.println(currencyFormatter.format(amount));

or

    double amount =200.0;
    System.out.println(NumberFormat.getCurrencyInstance(new Locale.Builder().setLanguage("en").setRegion("US").build()).format(amount));

Output

$200.00

If you don't want to use sign use this method

double amount = 200;
DecimalFormat twoPlaces = new DecimalFormat("0.00");
System.out.println(twoPlaces.format(amount));

200.00

This also can be use (With the thousand separator )

double amount = 2000000;    
System.out.println(String.format("%,.2f", amount));          

2,000,000.00

Amendment answered 20/8, 2014 at 19:20 Comment(3)
It doesn't look like "currency" is referenced or used after it is declared... is there a side effect of line 3? Or some reason you included it?Riverside
Read more about [Class Locale][1] [1]: docs.oracle.com/javase/7/docs/api/java/util/…Amendment
fyi. Locale is Threadsafe, NumberFormat is notMckenziemckeon
P
51

I doubt it. The problem is that 100 is never 100 if it's a float, it's normally 99.9999999999 or 100.0000001 or something like that.

If you do want to format it that way, you have to define an epsilon, that is, a maximum distance from an integer number, and use integer formatting if the difference is smaller, and a float otherwise.

Something like this would do the trick:

public String formatDecimal(float number) {
  float epsilon = 0.004f; // 4 tenths of a cent
  if (Math.abs(Math.round(number) - number) < epsilon) {
     return String.format("%10.0f", number); // sdb
  } else {
     return String.format("%10.2f", number); // dj_segfault
  }
}
Plast answered 4/3, 2010 at 12:51 Comment(2)
Minor nitpick: a float can be exactly 100, with bit pattern 0x42c80000.Ardor
Yes, as was stated by Karol S, many numbers CAN be exactly matched by floats. Just not ALL numbers. 100 is one number that can be represented, you should just account for numbers that can't be.Davenport
E
22

I did not find any good solution after google search, just post my solution for other to reference. use priceToString to format money.

public static String priceWithDecimal (Double price) {
    DecimalFormat formatter = new DecimalFormat("###,###,###.00");
    return formatter.format(price);
}

public static String priceWithoutDecimal (Double price) {
    DecimalFormat formatter = new DecimalFormat("###,###,###.##");
    return formatter.format(price);
}

public static String priceToString(Double price) {
    String toShow = priceWithoutDecimal(price);
    if (toShow.indexOf(".") > 0) {
        return priceWithDecimal(price);
    } else {
        return priceWithoutDecimal(price);
    }
}
Endospore answered 13/10, 2012 at 17:7 Comment(4)
He never said its a better one. HE just posted his solution so others can refer from it. Least you could say is a thanks.Nara
What if I want to display the price in Indian format. Without decimals. Format --> ##,##,###Dumfries
At priceWithDecimal(Double) method, try changing mask "###,###,###.00" to "###,###,##0.00" to show "0,00" when value is "0"Photoengraving
what will the vice-versa to converted the formatted currency to Double againHilaria
H
10
NumberFormat currency = NumberFormat.getCurrencyInstance();
String myCurrency = currency.format(123.5);
System.out.println(myCurrency);

output:

$123.50

If you want to change the currency,

NumberFormat currency = NumberFormat.getCurrencyInstance(Locale.CHINA);
String myCurrency = currency.format(123.5);
System.out.println(myCurrency);

output:

¥123.50
Harter answered 21/2, 2020 at 23:52 Comment(1)
how to get the reverse. non formatted raw string from the formated one?Yen
F
7

this best way to do that.

    public static String formatCurrency(String amount) {
        DecimalFormat formatter = new DecimalFormat("###,###,##0.00");
        return formatter.format(Double.parseDouble(amount));
    }

100 -> "100.00"
100.1 -> "100.10"

Flail answered 17/10, 2017 at 9:15 Comment(0)
C
6

I'm using this one (using StringUtils from commons-lang):

Double qty = 1.01;
String res = String.format(Locale.GERMANY, "%.2f", qty);
String fmt = StringUtils.removeEnd(res, ",00");

You must only take care of the locale and the corresponding String to chop.

Chloroform answered 7/12, 2012 at 13:29 Comment(0)
A
5

you should do something like this:

public static void main(String[] args) {
    double d1 = 100d;
    double d2 = 100.1d;
    print(d1);
    print(d2);
}

private static void print(double d) {
    String s = null;
    if (Math.round(d) != d) {
        s = String.format("%.2f", d);
    } else {
        s = String.format("%.0f", d);
    }
    System.out.println(s);
}

which prints:

100

100,10

Aestheticism answered 4/3, 2010 at 12:49 Comment(2)
Will Math.round(d) != d work? With floats it often != even if you think it is.Plast
the other way, if d would be 100.000000000000001 then it would still be printed as 100Aestheticism
N
5

I think this is simple and clear for printing a currency:

DecimalFormat df = new DecimalFormat("$###,###.##"); // or pattern "###,###.##$"
System.out.println(df.format(12345.678));

output: $12,345.68

And one of possible solutions for the question:

public static void twoDecimalsOrOmit(double d) {
    System.out.println(new DecimalFormat(d%1 == 0 ? "###.##" : "###.00").format(d));
}

twoDecimalsOrOmit((double) 100);
twoDecimalsOrOmit(100.1);

Output:

100

100.10

Nyeman answered 25/4, 2015 at 5:31 Comment(2)
You've missed the point of the post. If the number is a whole number I don't want to display any decimals.Sato
DD. I'm sorry, and I corrected answer according to the question.Nyeman
S
5

We will usually need to do the inverse, if your json money field is an float, it may come as 3.1 , 3.15 or just 3.

In this case you may need to round it for proper display (and to be able to use a mask on an input field later):

floatvalue = 200.0; // it may be 200, 200.3 or 200.37, BigDecimal will take care
Locale locale = new Locale("en", "US");      
NumberFormat currencyFormatter = NumberFormat.getCurrencyInstance(locale);

BigDecimal valueAsBD = BigDecimal.valueOf(value);
    valueAsBD.setScale(2, BigDecimal.ROUND_HALF_UP); // add digits to match .00 pattern

System.out.println(currencyFormatter.format(amount));
Synge answered 16/12, 2015 at 18:43 Comment(0)
M
4

Yes. You can use java.util.formatter. You can use a formatting string like "%10.2f"

Menorrhagia answered 4/3, 2010 at 12:43 Comment(3)
String.format() is a nice static wrapper for that. Not sure why you use '10', though.Melbamelborn
Given no guidance on the size of the number, I chose 10 Ex Recto. We don't know if this is the price of a candy bar or a car. I believe you can also just do "%.2f" to leave the total size unbounded.Menorrhagia
DD wanted the decimal part omitted, if the amount is a round number of currency units.Randazzo
K
4

I know this is an old question but...

import java.text.*;

public class FormatCurrency
{
    public static void main(String[] args)
    {
        double price = 123.4567;
        DecimalFormat df = new DecimalFormat("#.##");
        System.out.print(df.format(price));
    }
}
Killebrew answered 24/6, 2013 at 15:16 Comment(1)
This doesn't work, it does 100.1 -> "100.1" for example - see #5033904Ballet
G
4

You can just do something like this and pass in the whole number and then the cents after.

String.format("$%,d.%02d",wholeNum,change);
Glassine answered 23/8, 2013 at 1:23 Comment(0)
U
4

I agree with @duffymo that you need to use the java.text.NumberFormat methods for this sort of things. You can actually do all the formatting natively in it without doing any String compares yourself:

private String formatPrice(final double priceAsDouble) 
{
    NumberFormat formatter = NumberFormat.getCurrencyInstance();
    if (Math.round(priceAsDouble * 100) % 100 == 0) {
        formatter.setMaximumFractionDigits(0);
    }
    return formatter.format(priceAsDouble);
}

Couple bits to point out:

  • The whole Math.round(priceAsDouble * 100) % 100 is just working around the inaccuracies of doubles/floats. Basically just checking if we round to the hundreds place (maybe this is a U.S. bias) are there remaining cents.
  • The trick to remove the decimals is the setMaximumFractionDigits() method

Whatever your logic for determining whether or not the decimals should get truncated, setMaximumFractionDigits() should get used.

Unicameral answered 15/10, 2014 at 5:6 Comment(1)
Re your point about the *100 and %100 being US-biased, you could use Math.pow(10, formatter.getMaximumFractionDigits()) instead of a hard-coded 100 to use the correct number for the locale...Furze
S
3

Format from 1000000.2 to 1 000 000,20

private static final DecimalFormat DF = new DecimalFormat();

public static String toCurrency(Double d) {
    if (d == null || "".equals(d) || "NaN".equals(d)) {
        return " - ";
    }
    BigDecimal bd = new BigDecimal(d);
    bd = bd.setScale(2, BigDecimal.ROUND_HALF_UP);
    DecimalFormatSymbols symbols = DF.getDecimalFormatSymbols();
    symbols.setGroupingSeparator(' ');
    String ret = DF.format(bd) + "";
    if (ret.indexOf(",") == -1) {
        ret += ",00";
    }
    if (ret.split(",")[1].length() != 2) {
        ret += "0";
    }
    return ret;
}
Spiraea answered 18/4, 2013 at 9:57 Comment(0)
H
2

If you want work on currencies, you have to use BigDecimal class. The problem is, there's no way to store some float numbers in memory (eg. you can store 5.3456, but not 5.3455), which can effects in bad calculations.

There's an nice article how to cooperate with BigDecimal and currencies:

http://www.javaworld.com/javaworld/jw-06-2001/jw-0601-cents.html

Harned answered 13/10, 2012 at 17:22 Comment(1)
This is completely irrelevant to the question I have asked.Sato
M
2

This post really helped me to finally get what I want. So I just wanted to contribute my code here to help others. Here is my code with some explanation.

The following code:

double moneyWithDecimals = 5.50;
double moneyNoDecimals = 5.00;
System.out.println(jeroensFormat(moneyWithDecimals));
System.out.println(jeroensFormat(moneyNoDecimals));

Will return:

€ 5,-
€ 5,50

The actual jeroensFormat() method:

public String jeroensFormat(double money)//Wants to receive value of type double
{
        NumberFormat dutchFormat = NumberFormat.getCurrencyInstance();
        money = money;
        String twoDecimals = dutchFormat.format(money); //Format to string
        if(tweeDecimalen.matches(".*[.]...[,]00$")){
            String zeroDecimals = twoDecimals.substring(0, twoDecimals.length() -3);
                return zeroDecimals;
        }
        if(twoDecimals.endsWith(",00")){
            String zeroDecimals = String.format("€ %.0f,-", money);
            return zeroDecimals; //Return with ,00 replaced to ,-
        }
        else{ //If endsWith != ,00 the actual twoDecimals string can be returned
            return twoDecimals;
        }
}

The method displayJeroensFormat that calls the method jeroensFormat()

    public void displayJeroensFormat()//@parameter double:
    {
        System.out.println(jeroensFormat(10.5)); //Example for two decimals
        System.out.println(jeroensFormat(10.95)); //Example for two decimals
        System.out.println(jeroensFormat(10.00)); //Example for zero decimals
        System.out.println(jeroensFormat(100.000)); //Example for zero decimals
    }

Will have the following output:

€ 10,50
€ 10,95
€ 10,-
€ 100.000 (In Holland numbers bigger than € 999,- and wit no decimals don't have ,-)

This code uses your current currency. In my case that's Holland so the formatted string for me will be different than for someone in the US.

  • Holland: 999.999,99
  • US: 999,999.99

Just watch the last 3 characters of those numbers. My code has an if statement to check if the last 3 characters are equal to ",00". To use this in the US you might have to change that to ".00" if it doesn't work already.

Marrano answered 30/11, 2013 at 2:7 Comment(0)
L
2

For the people who wants to format the currency, but does not want it to be based on local, we can do this:

val numberFormat = NumberFormat.getCurrencyInstance() // Default local currency
val currency = Currency.getInstance("USD")            // This make the format not locale specific 
numberFormat.setCurrency(currency)

...use the formator as you want...
Labbe answered 2/7, 2019 at 15:5 Comment(0)
A
1

This is what I did, using an integer to represent the amount as cents instead:

public static String format(int moneyInCents) {
    String format;
    Number value;
    if (moneyInCents % 100 == 0) {
        format = "%d";
        value = moneyInCents / 100;
    } else {
        format = "%.2f";
        value = moneyInCents / 100.0;
    }
    return String.format(Locale.US, format, value);
}

The problem with NumberFormat.getCurrencyInstance() is that sometimes you really want $20 to be $20, it just looks better than $20.00.

If anyone finds a better way of doing this, using NumberFormat, I'm all ears.

Acacia answered 7/12, 2012 at 3:0 Comment(0)
L
1

I was crazy enough to write my own function:

This will convert integer to currency format (can be modified for decimals as well):

 String getCurrencyFormat(int v){
        String toReturn = "";
        String s =  String.valueOf(v);
        int length = s.length();
        for(int i = length; i >0 ; --i){
            toReturn += s.charAt(i - 1);
            if((i - length - 1) % 3 == 0 && i != 1) toReturn += ',';
        }
        return "$" + new StringBuilder(toReturn).reverse().toString();
    }
Les answered 15/4, 2018 at 4:36 Comment(0)
P
0
  public static String formatPrice(double value) {
        DecimalFormat formatter;
        if (value<=99999)
          formatter = new DecimalFormat("###,###,##0.00");
        else
            formatter = new DecimalFormat("#,##,##,###.00");

        return formatter.format(value);
    }
Period answered 1/11, 2018 at 13:34 Comment(0)
O
0
double amount = 200.0;

NumberFormat Us = NumberFormat.getCurrencyInstance(Locale.US);
System.out.println(Us.format(amount));

Output:
$200.00

Orpington answered 24/7, 2021 at 18:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.