Need to convert number with comma to decimal in C#? Call decimal.Parse with NumberStyles.Number and an explicit culture, so the comma is read as a thousands separator:
using System.Globalization;
var us = CultureInfo.GetCultureInfo("en-US");
CultureInfo.CurrentCulture = us;
decimal sales = decimal.Parse("1,234,567.89", NumberStyles.Number, us);
Console.WriteLine(sales); // 1234567.89
Console.WriteLine(sales + 0.11m); // 1234568.00
That turns “1,234,567.89” into a real decimal you can do math with. I ran every snippet below on .NET 10 with 2026 sales numbers, including the bad input and European formats that break this.
decimal.Parse with NumberStyles.Number: Convert a Comma Number to Decimal
decimal.Parse(string, NumberStyles, IFormatProvider) is the method you want. The style says which symbols may appear; the culture says what the comma and dot mean.
My running sample is a 2026 sales report from Front Range Outfitters, a made-up outdoor store in Denver. Here are four amounts the way the report prints them:
using System.Globalization;
var us = CultureInfo.GetCultureInfo("en-US");
CultureInfo.CurrentCulture = us; // print in en-US too
// Front Range Outfitters, Denver: 2026 sales report values
string[] amounts = { "1,234,567.89", "48,250", "-2,150.75", " 980.10 " };
foreach (string text in amounts)
{
decimal value = decimal.Parse(text, NumberStyles.Number, us);
Console.WriteLine($"{text,-14} -> {value}");
}
var flags = NumberStyles.AllowThousands | NumberStyles.AllowDecimalPoint;
Console.WriteLine(decimal.Parse("48,250.50", flags, us));
Output:
1,234,567.89 -> 1234567.89
48,250 -> 48250
-2,150.75 -> -2150.75
980.10 -> 980.10
48250.50

All four parse, including the minus sign and the padded ” 980.10 “. NumberStyles.Number allows thousands separators, a decimal point, a sign and white space.
The last line uses AllowThousands | AllowDecimalPoint instead. It also works (48250.50), but it rejects a minus sign and spaces, so I’d rather use NumberStyles.Number.
I use decimal rather than double for money because it keeps exact base-10 digits; the C# data types guide compares them. Going the other way, from a value back to “1,234,567.89”, is covered in format a number with commas and decimals in C#.
Which NumberStyles Value Accepts a Comma?
Plain decimal.Parse(text) already uses NumberStyles.Number, but with the PC’s current culture. These are the styles you’ll actually pick from (flags from Microsoft Learn’s NumberStyles table):
| NumberStyles | Thousands comma | Decimal point | $ sign | (45.00) as negative |
|---|---|---|---|---|
Number | Yes | Yes | No | No |
AllowThousands | AllowDecimalPoint | Yes | Yes | No | No |
Currency | Yes | Yes | Yes | Yes |
Float | No | Yes | No | No |
Integer | No | No | No | No |
So Float and Integer fail on “48,250”. That’s also why int.Parse chokes on a comma, which you can work around as shown in convert a string to int without int.Parse.
Use decimal.TryParse for User Input with Commas
decimal.Parse throws FormatException on bad text. For anything a person types, decimal.TryParse returns false instead. Same en-US culture, six inputs a cashier could enter:
using System.Globalization;
var us = CultureInfo.GetCultureInfo("en-US");
CultureInfo.CurrentCulture = us;
string?[] inputs = { "1,250.00", "abc", "", null, "12,50", "1,2,3" };
foreach (string? input in inputs)
{
if (decimal.TryParse(input, NumberStyles.Number, us, out decimal amount))
Console.WriteLine($"{input ?? "null",-10} -> {amount}");
else
Console.WriteLine($"{input ?? "null",-10} -> not a valid amount");
}
Output:
1,250.00 -> 1250.00
abc -> not a valid amount
-> not a valid amount
null -> not a valid amount
12,50 -> 1250
1,2,3 -> 123

“abc”, the empty string and null all print “not a valid amount” with no exception. That’s the main reason to prefer it over wrapping Parse in a try-catch block in C#.
Important: look at the last two lines. “12,50” became 1250 and “1,2,3” became 123, because .NET doesn’t check the group size around a comma. If a typo like that matters, validate the pattern before you parse.
The null case is the same idea as in convert null to int in C#: TryParse hands you a false and a 0, so pick your own default.
Parse Currency Strings with a Dollar Sign (NumberStyles.Currency)
Spreadsheet exports often keep the $ sign and use parentheses for refunds. NumberStyles.Number refuses the $, so switch to NumberStyles.Currency:
using System.Globalization;
var us = CultureInfo.GetCultureInfo("en-US");
CultureInfo.CurrentCulture = us;
string[] cells = { "$1,234.56", "($45.00)", "-$12.30", "$ 2,500" };
foreach (string cell in cells)
{
decimal value = decimal.Parse(cell, NumberStyles.Currency, us);
Console.WriteLine($"{cell,-10} -> {value}");
}
bool ok = decimal.TryParse("$1,234.56", NumberStyles.Number, us, out _);
Console.WriteLine($"Number style with $: {ok}");
Output:
$1,234.56 -> 1234.56
($45.00) -> -45.00
-$12.30 -> -12.30
$ 2,500 -> 2500
Number style with $: False

“$1,234.56” gives 1234.56, and the refund “($45.00)” comes back as -45.00. The last line confirms that NumberStyles.Number returns False for the same $ string.
How Do You Convert a European Number Like 1.234,56 to Decimal?
In Germany, France and much of Europe, the comma IS the decimal separator and the dot groups thousands. A Berlin supplier’s invoice total of “1.234,56” needs the de-DE culture:
using System.Globalization;
var de = CultureInfo.GetCultureInfo("de-DE");
var us = CultureInfo.GetCultureInfo("en-US");
CultureInfo.CurrentCulture = us;
string fromBerlin = "1.234,56";
decimal value = decimal.Parse(fromBerlin, NumberStyles.Number, de);
Console.WriteLine($"de-DE: {value}");
bool ok = decimal.TryParse(fromBerlin, NumberStyles.Number, us, out decimal wrong);
Console.WriteLine($"en-US: {ok} {wrong}");
Console.WriteLine($"de-DE \"12,50\": {decimal.Parse("12,50", de)}");
Console.WriteLine($"en-US \"12,50\": {decimal.Parse("12,50", us)}");
Output:
de-DE: 1234.56
en-US: False 0
de-DE "12,50": 12.50
en-US "12,50": 1250

With de-DE you get 1234.56. With en-US, TryParse returns False because a dot followed by a comma makes no sense there.
The scary pair is “12,50”: de-DE reads it as 12.50 and en-US as 1250. Neither throws, so you must know where the data came from.
The same culture rules apply to double.Parse; see convert a string to double in C# for the floating-point side.
Why Replace(“,”, “”) Is a Risky Way to Remove Commas
A lot of old code strips the commas and parses what’s left. It works on US text and quietly breaks on everything else:
using System.Globalization;
var inv = CultureInfo.InvariantCulture;
CultureInfo.CurrentCulture = inv;
string[] samples = { "1,234.56", "1.234,56", "12,50" };
foreach (string s in samples)
{
string stripped = s.Replace(",", "");
decimal value = decimal.Parse(stripped, inv);
Console.WriteLine($"{s,-9} -> \"{stripped}\" -> {value}");
}
Output:
1,234.56 -> "1234.56" -> 1234.56
1.234,56 -> "1.23456" -> 1.23456
12,50 -> "1250" -> 1250
“1,234.56” is fine. But the European “1.234,56” turns into 1.23456 and “12,50” into 1250, and nothing throws.
A culture-aware Parse either fails or reads the value right. If you need to round the result afterwards, show a number with 2 decimal places covers that part.
Always Pass a Culture to decimal.Parse: InvariantCulture vs Server Culture
Calls without a culture use CultureInfo.CurrentCulture, which comes from the machine. My own dev PC isn’t set to en-US, and a cloud server in Frankfurt won’t be either. Here’s “1,234.56” under three cultures:
using System.Globalization;
string text = "1,234.56";
var cultures = new[] { CultureInfo.InvariantCulture,
CultureInfo.GetCultureInfo("en-US"), CultureInfo.GetCultureInfo("de-DE") };
foreach (var culture in cultures)
{
CultureInfo.CurrentCulture = culture; // what the server is set to
bool ok = decimal.TryParse(text, out decimal value);
string name = culture.Name == "" ? "Invariant" : culture.Name;
Console.WriteLine($"{name,-10} {ok,-5} {value}");
}
Output:
Invariant True 1234.56
en-US True 1234.56
de-DE False 0
CultureInfo.InvariantCulture and en-US read 1234.56; de-DE returns False. The code didn’t change, only the machine setting did.
My rule: pass CultureInfo.InvariantCulture for files, APIs and config you control, pass the user’s culture for what people type, and never rely on the default. decimal.Parse(text, CultureInfo.InvariantCulture) already implies NumberStyles.Number.
Once the amount is a decimal, these are the next stops:
- Every ToString overload for printing it back
- Casting between decimal, double and int
- Parsing strings with leading zeros
Frequently Asked Questions
How do I convert “1,234.56” to decimal in C#?
Use decimal.Parse("1,234.56", NumberStyles.Number, CultureInfo.GetCultureInfo("en-US")). It returns 1234.56. Use decimal.TryParse with the same arguments when the text comes from a user.
Why does decimal.Parse throw FormatException on a comma?
The style or culture doesn’t allow it. NumberStyles.Float and Integer reject thousands separators, and a de-DE machine reads the comma as the decimal point. Pass NumberStyles.Number and the culture the text was written in.
How do I convert a string with a comma as the decimal separator?
Parse it with a culture that uses a comma decimal, such as de-DE: decimal.Parse("1.234,56", CultureInfo.GetCultureInfo("de-DE")) returns 1234.56.
Can I parse a string with a $ sign to decimal?
Yes, with NumberStyles.Currency and en-US. “$1,234.56” becomes 1234.56, and “($45.00)” becomes -45.00. NumberStyles.Number returns false for the $ sign.
Where are the NumberStyles flags documented?
The NumberStyles enum on Microsoft Learn lists every flag and which composite styles (Number, Currency, Float) include it.
Bijay Kumar is a renowned software engineer, accomplished author, and distinguished Microsoft Most Valuable Professional (MVP) specializing in SharePoint. With a rich professional background spanning over 15 years, Bijay has established himself as an authority in the field of information technology. He possesses unparalleled expertise in multiple programming languages and technologies such as ASP.NET, ASP.NET MVC, C#.NET, and SharePoint, which has enabled him to develop innovative and cutting-edge solutions for clients across the globe. Read more…