Reputation: 1017
I'm trying to print INR format currency like this:
NumberFormat fmt = NumberFormat.getCurrencyInstance();
fmt.setCurrency(Currency.getInstance("INR"));
fmt.format(30382.50);
shows Rs30,382.50
, but in India its written as Rs. 30,382.50
(see http://www.flipkart.com/)
how to solve without hardcoding for INR?
Upvotes: 20
Views: 10551
Reputation: 2175
Take into account the following:
Currency.symbol
to find it in the formatted string because in some locales $
becomes US$
while Currency.symbol
still returns $
The solution is (sorry for Kotlin code):
fun formatPrice(currencyCode: String, price: BigDecimal, locale: Locale? = null): String {
val resLocale = locale ?: Locale.getDefault()
val currencyFormat = NumberFormat.getCurrencyInstance(resLocale)
// decimalFormat formats the amount in the same way as currencyFormat, but without currency symbol.
// We can't use currency.symbol because it doesn't always match the way currency rendered in
// the resulting string (for some locales "$" becomes "US$")
val decimalFormat = NumberFormat.getNumberInstance(resLocale)
decimalFormat.maximumFractionDigits = currencyFormat.maximumFractionDigits
decimalFormat.maximumIntegerDigits = currencyFormat.maximumIntegerDigits
decimalFormat.isGroupingUsed = currencyFormat.isGroupingUsed
decimalFormat.minimumFractionDigits = currencyFormat.minimumFractionDigits
decimalFormat.minimumIntegerDigits = currencyFormat.minimumIntegerDigits
decimalFormat.roundingMode = currencyFormat.roundingMode
currencyFormat.currency = Currency.getInstance(currencyCode)
val priceFormatted = currencyFormat.format(price)
val amountFormatted = decimalFormat.format(price)
// 12 345,67 $ US
if (priceFormatted.startsWith(amountFormatted)) {
val suffix = priceFormatted.substringAfter(amountFormatted)
return if (suffix.isNotEmpty() && !suffix.first().isWhitespace()) {
"$amountFormatted $suffix" // use nbsp to prevent line break
} else {
priceFormatted
}
}
// US$12,345.67
if (priceFormatted.endsWith(amountFormatted)) {
val prefix = priceFormatted.substringBefore(amountFormatted)
return if (prefix.isNotEmpty() && !prefix.last().isWhitespace()) {
"$prefix $amountFormatted" // use nbsp to prevent line break
} else {
priceFormatted
}
}
// For negative amounts a sign normally goes before the currency symbol
// -US$12,345.67
val absAmountFormatted = decimalFormat.format(price.abs())
if (priceFormatted.endsWith(absAmountFormatted)) {
val prefix = priceFormatted.substringBefore(absAmountFormatted)
if (prefix.isNotEmpty() && !prefix.last().isWhitespace()) {
return "$prefix $absAmountFormatted" // use nbsp to prevent line break
}
}
return priceFormatted
}
Testing:
Locale: BigDecimal -> default_format -> custom_with_nbsp
en: 12345.673 -> $12,345.67 -> $ 12,345.67
en: 12345.67 -> $12,345.67 -> $ 12,345.67
en: -12345.67 -> -$12,345.67 -> -$ 12,345.67
en: 12345.67 -> €12,345.67 -> € 12,345.67
en: -12345.67 -> -€12,345.67 -> -€ 12,345.67
en: 12345.67 -> PLN12,345.67 -> PLN 12,345.67
en: -12345.67 -> -PLN12,345.67 -> -PLN 12,345.67
zh_CN: 12345.67 -> US$12,345.67 -> US$ 12,345.67
fr_CA: -12345.67 -> -12 345,67 PLN -> -12 345,67 PLN
pl_PL: 12345.67 -> 12 345,67 zł -> 12 345,67 zł
fr_FR: 12345.67 -> 12 345,67 PLN -> 12 345,67 PLN
Upvotes: 2
Reputation: 524
Here what I do to add space after currency symbol:
DecimalFormat numberFormat = (DecimalFormat) NumberFormat.getCurrencyInstance(new Locale("id", "ID"));
DecimalFormatSymbols symbol = new DecimalFormatSymbols(new Locale("id", "ID"));
// Add space to currency symbol
symbol.setCurrencySymbol(symbol.getCurrencySymbol() + " ");
numberFormat.setDecimalFormatSymbols(symbol);
Upvotes: 0
Reputation: 416
Sorry for Kotlin I came here from android). As I understood there is no correct solutions for that, so that's why my solution is also hack)
fun formatBalance(
amount: Float,
currencyCode: String,
languageLocale: Locale
): String {
amount
can be String as well.
val currencyFormatter: NumberFormat = NumberFormat.getCurrencyInstance(languageLocale)
currencyFormatter.currency = Currency.getInstance(currencyCode)
val formatted = currencyFormatter.format(amount)
formatted
will get amount with currency from correct side but without space. (Example: 100$, €100)
val amountFirstSymbol = amount.toString()[0]
val formattedFirstSymbol = formatted[0]
val currencySymbolIsBefore = amountFirstSymbol != formattedFirstSymbol
Then I use this little hack to understand if currency symbol is before amount. So for example amount
is 100
then amountFirstSymbol
will be "1"
. And if formatted is 100$
then formattedFirstSymbol
also will be "1"
. That means we can put our currency symbol behind amount but now with space.
val symbol = currencyFormatter.currency?.symbol
return if (currencySymbolIsBefore) "$symbol $amount"
else "$amount $symbol"
Upvotes: 0
Reputation: 475
An easier method, kind of workaround. For my locale, the currency symbol is "R$"
public static String moneyFormatter(double d){
DecimalFormat fmt = (DecimalFormat) NumberFormat.getInstance();
Locale locale = Locale.getDefault();
String symbol = Currency.getInstance(locale).getSymbol(locale);
fmt.setGroupingUsed(true);
fmt.setPositivePrefix(symbol + " ");
fmt.setNegativePrefix("-" + symbol + " ");
fmt.setMinimumFractionDigits(2);
fmt.setMaximumFractionDigits(2);
return fmt.format(d);
}
Input:
moneyFormatter(225.0);
Output:
"R$ 225,00"
Upvotes: 6
Reputation: 1219
I don't see any easy way to do this. Here's what I came up with...
The key to getting the actual currency symbol seems to be passing the destination locale into Currency.getSymbol:
currencyFormat.getCurrency().getSymbol(locale)
Here's some code that seems like it mostly works:
public static String formatPrice(String price, Locale locale, String currencyCode) {
NumberFormat currencyFormat = NumberFormat.getCurrencyInstance(locale);
Currency currency = Currency.getInstance(currencyCode);
currencyFormat.setCurrency(currency);
try {
String formatted = currencyFormat.format(NumberFormat.getNumberInstance().parse(price));
String symbol = currencyFormat.getCurrency().getSymbol(locale);
// Different locales put the symbol on opposite sides of the amount
// http://en.wikipedia.org/wiki/Currency_sign
// If there is already a space (like the fr_FR locale formats things),
// then return this as is, otherwise insert a space on either side
// and trim the result
if (StringUtils.contains(formatted, " " + symbol) || StringUtils.contains(formatted, symbol + " ")) {
return formatted;
} else {
return StringUtils.replaceOnce(formatted, symbol, " " + symbol + " ").trim();
}
} catch (ParseException e) {
// ignore
}
return null;
}
Upvotes: 2
Reputation: 108957
It's a bit of a hack but in a very similar situation, I used something like this
NumberFormat format = NumberFormat.getCurrencyInstance(new Locale("en", "in"));
String currencySymbol = format.format(0.00).replace("0.00", "");
System.out.println(format.format(30382.50).replace(currencySymbol, currencySymbol + " "));
all the currencies I had to deal with involved two decimal places so i was able to do "0.00"
for all of them but if you plan to use something like Japanese Yen, this has to be tweaked. There is a NumberFormat.getCurrency().getSymbol()
; but it returns INR
instead for Rs.
so that cannot be used for getting the currency symbol.
Upvotes: 7
Reputation: 24910
I dont think you can.
You should take a look at http://site.icu-project.org/
There might be better locale-specific currency formatting provided by icu4j.
Upvotes: 2
Reputation: 641
See if this works:
DecimalFormat fmt = (DecimalFormat) NumberFormat.getInstance();
fmt.setGroupingUsed(true);
fmt.setPositivePrefix("Rs. ");
fmt.setNegativePrefix("Rs. -");
fmt.setMinimumFractionDigits(2);
fmt.setMaximumFractionDigits(2);
fmt.format(30382.50);
Edit: Fixed the first line.
Upvotes: 6