Format BigDecimal number with commas upto 2 decimal places - java

I want to format BigDecimal numbers with comma and 2 decimal places.
If the decimal values in BigDecimal number are 0 then I want to remove the trailing zeros also.
E.g
Amount is 20000.00 and should be formatted to 20,000
Amount is 167.50 and should be formatted to 167.50
Amount is 20000.75 and should be formatted to 20,000.75
I have used this method-
public static String getNumberFormattedString(BigDecimal bigDecimal) {
if (bigDecimal != null) {
NumberFormat nf = NumberFormat.getInstance(new Locale("en", "IN"));
nf.setMinimumFractionDigits(0);
nf.setMaximumFractionDigits(2);
nf.setGroupingUsed(true);
return nf.format(bigDecimal);
}
return "";
}
This is not returning correct output for big decimal input 167.50.
The formatted output is coming as 167.5

You can use NumberFormat for what you want. Here is the function I use:
public static String GenerateFormat(Double value) {
if (value == null) return "";
NumberFormat nf = NumberFormat.getInstance(new Locale("de", "DE"));
nf.setMinimumFractionDigits(0);
nf.setMaximumFractionDigits(2);
nf.setGroupingUsed(true);
return nf.format(value);
}
In this, you can see that I am providing Locale as a parameter for NumberFormat. Each country has its own number formatting standard, and what you want can be achieved with this locale new Locale("en", "US"). Inside setMaximumFractionDigits you can place how much of fraction digits you want, in your case it is 2.
EDIT
Because of your situation, try this:
public static String GenerateFormat(Double value) {
if (value == null) return "";
NumberFormat nf = NumberFormat.getInstance(new Locale("de", "DE"));
if (value%1 == 0) nf.setMinimumFractionDigits(0);
else nf.setMinimumFractionDigits(2);
nf.setMaximumFractionDigits(2);
nf.setGroupingUsed(true);
return nf.format(value);
}

Related

How to get formatted currency value for India?

For example in USA 1000000 represented as 1,000,000 (1 million) but in India it is represented as 10,00,000 (10 lakh). For this I tried some methods
double value = 1000000d;
NumberFormat numberFormatter = NumberFormat.getNumberInstance(new Locale("en", "IN"));
System.out.println(numberFormatter.format(value));
NumberFormat deci = new DecimalFormat("#,##,##,###.##");
System.out.println("Decimal Format "+deci.format(value));
NumberFormat format = NumberFormat.getNumberInstance();
format.setCurrency(Currency.getInstance("INR"));
format.setMaximumFractionDigits(2);
System.out.println(format.format(value));
But all these methods give an output as 1,000,000 but I require format 10,00,000. What do I need to change here?
Java decimal formatter doesn't support groups From Docs :
The grouping separator is commonly used for thousands, but in some
countries it separates ten-thousands. The grouping size is a constant
number of digits between the grouping characters, such as 3 for
100,000,000 or 4 for 1,0000,0000. If you supply a pattern with
multiple grouping characters, the interval between the last one and
the end of the integer is the one that is used. So "#,##,###,####" ==
"######,####" == "##,####,####".
You will need another library for this. Suggest this :
http://site.icu-project.org/
https://mvnrepository.com/artifact/com.ibm.icu/icu4j/69.1
Code
double value = 1000000d;
NumberFormat numberFormatter = NumberFormat.getNumberInstance(new Locale("en", "IN"));
System.out.println(numberFormatter.format(value));
Output :
10,00,000
public static String fmt(String s)
{
String formatted = "";
if(s.length() > 1){
formatted = s.substring(0,1);
s = s.substring(1);
}
while(s.length() > 3){
formatted += "," + s.substring(0,2);
s = s.substring(2);
}
return formatted + "," + s + ".00";
}

How to convert Double to String with exponential sign

I want to convert a Double to String with exponential signs in it.
For example, Double value is 4.4395749E7 after converting to String it should be 4.4395749E+07 (Same as how it shows in MS Excel).
I have tried double.toString(), but it is converting to 4.4395749E7:
Double doubleValue = 44395749d;
doubleValue.toString();
Expected is 4.4395749E+07, but actual is 4.4395749E7.
you can use String.format(), E is the format code for exponentials
Double doubleValue = 44395749d;
System.out.println(String.format("%E", doubleValue));
You can use DecimalFormat to format your number:
Double value = 44395749d;
DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance();
if (value > 1 || value < -1) {
symbols.setExponentSeparator("E+");
}
DecimalFormat decimalFormat = new DecimalFormat("0E00", symbols);
decimalFormat.setMaximumFractionDigits(Integer.MAX_VALUE);
System.out.println(decimalFormat.format(value));
This uses DecimalFormatSymbols to add the + for the exponent if needed (value > 1 or value < -1). To get all fraction digits use setMaximumFractionDigits(Integer.MAX_VALUE). You can simply change the format if needed.
The result will be 4.4395749E+07.
Bare in mind to set a specific locale if needed:
DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(Locale.ENGLISH)

Is it normal that is not rounding while parsing? NumberFormat

Why does it not round in the parsing process?
NumberFormat format = NumberFormat.getInstance();
System.out.println(format.getMaximumFractionDigits());// 3
System.out.println(format.getRoundingMode());// half even
Double dob = (Double)format.parse("1212.35656");
System.out.println(dob);// output is 1212.35656
The digit counts are only used for formatting. When you parse a number you always get the number that best matches the input, even if it has more digits than the NumberFormat would use to format.
To parse a number from a string and then round to a given number of fractional digits you can use BigDecimal from the java.math package:
BigDecimal bd = BigDecimal("1212.35656");
double dob = bd.setScale(3, RoundingMode.HALF_EVEN).doubleValue();
To obtain what you desire you need to call the formatter metod of the implementation NumberFormat loaded (in your case DecimalFromat); i just added the needed lines at the end and wrapped in a main:
import java.text.NumberFormat;
public class NumberFormatRounding {
public static void main(String[] args) throws Exception{
NumberFormat formatter = NumberFormat.getInstance();
System.out.println(formatter.getMaximumFractionDigits());// 3
System.out.println(formatter.getRoundingMode());// half even
Double dob = (Double) formatter.parse("1212.35656");
System.out.println(dob);// output is 1212.35656
String formattedDob = formatter.format(dob.doubleValue());
System.out.println(formattedDob);// output is 1212.357
}
}
Note that the formattedDob is a String

Negative sign in case of zero in java

Is there any way to truncate the negative sign when the result returns zero; while using decimal format?
DecimalFormat df = new DecimalFormat("#,##0.0");
df.setRoundingMode(RoundingMode.HALF_UP);
formattedValue = df.format("-0.023");
The above code returns -0.0 . Is there any way by which it will return only 0.0? However, I want to retain the negative sign when the result is a negative number.
I don't think there's a way of doing it just with DecimalFormat, but this one-liner takes care of the problem:
formattedValue = formattedValue.replaceAll( "^-(?=0(\\.0*)?$)", "");
It removes (replaces with "") the minus sign if it's followed by 0-n characters of "0.00000...", so this will work for any similar result such as "-0", "-0." or "-0.000000000"
Here's some test code:
public static void main(String[] args) {
System.out.println(format(-0.023));
System.out.println(format(12.123));
System.out.println(format(-12.345));
System.out.println(format(-0.123));
System.out.println(format(-1.777));
}
public static String format(double number) {
DecimalFormat df = new DecimalFormat("#,##0.0");
df.setRoundingMode(RoundingMode.HALF_UP);
String formattedValue = df.format(number);
formattedValue = formattedValue.replaceAll("^-(?=0(\\.0*)?$)", "");
return formattedValue;
}
Output (as expected):
0.0
12.1
-12.3
-0.1
-1.8
I think this would be a workaround to avoid -0.0. Use following code :
DecimalFormat df = new DecimalFormat("#,##0.0");
df.setRoundingMode(RoundingMode.HALF_UP);
df.setNegativePrefix(""); // set negative prefix BLANK
String formattedValue = df.format(-0.023);
df.setNegativePrefix("-"); // set back to - again
System.out.println(formattedValue);
Output :
0.0
Try this: DecimalFormat df = new DecimalFormat("#,##0.0#;(#,##0.0#)");
According to the Javadoc for DecimalFormat:
A DecimalFormat pattern contains a positive and negative subpattern,
for example, "#,##0.00;(#,##0.00)". Each subpattern has a prefix,
numeric part, and suffix. The negative subpattern is optional; if
absent, then the positive subpattern prefixed with the localized minus
sign ('-' in most locales) is used as the negative subpattern. That
is, "0.00" alone is equivalent to "0.00;-0.00". If there is an
explicit negative subpattern, it serves only to specify the negative
prefix and suffix; the number of digits, minimal digits, and other
characteristics are all the same as the positive pattern. That means
that "#,##0.0#;(#)" produces precisely the same behavior as
"#,##0.0#;(#,##0.0#)".
I find the -0 quite useful because it informs you that the rounded value was in fact negative (which can have a lot of meaning for some functions). The only issue for me is that -1 * 0 is actually really 0 and should be formatted as 0 although it isn't with Java formatters.
The following formatter takes care of that, without the expensive cost of String manipulation (especially RegExps):
public static String formatWithoutMinusZeroIssue(double d, DecimalFormat yourFormatter) {
if (d == 0) {
return yourFormatter.format(0);
} else {
return yourFormatter.format(d);
}
}
This uses the fact that although -1 * 0 and 0 are formatted differently, they are equal.
That by check if the calculated value = "-0.0"
make it equal "0.0"
and you can capsulate the code sush as
public String getFormattedValue(String input) {
DecimalFormat df = new DecimalFormat("#,##0.0");
df.setRoundingMode(RoundingMode.HALF_UP);
String formattedValue = df.format(input);
if (formattedValue.equalsIgnoreCase("-0.0")) {
formattedValue = "0.0";
}
System.out.println(formattedValue);
return formattedValue;
}
Faster and works with arbitrary precision (also supports suffixes to ignore e.g. currencies, put 0 for no suffix):
public static String normalizeNegativeZero(final String str, final int skipSuffixLength) {
if (str.length() > 3 && str.charAt(0) == '-' && str.charAt(1) == '0'
&& (str.charAt(2) == '.' || str.charAt(2) == ',')) {
for (int i = 3; i < str.length() - skipSuffixLength; i++) {
if (str.charAt(i) != '0') {
return str;
}
}
return StringUtils.removeStart(str, "-");
} else {
return str;
}
}
Here the Testcases:
Assertions.assertThat(normalizeNegativeZero("-0.00000", 0)).isEqualTo("0.00000");
Assertions.assertThat(ScaledDecimalToStringBuilder.normalizeNegativeZero("-0.00001", 0)).isEqualTo("-0.00001");
Assertions.assertThat(normalizeNegativeZero("-0.00000EUR", "EUR".length())).isEqualTo("0.00000EUR");
Assertions.assertThat(normalizeNegativeZero("-0.00001EUR", "EUR".length())).isEqualTo("-0.00001EUR");
The Kotlin version of Bohemian's answer:
fun Double.formatAmount(): String {
val ds = DecimalFormatSymbols()
ds.decimalSeparator = '.'
ds.groupingSeparator = ','
val df = DecimalFormat("#,##0.##", ds)
df.roundingMode = RoundingMode.DOWN
var formattedDouble = df.format(this)
formattedDouble = formattedDouble.replace("^-(?=0(\\\\.0*)?\$)".toRegex(), "")
return formattedDouble
}

Convert a String to Double - Java

What is the easiest and correct way to convert a String number with commas (for example: 835,111.2) to a Double instance.
Thanks.
Have a look at java.text.NumberFormat. For example:
import java.text.*;
import java.util.*;
public class Test
{
// Just for the sake of a simple test program!
public static void main(String[] args) throws Exception
{
NumberFormat format = NumberFormat.getInstance(Locale.US);
Number number = format.parse("835,111.2");
System.out.println(number); // or use number.doubleValue()
}
}
Depending on what kind of quantity you're using though, you might want to parse to a BigDecimal instead. The easiest way of doing that is probably:
BigDecimal value = new BigDecimal(str.replace(",", ""));
or use a DecimalFormat with setParseBigDecimal(true):
DecimalFormat format = (DecimalFormat) NumberFormat.getInstance(Locale.US);
format.setParseBigDecimal(true);
BigDecimal number = (BigDecimal) format.parse("835,111.2");
The easiest is not always the most correct. Here's the easiest:
String s = "835,111.2";
// NumberFormatException possible.
Double d = Double.parseDouble(s.replaceAll(",",""));
I haven't bothered with locales since you specifically stated you wanted commas replaced so I'm assuming you've already established yourself as a locale with comma is the thousands separator and the period is the decimal separator. There are better answers here if you want correct (in terms of internationalization) behavior.
Use java.text.DecimalFormat:
DecimalFormat is a concrete subclass
of NumberFormat that formats decimal
numbers. It has a variety of features
designed to make it possible to parse
and format numbers in any locale,
including support for Western, Arabic,
and Indic digits. It also supports
different kinds of numbers, including
integers (123), fixed-point numbers
(123.4), scientific notation (1.23E4),
percentages (12%), and currency
amounts ($123). All of these can be
localized.
A link can say more than thousand words
// Format for CANADA locale
Locale locale = Locale.CANADA;
String string = NumberFormat.getNumberInstance(locale).format(-1234.56); // -1,234.56
// Format for GERMAN locale
locale = Locale.GERMAN;
string = NumberFormat.getNumberInstance(locale).format(-1234.56); // -1.234,56
// Format for the default locale
string = NumberFormat.getNumberInstance().format(-1234.56);
// Parse a GERMAN number
try {
Number number = NumberFormat.getNumberInstance(locale.GERMAN).parse("-1.234,56");
if (number instanceof Long) {
// Long value
} else {
// Double value
}
} catch (ParseException e) {
}
There is small method to convert german price format
public static BigDecimal getBigDecimalDe(String preis) throws ParseException {
NumberFormat nf = NumberFormat.getInstance(Locale.GERMAN);
Number number = nf.parse(preis);
return new BigDecimal(number.doubleValue());
}
----------------------------------------------------------------------------
German format BigDecimal Preis into decimal format
----------------------------------------------------------------------------
public static String decimalFormat(BigDecimal Preis){
String res = "0.00";
if (Preis != null){
NumberFormat nf = NumberFormat.getInstance(Locale.GERMANY);
if (nf instanceof DecimalFormat) {
((DecimalFormat) nf).applyPattern("###0.00");
}
res = nf.format(Preis);
}
return res;
}
---------------------------------------------------------------------------------------
/**
* This method converts Deutsche number format into Decimal format.
* #param Preis-String parameter.
* #return
*/
public static BigDecimal bigDecimalFormat(String Preis){
//MathContext mi = new MathContext(2);
BigDecimal bd = new BigDecimal(0.00);
if (!Util.isEmpty(Preis)){
try {
// getInstance() obtains local language format
NumberFormat nf = NumberFormat.getInstance(Locale.GERMAN);
nf.setMinimumFractionDigits(2);
nf.setMinimumIntegerDigits(1);
nf.setGroupingUsed(true);
java.lang.Number num = nf.parse(Preis);
double d = num.doubleValue();
bd = new BigDecimal(d);
} catch (ParseException e) {
e.printStackTrace();
}
}else{
bd = new BigDecimal(0.00);
}
//Rounding digits
return bd.setScale(2, RoundingMode.HALF_UP);
}

Categories