30

I read about NSLocaleCurrencySymbol, but where would I find the variable used to determine the "number of decimal places" used in a country's currency?

I.E. In the USA, it's common to see dollar amounts written with 2 decimal places: $1.23

What about many other countries?

BenMorel
  • 34,448
  • 50
  • 182
  • 322
Susanna
  • 771
  • 3
  • 10
  • 17

4 Answers4

34

There are a number of other countries that display a different number of decimal places. 2 is the majority, 0 (no cents in their currency, e.g., Japan) is the largest minority, 3 is used in just a few. No other number that I know off. When exchange rates are quoted, more decimals are typically used. The currencies with 0 and 3 that I'm aware of are shown below.

The ISO currency codes can be found at: http://www.iso.org/iso/support/currency_codes_list-1.htm http://en.wikipedia.org/wiki/ISO_4217 or http://www.currency-iso.org/en/home/tables/table-a1.html.

ISO Code           Currency Decimal places

ADP Andoran Peseta 0
AFA Afghani Afghani 0
BEF Belgian franc 0
BHD Bahraini dinar 3
BIF Burundi franc 0
BYB Belorussian rubel (old) 0
BYR Belorussian rubel (new) 0 
CLP Chilean peso 0
COP Colombian peso 0
DJF Djibouti franc 0
ECS Ecuadorian sucre 0
ESP Spanish peseta 0
GNF Guinea franc 0
GRD Greek drachma 0
HUF Hungarian forint 0
IDR Indonesian rupiah 0
IQD Iraqui dinar 3
ITL Italian lira 0
JOD Jordan dinar 3
JPY Japanese yen 0
KMF Comoros franc 0
KRW South Korean won 0
KWD Kuwaiti dinar 3
LAK Laos new kip 0
LUF Luxembourg franc 0
LYD Libyan dinar 3
MGF Madagascan franc 0
MZM Mozambique metical 0
OMR Omani rial 3
PTE Portugese escudo 0
PYG Paraguay guarani 0
ROL Roumanian Lei 0
RWF Rwanda franc 0
TJR Tadzhikistani rubel 0
TMM Turkmenistani manat 0
TND Tunesian dinar 3
TPE Timor escudo 0
TRL Turkish lira 0
TWD New Taiwan dollar 0
UGX Uganda shilling 0
VND Vietnamese dong 0
VUV Vanuata vatu 0
XAF CFA Franc BEAC 0
XOF CFA Franc BCEAO 0
XPF CFP Franc 0
nategood
  • 11,807
  • 4
  • 36
  • 44
Jorge Brana
  • 341
  • 3
  • 3
  • The link provided is no longer valid, I suspect it was meant to be: http://www.iso.org/iso/home/store/catalogue_tc/catalogue_detail.htm?csnumber=46121 but this just points to a page where you can buy the full spec. Wikipedia maintain the list here: http://en.wikipedia.org/wiki/ISO_4217 – knightpfhor Sep 25 '12 at 23:47
  • 1
    `DECIMAL(19, 4)` **is a popular choice** check [this](http://stackoverflow.com/questions/224462/storing-money-in-a-decimal-column-what-precision-and-scale) also check [here](http://www.thefinancials.com/Default.aspx?SubSectionID=curformat) World Currency Formats to decide how many decimal places to use , hope helps. – Shaiju T Oct 28 '15 at 12:53
  • MGA (Madagascar) and MRU (Mauritania) both has ⅕ coins, and commonly written as one decimal. CLF (Chile) seems to be using 4 decimal places. – This according to the Wikipedia article linked. – Liggliluff Jun 26 '18 at 07:16
  • Hi @Jorge Brana, would you be able to elaborate on where you obtained the list you copied? I notice that it has 0 given for the number of decimals used for COP, where as both of the lists you source show "2", as well as the ISO standard used by Java's Currency library. Unfortunately, 0 seems to be correct, rather than 2... – Fulluphigh Jul 30 '18 at 16:38
28

In iOS 6 (and possibly earlier) you can find out the number of digits after the decimal place of a currency from the minimumFractionDigits property of an NSNumberFormatter set to the correct locale:

void (^currency_test)(NSString *) = ^(NSString *locale) {
    NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
    [formatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:locale]];
    [formatter setNumberStyle:NSNumberFormatterCurrencyStyle];
    NSLog(@"%@: %@ (minimumFractionDigits = %d)", locale, [formatter stringFromNumber:@(1000)], [formatter minimumFractionDigits]);
};

currency_test(@"en_US");
currency_test(@"nl_NL");
currency_test(@"de_DE");
currency_test(@"fr_FR");
currency_test(@"jp_JP");
currency_test(@"ar_JO");

en_US: $1,000.00 (minimumFractionDigits = 2)
nl_NL: € 1.000,00 (minimumFractionDigits = 2)
de_DE: 1.000,00 € (minimumFractionDigits = 2)
jp_JP: ¥ 1000 (minimumFractionDigits = 0)
ar_JO: ١٠٠٠٫٠٠٠ د.أ.‏ (minimumFractionDigits = 3)

Note that you must call [formatter setNumberStyle:NSNumberFormatterCurrencyStyle] before the minimumFractionDigits property is populated with the correct value (that one only took me half an hour to work out!)

Robert Atkins
  • 23,528
  • 15
  • 68
  • 97
  • 2
    I can't believe this answer doesn't have more up votes and that it's not the accepted answer as it's the only one that really answers the OPs question. You've saved me hours of trial and error and trawling through docs. One of those valuable nuggets that only Stack Overflow can provide. Thanks! – mluisbrown Apr 05 '13 at 14:23
1

http://cldr.unicode.org/

This has much of what you're looking for.

S.Lott
  • 384,516
  • 81
  • 508
  • 779
1

Bulding on Robert Atkins' answer, it is possible to do the same thing on .NET. To test this code, create a Console App project and replace Program.cs with this:

using System;
using System.Globalization;
using System.Linq;

namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            decimal amount = 100.123M;

            Console.WriteLine(GetNumberOfDecimales("USD", 2));     // 2
            Console.WriteLine(GetNumberOfDecimales("EUR", 2));     // 2
            Console.WriteLine(GetNumberOfDecimales("JPY", 2));     // 0
            Console.WriteLine(GetNumberOfDecimales("BHD", 2));     // 3
            Console.WriteLine(GetNumberOfDecimales("___", 2));     // 2

            Console.WriteLine(LocalizeAmount(amount, "USD"));   // 100.12
            Console.WriteLine(LocalizeAmount(amount, "EUR"));   // 100.12
            Console.WriteLine(LocalizeAmount(amount, "JPY"));   // 100
            Console.WriteLine(LocalizeAmount(amount, "BHD"));   // 100.123
            Console.WriteLine(LocalizeAmount(amount, "___"));   // 100.12
        }

        /// <summary>
        /// 
        ///     Returns an amount with the correct number of decimals for the given currency.
        ///     The amount is rounded.
        ///     
        ///     Ex.: 
        ///         100.555 JPY => 101
        ///         100.555 USD => 100.56
        /// 
        /// </summary>
        static public string LocalizeAmount(decimal amount, string currencyCode)
        {
            var formatString = String.Concat("{0:F", GetNumberOfDecimales(currencyCode, 2), "}");      // {0:F2} for example
            return String.Format(formatString, amount);
        }

        /// <summary>
        /// 
        ///     Returns the number of decimal places for a currency.
        /// 
        ///     Ex.: 
        ///         JPY => 0
        ///         USD => 2
        ///         
        /// </summary>
        static public int GetNumberOfDecimales(string currencyCode, int defaultValue = 2)
        {
            var cultureInfo = GetFirstCultureInfoByCurrencySymbol(currencyCode);
            return cultureInfo?.NumberFormat?.CurrencyDecimalDigits ?? defaultValue;
        }

        static private CultureInfo GetFirstCultureInfoByCurrencySymbol(string currencySymbol)
        {
            if (string.IsNullOrWhiteSpace(currencySymbol))
                throw new ArgumentNullException("A valid currency must be provided.");

            return CultureInfo.GetCultures(CultureTypes.SpecificCultures)
                              .FirstOrDefault(x => new RegionInfo(x.LCID).ISOCurrencySymbol == currencySymbol);
        }
    }
}
Konrad Borowski
  • 11,584
  • 3
  • 57
  • 71
Sylvain Rodrigue
  • 4,751
  • 5
  • 53
  • 67