Exploring Windows Time Zones with System.TimeZoneInfo [Josh Free]

The main feature of the System.TimeZoneInfo class (previously named System.TimeZone2 in CTPs prior to .NET Framework 3.5 Beta 1) is to enable .NET developers to seamlessly work with Windows time zones in their applications. This includes enabling .NET applications to take advantage of the new Windows Vista Dynamic Daylight Saving Time functionality, which allows the operating system to store historically accurate time zone information (this includes both past and future time zone data).

With the release of .NET Framework 3.5 Beta 1, the BCL team has received several questions regarding time zone support in Windows and the differences between time zone support on Windows XP and on Windows Vista. In this article, I’ll attempt to explain a little bit about how time zones work in Windows so that .NET developers can have a better understanding of what happens under the hood when they use System.TimeZoneInfo to perform common time zone related tasks in their code.

Time Zones and the Windows Registry

Windows computers store time zone data in the Windows Registry. Before discussing the storage layout of time zones in the registry, I want to issue a standard disclaimer about modifying the Registry (e.g., please don’t email me if you inadvertently destroy your computer while changing registry values with regedit.exe. :-) ):

WARNING: Using Registry Editor incorrectly can cause serious problems that may require you to reinstall your operating system. Microsoft cannot guarantee that problems resulting from the incorrect use of Registry Editor can be solved. Use Registry Editor at your own risk.

Time Zones Registry Hive

All time zones installed on the computer are stored in the following registry hive:

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

Each time zone has its own unique key under this registry hive. Sub-keys are used to store information about the time zone such as the display name, standard name, daylight name, and the optional daylight start and daylight end times.

Alaskan Standard Time

TimeZoneInfo Instance Public Properties Example String Returned from Property HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\[Time Zone] Sub-Key Name
TimeZoneInfo.Id Alaskan Standard Time <Time Zone Root Key Name>
TimeZoneInfo.DisplayName (GMT-09:00) Alaska MUI_Display’ on Vista or ‘Display’ on down-level
TimeZoneInfo.StandardName Alaskan Standard Time MUI_Std’ on Vista or ‘Std’ on down-level
TimeZoneInfo.DaylightName Alaskan Daylight Time MUI_Dlt’ on Vista or ‘Dlt’ on down-level
TimeZoneInfo.BaseUtcOffset -09:00:00 TZI’ (REG_TZI_FORMAT struct)
TimeZoneInfo.SupportsDaylightSavingTime True TZI’ (REG_TZI_FORMAT struct)

As you can see above, the display strings are loaded either from the Multilingual User Interface (MUI) DLL, tzres.dll, or straight from the registry, when MUI support is unavailable. MUI-enabled operating systems such as Windows Vista contain MUI_Display, MUI_Std, and MUI_Dlt keys, which are indirectly controlled by the operating systems regional settings. On down-level platforms such as Windows XP and Windows Server 2003, only the Display, Std, and Dlt keys exist. The Display, Std, and Dlt key values are localized only in the default language of the operating system. Because of the Windows time zone registry architecture, CurrentUICulture settings do not impact the values of these TimeZoneInfo properties.

Here is a sample program that demonstrates the use of the TimeZoneInfo properties described above:

using System;

 

public class TimeZoneInfoSample {

    private static void Main() {

        String id = "Alaskan Standard Time";

        TimeZoneInfo tzi;

 

        try {

            tzi = TimeZoneInfo.FindSystemTimeZoneById(id);

        }

        catch (TimeZoneNotFoundException e) {

            Console.WriteLine(id + " not found on the local computer: " + e);

            return;

        }

        catch (InvalidTimeZoneException e) {

            Console.WriteLine(id + " is corrupt on the local computer: " + e);

            return;

        }

 

        Console.WriteLine("TimeZoneInfo.Id = " + tzi.Id);

        Console.WriteLine("TimeZoneInfo.DisplayName = " + tzi.DisplayName);

        Console.WriteLine("TimeZoneInfo.StandardName = " + tzi.StandardName);

        Console.WriteLine("TimeZoneInfo.DaylightName = " + tzi.DaylightName);

        Console.WriteLine("TimeZoneInfo.BaseUtcOffset = " + tzi.BaseUtcOffset);

        Console.WriteLine("TimeZoneInfo.SupportsDaylightSavingTime = " +

            tzi.SupportsDaylightSavingTime);

    }

}

Dynamic Daylight Saving Time (Dynamic DST)

The Dynamic DST sub-key stores historical time zone data.  Windows Vista comes pre-installed with this historical time zone data for many time zones.  Windows XP and Windows Server 2003 users can download the February 2007 cumulative time zone update (KB931836) to get these registry keys: http://support.microsoft.com/kb/931836.  Windows XP and Windows Server 2003 operating systems do not currently use the Dynamic DST data by default (even when the data exists after the KB931836 update is installed), but System.TimeZoneInfo is smart enough to use the Dynamic DST historical data when it exists, on any operating system version.

Alaskan Standard Time Dynamic DST

A Word about Local Time Zone and the ‘Automatically adjust clock for Daylight Saving Time’ Checkbox

TimeZoneInfo contains the static property “TimeZoneInfo.Local” which loads the current, local time zone off of the computer and returns a TimeZoneInfo object.  While loading the local time zone, TimeZoneInfo checks the operating system settings to see whether or not daylight saving time should be obeyed.

Computer users generally control this setting through the Date and Time control panel — specifically the ‘Automatically adjust clock for Daylight Saving Time’ checkbox:

Date and Time Control Panel

Depending on the version of Windows being used, this checkbox will set either the “DisableAutoDaylightTimeSet” or the “DynamicDaylightTimeDisabled” registry key values to one (1):

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation

        "DynamicDaylightTimeDisabled"=dword:00000001

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation

        "DisableAutoDaylightTimeSet"=dword:00000001

Local Time Zone

When daylight saving time is disabled for the local time zone, “TimeZoneInfo.Local” will return a TimeZoneInfo object with “TimeZoneInfo.SupportsDaylightSavingTime”set to False.  Any TimeZoneInfo.ConvertTime(...) calls using this TimeZoneInfo instance will not take daylight saving time into account.

Additional Resources