19

I am having trouble converting a long (cents) into currency format.

My Code:

long doublePayment = 1099;  //Should equal $10.99
DecimalFormat dFormat = new DecimalFormat();
String formattedString = dFormat.format(doublePayment);
System.out.println(formattedString);

Output: 1,099

I also tried:

long doublePayment = 1099;
NumberFormat n = NumberFormat.getCurrencyInstance(Locale.US); 
String s = n.format(doublePayment);
System.out.println(s);

Since this is cents, the output should be 10.99 or $10.99.

Cant figure out what I am doing wrong. Thanks!!!

A-Sharabiani
  • 17,750
  • 17
  • 113
  • 128
mcd
  • 6,446
  • 9
  • 27
  • 32
  • Oops sorry i dont know why my code didnt go into "CodeFormat" so sorry in advance. – mcd Sep 24 '12 at 07:34
  • Because you need a newline before the code; I fixed it for you. – Jesper Sep 24 '12 at 07:35
  • 2
    FYI, you should use BigDecimal for currency: http://stackoverflow.com/questions/285680/representing-monetary-values-in-java – wulfgarpro Sep 24 '12 at 07:42
  • I know this is a bit old but worth mentioning, if money is being sent in pennies/cents, for display purpose as the user asked, there will be no issues. It's only when making calculations should BigDecimal be used. – RED_ Aug 14 '17 at 16:49

7 Answers7

39

In case You have long to start with, you still should use java.math.BigDecimal.

    long doublePayment = 1099;
    BigDecimal payment = new BigDecimal(doublePayment).movePointLeft(2);
    System.out.println("$" + payment); // produces: $10.99

Let it be once again said out loud: One should never use floating-point variables to store money/currency value.

Lauri
  • 1,859
  • 2
  • 14
  • 17
  • 2
    Except most investment banks use `double`. There is no BigDecimal in C or C++ and yet a lot system use C or C++. ;) – Peter Lawrey Sep 24 '12 at 08:13
  • 3
    I would assume, that banks do use some integer or long form to store cents or fractions of cents, because floatingpoint arithmetic does produce minor errors, which are not allowed in banking systems. – Lauri Sep 24 '12 at 08:29
  • 2
    minor errors are not random errors. You can predict how large they can be and use appropriate rounding. You are right long and int are also used, but these are less common IMHO. I would agree that if you don't know how to use appropriate rounding, then use BigDecimal. – Peter Lawrey Sep 24 '12 at 08:38
  • 1
    While I'm a little late to the party, banks do more testing than almost anyone (pretty sure they're only beat out by things like NASA, the CIA, nuclear power plants maybe?) - if everyone tested their code like banks do, they would find the edge cases that prevent you from using floating point. Your typical web startup won't, and they should definitely use big decimal. (I know a company that processed hundreds of millions of dollars in transactions using floating point until a customer found a report off by a penny and went wtf? Took six months to fix!!) – corsiKa Apr 18 '21 at 00:12
28

To convert cents to dollars you can use

long doublePayment = 1099;
NumberFormat n = NumberFormat.getCurrencyInstance(Locale.US); 
String s = n.format(doublePayment / 100.0);
System.out.println(s);

This will be accurate up to $70 trillion.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • I had tried what I thought was this before but put "x / 100" not even thinking that is different than "x / 100.0" – mcd Sep 24 '12 at 15:11
  • 1
    Yes, An integer divided by an integer gives you an integer. It should give you a double really which you can cast to an integer for integer division, but you need to have at least double/integer or integer/double to get a double. – Peter Lawrey Sep 24 '12 at 15:14
10

Your literal is 1099, which is a thousand and ninety nine, coping with the Java rules for integer literals. According to your JVM locale, this number is represented with 1,099. If you were in Europe, it'd be 1.099. So, it's not an issue with your output, but with your input.

The problem is that you have to represent a fixed point value, but you don't know java.math.BigDecimal and try to fake it. Things will broken when you'll do some computations. Don't do it.

This is what you are supposed to do. Simply (it's far less code, too):

BigDecimal payment = new BigDecimal("10.99");
System.out.println(String.format("$%.2f", payment));

Note how you really initailize a number with a String. Also, String.format() will take care of the current locale, or you could supply the required one via the overloaded method.

Raffaele
  • 20,627
  • 6
  • 47
  • 86
  • 3
    Case might be, that David has long value of cents, then he should use new BigDecimal(doublePayment).movePointLeft(2); – Lauri Sep 24 '12 at 08:09
6

None of these answers take into account that currencies in different locales have different numbers of fractional digits. For example, the Japanese Yen has zero fractional digits while the Jordanian Dinar has three, and then of course, the US Dollar has two. I believe this is a more appropriate solution:

    long payment = 1099L;
    BigDecimal bd = new BigDecimal(payment);

    Locale jpLocale = new Locale("ja", "JP");//Japan

    Currency jpCurrency = Currency.getInstance(jpLocale);
    NumberFormat jpnf = NumberFormat.getCurrencyInstance(jpLocale);
    int jpNumFractionalDigits = jpCurrency.getDefaultFractionDigits();

    BigDecimal jpbd = bd.movePointLeft(jpNumFractionalDigits);


    Locale usLocale = new Locale("en", "US");//United States

    Currency usCurrency = Currency.getInstance(usLocale);
    NumberFormat usnf = NumberFormat.getCurrencyInstance(usLocale);
    int usNumFractionalDigits = usCurrency.getDefaultFractionDigits();

    BigDecimal usbd = bd.movePointLeft(usNumFractionalDigits);



    System.out.println(jpnf.format(jpbd)); //prints ¥1,099
    System.out.println(usnf.format(usbd));//prints $10.99
jwitt98
  • 1,194
  • 1
  • 16
  • 30
  • Furthermore, there have been even more odd money systems. E.g. British pound before decimation in 1971. 1 pound = 20 shillings. 1 shilling = 12 pennies. Hence 1 pound = 240 pennies. And they had also half pennies and quarter pennies. http://projectbritain.com/moneyold.htm – Lauri Feb 05 '21 at 09:02
  • exactly what I'm looking for, thanks and upvoted! – Jeff Jul 25 '23 at 04:46
2

It's not an issue with formatting, it's an issue with input. Divide your input by 100 and you'll be all set.

float payment = 1099 / ((float) 100);
pap
  • 27,064
  • 6
  • 41
  • 46
  • 1
    I would use double rather than float as there will be less representation error. i.e. `double payment = 1099 / 100.0;` – Peter Lawrey Sep 24 '12 at 08:10
0

double doublePayment = 10.99; You need to provide currency like this. NumberFormat will not understand whether you are providing it in cents or $ unless it see decimal point

Amit Deshpande
  • 19,001
  • 4
  • 46
  • 72
0

Use currency formatter:

NumberFormat nf = NumberFormat.getCurrencyInstance(Locale.ENGLISH);
String output = nf.format(value);
System.out.println(value + " " + output);
bigGuy
  • 1,732
  • 1
  • 22
  • 37