Java Currency and Locale - Miscellaneous Notes

09 Aug 2020

See also Java Currency and Locale - Updates for an update on this topic.

Some notes about managing locales in Java, with examples for custom currency formats, and some potentially surprising behavior for language tags. It is well worth reading the Javadoc for Locale.

Building a custom currency format:

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import java.util.Currency;  
import java.text.NumberFormat;  
import java.text.DecimalFormatSymbols;  

...  

Number rawNumber = 120798700;  
NumberFormat nf = NumberFormat.getCurrencyInstance();  
DecimalFormatSymbols dfs = new DecimalFormatSymbols();  
dfs.setCurrencySymbol("€");  
dfs.setGroupingSeparator('.');  
dfs.setMonetaryDecimalSeparator(',');  
((DecimalFormat) nf).setDecimalFormatSymbols(dfs);  
System.out.println(nf.format(rawNumber.floatValue() / 100));  

The above code outputs €1.207.987,00

How to see what separator a locale is using:

Java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import java.util.Locale;  
import java.text.NumberFormat;  
import java.text.DecimalFormat  

...

double d = 12345.67;  
Locale swissGermanLocale = new Locale("gsw");  
//Locale swissGermanLocale = new Locale("de", "CH");  
System.out.println(swissGermanLocale.getDisplayName());  // Swiss German  

final NumberFormat gswFormat = NumberFormat.getNumberInstance(swissGermanLocale);  

// Find out what the grouping separator is for the given locale:  
DecimalFormat decimalFormat = (DecimalFormat)  
NumberFormat.getNumberInstance(swissGermanLocale);  
char c = decimalFormat.getDecimalFormatSymbols().getGroupingSeparator();  
System.out.println(c);  // ’  

out.println(gswFormat.format(d));  // 12345.67

Unexpected locale behavior

Note that some locales may not behave the way you might expect. Consider this:

Java
1
2
3
4
5
6
7
8
import java.util.Locale;  

...  

Locale locale = new Locale("he", "IL");  
System.out.println(locale.getDisplayCountry());  
System.out.println(locale.getDisplayLanguage());  
System.out.println(locale);  

This prints the following:

Israel  
Hebrew  
iw_IL  

Note how the original language tag he has been changed from he to iw - the old, deprecated code. This is not considered a bug. Rather, the older code is used to maintain backwards compatibility with previous JDK releases. So, to compare two locales, you need to compare the locale objects, not the components (language tag, country tag, etc).