Idiomatic way to remove country code from currency format?
Asked Answered
M

1

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.

Marler answered 20/1, 2022 at 21:40 Comment(10)
What about just adding .replace(" CA", "") to the end? btw, this behaviour is not in java 15.Senghor
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.Marler
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.Senghor
couldn't you just call getCurrency on the result of NumberFormat.getCurrencyInstance(..)?Stalagmite
@Senghor yep that what I thought, but figured maybe I'm missing some secret api that can solve this.Marler
@Stalagmite can you elaborate?Marler
I tried to use reflection, but it's a "closed" package :(Senghor
@Marler I mistakenly assumed, that currencyFormat.getCurrency() would give $ but instead it results in CA$. So that way it is rather useless.Stalagmite
@Stalagmite Depends on your locale (Locale.setDefaultLocale).Burson
Instead of DecimalFormatSymbols.getInstance(Locale.CANADA_FRENCH) you can use decimalFormat.getDecimalFormatSymbols(). But that’s the only potential simplification I see.Gentianaceous
H
7

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.

Hyde answered 30/1, 2022 at 3:21 Comment(3)
Great detective work, sir.Marler
How can I do this on android?Pentahedron
@Pentahedron you should ask a specific question about this, I don’t know if it is the same issue (maybe link to this one) but here it is only about a Java 17 issue (and I have no experience with Android)Hyde

© 2022 - 2024 — McMap. All rights reserved.