I need to convert a string back to a double, but the string is not always the same format. In one case it is "N0", in another "#,##", and yet another is currency "C0". The good thing is, I know what format the string is in as earlier in the process it was converted from double to string.
How can I convert back to a double. The numeric only values double.parse or Convert.ToDouble with ease, but the currency values do not.
string format = "{0:C0}";
double dollar = 1,234.00;
string dollarString = String.Format(format, doubleValue); // == "$1,234"
double newDollar = Convert.ToDouble(dollarString); // Fails
This last line is where the issue is. I'm assuming I need to use IFormatProvider or Culture or something, but I'm not exactly sure.
I cannot specifically reference the format is a Currency as the "format" isn't always a currency.
Ideas?
As I was typing this I came up with the following. Further feedback on whether this is a good way of doing it or if I might run into issues later.
double newDollar;
double.TryParse(dollarString, NumberStyles.Any, CultureInfo.CurrentCulture.NumberFormat, out newDollar);
If you're using CultureInfo.CurrentCulture make sure to you set the CurrentCulture of your thread.
Else it can end up in parsing it the wrong way (depending on the language settings on your computer).
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US");
Then you can safely use this:
double.TryParse(dollarString, NumberStyles.Any,
CultureInfo.CurrentCulture.NumberFormat, out newDollar);
Alternatively, you can create a function like this (To get the right format without setting the culture).
side note: In Switzerland, this could cause troubles because the euros can still be parsed.
So 5,05 (€) would successfully be parsed to 505 (CHF). Trust me, you don't want this to happen.
public static double GetDouble(string value, double defaultValue)
{
double numberToConvert;
if (!double.TryParse(value, System.Globalization.NumberStyles.Any,
CultureInfo.CurrentCulture, out numberToConvert) &&
!double.TryParse(value, System.Globalization.NumberStyles.Any,
CultureInfo.GetCultureInfo("en-US"), out numberToConvert) &&
!double.TryParse(value, System.Globalization.NumberStyles.Any,
CultureInfo.InvariantCulture, out numberToConvert))
{
numberToConvert= defaultValue;
}
return numberToConvert;
}
Related
I have an ASP.NET MVC app that must work in both English and German. In one of my views, the user is inputting a decimal value and a date/time value.
// Get the price
string price = "1.23";
decimal priceValue = 0;
var allowedStyles = (NumberStyles.AllowDecimalPoint & NumberStyles.AllowThousands);
if (Decimal.TryParse(price, allowedStyles, CultureInfo.InvariantCulture, out priceValue))
{
model.Price = priceValue;
}
else
errors.Add("Please enter a valid price.");
// Parse the date
string date = "03/23/2015";
if (String.IsNullOrWhiteSpace(date) == false)
{
DateTime dateValue = DateTime.MinValue;
if (DateTime.TryParse(saleDate, out dateValue))
{
model.Date = dateValue;
}
else
errors.Add("Please enter a valid date.");
}
When the above code runs in the English culture, the Decimal.TryParse line returns false. When the code runs in the German culture, both the Decimal.TryParse and DateTime.TryParse lines return false. What am I doing wrong? How can I parse Decimal and DateTime values across cultures?
When the above code runs in the English culture, the Decimal.TryParse
line returns false
Because you are using bitwise AND with & operator and NumberStyles.AllowDecimalPoint & NumberStyles.AllowThousands generates NumberStyles.None which indicates no style for your element. From documentation;
Indicates that no style elements, such as leading or trailing white
space, thousands separators, or a decimal separator, can be present in
the parsed string. The string to be parsed must consist of integral
decimal digits only.
If you change & to | your Decimal.TryParse returns true.
When the code runs in the German culture, both the Decimal.TryParse
and DateTime.TryParse lines return false.
Same for Decimal.TryParse method. BUT, de-DE culture has , instead of . as a NumberDecimalSeparator. But it has . as a NumberGroupSeparator that's why it parses your 1.23 value as 123. It thinks this is a thousands separator, not a decimal separator.
For your DateTime.TryParse method, since you didn't tell us what is saleDate exactly, looks like it is not a standard date and time format for your CurrentCulture, that's why it returns false.
If you mean date instead of saleDate, that means MM/dd/yyyy is not a standard date and time format for your CurrentCulture and neither for de-DE culture.
You can use DateTime.TryParseExact or DateTime.ParseExact (preferable) method with a culture that has / as a DateSeparator like InvariantCulture like;
string date = "03/23/2015";
DateTime dt;
if(DateTime.TryParseExact(date, "MM/dd/yyyy", CultureInfo.InvariantCulture,
DateTimeStyles.None, out dt))
{
model.Date = dateValue;
}
You should not be using InvariantCulture for that. You should parsing using 1 culture at a time, then attempting the other if that fails.
When I tried to convert something like 0.1 (from user in textbox), My value b is always false.
bool b = Decimal.TryParse("0.1", out value);
How can it be here to work?
Specify the culture for the parsing. Your current culture uses some different number format, probably 0,1.
This will successfully parse the string:
bool b = Decimal.TryParse("0.1", NumberStyles.Any, CultureInfo.InvariantCulture, out value);
Too late to the party, but I was going to suggest forcing the culuture to en-US but Invariant is a better sln
decimal value;
bool b = Decimal.TryParse("0.1", NumberStyles.Any, new CultureInfo("en-US"), out value);
Use Culture in overload method
I want to convert "372551.40" to decimal. But I need to see it after converting this format 372.551,40.
To convert it to decimal, you can use:
decimal decimalValue = 0.0;
decimalValue = decimal.Parse("372551.40");
or
decimal.TryParse("372551.40", out decimalValue);
To display it in a specific format you can do:
CultureInfo tr = new CultureInfo("tr-TR");
string formattedValue = decimalValue.ToString("c", tr);
//result will be 372.551,40 YTL
formattedValue = decimalValue.ToString("0,0.00", tr);
//result will be 372.551,40
string value;
Decimal number;
value = "16,523,421";
if (!Decimal.TryParse(value,out number))
{
// set it to something if the "Value" is not a number
number = -1;
}
Do the following:
string s = "372551.40";
CultureInfo cultureInfo = CultureInfo.InvariantCulure; //Use relevant culture in which your number is formatted. In this case InvariantCulture would do.
decimal d;
bool succesful = Decimal.TryParse(s, NumberStyles.Number, cultureInfo, out d); //it will try to parse the string according to the specified culture.;
If you have a succesful parse, then d will store the numeric value represented by s as a decimal value which you can output into any formatted string and culture the ToString() or Format.String().
Note that if the culture in which the number represented by s is the current system culture, then you can use the TryParse(string s, out decimal d) overload where it is not necessary to specify NumberStyles and IFormatProvider.
Something like this?
string s = "372551.40";
decimal d;
if (decimal.TryParse(s, out d))
{
var culture = new CultureInfo("de-DE");
var result = d.ToString("0,0.00", culture);
// result is "372.551,40"
}
You can also use the current culture instead of hard-coding one like I did.
Hope this helps,
John
Use decimal.Parse() to make it a decimal. Then you have many formatting options.
The display as you mentioned is dependent on the culture setting.
Make your new CultureInfo and in the NumberFormat, you will have to modify some settings like Decimal Separator as , and Thousands Separator as . and provide this to the ToString method of the variable holding the decimal value.
This should display the value as 372.551,40
You can use .Replace
string string 1 = "372,551.40";
string1.Replace(",","");
decimalVal = System.Convert.ToDecimal(StringVal);
//shows 372551.40
You can always throw that into a for loop if you are playign with a ton of numbers.
You can find more in depth info and some examples on MSDN
The overload of decimal.Parse that takes an IFormatProvider will allow you to parse strings containing numbers with periods as decimal point symbols (in case the standard is a comma in your culture).
You can use ToString on the resulting decimal to format it with a comma by passing in an appropriate IFormatProvider. Both CulturInfo and NumberFormatInfo implement IFormatProvider.
You can get an instance of CultureInfo with the following code (this one is for English in Australia).
new CultureInfo("en-AU")
Also note that decimal.TryParse is a good alternative to the decimal.Parse method if you expect incorrectly formatted strings as it will allow you to handle them without an exception being raised.
The following code should give you the desired result (you wrote in one of the comments that the target system is SAP and that the culture is probably German (de-DE)).
var yourString = "372551.40";
var yourDecimal = decimal.Parse(yourString, CultureInfo.InvariantCulture);
var yourFormattedDecimal = yourDecimal.ToString(new CultureInfo("de-DE"));
From MSDN:
string value;
decimal number;
// Parse an integer with thousands separators.
value = "16,523,421";
number = Decimal.Parse(value);
Console.WriteLine("'{0}' converted to {1}.", value, number);
// Displays:
// 16,523,421' converted to 16523421.
Cheers
You can create custom NumberFormatInfo:
string s = "372551.40";
var dec = decimal.Parse(s, CultureInfo.InvariantCulture);
var nfi = new CultureInfo("en-US", false).NumberFormat;
nfi.NumberGroupSeparator = ".";
nfi.NumberDecimalSeparator = ",";
var res = dec.ToString("n", nfi);
var resDecimal = decimal.Parse(res, nfi);
Output is exactly what you need: 372.551,40
Thanks for taking the time to assist me with my problem.
In the code I'm writing, I'm iterating through a table, I get the appropriate values (confirmed it using the debugger) and I'm parsing them to the appropriate types before and finally I add them to an Object to be serialized into XML.
However, I bumped into a problem and that is I can't seem to find a way to parse the string into a decimal value. Take a look:
if (DateTime.TryParse(dateString, culture, styles, out date))
{
decimal LastValue;
string vrednost = String.Format("{0:0,0.0}",
row.SelectSingleNode("td[2]").InnerText);
if (Decimal.TryParse(vrednost, out LastValue))
list.Add(new StockEntry
{
Date = date,
PoslednaCena = LastValue
...
}
Note that the value of vrednost is 4.451,00 and I suspect that if I convert it to 4,451.00 it will get parsed.
I've succeeded in parsing date into the appropriate datetime value. However, the value of LastValue is always 0. I've exhausted all the resources that I know of. Do you have any idea how to solve my problem?
Thank you in advance!
This formatting will do nothing because you can't format strings like this. You have to use parse method with additional parameters and specify your own format
string s2 = "4.451,00";
NumberFormatInfo numberFormatInfo = new NumberFormatInfo();
numberFormatInfo.NumberDecimalSeparator = ",";
numberFormatInfo.NumberGroupSeparator = ".";
var d = decimal.Parse(s2, numberFormatInfo);
I think that your problem might be due to the culture used for the parsing. Try using CultureInfo.InvariantCulture for your parsing. It should work with "," as thousands separator and "." as decimal separator.
Decimal.TryParse(vrednost, NumberStyles.Number, CultureInfo.InvariantCulture, out LastValue);
If you want to swap them you could use another culture. Italian, for instance, works with your format (not sure about the others), so your code for "4.451,00" would look like:
Decimal.TryParse(vrednost, NumberStyles.Number, CultureInfo.GetCultureInfo("it"), out LastValue);
If you want to use a custom culture instead of forcing some culture which does what you want you can simply create your NumberFormatInfo class and pass it to the parse method.
NumberFormatInfo decimalNumber = new NumberFormatInfo();
decimalNumber.NumberDecimalSeparator = ",";
decimalNumber.NumberGroupSeparator = ".";
Decimal.TryParse(vrednost, NumberStyles.Number, decimalNumber, out LastValue);
Your row.SelectSingleNode("td[2]").InnerText is a string and you are trying to format it like a decimal.
Try parsing it directly:
decimal LastValue;
string vrednost = row.SelectSingleNode("td[2]").InnerText;
if (Decimal.TryParse(vrednost, out LastValue))
Check your cultureinfo at first and set it appropriately.
CultureInfo MyUsersCulture = Thread.CurrentThread.CurrentCulture;
Console.WriteLine("The culture: "+ MyUsersCulture.Name);
Thread.CurrentThread.CurrentCulture = new CultureInfo("de-DE");
ConsoleWriteLine("The culture: " + Thread.CurrentThread.CurrentCulture);
I have a field in DB which is float. My application is WindowsForm. I need to convert the value in textbox of the format 43.27 to double.
When I do this COnvert.ToDouble(txtbox.Text) I get exception saying input string is wrong format.
How to rectify this issue
Try specifying a culture when parsing:
// CultureInfo.InvariantCulture would use "." as decimal separator
// which might not be the case of the current culture
// you are using in your application. So this will parse
// values using "." as separator.
double d = double.Parse(txtbox.Text, CultureInfo.InvariantCulture);
And to handle the error case for gracefully instead of throwing exceptions around you could use the TryParse method:
double d;
if (double.TryParse(txtbox.Text, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out d))
{
// TODO: use the parsed value
}
else
{
// TODO: tell the user to enter a correct number
}
When you want to convert a string to number, you need to be sure which format does the string use. E.g. in English, there is a decimal point (“43.27”), while in Czech, there is a decimal comma (“43,27”).
By default, the current locale is used; if you know the number uses the English conversion, you need to specify the culture explicitly, e.g.
Convert.ToDouble(txtBox.Text, CultureInfo.InvariantCulture);