Favolas
Favolas

Reputation: 7243

Format received long number as a decimal one with custom format

I'm receiving a number formatted as long. Although i'm receiving this number as a long I now that the last 3 digits correspond to a decimal part so I want to show the number formatted with grouping and a decimal separator.

Example: if I receive the number 11111111111 I want it to be shown like 11 111 111.111

I have this code:

    DecimalFormat formatter = new DecimalFormat();
    DecimalFormatSymbols symbols = new DecimalFormatSymbols();
    formatter.setGroupingUsed(true);
    symbols.setDecimalSeparator('.');
    symbols.setGroupingSeparator(' ');
    formatter.setDecimalFormatSymbols(symbols);

    long valueAsLong = 11111111111L;
    double value = (double) valueAsLong / 1000;

    System.out.println(formatter.format(valueAsLong));
    System.out.println(formatter.format(value));

I want to know if I can achieve this without that cast, that is, setting a formatter that receives a long and format the number the way I want.

Upvotes: 2

Views: 657

Answers (2)

T.Gounelle
T.Gounelle

Reputation: 6033

You can actually do it without casting, but it will need parsing with java.text.DecimalFormat#parse, with "#\u2030" pattern, where \u2030 is the (per-mille) character.

    long myLong = 123456L;
    String asPerMille = 
       new StringBuffer().append(myLong).append('\u2030').toString();

    DecimalFormat perMilleFormat = new DecimalFormat("#\u2030");        
    Number myLongAsDec = perMilleFormat.parse(asPerMille);

    System.out.println(
        String.format("%d can be parsed with pattern %s as a per-mille and gives %f", 
        myLong, 
        perMilleFormat.toPattern(), 
        myLongAsDec.doubleValue()));

The output is :

123456 can be parsed with pattern #‰ as a per-mille and gives 123.456000

Note that performance wise, your method is certainly better than building and parsing a String and then reformatting it with the different groupings.

Upvotes: 0

Adrian Leonhard
Adrian Leonhard

Reputation: 7370

No DecimalFormat doesn't support this, as it's purpose is to format a number as a String without changing it's value.

format(longValue / 1000.0) is the easiest solution, note however that it will not work for very large longs:

public class Test {
    public static void main(String[] args) {
        DecimalFormat decimalFormat = (DecimalFormat) NumberFormat.getInstance(Locale.US);
        char decimalSeparator = decimalFormat.getDecimalFormatSymbols().getDecimalSeparator();

        // prints 123.456
        System.out.println(decimalFormat.format(123456 / 1000.0));

        // 9,223,372,036,854,775,807
        System.out.println(decimalFormat.format(Long.MAX_VALUE));

        // 9,223,372,036,854,776, not 9,223,372,036,854,776.807, as double's resolution is not sufficient
        System.out.println(decimalFormat.format(Long.MAX_VALUE / 1000.0));

        // 9,223,372,036,854,775.807
        BigInteger[] divAndRem = new BigInteger(Long.toString(Long.MAX_VALUE))
                .divideAndRemainder(new BigInteger("1000"));
        System.out.println(decimalFormat.format(divAndRem[0]) 
                + decimalSeparator + divAndRem[1]);

        // using String manipulation
        String longString = decimalFormat.format(Long.MAX_VALUE);
        System.out.println(new StringBuilder(longString).replace(
                longString.length() - 4, 
                longString.length() - 3, 
                Character.toString(decimalSeparator)));
    }
}

Upvotes: 1

Related Questions