I have a simple EditText, which allows the user to enter a number such as 45.60 (example for American Dollar). I then format this number using the following method:
public String format() {
NumberFormat formatter = NumberFormat.getCurrencyInstance(Locale.getDefault());
return formatter.format(amount.doubleValue());
}
And on my Android phone, the language is set to English (United States) - hence the Locale.getDefault() should return the US locale (and it does).
Now the edit text is correctly updated to: $45.60 (hence formatting the entered number works).
However if I attempt to parse the above String "$45.60" using the following method:
NumberFormat numberFormat = NumberFormat.getInstance(Locale.getDefault());
Number result = numberFormat.parse("$45.60");
It fails with:
java.lang.IllegalArgumentException: Failed to parse amount $45.60 using locale en_US.
If I set my phone to English/ UK, formatting this "45.60" to "£45.60" works correctly (as for US), however parsing "£45.60" fails, just as it does for the above US sample.
However, if I set my phone to German (Germany), formatting "45,60" to "45,60€" works correctly, AND parsing "45,60€" works correctly as well!
The only difference I see between those three currencies: The Euro is appended to the amount, while the Dollar and the Pound are prepended to the amount.
Does anyone have an idea, why the same code works for Euro, but not for Pound and Dollar? Am I missing something?
I also created a unit test, to reproduce the issue:
public void testCreateStringBased() throws Exception {
// For German locale
CurrencyAmount amount = new CurrencyAmount("25,46€", Locale.GERMANY);
assertEquals(25.46, amount.getAsDouble());
// For French locale
amount = new CurrencyAmount("25,46€", Locale.FRANCE);
assertEquals(25.46, amount.getAsDouble());
// For US locale
amount = new CurrencyAmount("$25.46", Locale.US);
assertEquals(25.46, amount.getAsDouble());
// For UK locale
amount = new CurrencyAmount("£25.46", Locale.UK);
assertEquals(25.46, amount.getAsDouble());
}
CurrencyAmount basically wraps the code I posted for parsing currency strings, except that it takes the given locale instead of the default locale. In the above example, the test succeeds for the GERMANY and FRANCE locale but fails for US and UK locale.
Since the answers that have been suggested thus far, did not completely solve the problem, I took a painfully amateurish approach:
String value = "$24,76"
value = value.replace(getCurrencySymbol(locale), StringUtils.EMPTY);
NumberFormat numberFormat = NumberFormat.getInstance(locale);
Number result = numberFormat.parse(value);
So now I simply strip the String value off it's currency symbol... This way I can process everything I want, such as: 45.78 or 45,78 or $45.78 or 45,78€ ....
Whatever the input, the currency symbol is simply stripped and I end up with the plain number. My unittests (see OP) now complete successfully.
If anyone comes up with something better, please let me know.
Try following:
NumberFormat numberFormat = new DecimalFormat("¤#.00", new DecimalFormatSymbols(Locale.UK));
numberFormat.parse("£123.5678");
¤ - currency sign, expects matches with currency symbol by Locale.
other pattern symbols you can see by following link http://docs.oracle.com/javase/6/docs/api/java/text/DecimalFormat.html
Try NumberFormat.getCurrencyInstance().parse() instead of NumberFormat.getInstance().parse().
You must know the locale of the string you wish to parse in order to have a locale-aware parser. The GBP string parse to a numeric ONLY when the NumberFormat's locale is en_GB; there is no such thing as a "universal" parser.
For example, how does the string "12.000" parse? For en-us, the answer is twelve; for de-de, the answer is twelve-thousand.
Always use NumberFormat.getCurrencyInstance( java.util.Locale ) to parse currency amounts.
I'm using below adapted from https://dzone.com/articles/currency-format-validation-and
import java.math.BigDecimal;
import org.apache.commons.validator.routines.*;
BigDecimalValidator currencyValidator = CurrencyValidator.getInstance();
BigDecimal parsedCurrency = currencyValidator.validate(currencyString);
if ( parsedCurrency == null ) {
throw new Exception("Invalid currency format (please also ensure it is UTF-8)");
}
If you need to insure the correct Locale is being used per user look at
Change locale on login
Sorry, but any answer provided are misleading. This is what I would call a BUG in Java.
An example like this explains it better. If I want to print a value in EUR using Locale.US and then I parse it again, it fails unless I specify on the DecimalFormat the currency (EUR). Using dollars, it works:
DecimalFormat df = new DecimalFormat("¤#,##0.00", new DecimalFormatSymbols(Locale.US));
df.setCurrency(Currency.getInstance("EUR"));
BigDecimal value = new BigDecimal("1.23");
String text = df.format(value);
System.out.println(text);
DecimalFormat df2 = new DecimalFormat("¤#,##0.00", new DecimalFormatSymbols(Locale.US));
df2.setParseBigDecimal(true);
BigDecimal parsed = (BigDecimal) df2.parse(text);
BigDecimalAsserts.assertBigDecimalEquals("parsed value is the same of the original", value, parsed);
Related
I tried a lot.But was unable to find a solution.
I have a code for formatting currency. I am using the below code :
NumberFormat numberFormat = NumberFormat.getCurrencyInstance(locale);
Here I am facing an issue.
Consider a case with France locale. In my case, locale can be en_FR and fr_FR.
DecimalFormatSymbols decimalFormats = new DecimalFormatSymbols();
decimalFormats.setCurrencySymbol(currencySymbol);
((DecimalFormat) numberFormat).setDecimalFormatSymbols(decimalFormats);
formattedCurrency = numberFormat.format(Double.valueOf(number));
So if the locale is en_FR, the formattedCurrency value will be € 10.00 and if the locale is fr_FR, the value will be 10.00 €.
So I would like to know the role of language code in this calculation methods.Since en_FR has en, I guess it is by default taking as en_US. So currency symbol coming left of price.
I need to get 10.00 € always if the country is France irrespective of language code. Is there are other way to get the currency formatting based on country, rather than locale?
Just specify the country code , instead of language and country
try to modify like below for you :
String countryCode="FR"; // or use "String countryCode=Locale.getDefault().getCountry();" for system default locale
NumberFormat numberFormat = NumberFormat.getCurrencyInstance(new Locale(countryCode));
Note:
The Locale points to language and not to country specific , above code will work as expected in most scenario where the ISO country code and language code will be the same.
FYI
You can simply specify FRANCE as your Locale, and it will always print it on the right hand side for you.
String formattedCurrency = DecimalFormat.getCurrencyInstance(Locale.FRANCE).format(10.00);
Output:
10,00 €
Edit:
You can get the user's Locale:
Locale currentLocale = Locale.getDefault();
And pass that as the parameter:
String formattedCurrency = DecimalFormat.getCurrencyInstance(currentLocale).format(10.00);
I'm not in France, but for me it will print:
€10.00
Which is correct for Ireland.
2nd Edit:
You can get the country name from the currentLocale above, by getting the display country - but this is stored as a String
String country = currentLocale.getDisplayCountry();
Then convert it to a Locale to use as a parameter
public static Locale getLocaleFromString(String localeString) {
return new Locale(localeString, "");
}
Note: this method is an edited snippet from here
And use it in your formatter then
Locale l = getLocaleFromString(country);
String number = DecimalFormat.getCurrencyInstance(l).format(10.00);
I'm trying to format and parse numbers using GWT's NumberFormat but I would like to use the default format (for ex. that of EN locale) regardless of user selected locale, so users can select any language, but I want the numbers to be displayed and parsed using the default format (for ex. 1,234.89).
Is there a way to do this?
EDIT:
For ex. this code only works in EN locale, in RU I get NumberFormatException
NumberFormat format = NumberFormat.getFormat("#,##0.00");
String n = "1,234.89";
double value = format.parse(n);
//do something with value...
I would need to get a NumberFormat instance for locale EN, but I can't find any method/constructor in the javadocs that can do this.
I you have the number you should use NumberFormat.format, not NumberFormat.parse:
NumberFormat format = NumberFormat.getFormat("#,##0.00");
Double n = 1234.89;
RootPanel.get().add(new HTML("Number: " + format.format(n)));
I you already have a formated String representation of the number, you don't need NumberFormat:
String n = "1,234.89";
RootPanel.get().add(new HTML("Number: " + n));
NumberFormat always parses a localized text. It uses NumberConstants witch are instantiated via deferred binding according to current locale. Unfortunately you can not force using other NumberConstants.
But you know the default grouping separator (,) and decimal separator (.). You can also get the grouping and decimal separator for current locale. So you just need to replace them before parsing.
String n = "1,234.89";
n = n.replace(",", LocaleInfo.getCurrentLocale().getNumberConstants().groupingSeparator());
n = n.replace(".", LocaleInfo.getCurrentLocale().getNumberConstants().decimalSeparator());
double value = format.parse(n);
This should work for any locale.
To format a number with default locale just do the opposite replacements after formatting in current locale.
I have a requirement to show a number value like 123456789.905 in the following format 123,456,789.90. But the comma separation changes depending on the locale selected in the phone (as if with US English selected comma separation is 3 places and if India English is selected it is like 12,34,56,789.90).
How can I format my Double?
So, java.text.NumberFormat doesn't slove the problem, unfortunately, but com.ibm.icu.text.NumberFormat does.
You can use this:
Double d = 123456789.905;
com.ibm.icu.text.NumberFormat format = com.ibm.icu.text.NumberFormat.getNumberInstance(new Locale("en", "in"));
format.setMinimumFractionDigits(2);
format.setMaximumFractionDigits(2);
System.out.println(format.format(d));
This outputs: 12,34,56,789.90.
For the generic case, use java.text.NumberFormat:
NumberFormat nf = NumberFormat.getInstance();
String formatted = nf.format(yourDoubleValue);
By default getInstance() returns a NumberFormat that is configured as appropriate for the current Locale. You can change the configuration yourself, too.
The "comma separation" is called "grouping".
For the specific case of grouping in an Indian currency format, see: Displaying Currency in Indian Numbering Format
Try this one:
try {
Locale l = Locale.getDefault();
NumberFormat nf = NumberFormat.getInstance(l);
String formato = NumberFormat.getInstance().format(your_data);
} catch (Exception e) {
e.printStackTrace();}
Use NumberFormat, which helps you to format and parse numbers for any locale.
Your code can be completely independent of the locale conventions for
decimal points, thousands-separators, or even the particular decimal
digits used, or whether the number format is even decimal.
Locale fmtLocale = Locale.getDefault();
NumberFormat formatter = NumberFormat.getInstance(fmtLocale);
formatter.format(your_number);
Hm, I have not found for any locale in NumberFormat.getAvailableLocales() a format with only two digits between grouping signs (for example for new Locale("en", "IN")). So I think you have to use DecimalFormat-pattern like this:
DecimalFormat df = new DecimalFormat("##,##,##,##,##.###");
System.out.println(df.format(123456789.905));
// Output: 1.23.45.67.89,905
It is not exactly the same since DecimalFormat is not able to have varying counts of grouping sizes, but maybe this is acceptable for you.
NumberFormat nf = NumberFormat.getInstance(Locale.getDefault());
double value = nf.parse(iValue).doubleValue();
I'm trying save a values' input field to a BigDecimal. Which already works.
But it produces strange results if I enter decimal deliminator that is not of the locale type.
eg:
class Payment {
BigDecimal amount;
}
<p:inputText id="amount" value="#{payment.amount}">
<f:convertNumber locale="en"/>
</p:inputText>
<h:outputText value="#{payment.amount}" />
If I input 10,10
I get: 1,010.00
So the value is taken as 1010
How could I work around this? What am I doing wrong here?
ty
The commas are not significant when parsing an English-locale number. Java's raw Number types will not retain any formatting information - that's just presentation data.
The logic for the inputText with a NumberConverter goes like this:
NumberFormat formatter = NumberFormat.getNumberInstance(Locale.ENGLISH);
// NumberConverter turns input string into Number
Number number = formatter.parse("10,10");
// Expression language coerces the Number to BigDecimal
BigDecimal decimal = BigDecimal.valueOf(number.doubleValue());
// On output back to browser:
String output = formatter.format(decimal);
System.out.println(output);
The outputText doesn't have a converter, so will merely call toString() on its value binding (the BigDecimal.)
I would expect the results to be 1,010 and 1010.0 respectively.
The behavior of NumberConverter is documented in the javadoc. The rules for EL type coercion are documented in JSR 245:
Coerce A to Number type N
If A is Number, coerce quietly to type N using the following algorithm:
If N is BigDecimal,
If A is a BigInteger, return new BigDecimal(A)
Otherwise, return new BigDecimal(A.doubleValue())
If you want to use the user's browser locale to interpret number formats, remove the locale attribute. If you want a converter to treat both periods and commas as decimal separators, provide your own Converter implementation.
As McDowel clearly stated in the comments - EN locale states that , is a delimiter for thousands and . is a delimiter for decimal point.. if you like to use "," as decimal separator, use a locale that has given format (for example french (fr))
In java i would suggest following:
// Using french locale as it is in form of "123 456 789,012345"
DecimalFormat df = (DecimalFormat)
NumberFormat.getInstance(Locale.FRENCH);
df.setParseBigDecimal(true);
// Replace all dots (due to the french format) so we handle "." as well as ","
hodnota = hodnota.replace('.', ',');
try {
return (BigDecimal) df.parseObject(hodnota);
} catch(ParseException e) {
// TODO: What ever you desire
}
I have this little crazy method that converts BigDecimal values into nice and readable Strings.
private String formatBigDecimal(BigDecimal bd){
DecimalFormat df = new DecimalFormat();
df.setMinimumFractionDigits(3);
df.setMaximumFractionDigits(3);
df.setMinimumIntegerDigits(1);
df.setMaximumIntegerDigits(3);
df.setGroupingSize(20);
return df.format(bd);
}
It however, also produces a so called grouping separator "," that makes all my values come out like this:
xxx,xxx
I do need the separator to be a dot or a point and not a comma.
Does anybody have a clue of how to accomplish this little feat?
I have read this and in particular this to death now but I cannot find a way to get this done.
Am I approaching this the wrong way? Is there a much more elegant way of doing this? Maybe even a solution that accounts for different local number representations, since the comma would be perfect by European standards.
You can change the separator either by setting a locale or using the DecimalFormatSymbols.
If you want the grouping separator to be a point, you can use an european locale:
NumberFormat nf = NumberFormat.getNumberInstance(Locale.GERMAN);
DecimalFormat df = (DecimalFormat)nf;
Alternatively you can use the DecimalFormatSymbols class to change the symbols that appear in the formatted numbers produced by the format method. These symbols include the decimal separator, the grouping separator, the minus sign, and the percent sign, among others:
DecimalFormatSymbols otherSymbols = new DecimalFormatSymbols(currentLocale);
otherSymbols.setDecimalSeparator(',');
otherSymbols.setGroupingSeparator('.');
DecimalFormat df = new DecimalFormat(formatString, otherSymbols);
currentLocale can be obtained from Locale.getDefault() i.e.:
Locale currentLocale = Locale.getDefault();
Europe is quite huge. I'm not sure if they use the same format all over. However this or this answer will be of help.
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);
I.e. use the correct locale.
public String getGermanCurrencyFormat(double value) {
NumberFormat nf = NumberFormat.getNumberInstance(Locale.GERMAN);
nf.setGroupingUsed(true);
return "€ " + nf.format(value);
}
This worked in my case:
DecimalFormat df2 = new DecimalFormat("#.##");
df2.setDecimalFormatSymbols(DecimalFormatSymbols.getInstance(Locale.ENGLISH));
BigDecimal does not seem to respect Locale settings.
Locale.getDefault(); //returns sl_SI
Slovenian locale should have a decimal comma. Guess I had strange misconceptions regarding numbers.
a = new BigDecimal("1,2") //throws exception
a = new BigDecimal("1.2") //is ok
a.toPlainString() // returns "1.2" always
I have edited a part of my message that made no sense since it proved to be due the human error (forgot to commit data and was looking at the wrong thing).
Same as BigDecimal can be said for any Java .toString() functions. I guess that is good in some ways. Serialization for example or debugging. There is an unique string representation.
Also as others mentioned using formatters works OK. Just use formatters, same for the JSF frontend, formatters do the job properly and are aware of the locale.
String money = output.replace(',', '.');
you could just use replace function before you return the string in the method
return df.format(bd).replace(",", ".")
This worked for me...
double num = 10025000;
new DecimalFormat("#,###.##");
DecimalFormat df = (DecimalFormat) DecimalFormat.getInstance(Locale.GERMAN);
System.out.println(df.format(num));