I have a question about how to handle culture while parsing doubles.
In a system price information from various servers comes together.
However the data thats given as input varies in culture.
two million and fifty cents is given as :
"2.000.000,50"
"2,000,000.50"
"2000000.50"
"2000000,50"
is there a generic way to handle these various types of input ?
No, there is no generic way. You either need to know what culture the double was formatted or all the servers need to send in a single format, say InvariantCulture.
If you guess the culture, there's a bad news waiting for you as different cultures use different decimal separator, group separator etc. So you can't.
Refer this to foresee what can go wrong if you guess.
Please see https://stackoverflow.com/a/27443540/1230816 for an answer to your examples without any cultural assumptions required.
Related
In dotnet, the recommended way of formatting currencies in a culture-specific way, is (as far as I can find):
using System.Globalization
var info = CultureInfo.GetCultureInfo("en-GB")
return string.Format(info, "{0:c}", 1234.5678)
This returns:
£1,234.57
However. No specific currency is given here. So if Great Britain ever converts to Euro, the same method would suddenly return something like:
€ 1,234.57
This has just happened to Latvia. This year, it converted to the euro. Various systems contain both amounts in letvian lats and euros. I need to be able to still print and format old currencies. And I need to be sure new currencies can also be handled. This formatting is not just about the symbol, but also about the placement (before, after, with or without space) and the local number format (decimal separator and thousands separator).
Every amount in our database has a currency (e.g. EUR) and a corresponding culture (e.g. nl-NL). Euro amounts are formatting differently depending on if they originate from our German or our Dutch office. (they both use euros, but format the amounts differently)
Does dotnet provide access to older currencies?
What is a future-proof way of writing the formatting amounts?
Right now, the only way I can think of, is to copy the culture-database to my database.
You can create a custom CultureInfo (by cloning one and modifying) which uses a different currency symbol/format (ie. set its NumberFormat to a different instance of NumberFormatInfo).
Then pass this CultureInfo to formatting functions as needed.
As the comment to the question notes, .NET (and Windows in general) doesn't provide historic data (similarly for time zones but there's a library for that). In the cases you need you'll need to hold enough data yourself.
Remember ISO-4217 currency codes are not reused under such a change, so holding that against amounts allows you to format correctly. Additionally just because a country formats their currency amounts one way doesn't mean everyone does. Eg. 25 French Francs was be "FF25.00" in the UK but "25FF00" or "FF25,00" in other locales. (EDIT: I note you covered this last paragraph in the question.)
Of course, the simplest way is to not use the locale-specific currency format, but rather to format the amount as a simple number and pre- or suffix it with the ISO currency code. The convention
------------
Sum: ATS 1.376,00 (= EUR 100,00)
is commonly found on invoices (using locale de-AT as an example).
If you want to use the built-in currency formatting options, I would suggest to replace the currency symbol with the one stored in the database. I.e., in your currency table, you'd need to map currencies to symbols:
EUR -> €
ATS -> S
...
and then you'd replace myCultureInfo.NumberFormat.CurrencySymbol with the one in the database. That way, you ensure that a value is never shown with the wrong currency symbol.
If you are targeting Windows 8 or above, this deficiency is addressed by the Windows.Globalization.NumberFormatting.CurrencyFormatter. It requires that you provide the explicit currency and you can also explicitly provide a language.
I need to write decimal value to ms access database, but i have a problem with conversion values to decimal in different cultures. Have a values from file, which separates by commma. I try:
public decimal CSingleCulture (string str)
{
string sep = System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
string s = str.Replace(",", sep);
return decimal.Parse(s);
}
if NumberDecimalSeparator = "." then work is good, but if NumberDecimalSeparator = "," problems begin... decimal.Parse(s) always return vlaues separates by dot. In this situation, when inserted into a database error occurs.
The recommended way to deal with this is to store the value as a number rather than a string. Both in the database and in your program. When you do that, your current problem simply never arises.
The only time you deal with numbers in string format is when you display them, or accept user input. In those scenarios you can use the user's culture settings to let them see and use their preferred separator.
Should you ever need to convert between string and number for persistence then you must use culture invariant conversion. This appears to be where you are falling down. I suspect that the file you read has no well-defined format. Make sure that when you read and write the file you use CultureInfo.InvariantCulture. If the file does have a well-defined format that differs from the invariant culture, then use an appropriate specific CultureInfo.
Can't actually understand what is it you're trying to accomplish, and I have to agree with the other answer. But one other thing that's good to know is you can use invariant culture like so:
double.Parse("15.0", CultureInfo.InvariantCulture)
This will always expect dot character to delimit your decimal digits regardless of what is set in current thread's culture.
I know that culture rules for dates/numbers is enough for an entire book, I think I have a simple question though..
Does using InvariantCulture basically mean that you explicitly define what culture the value (date/number/whatever) will be inputted/displayed as? And it overrides any other culture setting (such as the user agent's setting)?
If an app is built for an audience of one and only one culture, would it make sense to use InvariantCulture and define how you want values inputted/displayed each time?
Does using InvariantCulture basically mean that you explicitly define what culture the value (date/number/whatever) will be inputted/displayed as?
No. It's just a culture which is a bit like US English, except for a few things like currency sign. It's usually used to format/consume text which is to be understood or was produced by another computer rather than a human.
If an app is built for an audience of one and only one culture, would it make sense to use InvariantCulture and define how you want values inputted/displayed each time?
No, you would use the relevant CultureInfo for that culture. You could also explicitly define the format for dates etc, but that's an orthogonal concern. It may well be best to use one of the predefined standard formats for that culture, but if none of those meet your needs you can always be explicit.
InvariantCulture is Independent of any culture or any factor.
For example if you're using new CultureInfo("en-US") it will get you US English Culture(Which may not be actual US English Culture because OS gives you option to change these setting in Control Panel) it will return the modified version of Culture of "en-US" if any custom formatting applied to it.
In other words InvariantCulture will always gives you a Culture which can never be changed across Systems.
Let's assume you want to serialize some value(say double) and pass to another application or some other thread which is running in different culture leads to serious problems.
Consider the following code
Thread.CurrentThread.CurrentCulture = new CultureInfo("fr");
double source = 455.62d;
string serialized = source.ToString();//455,62 since `, is the decimal seperator` in "fr"
Thread t = new Thread((x) =>
{
double deserialized = double.Parse(((string)x));
Console.WriteLine(string.Format("Deserialized value is {0}", deserialized));//outputs 45562
});
t.CurrentCulture = new CultureInfo("en-US");
t.Start(serialized);
numbers matters more right? consider this string denotes AccountBalance?
Hope this helps
With specific regard to DateTime, the best advice I can give is to use CultureInfo.InvariantCulture for ParseExact and ToString when you have an exact format in mind. (You can also use it with Parse if you happen to know that your input format matches the invariant culture's formats, but I typically avoid this.)
Don't use the invariant culture when interacting with a user.
Keep in mind that the culture contains several items, including the ordering of day/month/year parts, the date and time part separator characters, the character encoding, and the language-specific names of the days of the week, months of the year, and abbreviations including am/pm.
Some examples of when you should use the invariant culture:
Files on disk, especially text files of a predefined format
External APIs, especially JSON or XML
Unit tests, unless you are specifically testing culture issues
Some examples of when you should use a specific culture such as en-US:
User Interface
Reports
When formatting a string as opposed to a DateTime, does the culture ever come into play? Are there any examples of strings that would be formatted differently with two different cultures?
I don't believe so in the current Framework. But if Microsoft ever implements this suggestion on the Connect feedback site, it includes a suggestion to have a format specifier to force upper case:
String.Format("{0:U}", "SomeString") => "SOMESTRING"
Such formatting would be culture-specific.
If you are displaying a string that is stored as a resource it will make a difference if you have separate strings for different cultures (you'd use CultureInfo.CurrentUICulture). For example error messages accessed via a ResourceManager.
String.Format("{0}", "This string") - which I believe is what you're implying by your question, is not affected by the culture.
There are many scenarios when you need culture based formatting.
For example: - Number Format
5.25 in English is written as 5,25 in French
So, if you want to display French formatted number in your program which is in English culture the culture based string format comes into action.
I'm writing program in C# for converting between model formats.
The model format has numbers as text such as "-0.136222".
I can use System.Convert.ToSingle() to convert this to a floating point number. But here in Germany we use commas as decimal points (-0,136222), and System.Convert picks up on this. Now I have the problem of it not recognizing decimal points since it expects commas.
In a nutshell;
We have this: "-0.136222"
We get this: -0136222.0f
because it expects this: "-0,136222"
Can I tell system to recognize commas as decimal points just for my program? A work around won't work since it needs to be portable (to other countries).
Use Single.Parse() instead, like this:
Single.Parse("-0.136222", CultureInfo.InvariantCulture);
InvariantCulture is the way to tell the method to parse the string ignoring locale-specific decimal and grouping separators.
Leave it as it is. The .Net framework installed on your clients' computers will automatically choose the correct way to parse the data for the country settings that computer is set for. So for example, in continental Europe it will parse your float using commas, but in the USA, UK and others where we use decimal points it will parse the data using decimal points.
Of course, you can override this Culture-specific localisation feature of .Net by using CultureInfo.InvariantCulture (like Pawel has suggested) or any other CultureInfo but this will mean you have to set it specifically for each country you sell your software to. Far better to just let the framework do the work for you :)
Note: It will also mean that a (say) German person working in the USA with his PC set to be localised for Germany will have his floats parsed with commas, as he expects, not with decimal points just because he is located in the USA.