26

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.

1
  • 6
    I get an error: Cannot format given Object as a Number. You should use the value -0.023 not the string "-0.023" Commented Aug 13, 2012 at 6:28

7 Answers 7

26

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
Sign up to request clarification or add additional context in comments.

5 Comments

In case you are using a currency formatter with the currency symbol in front of the zero you may want to change the regex to "^-(?=\D*0(.0*)?$)" (notice the \D* which will match any non digit characters zero or more times) This should match strings like: -$0
By any chance, can you give us the regex in Kotlin language as well? It didn't work on Kotlin and still getting -0
@Dr.jacky AFAIK Kotlin is syntactic sugar over java, so it should work as is. Check how you’re coding/using the regex. Can you post your code?
There are many countries using comma "," as a decimal separator. You may want to handle this case also: "^-(?=0([.,]0*)?$)".
@jackes why not include Arabic and Hindi numerals too? This code is an approach that shows a technique that can be adapted to a specific situation, not a lasting global specification.
5

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

2 Comments

Well I have put the above code in a utility method. Though it works for 0.0; it does not work for other negative numbers where I need to retain the -ve sign. resetting the negative prefix does not have any effect as every time the DecimalFormat instance is created.
You should not put workarounds in your utility classes. Let it be there where you are using it and keep it marked with markers like // FIXME. So next time if you find better solution you can implement that. I reset Negative Prefix above with intention, if you are going to use df instance again for different numbers. If you are going to use new instance then it is not necessary.
2

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#)".

Comments

1

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

1 Comment

This works but, becomes an explicit check. Won't work if the value is -0.00 etc.
1

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.

Comments

1

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

Comments

-1

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
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.