NumberFormat vs Joda money - java

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

Related

How to use decimal number without creating a String resource

In Java and Kotlin there is an API that can used to show a time without having to create a string resource.
In the example line of code below, this value allows the time of 8 hours after midnight to automatically chnage the way its displayed depending on the device locale.
val timeCustom = LocalTime.of(8, 0)
Is there something similar that can be used for a decimal number, where the value automatically uses a specific demical symbol dpending on the locale? (. or ,).
For example, to describe the height of something (e.g. 5 point 2 metres):
val decimalNumber = Decimal.of(5,2)
Is there something like this available?
You can use Locale.getDefault() e.g.
import java.text.NumberFormat;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
Locale currentLocale = Locale.getDefault();
Integer quantity = 123456;
Double amount = 345987.246;
NumberFormat numberFormatter;
String quantityOut;
String amountOut;
numberFormatter = NumberFormat.getNumberInstance(currentLocale);
quantityOut = numberFormatter.format(quantity);
amountOut = numberFormatter.format(amount);
System.out.println(quantityOut);
System.out.println(amountOut);
}
}
Output:
123,456
345,987.246

How can i format turkish lira with symbol?

I tried to do it with the locale, but it only appears as text and the symbol doesn't come out. I am using JAVA 14 SDK.
Code I tried:
Locale tr = new Locale("tr", "TR");
BigDecimal points = new BigDecimal(175678.64);
System.out.println(NumberFormat.getCurrencyInstance(tr).format(points));
Output:
175.678,64 TL
I want:
₺175.678,64
No problem
I broke out your code to multiple lines for easier debugging.
When I run it in the IdeOne.com site, I get your desired output.
By the way, you should pass your input number as text (add quote marks). Otherwise you are defeating the purpose of using BigDecimal.
/* package whatever; // don't place package name! */
import java.util.*;
import java.lang.*;
import java.io.*;
import java.math.* ;
import java.text.* ;
/* Name of the class has to be "Main" only if the class is public. */
class Ideone
{
public static void main (String[] args) throws java.lang.Exception
{
// your code goes here
Locale locale = new Locale("tr", "TR");
BigDecimal points = new BigDecimal( "175678.64" ) ;
NumberFormat f = NumberFormat.getCurrencyInstance( locale ) ;
String output = f.format( points ) ;
System.out.println( output ) ;
}
}
When run:
₺175.678,64
Consider using the Currency class of java.util.Currency.
The Currency class has two methods getSymbol() and getSymbol(Locale locale). In your case you should use the second method with the locale parameter. This will return a String that represents the currency symbol for turkish lira.
You can initialize your Currency object like this:
Currency currency = Currency.getInstance(tr);
and
currency.getSymbol(tr);
will return the currency symbol as a String
In addition, you should know that the unidoce representation of turkish lira symbol as a char in Java is \u20BA
try this change 'Locale.CANADA' with your country
NumberFormat format = NumberFormat.getCurrencyInstance(Locale.CANADA);
String currency = format.format(number);
System.out.println("Currency in Canada : " + currency);

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.

NumberFormat.parse() fails for some currency strings

I have a simple EditText, which allows the user to enter a number such as 45.60 (example for American Dollar). I then format this number using the following method:
public String format() {
NumberFormat formatter = NumberFormat.getCurrencyInstance(Locale.getDefault());
return formatter.format(amount.doubleValue());
}
And on my Android phone, the language is set to English (United States) - hence the Locale.getDefault() should return the US locale (and it does).
Now the edit text is correctly updated to: $45.60 (hence formatting the entered number works).
However if I attempt to parse the above String "$45.60" using the following method:
NumberFormat numberFormat = NumberFormat.getInstance(Locale.getDefault());
Number result = numberFormat.parse("$45.60");
It fails with:
java.lang.IllegalArgumentException: Failed to parse amount $45.60 using locale en_US.
If I set my phone to English/ UK, formatting this "45.60" to "£45.60" works correctly (as for US), however parsing "£45.60" fails, just as it does for the above US sample.
However, if I set my phone to German (Germany), formatting "45,60" to "45,60€" works correctly, AND parsing "45,60€" works correctly as well!
The only difference I see between those three currencies: The Euro is appended to the amount, while the Dollar and the Pound are prepended to the amount.
Does anyone have an idea, why the same code works for Euro, but not for Pound and Dollar? Am I missing something?
I also created a unit test, to reproduce the issue:
public void testCreateStringBased() throws Exception {
// For German locale
CurrencyAmount amount = new CurrencyAmount("25,46€", Locale.GERMANY);
assertEquals(25.46, amount.getAsDouble());
// For French locale
amount = new CurrencyAmount("25,46€", Locale.FRANCE);
assertEquals(25.46, amount.getAsDouble());
// For US locale
amount = new CurrencyAmount("$25.46", Locale.US);
assertEquals(25.46, amount.getAsDouble());
// For UK locale
amount = new CurrencyAmount("£25.46", Locale.UK);
assertEquals(25.46, amount.getAsDouble());
}
CurrencyAmount basically wraps the code I posted for parsing currency strings, except that it takes the given locale instead of the default locale. In the above example, the test succeeds for the GERMANY and FRANCE locale but fails for US and UK locale.
Since the answers that have been suggested thus far, did not completely solve the problem, I took a painfully amateurish approach:
String value = "$24,76"
value = value.replace(getCurrencySymbol(locale), StringUtils.EMPTY);
NumberFormat numberFormat = NumberFormat.getInstance(locale);
Number result = numberFormat.parse(value);
So now I simply strip the String value off it's currency symbol... This way I can process everything I want, such as: 45.78 or 45,78 or $45.78 or 45,78€ ....
Whatever the input, the currency symbol is simply stripped and I end up with the plain number. My unittests (see OP) now complete successfully.
If anyone comes up with something better, please let me know.
Try following:
NumberFormat numberFormat = new DecimalFormat("¤#.00", new DecimalFormatSymbols(Locale.UK));
numberFormat.parse("£123.5678");
¤ - currency sign, expects matches with currency symbol by Locale.
other pattern symbols you can see by following link http://docs.oracle.com/javase/6/docs/api/java/text/DecimalFormat.html
Try NumberFormat.getCurrencyInstance().parse() instead of NumberFormat.getInstance().parse().
You must know the locale of the string you wish to parse in order to have a locale-aware parser. The GBP string parse to a numeric ONLY when the NumberFormat's locale is en_GB; there is no such thing as a "universal" parser.
For example, how does the string "12.000" parse? For en-us, the answer is twelve; for de-de, the answer is twelve-thousand.
Always use NumberFormat.getCurrencyInstance( java.util.Locale ) to parse currency amounts.
I'm using below adapted from https://dzone.com/articles/currency-format-validation-and
import java.math.BigDecimal;
import org.apache.commons.validator.routines.*;
BigDecimalValidator currencyValidator = CurrencyValidator.getInstance();
BigDecimal parsedCurrency = currencyValidator.validate(currencyString);
if ( parsedCurrency == null ) {
throw new Exception("Invalid currency format (please also ensure it is UTF-8)");
}
If you need to insure the correct Locale is being used per user look at
Change locale on login
Sorry, but any answer provided are misleading. This is what I would call a BUG in Java.
An example like this explains it better. If I want to print a value in EUR using Locale.US and then I parse it again, it fails unless I specify on the DecimalFormat the currency (EUR). Using dollars, it works:
DecimalFormat df = new DecimalFormat("¤#,##0.00", new DecimalFormatSymbols(Locale.US));
df.setCurrency(Currency.getInstance("EUR"));
BigDecimal value = new BigDecimal("1.23");
String text = df.format(value);
System.out.println(text);
DecimalFormat df2 = new DecimalFormat("¤#,##0.00", new DecimalFormatSymbols(Locale.US));
df2.setParseBigDecimal(true);
BigDecimal parsed = (BigDecimal) df2.parse(text);
BigDecimalAsserts.assertBigDecimalEquals("parsed value is the same of the original", value, parsed);

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);
}
}

Categories