DateTime time zone conversion with .NET 3.5

Some time ago I wrote a blog post about Timezone conversion and handling within .NET which sucked at that time.

With .NET 3.5 its better, in fact much better, its actually usable :)

In .NET 1.1 and 2.0 there were not way to convert DateTime objects between different time zones to handle all the hassle of adding minutes, handling summer winter time, etc.

There is now. Its not perfect, but it does the job.

Its pretty straightforward.

I will provide an example, which should give you an idea of how to use in real life.

The example below takes two DateTime objects. One UTC Datetime, and one Danish DateTime.

Both DateTime object are created with the same numbers, one is just specified as UTC, the other one as local time.

//Create DateTime with UTC Kind specified, and with Current time in UTC
DateTime utcNow = new DateTime(2008, 8, 16, 21, 42, 32, DateTimeKind.Utc);

//Create danish local DateTime
DateTime dkNow = new DateTime(2008, 8, 16, 21, 42, 32, DateTimeKind.Local); ;
//Find timezone info for egypt
TimeZoneInfo egypt = TimeZoneInfo.FindSystemTimeZoneById("Egypt Standard Time");
//Convert danish local time to egypt time
DateTime egyptTime1 = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(dkNow, "Egypt Standard Time");
//Convert utc time to egypt local time
DateTime egyptTime2 = TimeZoneInfo.ConvertTimeFromUtc(utcNow, egypt);

//Write out initial DateTime objects
Console.WriteLine("{0} {1}", dkNow, dkNow.ToString("%K"));
//Writes out 16-08-2008 21:42:32 +02:00
Console.WriteLine("{0} {1}", utcNow, utcNow.ToString("%K"));
//Writes out 16-08-2008 21:42:32 Z
//Write out the results
Console.WriteLine("Danish NOW converted to Eqypt time:{0} {1}", egyptTime1,

DateTime.SpecifyKind(egyptTime1, DateTimeKind.Local).ToString("%K"));
//Writes out Danish NOW converted to Eqypt time:16-08-2008 22:42:32 +02:00
Console.WriteLine("UTC NOW converted to Eqypt time:{0} {1}", egyptTime2,
DateTime.SpecifyKind(egyptTime2, DateTimeKind.Local).ToString("%K"));
//Writes out UTC NOW converted to Eqypt time:16-08-2008 00:42:32 +02:00

As you can clearly see of the example it is fairly easy to convert DateTime's between timezones, but there is just one question that springs to mind.

Where do you get the list of Timezone ID's?

Well I will provide you with one here, but its a crappy solution Microsoft have chosen for timezone names.

 

Timezone IDUTC offset offset
Morocco Standard Time 0:0
GMT Standard Time 0:0
Greenwich Standard Time 0:0
W. Europe Standard Time 1:0
Central Europe Standard Time 1:0
Romance Standard Time 1:0
Central European Standard Time 1:0
W. Central Africa Standard Time 1:0
Jordan Standard Time 2:0
GTB Standard Time 2:0
Middle East Standard Time 2:0
Egypt Standard Time 2:0
South Africa Standard Time 2:0
FLE Standard Time 2:0
Israel Standard Time 2:0
E. Europe Standard Time 2:0
Namibia Standard Time 2:0
Arabic Standard Time 3:0
Arab Standard Time 3:0
Russian Standard Time 3:0
E. Africa Standard Time 3:0
Georgian Standard Time 3:0
Iran Standard Time 3:30
Arabian Standard Time 4:0
Azerbaijan Standard Time 4:0
Caucasus Standard Time 4:0
Armenian Standard Time 4:0
Afghanistan Standard Time 4:30
Ekaterinburg Standard Time 5:0
Pakistan Standard Time 5:0
West Asia Standard Time 5:0
India Standard Time 5:30
Sri Lanka Standard Time 5:30
Nepal Standard Time 5:45
N. Central Asia Standard Time 6:0
Central Asia Standard Time 6:0
Myanmar Standard Time 6:30
SE Asia Standard Time 7:0
North Asia Standard Time 7:0
China Standard Time 8:0
North Asia East Standard Time 8:0
Singapore Standard Time 8:0
W. Australia Standard Time 8:0
Taipei Standard Time 8:0
Tokyo Standard Time 9:0
Korea Standard Time 9:0
Yakutsk Standard Time 9:0
Cen. Australia Standard Time 9:30
AUS Central Standard Time 9:30
E. Australia Standard Time 10:0
AUS Eastern Standard Time 10:0
West Pacific Standard Time 10:0
Tasmania Standard Time 10:0
Vladivostok Standard Time 10:0
Central Pacific Standard Time 11:0
New Zealand Standard Time 12:0
Fiji Standard Time 12:0
Tonga Standard Time 13:0
Azores Standard Time -1:0
Cape Verde Standard Time -1:0
Mid-Atlantic Standard Time -2:0
E. South America Standard Time -3:0
Argentina Standard Time -3:0
SA Eastern Standard Time -3:0
Greenland Standard Time -3:0
Montevideo Standard Time -3:0
Newfoundland Standard Time -3:-30
Atlantic Standard Time -4:0
SA Western Standard Time -4:0
Central Brazilian Standard Time -4:0
Pacific SA Standard Time -4:0
Venezuela Standard Time -4:-30
SA Pacific Standard Time -5:0
Eastern Standard Time -5:0
US Eastern Standard Time -5:0
Central America Standard Time -6:0
Central Standard Time -6:0
Central Standard Time (Mexico) -6:0
Mexico Standard Time -6:0
Canada Central Standard Time -6:0
US Mountain Standard Time -7:0
Mountain Standard Time (Mexico) -7:0
Mexico Standard Time 2 -7:0
Mountain Standard Time -7:0
Pacific Standard Time -8:0
Pacific Standard Time (Mexico) -8:0
Alaskan Standard Time -9:0
Hawaiian Standard Time -10:0
Samoa Standard Time -11:0
Dateline Standard Time -12:0

 

Naturally the best solution would have been to use the Zoneinfo names for timezones since they are a lot more intuitive, and a lot of websites already use them out there, and oh btw all unix/linux/macos out there as well :) http://en.wikipedia.org/wiki/Zoneinfo

.NET TimeZone

Everyone working with .NET and TimeZones have at one point thought, why the #%&#&% can't I instantiate another TimeZone than the current one, i.e. why is it not possible to create a .NET TimeZone object in the following simple way.

TimeZone zone = new TimeZone("Europe/Copenhagen");

TimeZone zone = new TimeZone("CET");

It seems like Microsoft did not think of, or decided not to implement multi timezone support in .NET, and thats too bad, because Timezone handling, Daylight savings are just a bitch to work with.

Timezones are not so bad, since its pretty easy to identify what timezone a given country is in. There are numerous sources for this on the internet, such as http://www.timeanddate.com/worldclock/, and with a little manual work, or a little screen scraping you can have a combined country/timezone list in no time.

The real problems occurs when you want to find out whether or not a given TimeDate object is within the Daylight savings time for a given country and timezone, and in that, the timezone are of no use, since it says nothing about the daylight savings of the date.

I have tried some solutions where I try to identify the daylight savings time for the most used countries, for a few years in advance, but that won't help me with dates in the past, and is really not a good solution, since the completeness of the solution is at best lacking.

I have searched a lot of places on the internet for a proper solution, and someone have made a solution for retrieving the timezones from the windows registry combined with some dll imports fromt he win32 API, but those are not perfect either.

So having almost tossed the towel into the ring, I stumpled upon another page on the internet http://www.codeplex.com/publicdomain/, and I thought, hmm, another crappy implementation, but no, its a full .NET implementation of the tz database http://www.twinsun.com/tz/tz-link.htm. I had looked at that timezone database myself a few times, but the sheer size and format of the database was just such a daunting task, that I have never fathomed to even be able to read that into a sensible .NET format.

The .NET library called PublicDomain is very easy to work with, much intuitive, and handles timezones and daylight savings very nice.

Its as simple as:

// Get the local computer's time zone
TzTimeZone dkZone = TzTimeZone.GetTimeZone("Europe/Copenhagen");

TzTimeZone ausZone = TzTimeZone.GetTimeZone("Australia/Adelaide");

DateTime dkNow = DateTime.UtcNow; //When in danish timezone

DateTime auzNow = ausZone.ToLocalTime(dkNow);
Gracefully right :)

Too bad Microsoft did not implement this.

The good part is that they will in .NET 3.5. I'm not sure of the extend of the implementation, or how well the daylight saving rules for each country is implemented, but at least its good that Microsoft at least have started looking in this direction.