Java - Show me the money!

Carrying on with my posts about some of the i18n facilities
in Java, this time I’m looking at the Currency class. This is a Java util to
specifically to represent ISO 4217 currency information.

My main reason for doing these posts is to keep a record for my own sake of the
things to watch out for when doing i18n work. It’s also a good chance
to look at various interesting cases of the world, and people, being complicated.

As with a lot of Java’s i18n stuff, there was a lot of work done between Java 8
and Java 9, with Java 10 only making a few changes over Java 9.

The code used as the source of this article is here but basically it’s:

get a unicode capable output stream
get a sorted list of all the available Currency types
print a bunch of info about each Currency
* its ISO 4217 string code
* the currency symbol
* the number of fractional digits
* the DisplayName (in English)
print the count of known Currency types

I compiled that with OpenJDK’s Java 8 version, then ran it in OpenJDK’s JVMs for
Java 8, 9 and 10. I took the outputs from each and diffed them to see what has
changed between Java versions.

Usual Caveat: These results are from the OpenJDK JVM, on a Debian PC.
Different JVMs for different OSs on different hardware may have different
information. Do your own tests if you need to know for sure!

1. No new currencies

Count: 225

That’s the same in Java 8, 9 and 10. This surprises me becuase there is quite a
long period between Java 8 and Java 10. The version of Java 8 I’m using is
recently patched, but usually Java doesn’t introduce new i18n data in these patches.

I’m expecting a future version of Java to start including crypto-currencies, but
for the moment (despite supporting other odd currencies) it looks like the boom
in new currencies hasn’t reached the Java dev/spec teams yet.

2. New currency symbols in Java 9

If you read any of my other i18n posts this won’t be a surprise, but Java 8
used the ASCII 3-char codes for the vast majority of currency symbols; in fact
only two got symbols (and neither was a dollar sign!)

A surprising thing here is that none of the currencies use the
generic currency symbol ¤.
Although it shouldn’t be used for any specific currency I am surprised they didn’t
use it as the symbol for some of the placeholder currencies (mentioned later on).

3. Pseudo-currencies

The ISO (and Java) currency list also include a bunch of “supranational” currencies
to make various banking and financial tasks easier. These seem to fall into two
main groups.

Firstly, there are things which aren’t really currencies, but do get used to
transfer currency-like values. These all have a currency code starting with an ‘X’,
things like:

Some of these pseudo-currencies do look like they may be real ones, but the rule
to follow appears to be: if its code starts with an ‘X’, it’s a weird one.

code: XCD, symbol: EC$, fdigits: 2, name: East Caribbean Dollar

4. Placeholder/test currencies

The other group of “supranational” currencies is things which really aren’t
currencies at all, but placeholders for where a real currency will
be used. Again they all start with an ‘X’ in their code, and they all have
“-1” fraction digits (I’ll mention that below).

The ISO docs and Wikipedia explain more, but if you see those
XTS or XXX currencies check very carefully what you’re dealing with.
It’s unlikely to be real and it’s very likely to be awkward data.

5. Fractional Digits

It’s quite often forgetten that not every currency has “pence and cents”.
It’s also true that they don’t all use 2 fraction digits. I’ve dealt with Japanese
Yen frequently, which has no fraction digits, but I’ve never dealt with a currency
that had more than 2 fraction digits. However, they do exist, some go up to 4,
which could cause interesting edge cases.

Just to throw some craziness into this mix, those pseudo-currencies I mentioned
above - Java gives them “-1” fraction digits. Yup, you read that right:

Now this is exceptionally weird - because the ISO standard doesn’t state “-1” it
instead says that these currencies don’t have a fractional part. Specifically, they
state “N.A.” or “.” rather than the “0” that some real currencies use.

In the interests of pragmatism, you probably want to explicitly catch these
currencies and force those numbers to have zero decimals. Or alternatively, have
a special handler case if the currency code starts with an ‘X’.

So take care formatting numbers for currencies and maybe even revisit your
rounding rules for calculations. You may need to handle currencies that need
extra accuracy after the decimal and to handle cases where Java throws you a
nasty negative.

6. Time travelling in the USA

Most currencies have one entry, or maybe 2 if they had some interesting politics
recently. But the US Dollar, it has 3 entries, ‘cos yeah America!

That’s printing a monetary amount of 123456.789, in GBP currency, in the format used in Japan.
So we get the GBP symbol, but the amount is rounded to fit Japanese currency formatting.

8. Rolling your own

There could be good reasons to define your own currency. Maybe you’re adding support
for crypto-currencies and want to keep your existing currency code as
clean as possible. Maybe you need to support some historical currencies.

Whatever the reason, the Java Currency class describes how to define
new currencies using system properties. That includes specifying a start date
for the currency, but no end date. So if you’re doing historical stuff, you may
also need to add some sort of extra “stopper” currency to act as an end date.

9. Java 8 to 9, the big i18n push

As I’ve mentioned before, the Java team did a huge amount of i18n work for Java 9.
To summarise the changes in Java 9 I spotted from my diff trawling…

Unicode All The Things!!! (ahem, except the ISO codes)

More actual currency symbols and names, rather than slapping in the code again

Using em-dash for date ranges

A bunch of work adjusting display names

and finally, GBP lost its “Stirling” in Java, although ISO still says “Pound Stirling”