Cannot parse double - c#

I'm trying to parse values like $15,270.75 with the expression
double cost = 0;
double.TryParse("$15,270.75", NumberStyles.AllowThousands | NumberStyles.AllowCurrencySymbol | NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out cost);
but have no success

The currency symbol of Invariant culture is not $, its ¤. This works:
double cost = double.Parse("¤15,270.75", NumberStyles.AllowThousands | NumberStyles.AllowCurrencySymbol | NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture);
You'll need a CultureInfo that supports exactly this format.

The following works:
var culture = new CultureInfo("en-US");
culture.NumberFormat.CurrencyGroupSeparator = ".";
culture.NumberFormat.CurrencyDecimalSeparator = ",";
double.TryParse("$15.270,75", NumberStyles.AllowThousands | NumberStyles.AllowCurrencySymbol | NumberStyles.AllowDecimalPoint, culture, out cost);
The culture I used here is en-US for the $ symbol. The reason I manually set the group and decimal separators is because the format used in the input string are different from the culture of en-US.
Maybe you are expecting a specific culture that is not en-US. Try passing that one.

this is because you are using InvariantCulture. you need an american CultureInfo

This will not work with CultureInfo.Invariant culture. Use an appropriate CultureInfo.

If you want something that works for any locale, use CultureInfo.CurrentCulture for the IFormatProvider parameter.

Related

How to convert string into decimal?

I text box i have a value:
1212,12
Additionally my text box have a mask:
MaskType=Numeric
EditMask='n2'
i try to parse it:
var culture = CultureInfo.CreateSpecificCulture("en-US");
var value = decimal.Parse(myTextBox.Text, culture);
but get value=121212 when expected value=1212.12
What can be wrong?
en-US seperates the position after decimal point with a . instead of a ,
try another culture or set myTextBox.Text to 1212.12
You have a missmatching culture:
1212,12
and
en-US
Either use . as a decimal separator (i.e. 1212.12) or a culture which uses , (e.g. de-DE, de-AT, fr-FR), but en-US uses . as a decimal separator and , as a thousands separator.
Either change the separator or change the culture:
For en-US culture separator is .
If you want to use separator , use fr-FR culture !
var culture = CultureInfo.CreateSpecificCulture("fr-FR");
var value = decimal.Parse(myTextBox.Text, culture);
en-US culture have NumberDecimalSeparator as a . not , but it has NumberGroupSeparator as a ,
That's why it thinks your , is NumberGroupSeparator and that's why it parses as 121212.
As a solution, you can use different IFormatProvider which has , as a NumberDecimalSeparator or you can clone your en-US culture with CultureInfo.Clone method and set it's NumberDecimalSeparator property to , and changing it NumberGroupSeparator property something else.
string s = "1212,12";
var culture = (CultureInfo)CultureInfo.CreateSpecificCulture("en-US").Clone();
culture.NumberFormat.NumberDecimalSeparator = ",";
culture.NumberFormat.NumberGroupSeparator = ".";
decimal value = decimal.Parse(s, culture); // 1212.12

Converting Request QueryString to Decimal

I can not convert query string to decimal.
In this example, when I control Request.QueryString["Amount"] value, It is 32.52 After the below code works, The Amount values is 3252M like that. How can I easily do this?
decimal Amount= 0;
if (Request.QueryString["Amount"] != null)
Amount = Convert.ToDecimal(Request.QueryString["Amount"]);
Convert.ToDecimal uses your current culture settings by default.
I strongly suspect your CurrentCulture's NumberDecimalSeparator property is not ., but NumberGroupSeparator property is .
That's why your program thinks this is a thousands separator, not decimal separator and it parses as a 3252, not 32.52.
As a solution you can use a culture which have . as a NumberDecimalSeparator like InvariantCulture, or you can .Clone your current culture and set it's NumberDecimalSeparator to . 1
Amount = Convert.ToDecimal(Request.QueryString["Amount"], CultureInfo.InvariantCulture);
or
var culture = (CultureInfo)CultureInfo.CurrentCulture.Clone();
culture.NumberFormat.NumberDecimalSeparator = ".";
culture.NumberFormat.NumberGroupSeparator = ",";
Amount = Convert.ToDecimal("32.52", culture);
1: If your current culture's thousands separator is not . already. Otherwise, you need to change it as well. Both property can't have the same values for any culture
I think you are having problems with the Culture as stated in the rpevious answer. You may want to try using different cultures:
RetVal = decimal.Parse(Request.QueryString["Amount"], CultureInfo.CurrentCulture);
Then I would try:
RetVal = decimal.Parse(Request.QueryString["Amount"], CultureInfo.InvariantCulture);

Double.TryParse converts 0.1 to 1.0

Situation - The thread culture in my web app has been set to 'es' (Spanish)
Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture("es");
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("es");
The string value is "0.1"
For the following expression,
var value = "0.1"
provider = CultureInfo.CreateSpecificCulture("en-US")
double.TryParse(value.ToString(), NumberStyles.Any, provider, out number)
number returns 1.0. Which makes me think that it is picking the culture info from the thread. Not the one I provide.
The following unit test passes (as expected).
var numberInEnUS = "0.1";
var spanishCulture = CultureInfo.CreateSpecificCulture("es");
culture = new CultureInfo("en-US", false);
Thread.CurrentThread.CurrentCulture = spanishCulture;
Thread.CurrentThread.CurrentUICulture = spanishCulture;
double number;
double.TryParse(numberInEnUs, NumberStyles.Any, culture, out number);
Assert.AreEqual(0.1, number);
So, the question is why does double.TryParse fail in my application? Theoretically, 0.1 for Spanish is 1 (Separator for spanish is a decimal point '.'). However, number 1000.0 does not get converted to 10000. So, it seems that it fails only for 0.1
Any explanation is highly appreciated!
You say "0.1" is number in spanish. Actually not, It is numberInEnglish or something else
var numberInSpanish = "0.1";//this is number in english culture
It should be
var numberInSpanish = "0,1";//<--Note 0,1
NumberDecimalSeparator for spanish is ,. Parse 0,1 you'll get expected result.
var numberInSpanish = "0,1";
var spanishCulture = CultureInfo.CreateSpecificCulture("es");
var culture = new CultureInfo("en-US", false);
Thread.CurrentThread.CurrentCulture = spanishCulture;
Thread.CurrentThread.CurrentUICulture = spanishCulture;
double number;
double.TryParse(numberInSpanish, NumberStyles.Any, spanishCulture, out number);
Here number is correctly parsed to "0.1"
Your problem is in the mixture of decimal and thousand separators, namely:
'.' - thousand separator in "es" culture, when parsing, will be ignored (e.g. 1.000,0 == 1000,0)
',' - decimal deparator in "es" culture, separates integer and fractional parts
You can easily convince yourself:
var spanishCulture = CultureInfo.CreateSpecificCulture("es");
Char dS = spanishCulture.NumberFormat.NumberDecimalSeparator; // <- ','
Char tS = spanishCulture.NumberFormat.NumberGroupSeparator; // <- '.'
So, in your case the string "0.1" will be converted into 1.0 double since '.' as
being a thousand separator in es culture will be ignored.
You can do either:
Use Invariant culture instead of "es" one:
double.TryParse(numberInNeutral, NumberStyles.Any, CultureInfo.InvariantCulture, out number);
Or use actual Spanish number representation:
var numberInSpanish = "0,1";
double.TryParse(numberInSpanish, NumberStyles.Any, culture, out number);
I finally was able to identify what was wrong. The issue was not with the TryParse() function but the ToString() function.
The value was actually a Double type, not a string as I mentioned above. (My bad, I thought it was not relevant). I was actually doing a value.ToString(). This is where it uses the thread culture and changes the value.
So, if the value was 0.1, the value.ToString() changes it to "0,1". It automatically changes the decimal character based on the Thread culture. The TryParse then uses the en-US culture and convert "0,1" to 1.
To fix it, use Convert.ToString instead and pass in the culture info.
At the end, it was just a silly mistake.
LessonLearnt - Be careful when using ToString() in globalized applications!

Convert "2.45" to decimal

I know this is the silliest question to ask. But really I'm having trouble to convert price(string) to decimal. Here is what I have tried
string s = "123.45";
decimal d = decimal.Parse(s, NumberStyles.AllowCurrencySymbol | NumberStyles.AllowThousands | NumberStyles.AllowDecimalPoint);
But I'm getting Format exception
Also tried
decimal num;
bool pass = decimal.TryParse("2.85", out num);
num comes out as 0.
Any help will be greatly appreciated.
Try specifying an invariant culture in which . is the decimal separator:
string s = "123.45";
decimal d = decimal.Parse(
s,
NumberStyles.AllowCurrencySymbol | NumberStyles.AllowThousands | NumberStyles.AllowDecimalPoint,
CultureInfo.InvariantCulture
);
The Parse method uses the current thread culture to parse numbers. So if you are using some culture in which . is not the decimal separator (such as fr-FR for example) it won't work as it would expect the number to be 123,45 for instance.

Double parse with culture format

I have a double number as string. The number is
202.667,40
Which is 202667.4
How can I parse this string to get the value like: Double.Parse("202.667,40",?what here), or any other method to get the value would be great. Thanks
First, you need to know which culture this number is from, then:
CultureInfo culture = new CultureInfo("de"); // I'm assuming german here.
double number = Double.Parse("202.667,40", culture);
If you want to parse using the current thread culture, which by default is the one set for the current user:
double number = Double.Parse("202.667,40", CultureInfo.CurrentCulture);
I think i have found a solution which does not require a culture. Using a NumberFormatInfo you can force a format, no matter the culture:
// This is invariant
NumberFormatInfo format = new NumberFormatInfo();
// Set the 'splitter' for thousands
format.NumberGroupSeparator = ".";
// Set the decimal seperator
format.NumberDecimalSeparator = ",";
Then later:
System.Diagnostics.Debug.WriteLine(double.Parse("202.667,40", format)));
Outputs:
202667,4
Of course, this output (inner toString()) might differ per Culture(!)
Note that changing the input to "202,667.40" will result in a parse error, so the format should match your expected input.
Hope this helps someone..
Instead of having to specify a locale in all parses, I prefer to set an application wide locale, although if string formats are not consistent across the app, this might not work.
CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("pt-PT");
CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo("pt-PT");
Defining this at the begining of your application will make all double parses expect a comma as the decimal delimiter.
You could use Double.Parse(your_number, CultureInfo.CurrentCulture) and set CurrentCulture accordingly with Thread.CurrentThread.CurrentCulture.
Example:
Thread.CurrentThread.CurrentCulture = new CultureInfo("es-ES");
then later
Double.Parse(your_number, CultureInfo.CurrentCulture);
Note that if you explicitly assign the culture to the CurrentThread, it only applies to that thread.
var val=double.Parse( yourValue, CultureInfo.InvariantCulture);
http://www.erikschierboom.com/2014/09/01/numbers-and-culture/
For more flexibility you can set NumberDecimalSeparator
string number = "202.667,40";
double.Parse(number.Replace(".", ""), new CultureInfo(CultureInfo.CurrentCulture.Name) {NumberFormat = new NumberFormatInfo() {NumberDecimalSeparator = ","}});
Double.Parse("202.667,40", new System.Globalization.CultureInfo("de-DE"));
Instead of de-DE use whatever culture the string is in.

Categories