Localized time zone names in .NET

If you've ever used the TimeZoneInfo class in the .NET framework, you probably know that it has properties intended for display of a time zone to the end user.  Specifically, these are the DisplayName, StandardName, and DaylightName properties. However, there are a few problems with these.

  • Unlike many other items in the .NET framework, they aren't affected by the CurrentCulture or CurrentUICulture of the current thread, nor is there any way to pass in a culture or region when creating a TimeZoneInfo object.
  • However, they are indeed localized!  The language comes from the operating system, not from the application.  That means if you host your app on a Japanese server, you'll get "東部標準時" instead of "Eastern Standard Time" - even if your user has English settings for everything else in the application!
  • Even in English, a lot of the names are a bit too weird.  For example, the time zone for France will show up as "Romance Standard Time" instead of the correct "Central European Time".

Surely there is a way around this dilemma?  Indeed there is!  There is a large, publicly available source of localized strings, including time zone names, called the Unicode Common Locale Data Repository - or "CLDR" for short.   This is probably the best source of information of this type.  It's updated periodically, and it's data is available as a set of XML files.

But who wants to navigate through the complex set of rules for determining a time zone name?  You'll have to pull in all of the XML, parse out the bits you need, and handle a dizzying array of edge cases.  So to relieve you're burden, I've done the hard work for you.

Introducing, the TimeZoneNames Library!

This is a simple Nuget package you can install, which contains a library with the CLDR data for time zones included as an embedded resource.  This makes it very easy to get the correct language-specific strings for time zones within your .NET projects.  It's a Portable Class Library (PCL) (now a .NET Standard Library) - so it will work well in any .NET environment, including Windows Phone, Windows Store, and Xamarin applications.

Simply install the TimeZoneNames package from Nuget:

PM>  Install-Package TimeZoneNames

Then you can call simple functions, passing the time zone and locale code as parameters. For example:

var names = TZNames.GetNamesForTimeZone("America/Los_Angeles", "en-US");

names.Generic == "Pacific Time"
names.Standard == "Pacific Standard Time"
names.Daylight == "Pacific Daylight Time"

And this works nicely for other languages as well:

var names = TZNames.GetNamesForTimeZone("America/Los_Angeles", "fr-CA");

names.Generic == "heure du Pacifique"
names.Standard == "heure normale du Pacifique"
names.Daylight == "heure avancée du Pacifique"

I've also included functions to get abbreviations instead of names, and to list the time zones that are applicable for a given country.  You'll find examples and source code in the project's GitHub repository.

About the time zones

You'll notice that the time zones in these examples use names like "America/Los_Angeles".  These are standard IANA TZ identifiers, which are different than those you would normally use with TimeZoneInfo.   I built the library around these zones, because this is how the data is presented in the CLDR.  They work really well in .NET using the Noda Time library, which I highly recommend using instead of TimeZoneInfo - for a variety of reasons.

If your system is already built around the Windows time zone id's that TimeZoneInfo uses, fret not.  You can still use Noda Time, along with some simple conversion functions.  I'm also considering adding support for them directly into TimeZoneNames, but for now you'll have to convert.  (But really, just use Noda Time.)

UPDATE - As of version 1.2.0, Windows time zone IDs are directly supported.

UPDATE - Version 2.0.0 adds a lot more functionality, including supporting data needed for localizable time zone selection controls!

UPDATE - Version 3.0.0 is published as a .NET Standard library, so you can use it in .NET Core and other environments.