views:

2762

answers:

4

My percentages get truncated by the default java.text.MessageFormat function, how do you format a percentage without losing precision?

Example:

String expectedResult = "12.5%";
double fraction = 0.125;

String actualResult = MessageFormat.format("{0,number,percent}", fraction);
assert expectedResult.equals(actualResult) : actualResult +" should be formatted as "+expectedResult;
A: 

How about

DecimalFormat f = new DecimalFormat( "###.#" );
System.out.println( f.format( 12.5 ) );

The format char '#' does not print a 0 as absent. So 12.5 ->"12.5", 12.0 -> "12", not "12.0". You could of course set up your formatter with e.g. "###,###.##", the hundreths place will only show up if you need the precision.

Steve B.
+2  A: 

You do realize that "expectedResult == actualResult" will always be false, right?

Anyway, the best solution I can find is to set the formatter explicitly. This is the code I tested:

String expectedResult = "12.5%";
double fraction = 0.125;
MessageFormat fmt = new MessageFormat("{0,number,percent}");
NumberFormat nbFmt = NumberFormat.getPercentInstance();
nbFmt.setMaximumFractionDigits(1); // or 2, or however many you need
fmt.setFormatByArgumentIndex(0, nbFmt);
String actualResult = fmt.format(new Object[] {fraction});
assert expectedResult.equals(actualResult) : actualResult +" is getting rounded off";
Michael Myers
hah, yeah. sorry about that. I corrected the example.
Lorin
+6  A: 

Looks like this:

String actualResult = MessageFormat.format("{0,number,#.##%}", fraction);

... is working.

EDIT: To see how are the #'s and %'s interpreted, see the javadoc of java.text.DecimalFormat.

EDIT 2: And, yes, it is safe for internationalization. The dot in format string is interpreted as a decimal separator, not as a hardcoded dot. :-)

david a.
+1, this is wayyy easier than what I did.
Michael Myers
However, it might not be safe for internationalization. I don't know for sure.
Michael Myers
There is always the danger localizers breaking some formatting strings, but otherwise I can't think about any else concerns...
david a.
+3  A: 

I think the proper way to do it is the following:

NumberFormat percentFormat = NumberFormat.getPercentInstance();
percentFormat.setMaximumFractionDigits(1);
String result = percentFormat.format(0.125);

It also takes internalization into account. For example on my machine with hungarian locale I got "12,5%" as expected. Initializing percentFormat as NumberFormat.getPercentInstance(Locale.US) gives "12.5%" of course.

Chei