Introduction

Imagine you are developing a Web or desktop application where you need to work with DateTime values in a time zone specified by the user's preference. I got myself into such a situation several weeks ago and I started to search the Web for a suitable solution. Unfortunately I didn't find anything I liked, so I started to design my own solution.

The first article I took into consideration was Mike Dimmick's WorldClock article here on The Code Project. If you need to convert DateTime values from/to various time zones, this could be an acceptable solution. But it was not my case exactly because I just was to convert times from/to UTC values, so I came to the conclusion that I needed to extend the abstract System.TimeZone class provided by the .NET Framework. Furthermore, Mike's code doesn't really comply with my sense of object oriented design, no offence.

You may also find it useful to use the Olson time zone database, but remember that you will need the PublicDomain DLL installed in the GAC and you will have to care about the database updates.

UITimeZone and TimeZoneManager

As you can see in the picture above, the required functionality is implemented by two cooperating classes. There is a UITimeZone class that derives from the abstract System.TimeZone class. The TimeZone class contains a property called CurrentTimeZone which can be used to obtain the current time zone of the machine executing the calling assembly - in case of a Web application, this could be the time zone of the Web server. Similarly, the UITimeZone class provides the CurrentUITimeZone property that can be used to get or set the time zone of the user interface. It is an analogy of the CurrentCulture and CurrentUICulture properties of the Thread class.

The TimeZoneManager class has no special meaning; it's just a static class providing a list of available time zones and an implementation of the Greenwich Mean Time time zone that could be used as a default value in some scenarios. The list of available time zones is retrieved from the time zone database placed in the Windows registry, so you can rely on Microsoft to update the database when needed. But if you want to be perfect, you should monitor the Windows registry for changes and reload the collection of available time zones every time a modification is made to the time zone database.

If you need more detailed information about time zones and about the way time zones are organized in the Windows registry, see the Mike Dimmick's article or refer to the MSDN Library.

System.TimeZone Issues

There are several reasons why one should not try to use the System.TimeZone class as a base class. In my Web search for time zone solutions, I've found a thread in the MSDN Forums where a member of the Base Class Libraries development team classifies the attempt to make TimeZone a point of extensibility as a mistake. First of all, it is unclear what the ToLocalTime() method should do, whether it should convert from the represented time zone to the machine time zone or from UTC to the represented time zone. I see the latter perfectly suitable for the case of UITimeZone, because it seems clear to me that TimeZone.CurrentTimeZone.ToLocalTime() converts to machine local time, and UITimeZone.CurrentUITimeZone.ToLocalTime() converts to user local time. But I can understand that this could be a matter of opinion.

Another issue does not refer directly to the TimeZone class, but rather to the internal CurrentSystemTimeZone class that is used in the implementation of the TimeZone.CurrentTimeZone property. The problem doesn't appear until you need to work with historical data. Some of the existing time zones use so called Dynamic Daylight Saving Time which means that the dates and times at which the changes to and from Daylight Saving Time occur differ from one year to another. The CurrentSystemTimeZone class always uses the actual daylight saving time rules, whether the year of the processed time equals to the current year or not. Dynamic daylight changes are stored in the Windows registry, but neither .NET API nor Win32 API (except Windows Vista) provides functionality of querying this data. If you need to work with historical data, which should be the case in database applications and information systems, you may use the UITimeZone class because it handles historical data correctly.

Using the Code

First of all, you need to implement your own logic of retrieving and updating the user's time zone setting. The sample provided with this article stores the user preferences just in memory, so it is lost when the application ends.

The following code snippet shows how to use the current user interface time zone. Note that DateTime values retrieved from a database used to have their Kind property set to DateTimeKind.Unspecified, but it may differ with the particular database provider you might be using.

When you need to modify the user interface time zone, you can use the machine time zone, the Greenwich Mean Time time zone, or you can face the user with a drop-down displaying the list of available time zones which is provided by the TimeZoneManager class.

// Sets the UI time zone equal to the machine time zone
UITimeZone.CurrentUITimeZone = TimeZone.CurrentTimeZone;
// Sets the UI time zone to be the Greenwich time zone
UITimeZone.CurrentUITimeZone = TimeZoneManager.GmtTimeZone;
// Sets the UI time zone to be the 34th known time zone
UITimeZone.CurrentUITimeZone = TimeZoneManager.TimeZones[33];
// Sets the UI time zone to be the Prague's time zone
UITimeZone.CurrentUITimeZone =
TimeZoneManager.TimeZones["Central Europe Standard Time"];

Conclusion

Hopefully, enumerating the time zones and more will be soon directly supported by the .NET Framework and its TimeZoneInfo class. Until the .NET Framework 3.5 is released, you might find my classes useful, and I will appreciate any feedback on them. Also feel free to report any bugs discovered in my code. Thanks.

Share

About the Author

Jakub Novák (yes, this is his real name ) is a professional in the domain of information technologies in which he has been working since the year 2000. He's got a doctorate in Design and Process Engineering; during his PhD study he performed tasks of a consultant and analyst of the software parts of problems and was responsible for development of execution routines from the area of digital signal processing.

He's experienced in analysis and design of software applications using the techniques of OOP and UML and in development of computer programs in C++, C# and Visual Basic languages. He is very interested in new technologies.

Currently he works as a freelance senior software developer participating in stand-alone interesting and challenging projects.

Comments and Discussions

The TimeZoneManager class assumes that the Windows TimeZone for UTC is "GMT Standard Time". On at least my version of Windows (XP sp2 fully patched including the 2007 patch), the actual TimeZone for that zone is "Greenwich Standard Time". The difference is that "GMT" does have Daylight Savings while "Greenwich" does not. Since that is a key difference and since it is subject to change at Microsoft's whim, some additional checking is needed to determine which UITimeZone should be assigned to the gmtTimeZone variable. Specifically, the basic ZoneBias must be 0, and the DaylightDate member of the TimeZoneInfo structure must NOT be Enabled.
These bits of information are not available to TimeZoneManager, so appropriate properties must be added to BiasSettings and UITimeZone classes to permit this checking.

Well, it depends on your needs. In my implementation the GmtTimeZone property has no special function, it is just a value that can be used as a default value in some scenarios. I've chosen the "GMT Standard Time"; you may choose the "Greenwich Standard Time". As you wrote, the only difference is in the DST rules ...