We're updating the issue view to help you get more done. 

Add tests for "Fallback symbols displayed in formatted currency output when no currency is set in API" and for "Rounding behavior when no currency is set in API"

Description

This behavior difference was discovered between ICU4C and ICU4J.

Sample code, ICU4C:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 #include "common.h" int main() { ErrorCode status; { LocalPointer<DecimalFormat> df(dynamic_cast<DecimalFormat*>( NumberFormat::createInstance("en", UNUM_CURRENCY, status))); UnicodeString result; df->format(1.23, result, status); std::cout << "symbol: " << result << std::endl; } { LocalPointer<DecimalFormat> df(dynamic_cast<DecimalFormat*>( NumberFormat::createInstance("en", UNUM_CURRENCY_ISO, status))); UnicodeString result; df->format(1.23, result, status); std::cout << "iso_code: " << result << std::endl; } { LocalPointer<DecimalFormat> df(dynamic_cast<DecimalFormat*>( NumberFormat::createInstance("en", UNUM_CURRENCY_PLURAL, status))); UnicodeString result; df->format(1.23, result, status); std::cout << "plural: " << result << std::endl; } { LocalPointer<DecimalFormat> df(dynamic_cast<DecimalFormat*>( NumberFormat::createInstance("en", UNUM_CURRENCY, status))); UnicodeString currencyCode = UnicodeString(df->getCurrency()); std::cout << "currency: \"" << currencyCode << "\"" << std::endl; } std::cout << u_errorName(status) << std::endl; u_cleanup(); return 0; }

ICU4J:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import java.text.ParsePosition; import com.ibm.icu.text.*; import com.ibm.icu.util.*; public class NoCurrencyBehavior { public static void main(String[] args) { DecimalFormatSymbols EN = DecimalFormatSymbols.getInstance(ULocale.ENGLISH); { DecimalFormat df = (DecimalFormat) NumberFormat.getInstance(ULocale.ENGLISH, NumberFormat.CURRENCYSTYLE); System.out.println("symbol: " + df.format(1.23)); } { DecimalFormat df = (DecimalFormat) NumberFormat.getInstance(ULocale.ENGLISH, NumberFormat.ISOCURRENCYSTYLE); System.out.println("iso_code: " + df.format(1.23)); } { DecimalFormat df = (DecimalFormat) NumberFormat.getInstance(ULocale.ENGLISH, NumberFormat.PLURALCURRENCYSTYLE); System.out.println("plural: " + df.format(1.23)); } { DecimalFormat df = (DecimalFormat) NumberFormat.getInstance(ULocale.ENGLISH, NumberFormat.CURRENCYSTYLE); System.out.print("currency: " + df.getCurrency()); } } }

Consensus opinion: we should use the unknown currency "XXX", like ICU4J and JDK are already doing in the ISO code format, with the following output:

1 2 3 4 XXX 1.23 XXX 1.23 1.23 (unknown currency) currency: XXX

The plural long-name string, "unknown currency", comes from locale data.

Follow up with CLDR to add the currency symbol.

In addition, one more behavior difference was discovered.

ICU4C sample code:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 #include "common.h" int main() { ErrorCode status; const UChar pattern[] = {0xA4, u'0', u'.', u'#', u'#', 0}; const UChar XXX[] = {u'X', u'X', u'X', 0}; { DecimalFormat df(pattern, {"en", status}, status); UnicodeString result; df.format(1.1, result, status); std::cout << result << std::endl; } { DecimalFormat df(pattern, {"en", status}, status); df.setCurrency(XXX, status); UnicodeString result; df.format(1.1, result, status); std::cout << result << std::endl; } { LocalPointer<DecimalFormat> df(dynamic_cast<DecimalFormat*>( NumberFormat::createCurrencyInstance("en", status))); UnicodeString result; df->format(1.1, result, status); std::cout << result << std::endl; } std::cout << u_errorName(status) << std::endl; u_cleanup(); return 0; }

ICU4J:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import com.ibm.icu.text.*; import com.ibm.icu.util.*; public class RoundingNoCurrency { public static void main(String[] args) { { DecimalFormat df = new DecimalFormat("\u00A40.##", DecimalFormatSymbols.getInstance(ULocale.ENGLISH)); System.out.println(df.format(1.1)); } { DecimalFormat df = new DecimalFormat("\u00A40.##", DecimalFormatSymbols.getInstance(ULocale.ENGLISH)); df.setCurrency(Currency.getInstance("XXX")); System.out.println(df.format(1.1)); } { DecimalFormat df = (DecimalFormat) NumberFormat.getCurrencyInstance(ULocale.ENGLISH); System.out.println(df.format(1.1)); } } }

Consensus opinion: Since we should apply the default currency when no currency is set, as stated in row 10, we should also apply XXX's rounding rules, which are a fixed two fraction digits.

Desired output:

1 2 3 XXX 1.10 XXX 1.10 1.10 (unknown currency)

Environment

Status

Assignee

Shane Carr

Reporter

Shane Carr

Time Needed

Minutes

Reviewer

Peter Edberg

tracCc

pedberg

tracCreated

Apr 26, 2018, 4:10 AM

tracOwner

shane

tracProject

all

tracReporter

shane

tracStatus

accepted

Components

Fix versions

Priority

major