HomeCurrent ProjectsInterestsResumeE-mail

SimpleTimeZone class
  a programmable time zone class for the
  Microsoft .NET Framework
  by Michael R. Brumm
 

Introduction

I'm sure anyone working with globalization in the .NET Framework has been frustrated in the lack of native support for additional time zones (time zones other than the one provided by the local system). It is my hope that we (the .NET community) can develop a standard, programmable time zone which could be included in a future core library. To facilitate this, I posted an RFC to several of the microsoft.public.dotnet newsgroups. It requested comments and suggestions for an early time zone implementation I called "SimpleTimeZone".

Since then, I've received several suggestions, and made quite a few modifications to the class definition. Most notably:

  • Full Backward Compatibility with .NET Frameworks' System.TimeZone
    This means that if your computer is set to Pacific Daylight Time (PDT), the system's TimeZone.CurrentTimeZone object and a SimpleTimeZone (defined using PDT parameters) will always return the same results when queried.
     
  • More Methods Accept Universal Times
    One problem with using local times is that local times can be ambiguous (or even non-existant) during the daylight savings time changes. Universal Time, by contrast, is never ambiguous.
     
  • All New Methods and Properties are Overridable (Virtual)
    This makes derivation much easier and more powerful.
     
  • Source Code Simplification and Comments
    At the same time I made the source code simpler and easier to read, I also added comments.

Local Times are Ambiguous!

This issue rarely gets a lot of attention, so I thought this should be brought to everyone's attention right away. Local times can be ambiguous and should be used for display purposes only. When storing your data, use Universal Time (also known as Coordinated Universal Time, UTC, Greenwich Mean Time, or GMT), which is not ambiguous.

What do I mean when I say that local times are ambiguous? Consider the times during a switch to and from daylight savings time. For this example, assume that the switches occur at 2:00am, and daylight savings time "springs forward" (adds an hour in the Spring) and "falls back" (removes the hour in the Autumn). During the spring forward, the clock advances like this:
01:58am - - 01:59am - - 03:00am -- 03:01am

Note that 02:00am through 02:59am do not exist! What time is it when it is 02:30am local time? It's fairly safe to assume that 02:30am means 03:30am, but things get a lot more complicated during the fall back:
01:58am - - 01:59am - - 01:00am -- 01:01am

Note that the time between 01:00am and 01:59am is actually repeated! What time is it when it is 01:30am? In reality, this time can refer two two different times! If you had something scheduled to happen at 01:30am, it could happen twice that day!

Another problem with local times is that they change if your location changes. For example, let's say that you recorded appointments using local times in a database that was located in the Eastern Time Zone, then your company moved all its operations to the west coast. Now, your clients' and server's local time zone is the Pacific Time Zone, and all your appointments are 4 hours off!

Universal Time does not have any daylight savings time, or any other quirky rules like local times. It is always the same in any location, and is never ambiguous. So, store your data using Universal Time, and only convert to local time immediately before displaying the time to the user.

How to Construct a SimpleTimeZone

Personally, I find I learn best by example. So, here is an example of how to construct a time zone using "Mountain Time" (with daylight savings):

Dim mountainTimeZone As New SimpleTimeZone( _
  New TimeSpan(-7, 0, 0), _
  "Mountain Standard Time", _
  "MST", _
  New TimeSpan(1, 0, 0), _
  "Mountain Daylight Time", _
  "MDT", _
  New DaylightTimeChange( _
    4, DayOfWeek.Sunday, 0, New TimeSpan(2, 0, 0) _
  ), _
  New DaylightTimeChange( _
    10, DayOfWeek.Sunday, 4, New TimeSpan(2, 0, 0) _
  ) _
)

The standard offset of this time zone is -7 hours (off UTC).

The standard name and abbreviation:
 "Mountain Standard Time" and "MST"

The daylight savings delta is 1 hour (off standard offset).

The daylight savings name and abbreviation:
 "Mountain Daylight Time" and "MDT"

The time and date daylight savings starts:
 4th month (April), 0=1st, Sunday, 2:00am

The time and date daylight savings ends:
 10th month (October), 4=last, Sunday, 2:00am

How to Use SimpleTimeZone

SimpleTimeZone is derived from the System.TimeZone class, and therefore can be used in the same ways as it's base class. There are only a few new properties and methods which need explaining:

StandardAbbreviation
DaylightAbbreviation

    Similar to StandardName and DaylightName, except these hold the abbreviated versions of the time zone's name. For example: "PST" and "PDT"

GetNameLocalTime
GetNameUniversalTime

    These return the StandardName or DaylightName based on the time passed. If the time is during daylight savings time, then the DaylightName will be returned, otherwise the StandardName will be returned. Use GetNameUniversalTime whenever possible, because local time can be ambiguous.

GetAbbreviationLocalTime
GetAbbreviationUniversalTime

    Similar to GetNameLocalTime and GetNameUniversalTime, except using the abbreviated version of the time zone's name. Use GetAbbreviationUniversalTime whenever possible, because local time can be ambiguous.

IsDaylightSavingTimeUniversalTime

    This is similar to IsDaylightSavingTime, except that it allows you to pass in a Universal Time to determine whether the local time it represents in the time zone is during daylight savings. IsDaylightSavingTime, which only accepts a local time is ambiguous.

ToUniversalTime (additional overload)

    I've added an additional overload to ToUniversalTime which allows you to pass whether the local time being passed is a daylight savings time. This can help resolve an ambiguity during a fall back.

How to Derive and Store SimpleTimeZone

Unlike the SimpleTimeZone in other *cough* Java *cough* platforms, my class does not provide a list of pre-programmed time zones, and for good reason. Time zones are not physical entities, they are political and social constructs. Consequently, their definitions change fairly frequently on any public whim. Storing and updating these definitions is not a job in which I am particularly interested.

Instead, SimpleTimeZone's primary use is as a base class for more sophisticated derived classes. Using SimpleTimeZone as a base class, many different implementations can be derived to provide stores of time zones. A store is a collection of time zones which can be queried. Depending on your needs, you might create a store that exposes the time zones in a Unix zoneinfo database, or create a store that uses your own proprietary in-house database.

As a store example, I have provided the source code for a store which reads the time zones stored in the Windows registry. You can thus get an array of all the time zones available in Windows like this:

Dim winTimeZones As SimpleTimeZone()
winTimeZones = Microsoft.Win32.TimeZones.GetTimeZones()

Updates

UPDATE: 2003/07/25: Fixed a bug in calculating time during the end of daylight savings time. This bug went unnoticed because the referance I used to test against (.NET Framework 1.0 and 1.1 native timezone) also exibited the same bug. Microsoft has corrected the bug in version 1.2 of the .NET Framework, and I have corrected the bug in SimpleTimeZone.

UPDATE: 2003/05/04: I've changed the namespace from System.Globalization to MichaelBrumm.Globalization. My main reason for using the System namespace were: 1) to point out that these should be native classes, and 2) to shame Microsoft into including something similar (if not the same) in the .NET Framework. Unfortunately, as some pointed out, this could cause namespace conflicts in the future, so I created a new namespace to avoid complications with future versions of the .NET Framework. I am not particularly happy about using my own name as the namespace base, but this seemed to be the most prevalent and sensible proposal.

Downloads

I am releasing both the source code and a binary version which has been tested by myself and several other programmers. It is my hope that this release is bug-free, but there have been quite a few changes, so please test it yourself before relying on it for any critical systems. If you find any bugs, or have questions or comments, please send an e-mail to: me@michaelbrumm.com

The following source code and binary executables are FREE to be used for ANY use, including commercial and non-commercial.

HOWEVER, if you need to make modifications to the SimpleTimeZone class, I suggest you instead create a derived class and override the methods you need to change (as I have in the Win32 TimeZones Store example). It is much better design to derive a new class than modify the base class. You never know when your code might need to be version compatible with another class that uses SimpleTimeZone.

SimpleTimeZone:

Win32 TimeZones Store and Example:

 

 

 

 

All Material Copyright © Michael R. Brumm