3

With a quick test C#'s currency format doesn't appear to support optional decimal places.

CultureInfo ci = new CultureInfo("en-US");
String.Format(ci, "{0:C2}", number); // Always 2 decimals
String.Format(ci, "{0:C6}", number); // Always 6 decimals

Trying to customize it doesn't work.

String.Format(ci, "{0:C0.00####}", number); // two decimals always, 4 optional

Is it possible to use the currency format with an optional number of decimals?

e.g. $199.99 or $0.009999 or $5.00 are shown like this.

lko
  • 8,161
  • 9
  • 45
  • 62
  • 1
    I could suggest you to write a method, which will get first a string with maximum number of digits and then remove optional, if they are zeroes, before returning result. – Sinatr Jan 22 '14 at 14:31

2 Answers2

2

It's a bit long-winded, but you could first calculate the number of decimal places. Then, you can use that number to form your format string.

You'll need this utility function (credits go to a guy by the name of Joe):

private int CountDecimalPlaces(decimal value)
{
    value = decimal.Parse(value.ToString().TrimEnd('0'));
    return BitConverter.GetBytes(decimal.GetBits(value)[3])[2];
}

Then you can do something along these lines:

decimal number = 5.0M;

CultureInfo ci = CultureInfo.CurrentCulture;

NumberFormatInfo nfi = ci.NumberFormat.Clone() as NumberFormatInfo;

// Count the decimal places, but default to at least 2 decimals
nfi.CurrencyDecimalDigits = Math.Max(2 , CountDecimalPlaces(number));

// Apply the format string with the specified number format info
string displayString = string.Format(nfi, "{0:c}", number);

// Ta-da
Console.WriteLine(displayString);
Steven Liekens
  • 13,266
  • 8
  • 59
  • 85
  • I had to add a Decimal.TryParse with the value using a string format ("0.######") to first rid the excess 0's in the CountDecimalPlaces, otherwise it counted $0.100000 without removing the excess numbers past 2 decimals. If you add that I'll mark this as the answer. (Otherwise they aren't really optional, thanks to you and `Sinatr` the combination works perfectly) – lko Jan 23 '14 at 10:52
  • Yes, (the min decimals would be 2, and the max can easily be set if needed) and the rest of your code works perfectly. – lko Jan 23 '14 at 11:13
  • I didn't test that case, but now I'm surprised that the utility function also counts trailing zero's. I'll see if there's another way. – Steven Liekens Jan 23 '14 at 11:15
  • I think this works well, it just requires `Decimal.TryParse(amount.Value.ToString("0.######"), (hashes as needed for your max decimal) out removeTrailingZerosAmount)`and then `count = BitConverter.GetBytes(Decimal.GetBits(removeTrailingZerosAmount)[3])[2];` if the parse succeeded. Of course if there's a better way I'm interested, however this gets the job done too. – lko Jan 23 '14 at 11:17
  • @Iko there doesn't seem to be a way to discard the trailing zeros without converting to a string. See my updated answer. – Steven Liekens Jan 23 '14 at 11:28
  • You can use this method to get rid of trailing zeros without converting to a string: https://stackoverflow.com/a/7983330/3585218 – tipa Feb 10 '22 at 13:42
  • 1
    `CountDecimalPlaces()` will throw an exception if `value` is zero – Conman_123 Aug 17 '23 at 05:48
1

I am not sure if there is a direct way for doing that with using C but you can do:

decimal number = 1M;
CultureInfo ci = new CultureInfo("en-US");
string formattedValue = string.Format("{0}{1}", 
                                    ci.NumberFormat.CurrencySymbol, 
                                    number.ToString("0.00####")); 
Habib
  • 219,104
  • 29
  • 407
  • 436
  • Thanks, the main problem with this is you lose the ability to automatically format the currency according to culture (since you manually write the output). In some languages $199.99 is written as 199,99$. This example could work in certain cultures or cases but not in this case since it always outputs "$" and then the formatted number. – lko Jan 23 '14 at 06:58