6

Somewhere between Java 11 and 17 currency formatting changed to where this:

NumberFormat.getCurrencyInstance(Locale.CANADA_FRENCH).format(100.00)

would print 100,00 $ CA instead of 100,00 $.

Is there a better way than this to remove the country code CA?

var currencyFormat = NumberFormat.getCurrencyInstance(Locale.CANADA_FRENCH);
if (currencyFormat instanceof DecimalFormat decimalFormat) {
    var symbols = DecimalFormatSymbols.getInstance(Locale.CANADA_FRENCH);
    symbols.setCurrencySymbol("$");
    decimalFormat.setDecimalFormatSymbols(symbols);
}

Seems a bit much just to get back something that was the default behavior up until recently.

Didier L
  • 18,905
  • 10
  • 61
  • 103
O.m
  • 75
  • 4
  • What about just adding `.replace(" CA", "")` to the end? btw, this behaviour is not in java 15. – Bohemian Jan 20 '22 at 22:11
  • 2
    I don't think the code that's using the format should be aware of this issue and have to account for it. Especially when it's also using other locales that don't have that problem. – O.m Jan 20 '22 at 22:24
  • There's no easy way around this. One way would be to customise your format and cache it for general use, eg `public static final NumberFormat CANADA_FRENCH_FORMAT = customCanadaFormat();` and put your code in the `static customCanadaFormat()` method. If you *really* want to "undo" this behaviour change, you could use reflection to modify `Locale.CANADA_FRENCH`. It almost feels like a bug TBH. Generally, java is backwardly compatible. This is a (minor) breaking change. – Bohemian Jan 20 '22 at 22:31
  • 1
    couldn't you just call getCurrency on the result of NumberFormat.getCurrencyInstance(..)? – juwil Jan 20 '22 at 22:32
  • @Bohemian yep that what I thought, but figured maybe I'm missing some secret api that can solve this. – O.m Jan 20 '22 at 22:37
  • @juwil can you elaborate? – O.m Jan 20 '22 at 22:38
  • I tried to use reflection, but it's a "closed" package :( – Bohemian Jan 21 '22 at 03:22
  • @O.m I mistakenly assumed, that currencyFormat.getCurrency() would give $ but instead it results in CA$. So that way it is rather useless. – juwil Jan 21 '22 at 08:40
  • @juwil Depends on your locale (`Locale.setDefaultLocale`). – Johannes Kuhn Jan 21 '22 at 14:50
  • 2
    Instead of `DecimalFormatSymbols.getInstance(Locale.CANADA_FRENCH)` you can use `decimalFormat.getDecimalFormatSymbols()`. But that’s the only potential simplification I see. – Holger Jan 21 '22 at 15:41

1 Answers1

6

I dug a bit into this, the JDK locale data comes from Unicode CLDR by default, and it seems they reverted from $ CA to $ back in August, see CLDR-14862 and this commit (expand common/main/fr_CA.xml and then go to lines 5914/5923).

This was part of v40, released in October, so too late for JDK 17 whose doc says it uses CLDR v35.1 (which was introduced in Java 13) but it seems it was updated to v39 in April 2021 and they forgot the release note (JDK 16 appears to have been upgraded to v38 already).

CLDR v40 is planned for JDK 19.

You may want to run your application using the COMPAT locales first, with

-Djava.locale.providers=COMPAT,CLDR,SPI

(found here but see also LocaleServiceProvider)

This will use the locales compatible with Java 8, where this issue is not present.

Didier L
  • 18,905
  • 10
  • 61
  • 103