Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

World Clock and the TimeZoneInformation class

0.00/5 (No votes)
3 Jan 2006 1  
Using the operating system's time zone APIs to convert times from Universal time (UTC) to a specified time zone.

Introduction

This article was spurred by discussions on the Channel 9 forums around the time of the daylight changes this year. Some users were complaining that the site was not indicating the posting time accurately. I suggested a route forward but failed to convince the administrators. This article is an attempt to provide code that is useful for converting a time stamp into the end-user's own time zone.

Another group of users also need to deal with the time zones: travelers wishing to know the time at their destination, or the time at home - for example, when trying to call relatives or colleagues. The accompanying application, a demonstration of the TimeZoneInformation class, is useful here. It could also be useful for working out when a Webcast, for example, occurs in your local time zone.

Time zones

Different countries and locations around the world use different time zones - to match the time shown on a clock with the approximate local time observed. The simplest description is an offset from UTC - Universal Time (Coordinated) - although often erroneously described as an offset from GMT - Greenwich Mean Time. GMT can describe the time zone used in Britain, or a specific offset (UTC+0). The issue is complicated by the Daylight Savings Time; some locations observe daylight savings whereas others do not. Even when they do, they do not agree on the dates and times at which the changes to and from Daylight Savings occur.

Keeping an accurate record of the time zones used around the world is a hard task. Local administrations make rules about the local offset from UTC, and about whether to observe daylight savings, and if so, when. Fortunately, Windows has a database of time zone information installed on every system. Unfortunately, Microsoft failed to provide an API for querying this database.

In addition, Windows provides APIs for discovering the currently selected time zone, for converting from UTC to a specified time zone's local time, and (Windows XP and Server 2003 only) for converting from local time, in a specified zone, to UTC.

.NET APIs

.NET's base class library offers the System.TimeZone class. This class offers information about the current time zone. However, it does not offer any information about other time zones - what their names are, their offsets, or their daylight savings rules. This class is abstract, so could be extended. I have not yet done that as some of the features (GetDaylightChanges, IsDaylightSavingTime) will be difficult to implement, due to the apparent lack of OS support. A route of investigation would be to inspect the implementation of System.TimeZone in the Shared Source CLI [^].

The time zone database

Windows NT's time zone database is stored in the registry, at HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones. Under this key are the subkeys describing each time zone. Each subkey has the following values (examples taken from the GMT Standard Time key):

Value Type Purpose Example
Display REG_SZ Display name (GMT) Greenwich Mean Time: Dublin, Edinburgh, Lisbon, London
Dlt REG_SZ Name for the zone during daylight savings GMT Daylight Time
Index REG_DWORD Unique index number for zone 85
MapID REG_SZ Unknown. May be related to Win95 clickable time zone map. 0,1
Std REG_SZ Name for the zone outside daylight savings GMT Standard Time
TZI REG_BINARY Offsets and savings start/end date see below

The TZI value is the key part. It contains the offset from UTC, the additional offset for daylight savings, and the start and end dates for daylight savings. The structure is defined as follows:

[StructLayout( LayoutKind.Sequential )]
private struct TZI
{
    public int bias;
    public int standardBias;
    public int daylightBias;
    public SYSTEMTIME standardDate;
    public SYSTEMTIME daylightDate;
}

The bias, standardBias and daylightBias fields follow the rules for the corresponding members of the Win32 TIME_ZONE_INFORMATION structure: UTC = local + bias. A negative value indicates that the zone is ahead of UTC (typically east of London) while a positive one indicates behind UTC (typically west of London).

The TimeZoneInformation class provides access to the time zone database through the EnumZones static method. It exposes an Index property matching the Index registry value. The value of this field could be stored in a database, to persist, for example, a website user's time zone selection. I do not expect this value to change between operating system versions.

Converting times

The operating system provides two APIs for converting times relative to a time zone: SystemTimeToTzSpecificLocalTime and TzSpecificLocalTimeToSystemTime. The former is available only on NT-based operating systems, while the latter is only present on Windows XP and Server 2003 at the time of writing. To use these with a .NET DateTime structure, we must convert the DateTime to a SYSTEMTIME, the TZI to a TIME_ZONE_INFORMATION, and convert the resulting SYSTEMTIME back to a DateTime. DateTime conversions to and from SYSTEMTIME are performed via a FILETIME using the SystemTimeToFileTime and FileTimeToSystemTime APIs.

Mapping a TZI to a TIME_ZONE_INFORMATION is simply a matter of assigning the corresponding fields.

The TimeZoneInformation class converts from UTC to time-zone relative local time using the FromUniversalTime method, and from a time-zone relative local time to UTC using the ToUniversalTime method. This latter method will only work on Windows XP or Windows Server 2003; on down-level operating systems (Windows NT 4.0, Windows 2000) it throws a NotSupportedException.

The sample application

The supplied sample application converts either the current time, or a user-selected date and time, from the user's current time zone (or a selected time zone) to a user-selected time zone. The time zone selection defaults to the user's current time zone, so initially, the destination time will be the same as the current zone.

If the user selects Use Current, the local and the destination time update with the system clock.

If the Time Zone checkbox under Local Time is selected, the corresponding drop-down list can be used to select the time zone to convert from. On Windows 2000 or earlier, if this checkbox is selected, an error message will be displayed and the checkbox is subsequently disabled, reflecting the fact that the feature cannot be supported. The selected date and time are converted from the source time zone to UTC, and then from UTC to the destination zone.

I admit that the user interface is basic! I'm no graphic designer. Nevertheless, I hope it will be useful.

Updates

  • Version 1.2
    • TimeZoneInformation class: A bug-fix was made to the CurrentTimeZone static property to cope with the 'Automatically adjust clock for daylight saving changes' checkbox in the Date and Time control panel applet being unchecked. If this checkbox is unchecked, the GetTimeZoneInformation call returns a structure where DaylightBias and DaylightName are equal to their standard equivalents. This caused the comparison to fail.
    • World clock application: A bug-fix to prevent a crash if no time zone was selected in the Source Zone drop-down when the checkbox was checked.
  • Version 1.1
    • TimeZoneInformation class: The ToUniversalTime method was added to perform conversions to UTC using the TzSpecificLocalTimeToSystemTime API. Other new methods: FromIndex, a static method to locate a TimeZoneInformation object for a recorded Index, and static overloads of FromUniversalTime and ToUniversalTime which take an index argument.
    • World clock application: The Local Time Zone checkbox and drop-down list, allowing the user to specify the zone to convert from.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here