How to use CultureInfo to format deprecated currencies? - c#

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.

Related

Culture-insensitive VS Culture-sensitive

I've seen a lot of time about Culture-insensitive and Culture-sensitive i don't Knew exactly what are The difference between them.
In some books they divide the Specifiers into Two categories:
Culture-insensitive date/time format strings and
Culture-sensitive date/time format strings
I knew the specifiers but I have no idea abut sensitive and insensitive.
could anyone guide me in this?
To start, I would refer you to .NET Globalization & Localization for more information.
There are certain values/entities that get treated differently in different countries and regions. Such entities include currency symbol, digit separators, dates and more. When displaying this data to your user, you have to format it in a way that makes sense to them. If for instance you display money in a loan amortization application as follows:
Console.WritLine("$" + amount.ToString());
this will only work well in countries that use dollars. And there's no other formatting. To make this culture sensitive, you will have to do it this way...
Console.WriteLine(amount.ToString("C"));
By doing it that way, .NET will use the correct currency symbol, digit separator and decimal point for the culture the application is run in.
There are cases in which you will need to show such data in a specific culture. Doing it this way will change the way it is displayed, you can however provide the culture to use in the following way...
static void Main(string[] args)
{
decimal foo = 23434534.53M;
Dump(foo);
var culture = CultureInfo.CreateSpecificCulture("en");
CultureInfo.CurrentCulture = culture;
Dump(foo);
culture = CultureInfo.CreateSpecificCulture("es");
CultureInfo.CurrentCulture = culture;
Dump(foo);
culture = CultureInfo.CreateSpecificCulture("en-ZA"); // South Africa
CultureInfo.CurrentCulture = culture;
Dump(foo);
}
static void Dump(decimal value)
{
Console.WriteLine(value.ToString("C"));
Console.WriteLine(DateTime.Now.ToLongDateString());
}
When you change the culture at run time, subsequent calls to display the value as money will change the currency symbol, the location of said currency symbol in some cases, the digit separators and the decimal point.
This also affects how dats are displayed as you can see.
You can also use this to change the text displayed in your UI. If you have an app that supports multiple languages, for instance US English, British English, Spanish and French you are not required to know these languages beforehand. Also, you can no longer hard code you string literals like "First name:". Some simple things may differ like the spelling of color (UK English colour). Such things might be inconsequential to someone who doesn't speak English but are taken seriously in the respective countries. If your app is showing children the correct spellings for instance, you want it to get it right for the place it is in.
In this case you can set a UI culture and use resource (resx) files to place your strings in. At runtime you load your strings from the resource files and the .NET runtime can load the correct resx file based on the culture it detects the PC is set to. If there is no match, it will fall back to your default culture.
In my test app I created 2 resource files, one called Strings.resx and the other Strings.es.resx. The first will be the default language, and the other is for Spanish. When greeting a user, I won't have to hard code the greeting but can use it as follows
static void Main(string[] args)
{
Console.WriteLine(ConsoleApp1.Strings.HelloString);
CultureInfo.CurrentUICulture = CultureInfo.CreateSpecificCulture("es");
Console.WriteLine(ConsoleApp1.Strings.HelloString);
}
resulting in the following
Together these techniques can help you create an application that is sensitive to the language and culture of the user. If you need to override that, you can also do that knowingly by specifying which culture to use when presenting your data. Hard coding the entities that vary is not culture sensitive and will display the same regardless of the locale of the machine it is run on.
Culture-sensitive operations should be used when interacting directly with users. Culture-insensitive operations should always be used when interacting with back-end processes and interchange systems, including persisting data. The data that backs culture specific operations can change for many reasons. The data that backs culture-insensitive operations never changes and so is safe to persist and interchange.

CultureInfo.InvariantCulture in plain english

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

Internationalisation query in SQL SERVER and C#

I have to make an application that will be used in USA which has decimal separator as . and in
scandinavia which has decimal separator as ,
Also scandinavian countries have extra characters like ø æ å etc
I am fairly new to such type of internationlisation.
The application and the database will be same for both USA and scandinavia.
I need your help with these questions:-
What type of collation should I use in the database ?
In the front end ( C#) Is it possible that in USA I can show the numeric values displayed as 100.00 and in scandinavia to show them as 100,00 and somehow make sure that the calculations and saving to the database works without any problem?
Thank you
In SQL Server, collation is used for operations such as sorting on text data, so I don't think that decision would affect currency etc.
From .NET front-end (and sql back-end), you have to choose correct data type (such as Decimal, DateTime) for manipulating the data - for display & input purpose, you can do locale specific formatting (e.g. see currency format specifier in numeric formatting string). You can specify the format in functions such as Decimal.ToString or String.Format. These will use your current locale but you can have overrides to specify locale specific format providers. Similarly you have Parse method to convert from string to actual data type.
You can choose a collation here Selecting a SQL Server Collation there are scandinavian collations.
The decimal delimeter depends on Windows settings and will not affect your calculations.
You will have some problems with converting character expressions to a numeric data type.
Data Type Conversion:
Character expressions that are being converted to an exact numeric
data type must consist of digits, a decimal point, and an optional
plus (+) or minus (-). Leading blanks are ignored. Comma separators,
such as the thousands separator in 123,456.00, are not allowed in the
string.
Make all your string data types are NVARCHAR (or NCHAR if fixed length) so that you support unicode characters.
Since you say that your 'database' will be the same, do you mean that the server is the same physical instance, or just the same schema?
If you will have a separate server for USA to Scandinavia, this means you just set your SQL server collation and your Windows Server localization settings to USA or Scandinavia, you will need to test your solution under both environments continuously through development to ensure than any error doesn't propagate for too long unnoticed.
It's also possible to have a single database instance and then just change the localization at the WS / application side, for example this means you pass all times and numbers as USA format. But you display the values as either USA or Scandinavia format, if you're a installed (and not a web-app) you could run this control off the user's local computer localization setting which should do most of the heavy lifting for you without a problem.
eg: DateTime.Now.ToString() will report "16:34 14/11/2011" for one localization setting but "16:34 11/14/2011" for USA localization, internally the data is the same.
Lastly, if you are using a single central database, make sure you save your dates as UTC time rather than local time, otherwise you will be ignoring timezone differences between the data.

System.Convert.ToSingle() Problems, (1.5) vs (1,5)

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.

How to convert price by format

I have encountered with a problem with pricing.
I need to format price input to be of the type XXXX.YY
the problem is, the input price can be of shape XXX,YY in europe or XX,XXX.YY if talking about big numbers.
Is there a JS or C# lib that helps there?
thanks
You should use Decimal.Parse rather than Double.Parse when dealing with currency values. (The Decimal type reduces the possibility of rounding errors etc.)
To answer your question about differing cultural currency formatting, from MDSN:
Parameter s is parsed using the
formatting information in a
NumberFormatInfo initialized for the
current system culture. For more
information, see CurrentInfo. To parse
a string using the formatting
information of some other culture, use
the Decimal.Parse(String,
IFormatProvider) or
Decimal.Parse(String, NumberStyles,
IFormatProvider) method.
In case you are not aware, the .NET framework automatically takes the "current system culture" from the current regional settings of the operating system. In Windows this can be viewed/changed by the computer user in the "Regional Settings" or similar.
for American / British format:
Double.Parse("123,456.78", new CultureInfo("en-US"));
for German format:
Double.Parse("123.456,78", new CultureInfo("de-DE"));
Hint: If you are storing / reading data from file/Database etc. it is generally advisable to make use of CultureInfo.InvariantCulture
Double.Parse("123,456.78")
will work in C#
http://msdn.microsoft.com/en-us/library/7yd1h1be.aspx
Then ToString it to the format you want:
String.Format("£{0:##.##}", number);

Categories