DecimalSeparator issue with String.Format() - java

Please find my code below:
double value = (double)-16325.62015;
System.out.println(String.format("%s", value));//-16325.62015
System.out.println(String.format(new Locale("de", "DE"), "%s", value));//-16325.62015
DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(new Locale("de", "DE"));
System.out.println(dfs.getDecimalSeparator());//,
In the above code, Im getting the wrong decimal separator for German locale.
I have tried the below code also but it produces -16325,6
double value = (double)-16325.62015;
DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(new Locale("de", "DE"));
DecimalFormat df = new DecimalFormat("#.#", dfs );
System.out.println(df.format(value));
is there any alternative way to print the output as -16325,62015
Note: I want to print double value with n number of decimal places for any specific locale
Thanks in advance

You must use %f not %s. When %s is used, Java converts your value to String using String.valueOf which uses the default locale.
double value = (double)-16325.62015;
System.out.println(String.format("%f", value));
System.out.println(String.format(Locale.GERMANY, "%f", value));

Related

java.lang.NumberFormatException while executing in France machine

In below code while parsing the value sometimes i am facing NumberFormat Exception in France machine.
double txPower;
DecimalFormat df = new DecimalFormat("##.##");
txPower = txPower + getDeltaP();
log.info("txpower value is -- "+txPower);
txPower = Double.parseDouble(df.format(txPower));
protected double getDeltaP()
{
return isNewChannelAddition ? apaConfig.deltaPadd : apaConfig.deltaPtune;
}
logs:
txpower value is -- -7.9
java.lang.NumberFormatException: For input string: "-7,9"
I suggest to use the decimal separator configured as default for your locale.
new DecimalFormatSymbols(Locale.getDefault(Locale.Category.FORMA‌​T)).getDecimalSepara‌​tor();
You have to ways to solve your problem :
One, you can use replace(",", ".") like this :
txPower = Double.parseDouble(df.format(txPower).replace(",", "."));
Two, you can use the local for the DecimalFormat :
DecimalFormat df = (DecimalFormat) DecimalFormat.getInstance();
df.applyLocalizedPattern("##.##");
txPower = txPower + getDeltaP();
txPower = Double.parseDouble(df.format(txPower));
You can also call something like this String.format("%.2f", -7.9)
Double.parseDouble doesn't support locale-specific decimal points (see the doc here). Try using your DecimalFormat to parse instead:
txPower = df.parse(df.format(txPower)).doubleValue();
Having said that, I must ask what you are hoping to gain by to turning the double value txPower into a String, parsing the string into a double and putting the result back into txPower?

Format currency in Indian Numbering Format without symbol in java

I already tried some stuff but without success. Is there no simple decimal format for this ?
The first solution does the trick but i do not want to have the symbol
Format format = com.ibm.icu.text.NumberFormat.getCurrencyInstance(new Locale("en", "in"));
System.out.println(format.format(new BigDecimal("1000000")));
The second solution with decimal format gives me trouble when there are numbers after the separator.
DecimalFormatSymbols symbols5 = new DecimalFormatSymbols();
symbols5.setDecimalSeparator('.');
symbols5.setGroupingSeparator(',');
NumberFormat goodNumberFormat5 = new DecimalFormat("##,##,##1", symbols5);
System.out.println("************");
System.out.println("10,00,000.00");
System.out.println("************");
System.out.println(goodNumberFormat5.format(new BigDecimal(1000000)));
System.out.println(goodNumberFormat5.format(new BigDecimal(1000000.00)));
System.out.println();
The output of this is :
? 10,00,000.00
************
10,00,000.00
************
1,00,00,001
1,00,00,001
How could i fix this ?
The excepted output should be 10,00,000.00
With a bit of help from RC i found this solution.
Format format = com.ibm.icu.text.NumberFormat.getCurrencyInstance(new Locale("en", "in"));
String str = format.format(1000000);
String strWithoutSymbol = "";
strWithoutSymbol = str.substring(1,str.length());
System.out.println(strWithoutSymbol);

How to format a Double from 1234567 to 1 234.567 in a safe manner

All in the title.., I'm looking for a safe way to format all Double in this manner, some other examples:
1000 ==> 1.000
1500 ==> 1.500
22000 ==> 22.000
1555005 ==> 1 555.005
I have looked in this link but not helped...
there is a safe way to do that ? THX in advance
You want to print your input number divided by a thousand, using a decimal dot and space as thousand separator. The safe way is to first convert to BigDecimal, scale by 10-3, then print it using DecimalFormat.
final DecimalFormat f = new DecimalFormat("#,###.000");
final DecimalFormatSymbols s = new DecimalFormatSymbols();
s.setGroupingSeparator(' ');
s.setDecimalSeparator('.');
f.setDecimalFormatSymbols(s);
final double input = 1_555_005;
final BigDecimal x = new BigDecimal(input).scaleByPowerOfTen(-3);
System.out.println(f.format(x));
prints
1 555.005
Note that setting grouping/decimal separators explicitly like here is not the orthodox way to do this: normally you would let the Locale setting dictate the number format.
this is taken from here
static public void displayNumber(Locale currentLocale) {
Integer quantity = new Integer(123456);
Double amount = new Double(345987.246);
NumberFormat numberFormatter;
String quantityOut;
String amountOut;
numberFormatter = NumberFormat.getNumberInstance(currentLocale);
quantityOut = numberFormatter.format(quantity);
amountOut = numberFormatter.format(amount);
System.out.println(quantityOut + " " + currentLocale.toString());
System.out.println(amountOut + " " + currentLocale.toString());
}
This example prints the following; it shows how the format of the same number varies with Locale:
123 456 fr_FR
345 987,246 fr_FR
123.456 de_DE
345.987,246 de_DE
123,456 en_US
345,987.246 en_US
Always use the java formatting API. There is a nice tutorial on number formatting at - http://docs.oracle.com/javase/tutorial/i18n/format/decimalFormat.html.
You can get a locale based formatter for French and format:
NumberFormat nf = NumberFormat.getNumberInstance(loc);
DecimalFormat df = (DecimalFormat)nf;
df.applyPattern(pattern);
String output = df.format(value);
System.out.println(pattern + " " + output + " " + loc.toString());
For French the output will be something like this:
###,###.### 123 456,789 fr_FR

need space between currency symbol and amount

I'm trying to print INR format currency like this:
NumberFormat fmt = NumberFormat.getCurrencyInstance();
fmt.setCurrency(Currency.getInstance("INR"));
fmt.format(30382.50);
shows Rs30,382.50, but in India its written as Rs. 30,382.50(see http://www.flipkart.com/)
how to solve without hardcoding for INR?
It's a bit of a hack but in a very similar situation, I used something like this
NumberFormat format = NumberFormat.getCurrencyInstance(new Locale("en", "in"));
String currencySymbol = format.format(0.00).replace("0.00", "");
System.out.println(format.format(30382.50).replace(currencySymbol, currencySymbol + " "));
all the currencies I had to deal with involved two decimal places so i was able to do "0.00" for all of them but if you plan to use something like Japanese Yen, this has to be tweaked. There is a NumberFormat.getCurrency().getSymbol(); but it returns INR instead for Rs. so that cannot be used for getting the currency symbol.
An easier method, kind of workaround.
For my locale, the currency symbol is "R$"
public static String moneyFormatter(double d){
DecimalFormat fmt = (DecimalFormat) NumberFormat.getInstance();
Locale locale = Locale.getDefault();
String symbol = Currency.getInstance(locale).getSymbol(locale);
fmt.setGroupingUsed(true);
fmt.setPositivePrefix(symbol + " ");
fmt.setNegativePrefix("-" + symbol + " ");
fmt.setMinimumFractionDigits(2);
fmt.setMaximumFractionDigits(2);
return fmt.format(d);
}
Input:
moneyFormatter(225.0);
Output:
"R$ 225,00"
See if this works:
DecimalFormat fmt = (DecimalFormat) NumberFormat.getInstance();
fmt.setGroupingUsed(true);
fmt.setPositivePrefix("Rs. ");
fmt.setNegativePrefix("Rs. -");
fmt.setMinimumFractionDigits(2);
fmt.setMaximumFractionDigits(2);
fmt.format(30382.50);
Edit: Fixed the first line.
I dont think you can.
You should take a look at http://site.icu-project.org/
There might be better locale-specific currency formatting provided by icu4j.
I don't see any easy way to do this. Here's what I came up with...
The key to getting the actual currency symbol seems to be passing the destination locale into Currency.getSymbol:
currencyFormat.getCurrency().getSymbol(locale)
Here's some code that seems like it mostly works:
public static String formatPrice(String price, Locale locale, String currencyCode) {
NumberFormat currencyFormat = NumberFormat.getCurrencyInstance(locale);
Currency currency = Currency.getInstance(currencyCode);
currencyFormat.setCurrency(currency);
try {
String formatted = currencyFormat.format(NumberFormat.getNumberInstance().parse(price));
String symbol = currencyFormat.getCurrency().getSymbol(locale);
// Different locales put the symbol on opposite sides of the amount
// http://en.wikipedia.org/wiki/Currency_sign
// If there is already a space (like the fr_FR locale formats things),
// then return this as is, otherwise insert a space on either side
// and trim the result
if (StringUtils.contains(formatted, " " + symbol) || StringUtils.contains(formatted, symbol + " ")) {
return formatted;
} else {
return StringUtils.replaceOnce(formatted, symbol, " " + symbol + " ").trim();
}
} catch (ParseException e) {
// ignore
}
return null;
}
Sorry for Kotlin I came here from android).
As I understood there is no correct solutions for that, so that's why my solution is also hack)
fun formatBalance(
amount: Float,
currencyCode: String,
languageLocale: Locale
): String {
amount can be String as well.
val currencyFormatter: NumberFormat = NumberFormat.getCurrencyInstance(languageLocale)
currencyFormatter.currency = Currency.getInstance(currencyCode)
val formatted = currencyFormatter.format(amount)
formatted will get amount with currency from correct side but without space. (Example: 100$, €100)
val amountFirstSymbol = amount.toString()[0]
val formattedFirstSymbol = formatted[0]
val currencySymbolIsBefore = amountFirstSymbol != formattedFirstSymbol
Then I use this little hack to understand if currency symbol is before amount. So for example amount is 100 then amountFirstSymbol will be "1". And if formatted is 100$ then formattedFirstSymbol also will be "1". That means we can put our currency symbol behind amount but now with space.
val symbol = currencyFormatter.currency?.symbol
return if (currencySymbolIsBefore) "$symbol $amount"
else "$amount $symbol"
Here what I do to add space after currency symbol:
DecimalFormat numberFormat = (DecimalFormat) NumberFormat.getCurrencyInstance(new Locale("id", "ID"));
DecimalFormatSymbols symbol = new DecimalFormatSymbols(new Locale("id", "ID"));
// Add space to currency symbol
symbol.setCurrencySymbol(symbol.getCurrencySymbol() + " ");
numberFormat.setDecimalFormatSymbols(symbol);

Java - Decimal Format.parse to return double value with specified number of decimal places

I want to be able to convert a string to a Double given a number of decimal places in a format string. So "###,##0.000" should give me a Double to 3 decimal places.
Edit - added more info to what happens
The user enters the value in the UI - which is input into a String. The rule is this value is limited to 3 decimal places. The underlying code stores the value in the database which is then used in a calculation. Therefore the trailing decimal places will cause the calculations to be out slightly to what would be expected.
I have the following code:
try {
// output current locale we are running under (this happens to be "nl_BE")
System.out.println( "Current Locale is " + Locale.getDefault().toString() );
// number in Central European Format with a format string specified in UK format
String numberCE = "1,234567"; // 1.234567
String formatUK = "###,##0.000";
// do the format
DecimalFormat formatterUK = new DecimalFormat( formatUK );
Double valCEWithUKFormat = formatterUK.parse( numberCE ).doubleValue();
// I want the number to DPs in the format string!!!
System.out.println( "CE Value " + numberCE + " in UK format (" + formatUK + ") is "
+ valCEWithUKFormat );
} catch( ParseException ex ) {
System.out.println("Cannot parse number");
}
}
The DecimalFormat seems to ignore the format string and gives me the complete string as a Double of 1.234567.
Can DecimalFormat be forced to use the format string when parsing? Am I missing something?
Cheers,
Andez
DecimalFormat is used for two distinct purposes: parsing input and formatting output. If you want to do both, you'll have to use the format object twice.
If you want to take that value and format the output, restricting the number of significant digits, you need to use the format object again. This time it uses your formatting rules to create an output string from a numeric value:
String output = formatterUK.format(valCEWithUKFormat.doubleValue() );
This will give you the output of 1,235
It seems you want this numeric value to be presented in the 1.235 format. To do this, you should format the output using a specific locale (if yours uses a different format).
HOWEVER, I would recommend approaching this problem differently:
String text = "1,234567";
NumberFormat nf_in = NumberFormat.getNumberInstance(Locale.GERMANY);
double val = nf_in.parse(text).doubleValue();
NumberFormat nf_out = NumberFormat.getNumberInstance(Locale.UK);
nf_out.setMaximumFractionDigits(3);
String output = nf_out.format(val);
A few notes:
Input parsing should be kept separate from output formatting. Especially when you start throwing in multiple Locales.
Allow the standard library to do the heavy lifting for determining what a valid input value is for a given Locale. You just need to select an appropriate Locale (I chose GERMANY, but this would obviously work with others). Always use Locales when possible. Don't try to recreate formatting strings.
Always store your input value SEPARATE from any output formatting. IE, if you want to show only three digits in the output, that's fine, but store the whole double value anyway.
Taking on board what you said I have modified my code slightly to cover different locales. The key was taking a value string in a localised format to a Double that is rounded based on the format string.
The format string is always a UK based format with the decimal seperators specified as "." and thousand seperators specified as ",".
I am using the DecimalFormat to initially parse the localised format based on a specified locale. This gives a Double equivalent of the string correctly. I then use a BigDecimal to handle the rounding. I can get the number of decimal places from the DecimalFormat instance and call setScale on the BigDecimal to perform the rounding.
The initial code structure has been modified to allow you to see what happens under different locale circumstances thanks #RD01 for noting importance of other locales.
I now have code as follows:
private void runTests3() {
// output current locale we are running under
System.out.println( "Current Locale is " + Locale.getDefault().toString() );
// number in Central European Format with a format string specified in UK format
String numbersInEuropeanFormatString[] = new String[] { "1.000,234567", "1,2345678", "1.222.333,234567" };
String formatUK = "###,##0.0000";
// output numbers using the german locale
System.out.println("Output numbers using the German locale\n");
for(String num : numbersInEuropeanFormatString ) {
formatNumberAsDouble(num, formatUK, Locale.GERMAN);
}
// output numbers using the UK locale.
// this should return unexpected results as the number is in European format
System.out.println("Output numbers using the UK locale\n");
for(String num : numbersInEuropeanFormatString ) {
formatNumberAsDouble(num, formatUK, Locale.UK);
}
// output numbers using new DecimalFormat( formatUK ) - no locale specified
System.out.println("\n\nOutput numbers using new DecimalFormat( " + formatUK + " )\n");
for(String num : numbersInEuropeanFormatString ) {
formatNumberAsDouble( num, formatUK, null);
}
}
private void formatNumberAsDouble(String value, String format, Locale locale) {
NumberFormat formatter;
int decimalPlaces;
// create the formatter based on the specified locale
if( locale != null ) {
formatter = NumberFormat.getNumberInstance(locale);
// creating the above number format does not take in the format string
// so create a new one that we won't use at all just to get the
// decimal places in it
decimalPlaces = (new DecimalFormat(format)).getMaximumFractionDigits();
} else {
formatter = new DecimalFormat( format );
decimalPlaces = formatter.getMaximumFractionDigits();
}
// get the result as number
Double result = null;
try {
result = formatter.parse( value ).doubleValue();
} catch( ParseException ex ) {
// not bothered at minute
}
// round the Double to the precision specified in the format string
BigDecimal bd = new BigDecimal(result );
Double roundedValue = bd.setScale( decimalPlaces, RoundingMode.HALF_UP ).doubleValue();
// output summary
System.out.println("\tValue = " + value);
System.out.println( locale == null ? "\tLocale not specified" : "\tLocale = " + locale.toString());
System.out.println( format == null || format.length() == 0 ? "\tFormat = Not specified" : "\tFormat = " + format);
System.out.println("\tResult (Double) = " + result);
System.out.println("\tRounded Result (Double) (" + decimalPlaces + "dp) = " + roundedValue);
System.out.println("");
}
This produces the following output:
Current Locale is nl_BE
Output numbers using the German locale
Value = 1.000,234567
Locale = de
Format = ###,##0.0000
Result (Double) = 1000.234567
Rounded Result (Double) (4dp) = 1000.2346
Value = 1,2345678
Locale = de
Format = ###,##0.0000
Result (Double) = 1.2345678
Rounded Result (Double) (4dp) = 1.2346
Value = 1.222.333,234567
Locale = de
Format = ###,##0.0000
Result (Double) = 1222333.234567
Rounded Result (Double) (4dp) = 1222333.2346
Output numbers using the UK locale
Value = 1.000,234567
Locale = en_GB
Format = ###,##0.0000
Result (Double) = 1.0
Rounded Result (Double) (4dp) = 1.0
Value = 1,2345678
Locale = en_GB
Format = ###,##0.0000
Result (Double) = 1.2345678E7
Rounded Result (Double) (4dp) = 1.2345678E7
Value = 1.222.333,234567
Locale = en_GB
Format = ###,##0.0000
Result (Double) = 1.222
Rounded Result (Double) (4dp) = 1.222
Output numbers using new DecimalFormat( ###,##0.0000 )
Value = 1.000,234567
Locale not specified
Format = ###,##0.0000
Result (Double) = 1000.234567
Rounded Result (Double) (4dp) = 1000.2346
Value = 1,2345678
Locale not specified
Format = ###,##0.0000
Result (Double) = 1.2345678
Rounded Result (Double) (4dp) = 1.2346
Value = 1.222.333,234567
Locale not specified
Format = ###,##0.0000
Result (Double) = 1222333.234567
Rounded Result (Double) (4dp) = 1222333.2346
The restriction of decimal places in DecimalFormat is really meant for use in the format() method and doesn't have much effect in the parse() method.
In order to get what you want you need this:
try {
// output current locale we are running under (this happens to be "nl_BE")
System.out.println("Current Locale is " + Locale.getDefault().toString());
// number in Central European Format with a format string specified in UK format
String numberCE = "1,234567"; // 1.234567
String formatUK = "###,##0.000";
// do the format
DecimalFormat formatterUK = new DecimalFormat(formatUK);
Double valCEWithUKFormat = formatterUK.parse(numberCE).doubleValue();
// first convert to UK format string
String numberUK = formatterUK.format(valCEWithUKFormat);
// now parse that string to a double
valCEWithUKFormat = formatterUK.parse(numberUK).doubleValue();
// I want the number to DPs in the format string!!!
System.out.println("CE Value " + numberCE + " in UK format (" + formatUK + ") is " + valCEWithUKFormat);
} catch (ParseException ex) {
System.out.println("Cannot parse number");
}
You first need to get the number as a UK format string and then parse that number, using the UK formatter. That will get you the result you're looking for. NB, this will round the number to 3 decimal places, not truncate.
By the way, I'm slightly surprised that your UK formatter is able to parse the CE format number. You really should be parsing the original number with a CE format parser.
Sure you can. Try running this:
String in = "1,234567";
System.out.println(NumberFormat.getNumberFormat(new Locale("fr", "FR")).parse(in));
System.out.println(NumberFormat.getNumberFormat(new Locale("en", "GB")).parse(in));
Clearly they result in different output, the first reading 1.234567 and the second 1234567. Maybe there's something wrong with your pattern? Anyway the last line there would be the preferred way of getting the UK standard format.

Categories