Sdílet prostřednictvím


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!

Comments

  • Anonymous
    October 11, 2010
    Why did the BCL perpetuate the Windows 95 time zone debacle instead of using all the work Arthur Olson and subsequent contributors did? (See en.wikipedia.org/.../Tz_database) You mentioned Indiana's time zone "hasn't been used since 2006," but if you need to represent a date and time in 2006 or earlier in Indiana, what other time zone should you use? It appears that the Windows 95 team took some shortcuts, but the .NET team could have abstracted the resulting problems away, as you did with other Windows (and DOS!) zombie functions. (IIRC, Windows 95 even had to remove the map that showed the time zone outlines because, well, there are political implications to time zone names.) I hope that one of the secret things you're working on for BCL 5 is incorporating the Olson data into .NET. On second thought, no--I'd rather monetize the Olson parser I wrote for .NET. :)

  • Anonymous
    October 11, 2010
    The comment has been removed

  • Anonymous
    October 12, 2010
    For me, the use of tz names isn't primarily for user interface benefits - it's for interop with all the non-Windows systems out there. This is why for Noda Time we'll hopefully be able to work with both kinds of names, finding the Windows system name most closely corresponding to a given Olson name and vice versa :) When it comes to naming, I think the Windows names are just as bad or worse: the idea that a time zone name should talk about "standard time" is frankly bizarre. My time zone isn't standard time - it's a combination of standard time and daylight saving time. In particular, my time zone stays the same whether or not I'm currently observing DST. I live in London, but my time zone is neither GMT nor BST - it's both, with rules for when each "half" zone applies. Admittedly a lot of this isn't technology specific, but a failing of humanity: the fact that time zones keep changing and very few people in the "real world" actually have any clue about what a time zone means (or have an accurate idea of what time zone they live in, or would describe it differently on different days) makes it all very tricky.

  • Anonymous
    October 18, 2010
    Both naming systems - the one used in Windows and tz, as well as any other time zone naming convention I am aware of have their caveats that make them more convenient in some cases and more difficult to use in others. And so, the main idea of my small article is - Be Careful! Time zones can be tricky and confusing even for experts, so always double check that what you did will actually achieve what you intended. :) As for tz, - it has indeed both, benefits and shortcomings compared to the current state of affairs. When choosing a time zone database for .NET we need to consider a lot of factors. These include things like maintainability, guarantees about reaction times in case of necessary changes, existence of in-place update mechanisms, and many other factors. One of the key considerations is: Consistency (for end-users of .NET software). Imagine having 2 Windows applications running side by side on your monitor, both claiming a different time, because they use 2 different time zone databases that got out of sync. Also, just having to select your time zone twice after the installation - once for .NET and once for native Windows applications will be annoying for many users. So, we believe that for .NET-based desktop applications, the right way to go is to use the time zone data provided by the OS.