Easy way to change Locale based currency formatting in Java - java

Below is some code that shows how we can format currency based on Locale.
Is there an easy way to configure this behaviour in Java? For example, let's say that I want to make a slight adjustment to how currency is formatted in Italian, by putting the Currency symbol after the amount, instead of in front of the amount.
public static void main(String[] args)
{
displayCurrency(Locale.ENGLISH);
displayCurrency(Locale.FRENCH);
displayCurrency(Locale.ITALIAN);
}
static public void displayCurrency( Locale currentLocale) {
Double currencyAmount = new Double(9876543.21);
DecimalFormat currencyFormatter = (DecimalFormat)
NumberFormat.getCurrencyInstance(currentLocale);
System.out.println(currentLocale.getDisplayName() + ": " +
currencyFormatter.format(currencyAmount));
}
Output:
English: ¤9,876,543.21
French: 9 876 543,21 ¤
Italian: ¤ 9.876.543,21

Related

NumberFormat vs Joda money

I need to display currency amount with the symbol and format based on currency code. Currently, I'm using a default locale for each currency code since I don't have access to the exact locale along with the currency code and using NumberFormat.format() to get the formatted currency amount with format and symbol. Does Joda money do this all - provide currency code and it displays the formatted currency with symbol? Any help/direction regarding this is appreciated.
I just found out about joda-money, I'm testing it to see if it fits in my project requirements. I read your question and decided to answer it while testing the library.
For what I could see inside the joda-money jar it has very few classes and provide the basic currency management and a formatter.
It seems that at the early stage in which joda-money is the formatter still needs the Locale to print the money symbol, as you can see in my code. (The code is in scala but the methods call are the same in Java)
import org.joda.money.format.MoneyFormatterBuilder
import org.joda.money.{Money, CurrencyUnit}
def formatterBuilder() = new MoneyFormatterBuilder().appendCurrencySymbolLocalized().appendAmount()
def moneyFormatter(locale: java.util.Locale) = formatterBuilder().toFormatter(locale)
def moneyFormatter() = formatterBuilder().toFormatter
val usd: CurrencyUnit = CurrencyUnit.of("USD")
val money = Money.of(usd, 23232312d) // or just Money.parse("USD 23232312")
moneyFormatter().print(money) // res0: String = USD23,232,312.00
moneyFormatter(java.util.Locale.US).print(money) // res1: String = $23,232,312.00
As you can see, the Locale is needed to print the '$' symbol.
Additionally I tried with another currency, the yen (Japan currency). I printed it with the US locale and the result was something I didn't spec.
val japan = Money.parse("JPY 23232312")
moneyFormatter().print(japan) // res2: String = JPY23,232,312
moneyFormatter(java.util.Locale.JAPAN).print(japan) // res3: String = ¥23,232,312
moneyFormatter(java.util.Locale.US).print(japan) // res4: String = JPY23,232,312
EDIT:
You could also create an abstract class as a wrapper for Money, like this:
abstract class Currency(amount: BigDecimal, locale: java.util.Locale) {
val currencyUnit: CurrencyUnit = CurrencyUnit.getInstance(locale)
val money: Money = Money.of(currencyUnit, amount)
def formatted: String = new MoneyFormatterBuilder().appendCurrencySymbolLocalized().appendAmount().toFormatter(locale).print(money)
// implement others Money methods
}
class USDollars(amount: BigDecimal) extends Currency(amount, java.util.Locale.US)
public static void main(String[] args) throws Exception {
Currency usd = java.util.Currency.getInstance("USD");
NumberFormat format = java.text.NumberFormat.getCurrencyInstance(java.util.Locale.US);
format.setCurrency(usd);
System.out.println(format.format(23232312));
}
Output
$23,232,312.00

Java euro symbol is converted to currency symbol

I'm trying to format a double variable to a price string (example: €59,00) using NumberFormat
Here is the method I written:
private String formatValue (double price){
NumberFormat f = NumberFormat.getCurrencyInstance(Locale.ITALIAN);
String value = f.format(new BigDecimal(price));
return value;
}
then, I write the returned value in a pdf field using iText library.
form.setField("value", formatValue(price));
Now, when I open the generated pdf in a browser's pdf viewer (like chrome or firefox), the field looks like:
€59,00
but when I open it in adobe reader, or I try to physically print, it appears like
¤59,00.
If I open the variable value in debug, I see the string formatted as ¤59,00.
What I'm doing wrong?
I solved using DecimalFormat instead NumberFormat, and passing the € symbol in utf-8 encode (an input by mwhs [thanks])
private String formatValue (double price){
DecimalFormat formatter = new DecimalFormat("\u20ac0.00");
String value = formatter.format(price);
return value;
}
You may be using separate encoding. Browsers may be using UTF-8, Whereas adobe reader may be using ANSI or another localization of UTF. (Note these are not necessarily the encoding they use, just an example) so check your preferences, and try again.
You can use the actual UTF-8 Euro symbol which makes the code more readable.
private static final DecimalFormat EURO_FORMAT = new DecimalFormat("€0.00");
private String formatValue (double price){
return EURO_FORMAT.format(price);
}
But the java.util.NumberFormat is a better choice since you can use the Locale for the correct number format. In France, Germany and the Netherlands the comma is used instead of the decimal point before the cents. But the format for thousands is different. See below for an example:
public class NumberFormatLocaleExample {
public static void main(final String[] args) {
double price = 1249.69;
System.out.println(formatValueGermany(price));
System.out.println(formatValueFrance(price));
}
private static final NumberFormat EURO_FORMAT_GER = NumberFormat.getCurrencyInstance(Locale.GERMAN);
private static String formatValueGermany(double price){
return String.format("€%s", EURO_FORMAT_GER.format(price));
}
private static final NumberFormat EURO_FORMAT_FRANCE = NumberFormat.getCurrencyInstance(Locale.FRENCH);
private static String formatValueFrance(double price){
return String.format("€%s", EURO_FORMAT_FRANCE.format(price));
}
}
Problem is the Locale: you are using ITALIAN, correct would be ITALY, because ITALIAN may refer to other countries where they speak Italian, but ITALY means the country with its units including the currency.
private String formatValue (double price){
NumberFormat f = NumberFormat.getCurrencyInstance(Locale.ITALY);
String value = f.format(new BigDecimal(price));
return value;
}
Would give you the right Euro-symbol. Same is true for GERMAN vs. GERMANY or FRENCH vs. FRANCE btw.

How to get NumberFormat instance from currency code?

How can I get a NumberFormat (or DecimalFormat) instance corresponding to an ISO 4217 currency code (such as "EUR" or "USD") in order to format prices correctly?
Note 1: The problem I'm having is that the NumberFormat/DecimalFormat classes have a
getCurrencyInstance(Locale locale) method but I can't figure out how
to get to a Locale object from an ISO 4217 currency code.
Note 2: There is also a java.util.Currency class which has a getInstance(String currencyCode) method (returning the Currency
instance for a given ISO 4217 currency code) but again I can't figure
out how to get from a Currency object to a NumberFormat
instance...
I'm not sure I understood this correctly, but you could try something like:
public class CurrencyTest
{
#Test
public void testGetNumberFormatForCurrencyCode()
{
NumberFormat format = NumberFormat.getInstance();
format.setMaximumFractionDigits(2);
Currency currency = Currency.getInstance("USD");
format.setCurrency(currency);
System.out.println(format.format(1234.23434));
}
}
Output:
1,234.23
Notice that I set the maximum amount of fractional digits separately, the NumberFormat.setCurrency doesn't touch the maximum amount of fractional digits:
Sets the currency used by this number format when formatting currency
values. This does not update the minimum or maximum number of fraction
digits used by the number format.
Locale can be used both to get the standard currency for the Locale and to print any currency symbol properly in the locale you specify. These are two distinct operations, and not really related.
From the Java Internationalization tutorial, you first get an instance of the Currency using either the Locale or the ISO code. Then you can print the symbol using another Locale. So if you get the US Currency from the en_US Locale, and call getSymbol() it will print "$". But if you call getSymbol(Locale) with the British Locale, it will print "USD".
So if you don't care what your current user's locale is, and you just care about the currencies, then you can ignore the Locale in all cases.
If you care about representing the currency symbol correctly based on your current user, then you need to get the Locale of the user specific to the user's location.
The mapping is sometimes one to many... Like the euro is used in many countries (locales)...
Just because the currency code is the same the format might be different as this example shows:
private static Collection<Locale> getLocalesFromIso4217(String iso4217code) {
Collection<Locale> returnValue = new LinkedList<Locale>();
for (Locale locale : NumberFormat.getAvailableLocales()) {
String code = NumberFormat.getCurrencyInstance(locale).
getCurrency().getCurrencyCode();
if (iso4217code.equals(code)) {
returnValue.add(locale);
}
}
return returnValue;
}
public static void main(String[] args) {
System.out.println(getLocalesFromIso4217("USD"));
System.out.println(getLocalesFromIso4217("EUR"));
for (Locale locale : getLocalesFromIso4217("EUR")) {
System.out.println(locale + "=>" + NumberFormat.getCurrencyInstance(locale).format(1234));
}
}
Output
[en_US, es_US, es_EC, es_PR]
[pt_PT, el_CY, fi_FI, en_MT, sl_SI, ga_IE, fr_BE, es_ES, de_AT, nl_NL, el_GR, it_IT, en_IE, fr_LU, nl_BE, ca_ES, sr_ME, mt_MT, fr_FR, de_DE, de_LU]
pt_PT=>1.234,00 €
el_CY=>€1.234,00
fi_FI=>1 234,00 €
en_MT=>€1,234.00
sl_SI=>€ 1.234
ga_IE=>€1,234.00
fr_BE=>1.234,00 €
es_ES=>1.234,00 €
de_AT=>€ 1.234,00
nl_NL=>€ 1.234,00
el_GR=>1.234,00 €
it_IT=>€ 1.234,00
en_IE=>€1,234.00
fr_LU=>1 234,00 €
nl_BE=>1.234,00 €
ca_ES=>€ 1.234,00
sr_ME=>€ 1.234,00
mt_MT=>€1,234.00
fr_FR=>1 234,00 €
de_DE=>1.234,00 €
de_LU=>1.234,00 €
For completeness, though I've never used it, you might want to give Joda Money a try. If it's as good as Joda-Time, it probably is easier and more powerful than the standard JDK stuff.
Try the following method:
private static NumberFormat getNumberFormat(String currencyCode)
{
Currency currency = Currency.getInstance(currencyCode);
Locale[] locales = NumberFormat.getAvailableLocales();
for (Locale locale : locales)
{
NumberFormat numberFormat = NumberFormat.getCurrencyInstance(locale);
if (numberFormat.getCurrency() == currency)
return numberFormat;
}
return null;
}
public class PriceHelper {
public static String formatPrice(Context context, String currencyCode,
double price) {
if (price == 0) {
return context.getString(R.string.free);
}
Currency currency = Currency.getInstance(currencyCode);
NumberFormat format = NumberFormat.getCurrencyInstance();
format.setCurrency(currency);
return format.format(price);
}
}

How to format a number from other locale to normal en locale

I have a String "45,78". How can i format it to normal format like 45.78 in java?
Probably i think i need to create some format object and than format this according to en number format.
How can i do that?
Use the predefined DecimalFormats that the JDK offers for Locales:
public static void main(String[] args) throws ParseException {
String input = "45,78";
NumberFormat from = DecimalFormat.getNumberInstance(Locale.FRANCE);
NumberFormat to = DecimalFormat.getNumberInstance(Locale.US);
String output = to.format(from.parse(input));
System.out.println(output); // "45.78"
}
Chose Locales to suit you.
This is another case of "don't reinvent the wheel" and "use what the JDK offers"

Convert a String to Double - Java

What is the easiest and correct way to convert a String number with commas (for example: 835,111.2) to a Double instance.
Thanks.
Have a look at java.text.NumberFormat. For example:
import java.text.*;
import java.util.*;
public class Test
{
// Just for the sake of a simple test program!
public static void main(String[] args) throws Exception
{
NumberFormat format = NumberFormat.getInstance(Locale.US);
Number number = format.parse("835,111.2");
System.out.println(number); // or use number.doubleValue()
}
}
Depending on what kind of quantity you're using though, you might want to parse to a BigDecimal instead. The easiest way of doing that is probably:
BigDecimal value = new BigDecimal(str.replace(",", ""));
or use a DecimalFormat with setParseBigDecimal(true):
DecimalFormat format = (DecimalFormat) NumberFormat.getInstance(Locale.US);
format.setParseBigDecimal(true);
BigDecimal number = (BigDecimal) format.parse("835,111.2");
The easiest is not always the most correct. Here's the easiest:
String s = "835,111.2";
// NumberFormatException possible.
Double d = Double.parseDouble(s.replaceAll(",",""));
I haven't bothered with locales since you specifically stated you wanted commas replaced so I'm assuming you've already established yourself as a locale with comma is the thousands separator and the period is the decimal separator. There are better answers here if you want correct (in terms of internationalization) behavior.
Use java.text.DecimalFormat:
DecimalFormat is a concrete subclass
of NumberFormat that formats decimal
numbers. It has a variety of features
designed to make it possible to parse
and format numbers in any locale,
including support for Western, Arabic,
and Indic digits. It also supports
different kinds of numbers, including
integers (123), fixed-point numbers
(123.4), scientific notation (1.23E4),
percentages (12%), and currency
amounts ($123). All of these can be
localized.
A link can say more than thousand words
// Format for CANADA locale
Locale locale = Locale.CANADA;
String string = NumberFormat.getNumberInstance(locale).format(-1234.56); // -1,234.56
// Format for GERMAN locale
locale = Locale.GERMAN;
string = NumberFormat.getNumberInstance(locale).format(-1234.56); // -1.234,56
// Format for the default locale
string = NumberFormat.getNumberInstance().format(-1234.56);
// Parse a GERMAN number
try {
Number number = NumberFormat.getNumberInstance(locale.GERMAN).parse("-1.234,56");
if (number instanceof Long) {
// Long value
} else {
// Double value
}
} catch (ParseException e) {
}
There is small method to convert german price format
public static BigDecimal getBigDecimalDe(String preis) throws ParseException {
NumberFormat nf = NumberFormat.getInstance(Locale.GERMAN);
Number number = nf.parse(preis);
return new BigDecimal(number.doubleValue());
}
----------------------------------------------------------------------------
German format BigDecimal Preis into decimal format
----------------------------------------------------------------------------
public static String decimalFormat(BigDecimal Preis){
String res = "0.00";
if (Preis != null){
NumberFormat nf = NumberFormat.getInstance(Locale.GERMANY);
if (nf instanceof DecimalFormat) {
((DecimalFormat) nf).applyPattern("###0.00");
}
res = nf.format(Preis);
}
return res;
}
---------------------------------------------------------------------------------------
/**
* This method converts Deutsche number format into Decimal format.
* #param Preis-String parameter.
* #return
*/
public static BigDecimal bigDecimalFormat(String Preis){
//MathContext mi = new MathContext(2);
BigDecimal bd = new BigDecimal(0.00);
if (!Util.isEmpty(Preis)){
try {
// getInstance() obtains local language format
NumberFormat nf = NumberFormat.getInstance(Locale.GERMAN);
nf.setMinimumFractionDigits(2);
nf.setMinimumIntegerDigits(1);
nf.setGroupingUsed(true);
java.lang.Number num = nf.parse(Preis);
double d = num.doubleValue();
bd = new BigDecimal(d);
} catch (ParseException e) {
e.printStackTrace();
}
}else{
bd = new BigDecimal(0.00);
}
//Rounding digits
return bd.setScale(2, RoundingMode.HALF_UP);
}

Categories