68

Is there a way to format the correct currency representation for a country?

Example UK -£127.54 Netherlands € 127,54- USA $127.54

etc..

Some things to consider,

  1. Currency Symbol

  2. Currency symbol placement -- It can be either place before or after the digits.

  3. Negative-amount display

001
  • 62,807
  • 94
  • 230
  • 350

8 Answers8

118

Try the Currency Format Specifier ("C"). It automatically takes the current UI culture into account and displays currency values accordingly.

You can use it with either String.Format or the overloaded ToString method for a numeric type.

For example:

decimal value = 12345.6789M; // Be sure to use Decimal for money values. Do not use IEEE-754 types such as float (System.Single) and double (System.Double) as they can only store approximate values.
Console.WriteLine(value.ToString("C", CultureInfo.CurrentCulture));

Console.WriteLine(value.ToString("C3", CultureInfo.CurrentCulture));

Console.WriteLine(value.ToString("C3", CultureInfo.CreateSpecificCulture("da-DK")));

// The example displays the following output on a system whose
// current culture is English (United States):
//       $12,345.68
//       $12,345.679
//       kr 12.345,679
Dai
  • 141,631
  • 28
  • 261
  • 374
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
  • 1
    One small note for future readers, decimals are the preferred type for currency values. Please see this answer by Zneak for more detail: https://stackoverflow.com/a/3730040/2573109 – Trevor.Screws Dec 04 '17 at 02:10
42

This kind of functionality is built in.

When using a decimal you can use a format string "C" or "c".

decimal dec = 123.00M;
string uk = dec.ToString("C", new CultureInfo("en-GB")); // uk holds "£123.00"
string us = dec.ToString("C", new CultureInfo("en-US")); // us holds "$123.00"
JumpingJezza
  • 5,498
  • 11
  • 67
  • 106
Oded
  • 489,969
  • 99
  • 883
  • 1,009
22

You can use string.Format("{0:c}", value).

See also here:

sikander
  • 2,286
  • 16
  • 23
Martin Buberl
  • 45,844
  • 25
  • 100
  • 144
  • Link is no longer valid, try this instead: https://learn.microsoft.com/en-us/globalization/locale/currency-formatting-in-the-dotnet-framework – keithl8041 Jan 11 '21 at 09:18
10

The problem with taking a given number and displaying it with .ToString("C", culture) is that it effectively changes the amount to the default currency of the given culture. If you have a given amount, the ISO currency code of that amount, and you want to display it for a given culture, I would recommend just creating a decimal extension method like the one below. This will not automatically assume that the currency is in the default currency of the culture:

public static string ToFormattedCurrencyString(
    this decimal currencyAmount,
    string isoCurrencyCode,
CultureInfo userCulture)
{
    var userCurrencyCode = new RegionInfo(userCulture.Name).ISOCurrencySymbol;

    if (userCurrencyCode == isoCurrencyCode)
    {
        return currencyAmount.ToString("C", userCulture);
    }

    return string.Format(
        "{0} {1}", 
        isoCurrencyCode, 
        currencyAmount.ToString("N2", userCulture));
}

This will either use the local currency symbol or the ISO currency code with the amount -- whichever is more appropriate. More on the topic in this blog post.

jakejgordon
  • 4,008
  • 7
  • 36
  • 45
  • In some cultures the number format is different to the currency format, so this cannot work in any culture. You'd rather accept that your format changes with the currency or you simply need to do the formatting entirely yourself. – Martin Braun Nov 14 '21 at 12:31
3

This code- (sets currency to GB(Britain/UK/England/£) then prints a line. Then sets currency to US/$ and prints a line)

Thread.CurrentThread.CurrentCulture = new CultureInfo("en-GB",false);         
Console.WriteLine("bbbbbbb   {0:c}",4321.2);
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US",false);
Console.WriteLine("bbbbbbb   {0:c}",4321.2);

Will display-

bbbbbbb   £4,321.20
bbbbbbb   $4,321.20

For a list of culture names e.g. en-GB en-US e.t.c.
http://msdn.microsoft.com/en-us/library/system.globalization.cultureinfo(v=vs.80).aspx

barlop
  • 12,887
  • 8
  • 80
  • 109
3

If you just have the currency symbol and the number of decimal places, you can use the following helper function, which respects the symbol/amount order, separators etc, only changing the currency symbol itself and the number of decimal places to display to.

public static string FormatCurrency(string currencySymbol, Decimal currency, int decPlaces)
{
    NumberFormatInfo localFormat = (NumberFormatInfo)NumberFormatInfo.CurrentInfo.Clone();
    localFormat.CurrencySymbol = currencySymbol;
    localFormat.CurrencyDecimalDigits = decPlaces;
    return currency.ToString("c", localFormat);
}
Clint Good
  • 820
  • 6
  • 14
0

It might be the case that you cannot use the culture approach at all, for instance when you want to have a specific formatting independently from any culture or currency. Even @jackjgordon's approach is not reliable, because some cultures have a different number format than currency format, making this inconsistent.

Here is a manual formatter that works without any culture, so you can format your numbers independently.

public static class CustomNumberFormatExtensions
{
    static readonly StringBuilder formatTextBuilder = new StringBuilder();

    public static string ToCustomFormattedString(this decimal d, int decimalPrecision, string decimalPoint, string groupSeperator = "", int groupLength = 3, MidpointRounding rounding = MidpointRounding.AwayFromZero)
    {
        lock (formatTextBuilder)
        {
            formatTextBuilder.Clear();

            string rawDigits = Math.Round(d * (decimal)Math.Pow(10, decimalPrecision), 0, rounding).ToString();
            rawDigits = rawDigits.PadLeft(decimalPrecision + 1, '0');

            if (decimalPrecision > 0)
            {
                formatTextBuilder.Insert(0, rawDigits.Substring(rawDigits.Length - decimalPrecision));
                rawDigits = rawDigits.Substring(0, rawDigits.Length - decimalPrecision);
                formatTextBuilder.Insert(0, decimalPoint);
            }

            while (rawDigits.Length > groupLength)
            {
                formatTextBuilder.Insert(0, rawDigits.Substring(rawDigits.Length - groupLength));
                rawDigits = rawDigits.Substring(0, rawDigits.Length - groupLength);
                formatTextBuilder.Insert(0, groupSeperator);
            }

            return rawDigits + formatTextBuilder.ToString();
        }
    }

    public static string ToCustomFormattedString(this double d, int decimalPrecision, string decimalSeperator, string groupSeperator = "", int groupLength = 3, MidpointRounding rounding = MidpointRounding.AwayFromZero)
    {
        return ((decimal)d).ToCustomFormattedString(decimalPrecision, decimalSeperator, groupSeperator, groupLength, rounding);
    }
}
Martin Braun
  • 10,906
  • 9
  • 64
  • 105
-7
public static string ToFormattedCurrencyString(
    this decimal currencyAmount,
    string isoCurrencyCode,
    CultureInfo userCulture)
{
    var userCurrencyCode = new RegionInfo(userCulture.Name).ISOCurrencySymbol;

if (userCurrencyCode == isoCurrencyCode)
{
    return currencyAmount.ToString("C", userCulture);
}

return string.Format(
    "{0} {1}", 
    isoCurrencyCode, 
    currencyAmount.ToString("N2", userCulture));

}

Trimax
  • 2,413
  • 7
  • 35
  • 59