NumberFormatException on European Versions of Android? - java

I have an app which runs the following two lines of code upon starting:
DecimalFormat decim = new DecimalFormat("#.00");
return Double.parseDouble(decim.format(totalNumberOfCredits));
When I start the app on my American phone, the value of decim.format(totalNumberOfCredits) is .00.
However, in my Google Play Developer Console, I have a dozen crashes, all of which look like this:
Caused by: java.lang.NumberFormatException: Invalid double: ",00"
at java.lang.StringToReal.invalidReal(StringToReal.java:63)
at java.lang.StringToReal.parseDouble(StringToReal.java:269)
at java.lang.Double.parseDouble(Double.java:295)
Is it really possible that DecimalFormat is producing a comma version of the decimal on European phones?

Is it really possible that DecimalFormat is producing a comma version of the decimal on European phones?
Yes, absolutely. That's what it's meant to do, after all:
Creates a DecimalFormat using the given pattern and the symbols for the default locale. This is a convenient way to obtain a DecimalFormat when internationalization is not the main concern.
To obtain standard formats for a given locale, use the factory methods on NumberFormat such as getNumberInstance. These factories will return the most appropriate sub-class of NumberFormat for a given locale.
Note that this isn't a matter of a "European version of Android" - it's just a matter of using Android in a context where the default locale uses , as the decimal separator.
If you want to use the symbols for a particular locale, but using a specific pattern, you could use:
DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(Locale.US);
DecimalFormat format = new DecimalFormat("#.00", symbols);
Having said that, it's not at all clear what you're trying to do in the first place - why would you format and then parse a number? You should almost always avoid string conversions when you don't really need them. Why not just convert it directly? (We don't know what totalNumberOfCredits is, which doesn't help.)

public double getTwoPointDecimal(double value) {
DecimalFormatSymbols symbols = new DecimalFormatSymbols(Locale.US);
return Double.parseDouble(new DecimalFormat("##.##", symbols).format(value));
}
try it, its help me in my project

double unit = Float.parseFloat(String);
DecimalFormat decimal = new DecimalFormat("##.###").format(unit);
try this it help me in my project

Related

String format and locale problems - Android

When I perform a truncate using:
label.setText(String.format("%.2f", 1.2975118));
// 1,30
I get comma(,) instead of point(.) and this causes my program crash since I need to perform operation on float numbers.
How I can truncate a float and .setText with a point instead of comma?
Please be careful as String.format depend on your current Local configuration, you may not get a dot as a separator.
Prefer using String.format(java.util.Locale.US,"%.2f", floatValue);
Locale independent :
double d = 1.234567;
DecimalFormat df = new DecimalFormat("#.##");
System.out.print(df.format(d));

Currency symbol with another number format

I was wondering if there was an elegant way to set the currency format of a number in one way but keep the actual number formatting in another. It is Java. Essentially I am doing this
NumberFormat format = NumberFormat.getCurrencyInstance(locale);
This is largely fine except I am writing a system for UK based users and my users are upset that when showing (for example) euros the number is formatted as europeans would use it. So € 500,000 as a UK person would write it is displaying as € 500.000 (i.e. swap , for .). I was going to swap locale for locale.UK but then I will have the wrong currency symbol!
I have a couple of dirty fixes for this but I wondered if there was an elegant way to keep the currency symbol of the locale with the local locale (locale.UK) number format.
Different currencies can also place the currency symbol before or after the string, or have a different number of decimal places (if any). It is not really clear from your question how you want to handle those cases, but assuming you want to preserve those differences, try this.
Instead of just swapping in the currency symbol into your local number format, you could start with the foreign format and substitute the decimal format symbols with your local version. Those also include the currency, so you have to swap that back (don't worry, it's a copy).
public static NumberFormat localStyleForeignFormat(Locale locale) {
NumberFormat format = NumberFormat.getCurrencyInstance(locale);
if (format instanceof DecimalFormat) {
DecimalFormat df = (DecimalFormat) format;
// use local/default decimal symbols with original currency symbol
DecimalFormatSymbols dfs = new DecimalFormat().getDecimalFormatSymbols();
dfs.setCurrency(df.getCurrency());
df.setDecimalFormatSymbols(dfs);
}
return format;
}
This way, you also retain the correct positioning of the currency symbol and the number of decimal places. Some examples, for default-Locale Locale.UK
en_GB £500,000.00 £500,000.00
fr_FR 500 000,00 € 500,000.00 €
it_IT € 500.000,00 € 500,000.00
ja_JP ¥500,000 JPY500,000
hi_IN रू ५००,०००.०० INR 500,000.00
If you also want to preserve the foreign currency symbol, instead of the local equivalent, use
localDfs.setCurrencySymbol(df.getCurrency().getSymbol(locale));
You can specify the currency symbol on the NumberFormat with the setCurrency method.
Then simply use the Locale.UK to have the proper grouping separator displayed.
format.setCurrency(Currency.getInstance("EUR"));
Note that for a better handling of the grouping/decimal separator you might want to use a DecimalFormat instead.
DecimalFormatSymbols custom=new DecimalFormatSymbols();
custom.setDecimalSeparator('.');
custom.setGroupingSeparator(',');
DecimalFormat format = DecimalFormat.getInstance();
format.setDecimalFormatSymbols(custom);
format.setCurrency(Currency.getInstance("EUR"));
Then specify the correct pattern, example "€ ###,###.00".

Using Default Locale Separator with NumberFormat, and then rounding number

I have this Java code:
NumberFormat nf = NumberFormat.getNumberInstance(Locale.getDefault());
DecimalFormat df = (DecimalFormat)nf;
newCurr = df.format(dCurr);
Basically, I pass in a number, say 12.344.
I want it rounded two places AND to use the Locale's default separator (either "." or ","). So, for example in some countries in Europe, I want this to be 12,34
So far with code above, I am halfway there. I get 12,344. I can't find where to place the DecimalFormat of ("#.##") so it can be rounded.
In other words, I can I incorporate DecimalFormat df=new DecimalFormat("#.##"); in the above? or do I have to find another way?
Edit: I am thinking I have to do the old way of (100.00 * var)/ 100.00 and pass that in?
The method setMaximumFractionDigit will do the work. See the rest of the available methods: http://docs.oracle.com/javase/7/docs/api/java/text/DecimalFormat.html#setMaximumFractionDigits%28int%29

Formatting numeric values on Android that don't use western digits

On iOS there's a handy function on NSNumber
localizedStringWithStyle:
Which will format a numeric value into a string using digits appropriate to that region (possibly Western, possible Arabic, etc).
I assume in Java on Android a NumberFormat object (or similar) could be configured to do this but I'm not sure how.
So my question. In Android how to you format a number in locale specific digits?
When you instantiate the NumberFormat object, you call it like this:
NumberFormat formatter = NumberFormat.getInstance(Locale.US);
You can pick from the list of static Locales or call NumberFormat.getAvailableLocales() to search for a locale which matches your desired output.
int n;
String.format("%d", n);
That's all. String.format uses the user's locale by default. You can request a particular locale by passing it as the first argument (i.e. before the format string).

Java Decimal Format - as much precision as given

I'm working with DecimalFormat, I want to be able to read and write decimals with as much precision as given (I'm converting to BigDecimal).
Essentially, I want a DecimalFormat which enforces the following pattern "\d+(\.\d+)?" i.e. "at least one digit then, optionally, a decimal separator followed by at least one digit".
I'm struggling to be able to implement this using DecimalFormat, I've tried several patterns but they seem to enforced fixed number of digits.
I'm open to alternative ways of achieving this too.
Edit:
For a little more background, I'm parsing user-supplied data in which decimals could be formatted in any way, and possibly not in the locale format. I'm hoping to let them supply a decimal format string which I can use the parse the data.
Since you noted in a comment that you need Locale support:
Locale locale = //get this from somewhere else
DecimalFormat df = new DecimalFormat();
df.setDecimalFormatSymbols(new DecimalFormatSymbols(locale));
df.setMaximumFractionDigits(Integer.MAX_VALUE);
df.setMinimumFractionDigits(1);
df.setParseBigDecimal(true);
And then parse.
This seems to work fine:
public static void main(String[] args) throws Exception{
DecimalFormat f = new DecimalFormat("0.#");
f.setParseBigDecimal(true);
f.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.US));// if required
System.out.println(f.parse("1.0")); // 1.0
System.out.println(f.parse("1")); // 1
System.out.println(f.parse("1.1")); // 1.1
System.out.println(f.parse("1.123")); // 1.123
System.out.println(f.parse("1.")); // 1
System.out.println(f.parse(".01")); // 0.01
}
Except for the last two that violate your "at least one digit" requirement. You may have to check that separately using a regex if it's really important.

Categories

Resources