The Caveats of Time Zone Names [Greg]

Hi Everyone!

My name is Greg, I joined the NetFx Base Class Libraries (BCL) team a few months ago, and I am really excited about my work on some very cool new framework features. Before joining the BCL team I was working in academic research in complex systems, network theory and artificial life at Monash University in Australia, and previously I was running a small software development and consulting company with clients in Germany and the UK.

Besides adding some awesome new stuff to the next release for the framework (can’t talk about that yet!) I am also maintaining and improving some of the existing namespaces. This involves fixing some bugs and helping our customers by explaining how to use the framework on the Connect portal. There are a few issues that come up regularly and are particularly tricky to deal with, so I would like to talk about them briefly to a wider audience and in a more generic context (i.e. here). Today I will be talking about time zones and, in particular, potential pitfalls associated with their naming.

In .NET, the class that provides most of the functionality for dealing with time zones, converting times from one zone to another, and working with daylight saving time (DST), is System.TimeZoneInfo. In turn, the data that TimeZoneInfo uses for its calculations is provided by Windows in the registry under this key:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones

(Note: be very careful if you touch the registry, never change anything if you are not absolutely sure what you are doing, and always create a back-up before your changes.)

In order to access information about a specific time zone in a .NET application, you need to instantiate a TimeZoneInfo object that represents that time zone using the factory method TimeZoneInfo.FindSystemTimeZoneById(String id) (see also here for more information). That factory method takes a string parameter specifying a time zone name and returns a TimeZoneInfo instance that represents the specified time zone. It provides information including offset from the universal standard time (UTC), information about DST adjustments, time conversion routines and more.

The difficulty is in providing the correct ID (name) of a time zone in order to get hold of the corresponding object: The naming for the time zones is not always intuitive. As a result, it is easy to get confused and to create program bugs and unexpected behaviour. Consider for instance the zone named "US Eastern Standard Time". Unexpectedly this is not the EST/EDT observed on most of the US east coast. Instead, it is a US-Indiana-Only time zone that is not used any more since 2006 and does not change to DST. The name of the time zone that people are probably looking for instead is "Eastern Standard Time". That is the ID you need to get the TimeZoneInfo object that represents the time zone used in most of east North America. That time zone does use DST.

Another time zone with a misleading name is "Greenwich Standard Time". This zone applies to places like Monrovia (Liberia) and Reykjavik (Island). These places do not observe DST in 2010. This zone is easily confused with "GMT Standard Time" that contains Portugal and the UK and does observe DST.

To exemplify the issue, consider the following code sample. Its output is given below.

 using System;
 
namespace Microsoft.Misc.MSDNBlog {
public static class ConfusingTimeZoneNames_Demo {
 
private static String[] zoneIDs = new String[] {
            "China Standard Time",
            "AUS Eastern Standard Time",
            "Pacific Standard Time",
            "US Eastern Standard Time",
            "Eastern Standard Time",
            "Greenwich Standard Time",
            "GMT Standard Time"
        };
 
 
public static void Main(String[] unusedArgs) {
 
  const String format = "{0,-26} | {1} {2}| {3}";
  DateTime utcTime = new DateTime(2010, 06, 01, 12, 30, 0);
 
  Console.WriteLine(format, "Time Zone Name (ID)",
                            "Local Time      ",
                            "DST?",
                            "Time Zone Information");
  Console.WriteLine("---------------------------+------------"
          + "----------+---------------------------------------");
 
  foreach (String tzID in zoneIDs) {
 
    TimeZoneInfo tzInfo = TimeZoneInfo.FindSystemTimeZoneById(tzID);
    DateTime tzTime = TimeZoneInfo.ConvertTime(utcTime, tzInfo);
 
    Console.WriteLine(format, tzID,
              tzTime.ToString("yyyy-MM-dd HH:mm"),
              tzInfo.IsDaylightSavingTime(tzTime) ? "DST " : "    ",
              tzInfo.DisplayName);
  }        
}
 
}  // public static class ConfusingTimeZoneNames_Demo
}  // namespace Microsoft.Misc.MSDNBlog

image

To summarise: Be careful when instantiating TimeZoneInfo objects. Always double-check that the zone name you are using is the correct one, even if it appears obvious at first. And if your application behaves weirdly, double-check if you have possibly created the wrong TimeZoneInfo object due to a similarity in name IDs. For more information about time zones in various places around the world, check out https://www.timeanddate.com/worldclock/full.html

Enjoy!