Click here to Skip to main content
15,860,972 members
Articles / Programming Languages / C#

ZoneInfo (tz Database / Olson Database) .NET API

Rate me:
Please Sign up or sign in to vote.
3.80/5 (7 votes)
7 Apr 2008Ms-PL3 min read 106.6K   11   30
A simple .NET interface for utilising the ZoneInfo database

Introduction

This article describes a simple .NET API for using the ZoneInfo database, which is also known as the tz database or Olson database.

The API is available here.

I hope you find it useful. :)

Background

I have been developing a web site which schedules meetings and events across multiple time zones for more than a year now.

I previously used the .NET PublicDomain library discussed in another CodeProject article but had a number of issues including:

  • Just not working for Australia
  • It seems to hard code in the tz database rather than reading it from the file system; therefore if you need to update the database, you need to wait for the source code to be updated
  • The library seems to have a lot of other things in it which I just don't need (which is not a major issue though)

One of the big things I wanted was to have an API by which I can just download the latest tz database and off I go.

I am not a big fan of reinventing the wheel so if this library just isn't needed, PLEASE let me know. :)

Using the Code

Talking a fairly agile approach to this, I have just implemented the APIs which I have needed.

The interface itself is extremely simple and hopefully is well illustrated by the examples below.

Loading the Data

C#
// Load all the files
Database.LoadFiles(@"c:\src\trunk\TimeZoneTest\tzdata");

Before you start to use any of the functions, you need to make sure that the database of files are loaded.

Right now *.tab files in the timeinfo distribution are not loaded, but they are needed for the current set of APIs.

Getting the Local Time Somewhere Else

C#
// Iterate through all the zone strings
foreach (string zoneName in Database.GetZoneNames())
{
    Zone z = Database.GetZone(zoneName);

    Console.WriteLine("Zone: " + z.Name
                        + "\n\thas a local date time of "
                        + z.Now.ToString()
                        + "\n\twhich is a GMT offset of "
                        + z.GetUtcOffset(z.Now).ToString());
}

The sample above gets all the time zone names and then gets the corresponding ZoneInfo.Zone instance.

From this instance, you can do a number of things like getting the local time in that zone and its current UTC offset.

Zone: Europe/Malta
        has a local date time of 8/04/2008 9:40:52 AM
        which is a GMT offset of 02:00:00
Zone: Europe/Minsk
        has a local date time of 8/04/2008 10:40:52 AM
        which is a GMT offset of 03:00:00
Zone: Europe/Monaco
        has a local date time of 8/04/2008 9:40:52 AM
        which is a GMT offset of 02:00:00
Zone: Europe/Moscow
        has a local date time of 8/04/2008 11:40:52 AM
        which is a GMT offset of 04:00:00 

Convert Times between Time Zones

C#
// What is the time in Sao Paulo when it is new year's day in Melbourne?
Zone melbTz = Database.GetZone("Australia/Melbourne");
Zone spTz = Database.GetZone("America/Sao_Paulo");

DateTime melbTime = new DateTime(2009, 1, 1, 0, 0, 0, DateTimeKind.Local);
DateTime utcTime = melbTz.ConvertToUtc(melbTime);
DateTime spTime = spTz.ConvertToLocal(utcTime);

Console.WriteLine("Melbourne " + melbTime.ToString()
                  + "\nSao Paulo " + spTime.ToString()
                  + "\nUTC " + utcTime.ToString());

One of the most useful features of the API is the ability to convert arbitrary dates between time zones. A lot of TimeZone APIs only really know what the UTC offset is right now, not 6 months from now.

Melbourne 1/01/2009 12:00:00 AM
Sao Paulo 31/12/2008 11:00:00 AM
UTC 31/12/2008 1:00:00 PM

Offset Cut-over Windows

C#
// What are all the timezone cutover windows for Melbourne in the last few years?
List<DateTime> dates =
         melbTz.GetCutoverWindows(
                    new DateTime(2007, 1, 1, 0, 0, 0, DateTimeKind.Local),
                    new DateTime(2009, 12, 31, 23, 59, 59, DateTimeKind.Local));

Console.WriteLine("Printing cutovers between 1/1/2007 - 31/12/2009");
foreach (DateTime dt in dates)
{
     Console.WriteLine("\t" + dt.ToString());
}

This functionality may seem useless ... until you actually need it.

If you store dates in the database in UTC and need to convert them to the local time of the user, you need to apply a UTC offset. What happens if the daylight offset changes within this window? Well, you can know if this is the case rather than assuming that it doesn't matter.

Printing cutovers between 1/1/2007 - 31/12/2009
        30/03/2007 2:00:00 AM
        27/10/2007 2:00:00 AM
        6/04/2008 2:00:00 AM
        5/10/2008 2:00:00 AM
        5/04/2009 2:00:00 AM
        4/10/2009 2:00:00 AM  

Points of Interest

The code seems to work well for Australia and the other zones I have tested this with. I am sure as more people use it in different scenarios, it will continue to mature.

One thing I did notice was just how un-standard the format of the tz database was with respect to tab and space delimiting of fields ... the code has a number of hacks unfortunately to compensate this.

More Information

Check out the latest version of the code on CodePlex.

If you have any issues, please log it there and I will look at any changes which need to get done.

History

  • 7th April, 2008: Initial post

There are still a number of things to be done including handling of Link entries in the files. The current format allows for backward compatibility in the old names. This is not hard to do and will happen soon (or if someone needs it).

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)


Written By
Chief Technology Officer Attend Anywhere
Australia Australia
I don't get my hands dirty that much any more but enjoy it when I do Smile | :)

Comments and Discussions

 
GeneralThank you for sharing! Pin
agatonek29-May-14 8:11
agatonek29-May-14 8:11 
QuestionDatabase.cs {"Input string was not in a correct format."} Pin
dburtsev7-Jun-13 9:02
dburtsev7-Jun-13 9:02 
AnswerSilverlight Developers Rejoice!!! Pin
ABOHAK23-Feb-12 2:10
ABOHAK23-Feb-12 2:10 
GeneralRe: Silverlight Developers Rejoice!!! Pin
Mark Rodrigues23-Feb-12 11:34
Mark Rodrigues23-Feb-12 11:34 
GeneralImplementation in VB6 Pin
cptolemy7-Dec-10 8:15
cptolemy7-Dec-10 8:15 
GeneralRe: Implementation in VB6 Pin
Mark Rodrigues7-Dec-10 10:09
Mark Rodrigues7-Dec-10 10:09 
GeneralMy vote of 2 Pin
Pooya Paridel7-Jan-10 21:43
Pooya Paridel7-Jan-10 21:43 
QuestionGetting time zone info from Windows OS Pin
mr.sonntag27-Apr-09 21:10
mr.sonntag27-Apr-09 21:10 
QuestionGetZoneNames() Pin
thaddeusbort4-Sep-08 8:50
thaddeusbort4-Sep-08 8:50 
AnswerRe: GetZoneNames() Pin
Mark Rodrigues4-Sep-08 13:01
Mark Rodrigues4-Sep-08 13:01 
GeneralRe: GetZoneNames() Pin
thaddeusbort10-Sep-08 8:16
thaddeusbort10-Sep-08 8:16 
NewsRe: GetZoneNames() Pin
Mark Rodrigues10-Sep-08 12:14
Mark Rodrigues10-Sep-08 12:14 
GeneralDST Not accounted for in ConvertToLocal Pin
KragAapie21-Jul-08 21:18
KragAapie21-Jul-08 21:18 
I have had a look at this library and it seems to work for time zone conversions but the ConvertToLocal expects a UTC DateTime but the GetUtcOffset that is called with in the convert method expects a local time.

Therefore if you have dates that cross over the DS period the offset is not calculated correctly.
E.g.

So to get the correct time I hacked my code a bit.

TimeSpan initialSpan = localZone.GetUtcOffset(dtUtc);
DateTime localTime = localZone.ConvertToLocal(dtUtc);
TimeSpan span = localZone.GetUtcOffset(localTime);
if(initialSpan != span)
localTime = new DateTime((dtUtc+ span).Ticks, DateTimeKind.Local);

If your API provides a better way to do this that I'm not seeing please let me know.

Cheers
GeneralError in negative minute offeset Pin
Wayne Hetherington25-Jun-08 10:12
Wayne Hetherington25-Jun-08 10:12 
AnswerRe: Error in negative minute offeset Pin
Mark Rodrigues4-Sep-08 13:30
Mark Rodrigues4-Sep-08 13:30 
GeneralRe: Error in negative minute offeset Pin
Wayne Hetherington5-Sep-08 4:26
Wayne Hetherington5-Sep-08 4:26 
GeneralRe: Error in negative minute offeset Pin
Mark Rodrigues5-Sep-08 17:43
Mark Rodrigues5-Sep-08 17:43 
GeneralEtc/GMT is altering minutes, not hours Pin
AbbydonKrafts10-May-08 10:23
professionalAbbydonKrafts10-May-08 10:23 
AnswerRe: Etc/GMT is altering minutes, not hours Pin
Mark Rodrigues11-May-08 2:34
Mark Rodrigues11-May-08 2:34 
NewsJust updated API and article Pin
Mark Rodrigues7-Apr-08 21:54
Mark Rodrigues7-Apr-08 21:54 
GeneralThe only issue .. Pin
Garth J Lancaster7-Apr-08 12:28
professionalGarth J Lancaster7-Apr-08 12:28 
GeneralRe: The only issue .. Pin
Mark Rodrigues7-Apr-08 19:26
Mark Rodrigues7-Apr-08 19:26 
GeneralRe: The only issue .. Pin
Garth J Lancaster7-Apr-08 19:43
professionalGarth J Lancaster7-Apr-08 19:43 
GeneralRe: The only issue .. Pin
Mark Rodrigues7-Apr-08 19:50
Mark Rodrigues7-Apr-08 19:50 
GeneralRe: The only issue .. Pin
Garth J Lancaster9-Apr-08 1:21
professionalGarth J Lancaster9-Apr-08 1:21 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.