Click here to Skip to main content
Email Password   helpLost your password?

Introduction

Dates, time zones, and overall internationalization are not a programmer's friend, historically. From Julius Caesar in 45 B.C.E. (Julian calendar) through Pope Gregory the XIII in 1582 C.E. (Gregorian calendar), UTC and world-wide calendars, dates and times have shifted to ever-changing politics and new scientific understandings. Although the invention of computing and information exchange is relatively new, many concepts of date and time zone information are not ingrained in the architectures and frameworks we use every day.

Windows time zone support is sufficient, but has drawbacks and is not exposed easily in .NET (requiring registry queries and WIN32 calls).

Enter the Olson Time Zone database, a public domain database of historical time zone data points. It is well maintained and used by Unix, Linux, and Java, just to name a few. It is not used by Windows nor .NET, but can be used with the PublicDomain package.

PublicDomain

The PublicDomain package is a completely free, public domain collection of oft-needed code and packages for .NET. There is no license, so the code (or any part of it) may be included even in corporate applications. Public domain code has no authority and is provided 'AS-IS'. See this link for more details.

First, An Example

Getting right to the code, here is an example of using the Olson tz database through the PublicDomain DLL (installed in the GAC):

// Common usage examples:
// ======================

// Get the local computer's time zone
TzTimeZone zone = TzTimeZone.CurrentTimeZone;

// Get a common time zone
zone = TzTimeZone.ZoneUsEastern;

// Get a zone in the time zone database
zone = TzTimeZone.GetTimeZone(TzConstants.TimezoneEuropeMoscow);

// Get a TzDateTime representing the current time in Moscow.
// TzDateTime wraps a UTC value and exposes DateTimeLocal and
// DateTimeUTC version of the data for use
TzDateTime moscowLocal = zone.Now;

// All DateTime operations exist on TzDateTime, but the actual data
// is in the aforementioned properties
moscowLocal += new TimeSpan(1, 0, 0);

Console.WriteLine(moscowLocal.DateTimeLocal);
Console.WriteLine(moscowLocal.DateTimeUtc);

// Switch back to the local time zone:
zone = TzTimeZone.ZoneUsEastern;

// Get the abbreviated form of the zone, being
// daylight time sensitive. For example, for this
// zone, it will either return EST or EDT, depending
// on the date passed (DateTime.Now is used if not date
// is specified)
Console.WriteLine(zone.GetAbbreviation());

// Convert a DateTime (either local or UTC) to
// a TzDateTime, which will then carry around its
// time zone
TzDateTime localNow = new TzDateTime(zone.ToLocalTime(DateTime.UtcNow), zone);

// Now we can use this TzDateTime wrapper without ever
// losing the time zone information. If the object
// is serialized, only the UTC value is serialized (as
// well as the zone name).
Console.WriteLine(localNow.DateTimeLocal.ToString("G"));

// This provides a common data interchange and storage pattern.
// The data is always in UTC, and the TzTimeZone context
// is used to convert to local times. This is the way
// time zones should have been designed from the beginning.

Aspects of the code:

TzDateTime/TzTimeZone Design

Converting Existing Code

The TzDateTime and TzTimeZone classes have been designed to make converting almost as simple as doing a large Find & Replace for DateTime -> TzDateTime, and TimeZone -> TzTimeZone. However, migration is not always as trivial. The TzDateTime constructors mimic the DateTime constructors, but also require an added parameter which specifies the time zone, or a boolean which specifies that the DateTime provided is a UTC date/time. Time zone support should be architected well, but in general, the recommendation is to create a statically initialized TzTimeZone in your code which represents the canonical time zone of your application, and use this static variable where time zones are required. This makes future modification/internationalization easier.

History

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralGAC???
agnostos
2:29 13 Jan '09  
what is GAC and how can i installed there ?
GeneralRe: GAC???
schizoidboy
17:58 13 Jan '09  
The GAC is the Global Assembly Cache. There is one on every computer with .NET installed. The GAC is a place to put commonly used, global DLLs. You can read more here:

http://msdn.microsoft.com/en-us/library/yf1d93sz(VS.71).aspx
And here:

http://msdn.microsoft.com/en-us/library/aa559668.aspx
If you install PublicDomain.msi, it will put PublicDomain into the GAC for you.
GeneralAnother option...
Mark Rodrigues
14:27 8 Apr '08  
I had been using this library for 6 months.
I am based in Melbourne, Australia and had a lot of troubles getting it to work for my region, but was able to make some hacks to it to get it to go.

Australia had a change of day light savings rules this year and so I needed to update the Olson database and found out that this API didn't look like it was actually being read dynamically - it looked like all the zones and rules were hard-coded as structs into the code.
(I am happy to be told that this understanding is incorrect D'Oh! )

I ended up writing a simpler version of the API which can be seen here[^] on the code project.

I don't claim that it isbetter than what is described here and it certainly isn't as mature.

The PublicDomain library here has a lot of other cool stuff not related to time zones which you may also find useful.

But if you are just looking for a simple Olson database API which reads the latest tz database files as you download them) then it may be an option for you.

Thanks to the author of this work though for giving me 6 months of joy Big Grin

Mark
GeneralBug in southern hemisphere
Codeka
20:08 20 Nov '07  
This is great stuff!! However, there are two bugs that make the code completely useless in the southern hemisphere.

First of all, you're assuming the "LETTER/S" field in the database is set to "S" for standard time and "D" for daylight time. That's not true in many locations (for example, Australia). I've changed your code for FindRuleIndex so that instead of taking an "avoidModifier" parameter, it takes a bool? parameter that is null if we don't care, true to avoid the standard time and false to avoid the daylight savings time. It's basically the same as your avoidModifier parameter, but based off the TzRule.SaveTime property rather than TzRule.Modifier.

Secondly, you're assuming that daylight saving time starts in the first half of the year, and ends in the second half of the year. That's true in the northern hemisphere (U.S. and Europe, for example) but it's not true in the southern hemisphere, where daylight saving time starts at the end of the year, and finishes at the beginning of the next year. This is evident in the GetDaylightChangeRules method, where you're assuming the "from" and "to" date/time values have the same Year component.
GeneralRe: Bug in southern hemisphere
Nestor Sulikowski
8:04 29 Nov '07  
I'm curious. Was this fixed?
GeneralRe: Bug in southern hemisphere
eydelbergo
7:03 11 Dec '07  
Hi, I wrote this code, but I hadn't seen this comment, sorry about that! I've been tracking this project including bugs at codeplex.com/PublicDomain. I will certainly look into this bug, it sounds bad. Do you have the code changes you made, although they seem very logical, it sounds like you've tested this and I don't have much time right now. If you do still have the code, please post to this bug tracker:

[^]

I will be looking in to this issue...

Thanks!
GeneralThanks
JasonBSteele
9:12 24 Jul '07  
Thanks for this!


Last Updated 21 Jul 2007 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010