Search code examples
c#formattingdouble

How to use NumberFormatInfo


I want to be able to format any decimal number as I want. Specifically I want to be able to control:

  1. the number of decimals
  2. the decimal separator
  3. the thousand separator

I have tried to do that

var nfi = new NumberFormatInfo();
nfi.NumberDecimalDigits= 4;       <----- for point 1
nfi.NumberDecimalSeparator = "@"; <----- for point 2
nfi.NumberGroupSeparator = "^";   <----- for point 3? or
nfi.PerMilleSymbol= "#";          <----- for point 3?

and then I have applied it:

enter image description here

but for some reasons I can't get to have what I expect.

If I look here it seems that it applies to integers?

And also this answer is not helping.


Solution

  • The formatting properties NumberDecimalDigits, NumberDecimalSeparator, NumberGroupSeparator and PerMilleSymbol do not apply to all format strings. To determine their applicability you need to check the docs:

    • NumberDecimalDigits: The NumberDecimalDigits property is used with the "F" and "N" standard format strings without a precision specifier in numeric formatting operations.

    • NumberDecimalSeparator: The NumberDecimalSeparator property is used with the "E", "F", "G", "N", and "R" standard format strings to define the symbol that separates integral from fractional digits.

      It also used by the "." custom specifier.

    • NumberGroupSeparator: The NumberGroupSeparator property is used with the "N" standard format string to define the symbol that separates groups of integral digits.

      It is also used by the "," custom specifier.

    • PerMilleSymbol: The string assigned to the PerMilleSymbol property is included in the result string when a numeric value is formatted with a format string that includes the "‰" .

    Since, as noted in the doc remarks for ToString(IFormatProvider):

    The ToString(IFormatProvider) method formats a Double value in the default ("G", or general) format of a specified culture.

    Only NumberDecimalSeparator applies in this format. You need to pass formats for which you the other options are implemented to see their effect. For instance:

    double aaa = -123456.789;
    foreach (var formatString in new [] { "G", "N", "F", "P", "#0.## " + '\u2030'})
    {
        string str = aaa.ToString(formatString, nfi);
        Console.WriteLine("aaa.ToString(\"{0}\", nfi) = {1}", formatString, str);
    }
    

    Results in:

    aaa.ToString("G", nfi) = -123456@789
    aaa.ToString("N", nfi) = -123^456@7890
    aaa.ToString("F", nfi) = -123456@7890
    aaa.ToString("P", nfi) = -12,345,678.90 %
    aaa.ToString("#0.## ‰", nfi) = -123456789 #
    

    Demo fiddle here: https://dotnetfiddle.net/81HXz9