The SLAR (vol2) on System.Globalization.CultureInfo


Continuing in the series sharing some of the information in the .NET Framework Standard Library Annotated Reference Vol 1 and .NET Framework Standard Library Annotated Reference Vol 2 with some information on CultureInfo.


 


SS (Shawn Steele)


 


Always use cultures when appropriate, but be careful where you use them. They are meant to


be specific for a user or machine, and they could change. For example, as countries join the EU,


their currency symbols or formats change. In other cases, companies or users may prefer a 24-


hour clock to a 12-hour default. Culture data is necessary and great when presenting data to the


humans who are actually using the computer, but it’s an awful way to store data. If you have to


read something back later, save it in a binary format, use CultureInfo.InvariantCulture,


or specify a specific format to the formatting functions. Except for Invariant, don’t expect the


culture data provided by this class to remain the same, even between instances running as the


same user.


 


IA (Ihab Abdelhalim)


One of my biggest regrets is that CultureInfo.ClearCachedData() is an instance method


rather than a static method. This method actually clears shared (static) caches for system


settings like CurrentCulture, CurrentRegion, and the like. It does nothing to individual


instances, so it is very confusing to have this as an instance method. Unfortunately, this was


discovered very late in the .NET Framework cycle, and it was considered a breaking change to


make it static, so it had to ship this way.


 


 


using System;


using System.Globalization;


/// <summary>


/// Sample demonstrating the use of the CultureInfo class.


/// Use this class to retrieve information about a specific culture, such as


/// date/time formats and number formats.


/// </summary>


internal class CultureInfoSample


{


private static void Main()


{


Console.WriteLine(“Summary for the current thread culture:”);


WriteCultureInfoSummary(CultureInfo.CurrentCulture);


Console.WriteLine(“Summary for the current thread UI culture:”);


WriteCultureInfoSummary(CultureInfo.CurrentUICulture);


Console.WriteLine(“Summary for the operating system UI culture:”);


WriteCultureInfoSummary(CultureInfo.InstalledUICulture);


Console.WriteLine();


Console.WriteLine();


Console.WriteLine(“Press Enter to continue”);


Console.ReadLine();


}


// Writes a summary of the specified CultureInfo to the console.


private static void WriteCultureInfoSummary(CultureInfo info)


{


Console.WriteLine(” Culture name: {0} ({1})”,


info.DisplayName, info.Name);


WriteDateTimeFormatInfoSummary(info.DateTimeFormat);


WriteNumberFormatInfoSummary(info.NumberFormat);


Console.WriteLine();


}


// Writes a summary of the specified DateTimeFormatInfo to the console.


private static void WriteDateTimeFormatInfoSummary(DateTimeFormatInfo info)


{


Console.WriteLine(


” Long date/time pattern: {0} {1}”,


info.LongDatePattern, info.LongTimePattern);


Console.WriteLine(


” Short date/time pattern: {0} {1}”,


info.ShortDatePattern, info.ShortTimePattern);


Console.WriteLine(


” AM/PM designators: {0}/{1}”,


info.AMDesignator, info.PMDesignator);


}


// Writes a summary of the specified NumberFormatInfo to the console.


private static void WriteNumberFormatInfoSummary(NumberFormatInfo info)


{


Console.WriteLine(


” Currency symbol: {0}”, info.CurrencySymbol);


Console.WriteLine(


” Percent symbol: {0}”, info.PercentSymbol);


Console.WriteLine(


” Negative sign: {0}”, info.NegativeSign);


Console.WriteLine(


” Positive sign: {0}”, info.PositiveSign);


Console.WriteLine(


” Decimal separator: {0}”, info.NumberDecimalSeparator);


Console.WriteLine(


” Thousands separator: {0}”, info.NumberGroupSeparator);


}


}


The output is


Summary for the current thread culture:


Culture name: English (United States) (en-US)


Long date/time pattern: dddd, MMMM dd, yyyy h:mm:ss tt


Short date/time pattern: M/d/yyyy h:mm tt


AM/PM designators: AM/PM


Currency symbol: $


Percent symbol: %


Negative sign: –


Positive sign: +


Decimal separator: .


Thousands separator: ,


Summary for the current thread UI culture:


Culture name: English (United States) (en-US)


Long date/time pattern: dddd, MMMM dd, yyyy h:mm:ss tt


Short date/time pattern: M/d/yyyy h:mm tt


AM/PM designators: AM/PM


Currency symbol: $


Percent symbol: %


Negative sign: –


Positive sign: +


Decimal separator: .


Thousands separator: ,


Summary for the operating system UI culture:


Culture name: English (United States) (en-US)


Long date/time pattern: dddd, MMMM dd, yyyy h:mm:ss tt


Short date/time pattern: M/d/yyyy h:mm tt


AM/PM designators: AM/PM


Currency symbol: $


Percent symbol: %


Negative sign: –


Positive sign: +


Decimal separator: .


Thousands separator: ,


Press Enter to continue


 

Comments (5)

  1. Andrew Webb says:

    SS: "Culture data […], but it’s an awful way to store data"

    We store data as strings these days by virtue of using XML. All .NET programmers whose code I have inspected _do_ store culturally-variant data in XML files without realizing it because they do this:-

    myObject.ToString ();

    and thus use the current culture by default. When I point out the problem, I don’t think that one person has changed their habits – they’re too ingrained. Plus the thought of having to change ALL of those ToString calls…!

    My approach has been to read and cache the current thread’s current culture at startup, change the current culture to be the invariant culture, and then use the cached current culture as and when I need it at the statement level. Even then, my code can’t be fully correct until I start using .NET 2.0 (see below).

    The message hasn’t gotten out yet. Plus .NET 1.x lacks the full set of string comparison options that are needed to cope fully (e.g. ordinal + ignore-case). .NET 2.0 plugs that gap, but I predict that takeup will be slow because of the sheer success of .NET 1.1 and VS 2003 which will lead to inertia, but also because firms (including the one I work for) have been put off rushing to adopt VS 2005 because of the recent scares about crashing IDE bugs.

    I’m looking forward to getting hold of the finished .NET 2.0 / 2005 Library documentation, so that I can finish off my article on this matter, which was written when VS 2005 was at the Beta 2 stage. Is the final, RTM documentation online yet?

  2. Ed Evans says:

    Can anyone comment on why changing ClearCachedData to a static method might be considered a breaking change? I can see how changing from static to instance would be a breaking change but not the other way round.

  3. Kevin Westhead says:

    Ed, it’s a breaking change because the IL required to make the call will be different.

    E.g. the instance call looks something like this:

    callvirt instance void [mscorlib]System.Globalization.CultureInfo::ClearCachedData()

    Whereas a static call would look something like this:

    call void [mscorlib]System.Globalization.CultureInfo::ClearCachedData()

    Some languages, like VB, allow you to access static members via instances at the source code level, but that doesn’t change the IL required to make the call.