Convert input of BigDecimal locale dependent? - java

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
}

Related

how to display a string with two decimal places which is carrying currency value in dollar

I'm taking a value from the mobile application which I'm getting in string format something like "$000"(which actually $0.00 ) similarly I want to convert all the value into two decimal place say if I get "$279"(which is in application actually $2.79)
I don't know the correct approach because further in I have compair this value to some other string.
so I want to keep this as String but at the same time I want to put decimal after two place always whatever the number.
I tried to Decimal formatter for money but gave me "object as a number format" exception
sends
String accLastFourDigits, getCurrAmt, currAmt;
getCurrAmt = getDriver().findElement(by("overview.current_balance")).getText();
DecimalFormat money = new DecimalFormat("$0.00");
currAmt = money.format(getCurrAmt);
You could use builtin NumberFormat provided by JAVA to parse different country Currencies as shown below. Also I am dividing the resulting number by 100, so as to satisfy the requirement, that $978 is read as 9.78.
NumberFormat usFormat = NumberFormat.getCurrencyInstance(Locale.US);
String currencyValue = "$100";
try {
System.out.println(usFormat.parse(currencyValue).intValue()/100);
}catch(ParseException e) {
e.printStackTrace();
}
Here, I am setting the currency to US and then parsing a string with dollar sign.
You could also use the format method of NumberFormat to print the currency value in respective currency formats, as shown below
NumberFormat usFormat = NumberFormat.getCurrencyInstance(Locale.US);
String currencyValue = "$100";
try {
Number value = usFormat.parse(currencyValue).intValue()/100;
System.out.println("Number value : " + value);
System.out.printf("In Currency : "+usFormat.format(value));
}catch(ParseException e) {
e.printStackTrace();
}
You have this exception because format method expect number type argument. What you need to do then is to remove all non digits characters from the input string
getCurrAmt = getCurrAmt.replaceAll("[^\\d.]", ""); // please note that replaceAll method has poor performance
and parse it to Integer when calling format method
money.format(Integer.parseInt(getCurrAmt))
As pointed out replaceAll method is not very efficient because it needs to compile Pattern every single time and it's better to use Matcher - you can read about this in this topic:
String replaceAll() vs. Matcher replaceAll() (Performance differences)
How about this?
String inputStr = "$279";
NumberFormat usCurrency = NumberFormat.getCurrencyInstance(Locale.US);
usCurrency.setParseIntegerOnly(true);
long num = (Long)usCurrency.parse(inputStr);
BigDecimal amount = new BigDecimal(num);
amount = amount.scaleByPowerOfTen(-2);
log.info("amount: {}", usCurrency.format(amount));

JFormattedTextField: the formatted text to numbers without spaces

I've got a little problem with JFormattedTextField: I want to hold and retrieve numbers from 1000 to 65535. But when I retriev value (7000) from JFormattedTextField, it have one space like 7 000, and when I parse value to Integer (Integer.parseInt(formattedTextField.getText())), it fail.
java.lang.NumberFormatException: For input string: "7 000"
If I do this with MaskFormatter() and .setMask("#####") it's ok, but I want to do this with NumberFormatter().
How can I setup JFormattedTextField without an additon space?
NumberFormatter nfsoc = new NumberFormatter();
nfsoc.setMaximum(Short.MAX_VALUE*2 - 1);
nfsoc.setMinimum(1);
nfsoc.setAllowsInvalid(false);
formattedTextField = new JFormattedTextField(nfsoc);
formattedTextField.setText("7000");
int socket = Integer.parseInt(formattedTextField.getText())
//java.lang.NumberFormatException: For input string: "7 000"
I expect the output of Integer.parseInt(tfServerSocket.getText()) to be 7000, but the actual output is //java.lang.NumberFormatException: For input string: "7 000"
There are two ways to parse an integer.
NumberFormatter uses a localized NumberFormat, which means it formats and parses according to your locale (country/region).
Integer.parseInt doesn’t care about locale. It always expects numbers in the same format used by Java source code, namely “[±]ddd…” (all ASCII digits, optionally preceded by a sign).
Use the getValue() method of JFormattedTextField. It exists specifically to do what you’re trying to do: obtain the value of the JFormattedTextField.
It also has the advantage that it will allow your code to work in all locales, not just yours. For instance, in the United States, your example value is written 7,000. In Germany, it’s written 7.000.
Number socketValue = (Number) formattedTextField.getValue();
if (socketValue == null) {
JOptionPane.showMessageDialog(
formattedTextField.getTopLevelAncestor(),
"A valid port valid is required.",
"Cannot create connection",
JOptionPane.ERROR_MESSAGE);
return;
}
int socket = socketValue.intValue();
To get rid of addition space:
NumberFormatter nfsoc = new NumberFormatter();
NumberFormat nf = NumberFormat.getIntegerInstance();
nf.setGroupingUsed(false); // It removes any separator
nfsoc.setFormat(nf);
nfsoc.setMaximum(Short.MAX_VALUE*2 - 1);
nfsoc.setMinimum(1);
nfsoc.setAllowsInvalid(false);
I've found out it not a space but special character \p{Zs}
tfServerSocket.getText().replaceAll("\p{Zs}", "") = 7000 // without any addition character!

GWT - formatting numbers in default locale regardless of selected locale

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.

NumberFormat.parse() fails for some currency strings

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);

How can I format a String number to have commas and round?

What is the best way to format the following number that is given to me as a String?
String number = "1000500000.574" //assume my value will always be a String
I want this to be a String with the value: 1,000,500,000.57
How can I format it as such?
You might want to look at the DecimalFormat class; it supports different locales (eg: in some countries that would get formatted as 1.000.500.000,57 instead).
You also need to convert that string into a number, this can be done with:
double amount = Double.parseDouble(number);
Code sample:
String number = "1000500000.574";
double amount = Double.parseDouble(number);
DecimalFormat formatter = new DecimalFormat("#,###.00");
System.out.println(formatter.format(amount));
This can also be accomplished using String.format(), which may be easier and/or more flexible if you are formatting multiple numbers in one string.
String number = "1000500000.574";
Double numParsed = Double.parseDouble(number);
System.out.println(String.format("The input number is: %,.2f", numParsed));
// Or
String numString = String.format("%,.2f", numParsed);
For the format string "%,.2f" - "," means separate digit groups with commas, and ".2" means round to two places after the decimal.
For reference on other formatting options, see https://docs.oracle.com/javase/tutorial/java/data/numberformat.html
Given this is the number one Google result for format number commas java, here's an answer that works for people who are working with whole numbers and don't care about decimals.
String.format("%,d", 2000000)
outputs:
2,000,000
Once you've converted your String to a number, you can use
// format the number for the default locale
NumberFormat.getInstance().format(num)
or
// format the number for a particular locale
NumberFormat.getInstance(locale).format(num)
I've created my own formatting utility. Which is extremely fast at processing the formatting along with giving you many features :)
It supports:
Comma Formatting E.g. 1234567 becomes 1,234,567.
Prefixing with "Thousand(K),Million(M),Billion(B),Trillion(T)".
Precision of 0 through 15.
Precision re-sizing (Means if you want 6 digit precision, but only have 3 available digits it forces it to 3).
Prefix lowering (Means if the prefix you choose is too large it lowers it to a more suitable prefix).
The code can be found here. You call it like this:
public static void main(String[])
{
int settings = ValueFormat.COMMAS | ValueFormat.PRECISION(2) | ValueFormat.MILLIONS;
String formatted = ValueFormat.format(1234567, settings);
}
I should also point out this doesn't handle decimal support, but is very useful for integer values. The above example would show "1.23M" as the output. I could probably add decimal support maybe, but didn't see too much use for it since then I might as well merge this into a BigInteger type of class that handles compressed char[] arrays for math computations.
you can also use the below solution
public static String getRoundOffValue(double value){
DecimalFormat df = new DecimalFormat("##,##,##,##,##,##,##0.00");
return df.format(value);
}
public void convert(int s)
{
System.out.println(NumberFormat.getNumberInstance(Locale.US).format(s));
}
public static void main(String args[])
{
LocalEx n=new LocalEx();
n.convert(10000);
}
You can do the entire conversion in one line, using the following code:
String number = "1000500000.574";
String convertedString = new DecimalFormat("#,###.##").format(Double.parseDouble(number));
The last two # signs in the DecimalFormat constructor can also be 0s. Either way works.
Here is the simplest way to get there:
String number = "10987655.876";
double result = Double.parseDouble(number);
System.out.println(String.format("%,.2f",result));
output:
10,987,655.88
The first answer works very well, but for ZERO / 0 it will format as .00
Hence the format #,##0.00 is working well for me.
Always test different numbers such as 0 / 100 / 2334.30 and negative numbers before deploying to production system.
According to chartGPT
Using DecimalFormat:
DecimalFormat df = new DecimalFormat("#,###.00");
String formattedNumber = df.format(yourNumber);
Using NumberFormat:
NumberFormat nf = NumberFormat.getNumberInstance();
nf.setGroupingUsed(true);
String formattedNumber = nf.format(yourNumber);
Using String.format():
String formattedNumber = String.format("%,.2f", yourNumber);
Note: In all the above examples, "yourNumber" is the double value that you want to format with a comma. The ".2f" in the format string indicates that the decimal places should be rounded to 2 decimal places. You can adjust this value as needed.

Categories