Format Data Based on Culture Information

Don’t let yourself fooled by the title, we’ll discuss the topics of Globalization here. You’ll need the System.Globalization and System.Threading namespaces and possibly Sysglobl.dll to build custom cultures.

A little terminology: today, culture will mean the language, currency, date-format, calendar, writing system and different names of a given group of people. There are two types of cultures: neutral, which only provides information of the language spoken, and specific culture, which provides information about the region/country. For example “es” means the Spanish neutral culture, and “es-MX” means the Mexican culture with the appropriate region information (such as the unit of currency, date format, etc.). There’s also a special culture, called Invariant culture. This one is associated with the English language, but not with any region/country. You’ll use this one when you need consistency across different cultures in your application.

To play around a little with cultures, you can set the System.Threading.CurrentThread.CurrentCulture or CurrentUICulture. The main difference is that tha CurrentCulture sets everything (and only accepts specific culture information), while the CurrentUICulture just sets the UI elements (thus it won’t format currencies, which is a good thing in a multi-language auction site, where $200 certainly shouldn’t be equal to 200€). These properties accepts instances of the CultureInfo class.

A CultureInfo represents a given culture, with all available information of it. There are two interesting classes which you can access from it: NumberFormatInfo and DateTimeFormatInfo. I’m sure you’ll find the properties which expose these classes. Now NumberFormatInfo holds information about the number and the currency  format used by the culture. It has the following properties:

  • CurrencyDecimalDigits
  • CurrencyDecimalSeparator
  • CurrencyGroupSeparator
  • CurrencyGoroupSizes
  • CurrencyNegativePattern
  • CurrencyPositivePattern
  • CurrencySymbol
  • DigitSubstitution
  • IsReadOnly
  • NaNSymbol
  • NativeDigits
  • NegativeInfinitySymbol
  • NegativeSign
  • NumberDecimalDigits
  • NumberDecimalSeparator
  • NumberGroupSeparator
  • NumberGroupSizes
  • NumberNegativePattern
  • PercentDecimalDigits
  • PercentDecimalSeparator
  • PercentGroupSeparator
  • PercentGroupSizes
  • PercentNegativePattern
  • PercentPositivePattern
  • PercentSymbol
  • PerMilleSymbol
  • PositiveInfinitySymbol
  • PositiveSign

I wouldn’t like to comment these properties, I’m quite sure you’ll find out what they mean.

After you’ve played around a little with the settings, you can use the following code to format a number:

CultureInfo cil = new CultureInfo(“en-US”);
NumberFormatInfo nufo = new NumberFormatInfo();
//Code for setting the number format
cil.NumberFormat = nufo;
decimal dec = 12345.67M;
Console.WriteLine(dec.ToString(“C”, cil);

And your decimal will be formatted by your own custom settings.

There may be times when you want to create a number from a string, like from “$ (-32)”. To achieve this, you can use the TryParse or Parse method of the appropriate value type (difference between Parse and TryParse: Parse throws an exception on error, TryParse just returns false) with the specified NumberStyles and CultureInfo. NumberStyles is an enumeration you’ll love. With it you can control what or what not can be a part of a number (like parentheses, currency symbol). Refer to MSDN for the full list.

Numbers aren’t the only thing which can be converted from strings. Consider dates and times now! You convert a string to a DateTime object by using the Parse, ParseExact, TryParse, TryParseExact methods. You can specify members of the DateTimeStyles enumeration in every one of these methods. The values can be the following:  AdjustToUniversal, AllowInnerWhite, AllowLeadingWhite, AllowTrailingWhite, AllowWhiteSpaces, AssumeLocal, AssumeUniversal, NoCurrentDateDefault, None, RoundTripKind.

When you need to preserve all information in a given DateTime object, but you need to send it somewhere (like you’d do in a web service) call the instance’s ToBinary method. This will store everything (time zone, local time, etc.) in a long variable.

When you need to compare two strings with or without culture-sensitivity, you’ll call the string.Compare static method. The first two parameters will be the strings to compare, the third is the IgnoreCase Boolean (or members of the StringComparsion enumeration). There are more overloads, but I think the first three will do most of your work. StringComparsion enumeration has the following members: CurrentCulture, CurrentCultureIgnoreCase, InvariantCulture, InvariantCultureIgnoreCase, Ordinal, OrdinalIgnoreCase. Such speaking names! You can achieve the same result by using the CompareInfo class, an example:

CompareInfo myInfo = CompareInfo.GetCompareInfo(“en-US”);
myInfo.Compare(“Hi man”, “Hi Man”, CompareOptions.IgnoreCase);

Hah, CompareOptions is a new enumeration, the most useful members: IgnoreCase, IgnoreNonSpace, IgnoreSymbols, None, Ordinal, OrdinalIgnoreCase, StringSort.

The last objective in the list is to build a custom culture based on an existing one. For this, you’ll need the power of CultureAndRegionInfoBuilder (yes, it’s actually called this) and Sysglobl.dll. You can set the same thing mentioned above. If you want to create a custom culture, and use it constantly, in different applications (and why you wouldn’t want to do so), you’ll need to register it. It isn’t a big deal, simply call the Register method of your instance (requires administrative privileges).

Further Reading

CultureInfo Class

NumberStyles Enumeration

CultureAndRegionInfoBuilder Class

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s