Use of CultureInfo.InvariantCulture - c#

I'm working on a project that uses decimals in a textbox. I'm currently developing in a machine that has decimal separators set to "," instead of "." so I had to use this sentence when parsing text string into decimal:
decimal number = Decimal.Parse(number.Text, CultureInfo.InvariantCulture);
Now... Is CultureInfo.InvariantCulture the right thing to do or should I use CurrentCulture instead?
Thank you,
Matias.

For user input, you usually want CultureInfo.CurrentCulture. The fact that you're using a locale that's not natural to you is not the usual user case - if the user has , as the decimal point in their whole system, they're probably used to using that, instead of your preferred .. In other words, while you're testing on a system with locale like that, learn to use , instead of . - it's part of what makes locale testing useful :)
On the other hand, if you're e.g. storing the values in a configuration file or something like that, you really want to use CultureInfo.InvariantCulture.
The thinking is rather simple - is it the user's data (=> CurrentCulture), or is it supposed to be global (=> InvariantCulture)?

If you do a correctly internationalized program...
A) If you are using Winforms or WPF or in general the user will "work" on the machine of the program, then input parsing should be done with the CurrentCulture
B) If you are web-programming, then the user should be able to select its culture, and CurrentCulture (the culture of the web-server) should be only used as a default
And then,
A) data you save "internally" (so to be written and then read by your program) should use InvariantCulture,
B) data you interchange with other apps would be better to be written with InvariantCulture (unless the other app is badly written and requires a specific format),
C) files you export to the user should follow the previous rules (the ones about user interface), unless you are using a "standard-defined format" like XML (then use Xml formatters)

Related

How to parse international currency strings reliably with minimal code

A bit of background - I am writing some automated user acceptance tests for a mobile application and I don't always have control over the culture of the device that the tests will be executed on.
This application deals with currencies and I was wondering what the best approach might be to parse a string with a currency amount reliably without knowing the device culture.
For example, I would like to parse €12.34 or $12.34 or £12.34 etc to a double value (or whatever).
A workaround is to ignore the first character in the string but that's not necessarily an ideal solution.
What I did eventually to address this was to get all possible international currency symbols as per the snippet below (thanks to stuard) and then to check my own string against each of these values.
string[] currencySymbols = System.Globalization.CultureInfo.GetCultures(System.Globalization.CultureTypes.A‌​llCultures).Select(culture => culture.NumberFormat.CurrencySymbol) .Distinct() .ToArray();
I stripped any numeric characters, '.' and ',' from my own string, leaving just leave the currency prefix, before doing the comparison.
I'm not sure if it's the best possible solution but it works!

MVC3 Number format

I'm developing an MVC3 application and I have the problem that many users according with their preferences prefer dot as decimal separator or comma (for example the download of Excel files using a csv file with changed extension required a specific format for avoiding user have to replace dot for comma and viceversa).
My solution for now is a radiobutton and store everything as string and replace the default by the selected value (comma or dot)
There is another solution which avoid the transformation of everything to string?
Yeah, CultureInfo. Store things internaly using a predefined CultureInfo (whatever is local to your region). Associate the radion button values to cultures that are using dot (english) or comma(french) and then serve the values using the chosen culture info.
The point is you keep the values internally using ONE format then use the desired culture info to display them.

How to safely and correctly convert a number from user input to double?

This is, basically, a CultureInfo problem. Formally, in my country, the decimal separator is a comma (,) and a thousands separator is a dot (.). In practice, however, this is only used by accountants and diligent people. Normally people never use a thousands separator, and they use both a comma and a dot interchangeably as a decimal separator. I've seen this being the problem even in some Excel spreadsheets that I received from other people, with Excel not having recognized a dot as a decimal separator, leaving the field formatted as a string, rather than a number.
My "solution" thus far has been to simply replace all commas in user input with dots and then parsing the double with InvariantCulture, like so:
string userInput;
...
userInput = userInput.Replace(',', '.');
double result;
double.TryParse(userInput, NumberStyles.Float, CultureInfo.InvariantCulture, out result);
This will obviously fail when someone actually enters the thousands separator and this seems to me more like a hack than a real solution. So, other than making my own parser for doubles, are there any cleaner ways to handle this problem?
If you are using ASP.Net you can use the AjaxControlToolkit FilteredTextBox you can also accomplish the task using regular expressions and pattern matching. It is nearly always better to try and get a standard input than attempting to deal with every possible human input variable.
Some other links:
MaskedTextBox
WPF Tools FilteredTextBox
If there are rules that can conclusively determine what they meant, then you can code the logic. With this problem, though, it is impossible to know the intent in every case:
1,001 === 1.001 or 1001
Also, even though any "better" logic might assume that numbers like "1,01" are unambiguous, such an entry might be a typo of "1,001." How likely this is depends on what kind of data you're gathering.
If people rarely use a thousands separator, then your existing logic seems good. If you want to be 100% certain of intent, though, the only way to be sure is to ask them what they meant in such cases. E.g. if someone enters 1,001 or 1.001 then fail validation, but recode it as "1,001.0" (or .00 if dealing with currency) to disambiguate it, forcing them to resumbit it.
In practice, you probably would cause more harm than good with this kind of abundance of caution since people don't really use the thousands separator. I'd stick with what you got.

Avoiding localiztion on formatting numbers written to file

I have a program that sometimes is used in locales that use commas for the decimal separator. Its nice how C# handles all that (good for the UI), but when I export to a file, I need to always use a ".", not the locale specific number. Currently, I do:
String.Format("{0:0.####},{1:0.####}", x, y)
Problem is that in some locales, that ends up using commas instead of periods. Question is, is there a format code that says "always use period", or is the only solution to mess with one's locale?
Simply use:
String.Format(CultureInfo.InvariantCulture, "{0:0.####},{1:0.####}", x, y)
I'd recommend trying FxCop (or the Code Analysis feature of the Team variants of VS2005+).
It generates a lot of noise (false positives), but does provide a lot of good practice.
Including: always use the overload that takes an IFormatProvider parameter if one is available - typically you will use CultureInfo.CurrentCulture for formatting output for the user, and CultureInfo.InvariantCulture for storing data in files, the registry etc.

Best way to parse float?

What is the best way to parse a float in CSharp?
I know about TryParse, but what I'm particularly wondering about is dots, commas etc.
I'm having problems with my website. On my dev server, the ',' is for decimals, the '.' for separator. On the prod server though, it is the other way round.
How can I best capture this?
I agree with leppie's reply; to put that in terms of code:
string s = "123,456.789";
float f = float.Parse(s, CultureInfo.InvariantCulture);
Depends where the input is coming from.
If your input comes from the user, you should use the CultureInfo the user/page is using (Thread.CurrentThread.CurrentUICulture).
You can get and indication of the culture of the user, by looking at the HttpRequest.UserLanguages property. (Not correct 100%, but I've found it a very good first guess) With that information, you can set the Thread.CurrentThread.CurrentUICulture at the start of the page.
If your input comes from an internal source, you can use the InvariantCulture to parse the string.
The Parse method is somewhat easier to use, if your input is from a controlled source. That is, you have already validated the string. Parse throws a (slow) exception if its fails.
If the input is uncontrolled, (from the user, or other Internet source) the TryParse looks better to me.
If you want persist values ( numbers, date, time, etc... ) for internal purpose. Everytime use "InvariantCulture" for formating & parsing values. "InvariantCulture" is same on every computer, every OS with any user's culture/language/etc...
string strFloat = (15.789f).ToString(System.Globalization.CultureInfo.InvariantInfo);
float numFloat = float.Parse(System.Globalization.CultureInfo.InvariantInfo, strFloat);
string strNow = DateTime.Now.ToString(System.Globalization.CultureInfo.InvariantInfo);
DateTime now = DateTime.Parse(System.Globalization.CultureInfo.InvariantInfo, strNow);
You could always use the overload of Parse which includes the culture to use?
For instance:
double number = Double.Parse("42,22", new CultureInfo("nl-NL").NumberFormat); // dutch number formatting
If you have control over all your data, you should use "CultureInfo.InvariantCulture" in all of your code.
Use a neutral culture (or one you know) when parsing with Try/Parse.
Pass in a CultureInfo or NumberFormatInfo that represents the culture you want to parse the float as; this controls what characters are used for decimals, group separators, etc.
For example to ensure that the '.' character was treated as the decimal indicator you could pass in CultureInfo.InvariantCulture (this one is typically very useful in server applications where you tend to want things to be the same irrespective of the environment's culture).
Try to avoid float.Parse, use TryParse instead as it performs a lot better but does the same job.
this also applies to double, DateTime, etc...
(some types also offer TryParseExact which also performs even better!)
The source is an input from a website. I can't rely on it being valid. So I went with TryParse as mentioned before.
But I can't figure out how to give the currentCulture to it.
Also, this would give me the culture of the server it's currently running on, but since it's the world wide web, the user can be from anywhere...
you can know current Cuklture of your server with a simple statement:
System.Globalization.CultureInfo culture = System.Globalization.CultureInfo.CurrentCulture;
Note that there id a CurrentUICulture property, but UICulture is used from ResourceMeanager form multilanguages applications. for number formatting, you must considere CurrentCulture.
I hope this will help you
One approach is to force localization to use dot instead of comma separator - this way your code will work identically on all windows machines independently from selected language and settings.
This approach is applicable to small gained applications, like test applications, console applications and so on. For application, which was localization in use this is not so useful, but depends on requirements of application.
var CurrentCultureInfo = new CultureInfo("en", false);
CurrentCultureInfo.NumberFormat.NumberDecimalSeparator = ".";
CurrentCultureInfo.NumberFormat.CurrencyDecimalSeparator = ".";
Thread.CurrentThread.CurrentUICulture = CurrentCultureInfo;
Thread.CurrentThread.CurrentCulture = CurrentCultureInfo;
CultureInfo.DefaultThreadCurrentCulture = CurrentCultureInfo;
This code forces to use dot ('.') instead of comma, needs to be placed at application startup.
Since you don't know the web user's culture, you can do some guesswork. TryParse with a culture that uses , for separators and . for decimal, AND TryParse with a culture that uses . for separators and , for decimal. If they both succeed but yield different answers then you'll have to ask the user which they intended. Otherwise you can proceed normally, given your two equal results or one usable result or no usable result.

Categories