405

I have got a price field to display which sometimes can be either 100 or 100.99 or 100.9, What I want is to display the price in 2 decimal places only if the decimals are entered for that price , for instance if its 100 so it should only show 100 not 100.00 and if the price is 100.2 it should display 100.20 similarly for 100.22 should be same . I googled and came across some examples but they didn't match exactly what i wanted :

// just two decimal places
String.Format("{0:0.00}", 123.4567);      // "123.46"
String.Format("{0:0.00}", 123.4);         // "123.40"
String.Format("{0:0.00}", 123.0);         // "123.00"
7
  • 4
    possible duplicate of .net Format decimal to two places or a whole number Commented Aug 16, 2011 at 10:41
  • 2
    RE: "What I want is to display the price in 2 decimal places only if the decimals are entered for that price" -- so if the user types "100.00" you want to show "100.00", but if they type "100" you only want to show "100"? -- number types only track the value of the number -- not which of the insignificant digits were entered by a user and which were not -- for that you will need to use a string. Commented Dec 10, 2013 at 22:26
  • 2
    @BinaryWorrier I think that this question may be a duplicate, but it has much better and more complete answers. IMO the other one should be marked as a duplicate of this one.
    – Ryan Gates
    Commented Jan 31, 2015 at 10:50
  • 3
    just add .Replace(".00","") Commented Jun 2, 2017 at 9:01
  • 3
    All you need is value.ToString("0.##");
    – Mehdi
    Commented Nov 17, 2020 at 10:25

18 Answers 18

706

Sorry for reactivating this question, but I didn't find the right answer here.

In formatting numbers you can use 0 as a mandatory place and # as an optional place.

So:

// just two decimal places
String.Format("{0:0.##}", 123.4567);      // "123.46"
String.Format("{0:0.##}", 123.4);         // "123.4"
String.Format("{0:0.##}", 123.0);         // "123"

You can also combine 0 with #.

String.Format("{0:0.0#}", 123.4567)       // "123.46"
String.Format("{0:0.0#}", 123.4)          // "123.4"
String.Format("{0:0.0#}", 123.0)          // "123.0"

For this formating method is always used CurrentCulture. For some Cultures . will be changed to ,.

Answer to original question:

The simpliest solution comes from @Andrew (here). So I personally would use something like this:

var number = 123.46;
number.ToString(number % 1 == 0 ? "0" : "0.00");
4
  • 23
    At first, I thought this should be the answer, until I re-read the original question multiple times. The OP is not entirely clear what he exactly wants, but it seems he always wants 2 decimal places if someone enters a fraction. So if someone entered 1.1 then he'd want 1.10; this code wouldn't do that.
    – Doug S
    Commented May 27, 2014 at 1:45
  • 47
    Oops, I read it again and you're right. So, this isn't the right answer but at least someone might find this useful.
    – Gh61
    Commented May 29, 2014 at 17:11
  • 3
    What OP needed can be achieved with this: stackoverflow.com/a/33180829/2321042
    – Andrew
    Commented Jul 14, 2016 at 21:53
  • I just found it useful, and (somewhat) matching what a BoundField in a GridView does with a SqlDouble and no format instruction. You have to indicate the max# you'll show. (Vs. BoundField, happy to show as many or as few as you like)
    – fortboise
    Commented Dec 30, 2016 at 17:32
178

An inelegant way would be:

var my = DoFormat(123.0);

With DoFormat being something like:

public static string DoFormat( double myNumber )
{
    var s = string.Format("{0:0.00}", myNumber);

    if ( s.EndsWith("00") )
    {
        return ((int)myNumber).ToString();
    }
    else
    {
        return s;
    }
}

Not elegant but working for me in similar situations in some projects.

4
  • 10
    This isn't really the question that was asked -- but had it been -- why not just use string.Format("{0:0.00}").Replace(".00", "")? Commented Dec 10, 2013 at 22:28
  • 25
    @BrainSlugs83: depending on the current thread's CurrentCulture, decimal separator might not be .. Unless CultureInfo.InvariantCulture is used with string.Format, you would have to check the value of CultureInfo.NumberFormat.NumberDecimalSeparator, and that would be a real PITA. :)
    – vgru
    Commented Jan 15, 2014 at 13:08
  • @Uwe Keim What if i have 60000 int and I want it to be 60.000? Commented Mar 20, 2019 at 6:53
  • 2
    This answer is a case of "reinventing a square wheel". Does not take into account culture or the fact that this has already been handled by .NET.
    – bytedev
    Commented Apr 13, 2020 at 7:01
96

This is a common formatting floating number use case.

Unfortunately, all of the built-in one-letter format strings (eg. F, G, N) won't achieve this directly.
For example, num.ToString("F2") will always show 2 decimal places like 123.40.

You'll have to use 0.## pattern even it looks a little verbose.

A complete code example:

double a = 123.4567;
double b = 123.40;
double c = 123.00;

string sa = a.ToString("0.##"); // 123.46
string sb = b.ToString("0.##"); // 123.4
string sc = c.ToString("0.##"); // 123
2
  • 14
    But he wants 123.40, not 123.4.
    – Andrew
    Commented Jul 14, 2016 at 21:52
  • 15
    Not solving this question but solving mine. I upvote this to come up for everyone else to see.
    – Emad
    Commented Feb 7, 2017 at 8:20
68

Old question but I wanted to add the simplest option in my opinion.

Without thousands separators:

value.ToString(value % 1 == 0 ? "F0" : "F2")

With thousands separators:

value.ToString(value % 1 == 0 ? "N0" : "N2")

The same but with String.Format:

String.Format(value % 1 == 0 ? "{0:F0}" : "{0:F2}", value) // Without thousands separators
String.Format(value % 1 == 0 ? "{0:N0}" : "{0:N2}", value) // With thousands separators

If you need it in many places, I would use this logic in an extension method:

public static string ToCoolString(this decimal value)
{
    return value.ToString(value % 1 == 0 ? "N0" : "N2"); // Or F0/F2 ;)
}
0
31

try

double myPrice = 123.0;

String.Format(((Math.Round(myPrice) == myPrice) ? "{0:0}" : "{0:0.00}"), myPrice);
1
  • 6
    string.Format((number % 1) == 0 ? "{0:0}" : "{0:0.00}", number);
    – Patrick
    Commented May 2, 2014 at 13:20
15

If your program needs to run quickly, call value.ToString(formatString) for ~35% faster string formatting performance relative to $"{value:formatString}" and string.Format(formatString, value).

Data

C# String Formatting Performance - VS2017 15.4.5

Code

using System;
using System.Diagnostics;

public static class StringFormattingPerformance
{
   public static void Main()
   {
      Console.WriteLine("C# String Formatting Performance");
      Console.WriteLine("Milliseconds Per 1 Million Iterations - Best Of 5");
      long stringInterpolationBestOf5 = Measure1MillionIterationsBestOf5(
          (double randomDouble) =>
          {
             return $"{randomDouble:0.##}";
          });
      long stringDotFormatBestOf5 = Measure1MillionIterationsBestOf5(
          (double randomDouble) =>
          {
             return string.Format("{0:0.##}", randomDouble);
          });
      long valueDotToStringBestOf5 = Measure1MillionIterationsBestOf5(
          (double randomDouble) =>
          {
             return randomDouble.ToString("0.##");
          });
      Console.WriteLine(
$@"            $""{{value:formatString}}"": {stringInterpolationBestOf5} ms
 string.Format(formatString, value): {stringDotFormatBestOf5} ms
       value.ToString(formatString): {valueDotToStringBestOf5} ms");
   }

   private static long Measure1MillionIterationsBestOf5(
       Func<double, string> formatDoubleUpToTwoDecimalPlaces)
   {
      long elapsedMillisecondsBestOf5 = long.MaxValue;
      for (int perfRunIndex = 0; perfRunIndex < 5; ++perfRunIndex)
      {
         var random = new Random();
         var stopwatch = Stopwatch.StartNew();
         for (int i = 0; i < 1000000; ++i)
         {
            double randomDouble = random.NextDouble();
            formatDoubleUpToTwoDecimalPlaces(randomDouble);
         }
         stopwatch.Stop();
         elapsedMillisecondsBestOf5 = Math.Min(
            elapsedMillisecondsBestOf5, stopwatch.ElapsedMilliseconds);
      }
      return elapsedMillisecondsBestOf5;
   }
}

Code Output

C# String Formatting Performance
Milliseconds Per 1 Million Iterations - Best Of 5
            $"{value:formatString}": 419 ms
 string.Format(formatString, value): 419 ms
       value.ToString(formatString): 264 ms

References

Custom Numeric Format Strings [learn.microsoft.com]

Qt Charts BarChart Example [doc.qt.io]

2
  • Great to know it can be done within the $string notation. And if it's not used in a tight loop, then no worries about the performance hit. Commented Oct 20, 2020 at 9:55
  • This is mainly due to boxing and other extra allocations. See this answer for more details.
    – l33t
    Commented Jun 17, 2021 at 12:59
9

I don't know of anyway to put a condition in the format specifier, but you can write your own formatter:

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
               // all of these don't work
            Console.WriteLine("{0:C}", 10);
            Console.WriteLine("{0:00.0}", 10);
            Console.WriteLine("{0:0}", 10);
            Console.WriteLine("{0:0.00}", 10);
            Console.WriteLine("{0:0}", 10.0);
            Console.WriteLine("{0:0}", 10.1);
            Console.WriteLine("{0:0.00}", 10.1);

          // works
            Console.WriteLine(String.Format(new MyFormatter(),"{0:custom}", 9));
            Console.WriteLine(String.Format(new MyFormatter(),"{0:custom}", 9.1));
            Console.ReadKey();
        }
    }

    class MyFormatter : IFormatProvider, ICustomFormatter
    {
        public string Format(string format, object arg, IFormatProvider formatProvider)
        {
            switch (format.ToUpper())
            {
                case "CUSTOM":
                    if (arg is short || arg is int || arg is long)
                        return arg.ToString();
                    if (arg is Single || arg is Double)
                        return String.Format("{0:0.00}",arg);
                    break;
                // Handle other
                default:
                    try
                    {
                        return HandleOtherFormats(format, arg);
                    }
                    catch (FormatException e)
                    {
                        throw new FormatException(String.Format("The format of '{0}' is invalid.", format), e);
                    }
            }
            return arg.ToString(); // only as a last resort
        }

        private string HandleOtherFormats(string format, object arg)
        {
            if (arg is IFormattable)
                return ((IFormattable)arg).ToString(format, CultureInfo.CurrentCulture);
            if (arg != null)
                return arg.ToString();
            return String.Empty;
        }

        public object GetFormat(Type formatType)
        {
            if (formatType == typeof(ICustomFormatter))
                return this;
            return null;
        }
    }
}
0
8

Here is an alternative to Uwe Keim's method, which would still maintain the same method call:

var example1 = MyCustomFormat(123.1);  // Output: 123.10
var example2 = MyCustomFormat(123.95); // Output: 123.95
var example3 = MyCustomFormat(123);    // Output: 123

With MyCustomFormat being something like:

public static string MyCustomFormat( double myNumber )
{
    var str (string.Format("{0:0.00}", myNumber))
    return (str.EndsWith(".00") ? str.Substring(0, strLastIndexOf(".00")) : str;
}
3
  • This didn't work for me as it seems TrimEnd takes an array of chars like {',', '.', ' '} rather than a string like ".00" - See msdn.microsoft.com/en-us/library/system.string.trimend.aspx Commented Dec 4, 2013 at 15:28
  • You're right - not sure how I missed that. I've updated to work correctly.
    – Steve
    Commented Dec 5, 2013 at 15:29
  • 5
    Depending on the current thread's CurrentCulture, decimal separator might not be .. Unless CultureInfo.InvariantCulture is used with string.Format, you would have to check the value of CultureInfo.NumberFormat.NumberDecimalSeparator, which is rather inelegant.
    – vgru
    Commented Jan 15, 2014 at 13:09
7

Simple one line code :

public static string DoFormat(double myNumber)
{
    return string.Format("{0:0.00}", myNumber).Replace(".00","");
}
1
  • The problem with this is if it is run where the decimal separator is a comma. Check the comments for this answer.
    – Andrew
    Commented Feb 27, 2019 at 13:23
6

Try:

String.Format("{0:0.00}", Convert.ToDecimal(totalPrice));
1
  • 1
    This will fail on a culture where point is used as a thousands separator. I just tried it now.
    – sergiol
    Commented May 10, 2022 at 13:22
6

Try this:

var number = 123.4567;
var str = number.ToString("N2");
2
  • Thanks for your recomandation @help-info.de , that's right :)
    – Sepideh I
    Commented Jul 2, 2022 at 4:54
  • For me, this displays the value 100 as 100.00, which is not what the OP wanted.
    – Joe Strout
    Commented Aug 30, 2023 at 16:54
5

I am afraid there is no built-in format that will do this. You will have to use a different format depending on whether the value is a whole number or not. Or always format to 2 decimal places, and manipulate the string afterwards to remove any trailing ".00".

4

If none of the other answers work for you, it may be because you are binding the ContentProperty of a control in the OnLoad function, which means this won't work:

private void UserControl_Load(object sender, RoutedEventArgs e)
{
  Bind.SetBindingElement(labelName, String.Format("{0:0.00}", PropertyName), Label.ContentProperty) 
}

The solution is simple: there is a ContentStringFormat property in the xaml. So when you create the label do this:

//if you want the decimal places definite
<Label Content="0" Name="labelName" ContentStringFormat="0.00"/>

Or

//if you want the decimal places to be optional
<Label Content="0" Name="labelName" ContentStringFormat="0.##"/>
3

something like this will work too:

String.Format("{0:P}", decimal.Parse(Resellers.Fee)).Replace(".00", "")
1
  • That gives a percent?
    – user2761580
    Commented Jan 26, 2017 at 17:03
3

When dealing with decimals coming from a (T-)SQL database, you want to be able to convert nullable and non-nullable decimals with x decimal places and be able to review the code easily against your table definitions - and of course, display the right number of decimals to the user.

Unfortunately, the Entity Framework doesn't automatically convert something like a SQL decimal(18,2) into a .NET equivalent with the same number of decimal places (since there is only decimal with full precision available). You have to truncate the decimal places manually.

So, I did it this way:

public static class Extensions
{
    public static string ToStringDecimal(this decimal d, byte decimals)
    {
        var fmt = (decimals>0) ? "0." + new string('0', decimals) : "0";
        return d.ToString(fmt);
    }

    public static string ToStringDecimal(this decimal? d, byte decimals)
    {
        if (!d.HasValue) return "";
        return ToStringDecimal(d.Value, decimals);
    }
}

Example Usage:

void Main()
{
    decimal d = (decimal)1.2345;
    decimal? d2 = null; 

    Console.WriteLine(d.ToStringDecinal(2)); // prints: "1.23" (2 decimal places)
    Console.WriteLine(d.ToStringDecinal(0)); // prints: "1" (show integer number)
    Console.WriteLine(d2.ToStringDecimal(2)); // prints: "" (show null as empty string)
}
2

To make the code more clear that Kahia wrote in (it is clear but gets tricky when you want to add more text to it)...try this simple solution.

if (Math.Round((decimal)user.CurrentPoints) == user.CurrentPoints)
     ViewBag.MyCurrentPoints = String.Format("Your current Points: {0:0}",user.CurrentPoints);
else
     ViewBag.MyCurrentPoints = String.Format("Your current Points: {0:0.0}",user.CurrentPoints);

I had to add the extra cast (decimal) to have Math.Round compare the two decimal variables.

1

A recent project has a similar requirement. I wrote this decimal extension method, which uses the currency ("C") Format Specifier. In addition to removing zeros, it also has options for decimal digits precision, currency symbol, separator and culture.

public static DecimalExtension{

     public static string ToCurrency(this decimal val, 
                                     int precision = 2, 
                                     bool currencySymbol = false, 
                                     bool separator = false, 
                                     CultureInfo culture = null)
      {     
         if(culture == null) culture = new CultureInfo("en-US");
                                                   
         NumberFormatInfo nfi = culture.NumberFormat;
         nfi.CurrencyDecimalDigits = precision;
            
         string zeros = new String('0', precision);       
                    
         //Remove zeros
         var result = val.ToString("C",fi).Replace(nfi.CurrencyDecimalSeparator + zeros,"");
                     
         if(!separator) result = result.Replace(nfi.CurrencyGroupSeparator,"");
                    
         return currencySymbol? result: result.Replace(nfi.CurrencySymbol,"");      
        }   
}

Examples:

decimal Total = 123.00M;
Console.WriteLine(Total.ToCurrency());  
//output: 123

decimal Total = 1123.12M;
Console.WriteLine(Total.ToCurrency()); 
//Output:  1123.12

Console.WriteLine(Total.ToCurrency(4));
//Output:  1123.1200

Console.WriteLine(Total.ToCurrency(2,true,true));
//output:  $1,123.12
 
CultureInfo culture = new CultureInfo("pt-BR")  //Brazil
Console.WriteLine(Total.ToCurrency(2,true,true, culture));
//output:  R$ 1.123,12
-1

Try This

string Output = String.Format("{0:0.00}", Decimal.Parse(InputStringValue));

Not the answer you're looking for? Browse other questions tagged or ask your own question.