Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting time between Timezones

Tags:

timezone

c#

.net

I'm using TimeZoneInfo.ConvertTime method to convert time from one to another.

While converting the Date Time 1/1/2006 2.00 AM from Perth to Sri Jeyawardenepura its converted to 1/31/2005 11.30pm

While converting the same time back (1/31/2005 11.30pm) from Sri Jeyawardenepura to Perth its converted to 1/1/2006 3.00 AM.

Why there is one hour difference in the Time Zone conversion?

like image 238
LokiDil Avatar asked Apr 04 '12 08:04

LokiDil


People also ask

How to convert local time to another time zone?

Time Zone Converter This converter is a useful tool whenever you want to know what the time will be in other time zone in addition to your local time. Simply choose your Time zone and any Time&Date you want and then choose your target time zone.

How to convert NY time to another time zone in Excel?

Time: the time you want to convert to time in another time zone. Difference: the time difference between the old time zone and the new time zone. It returns a decimal value, then you need to format it to a time format you want. Use below formula to convert the NY time in cell B3:B6 to the new time based on the time differences in cell D3:D6:

What is the time zone converter tool?

The time zone converter tool is a fast, easy, and simple way to find out exactly what time it is around the world and stay on top of all your international communications, calls, and meetings as well as staying in touch with friends and family abroad. Sign Up To Our Newsletter

How many hours are there in a time zone?

All the time zones around the world together represent twenty-four hours. In reality, though, a time zone is a region of the Earth that has the same time. Therefore, the world is theoretically divided into twenty-four 15 degree longitudinal sections that serve as time zones.


1 Answers

Wow, this is a Double Whammy! I just stumbled across this post and wasn't going to post anything at all since it's so old and the OP didn't show any code. But then curiosity got the best of me so I checked it out.

Using just the .NET BCL:

string tzid1 = "W. Australia Standard Time"; // Perth
TimeZoneInfo tz1 = TimeZoneInfo.FindSystemTimeZoneById(tzid1);

string tzid2 = "Sri Lanka Standard Time"; // Sri Jeyawardenepura
TimeZoneInfo tz2 = TimeZoneInfo.FindSystemTimeZoneById(tzid2);

DateTime dt1 = new DateTime(2006, 1, 1, 2, 0, 0);
Debug.WriteLine(dt1); // 1/1/2006 2:00:00 AM
DateTime dt2 = TimeZoneInfo.ConvertTime(dt1, tz1, tz2);
Debug.WriteLine(dt2); // 12/31/2005 11:30:00 PM
DateTime dt3 = TimeZoneInfo.ConvertTime(dt2, tz2, tz1);
Debug.WriteLine(dt3); // 1/1/2006 3:00:00 AM

Sure enough, there is the discrepancy that the OP described. At first I thought this must be due to some kind of DST issue, so I checked for Sri Lanka and Perth. While both had a transition in 2006, neither were anywhere close to it for this date. Still, I thought I should check using DateTimeOffset to avoid any ambiguity issues:

string tzid1 = "W. Australia Standard Time"; // Perth
TimeZoneInfo tz1 = TimeZoneInfo.FindSystemTimeZoneById(tzid1);

string tzid2 = "Sri Lanka Standard Time"; // Sri Jeyawardenepura
TimeZoneInfo tz2 = TimeZoneInfo.FindSystemTimeZoneById(tzid2);

DateTime dt = new DateTime(2006, 1, 1, 2, 0, 0);
DateTimeOffset dto1 = new DateTimeOffset(dt, tz1.GetUtcOffset(dt));
Debug.WriteLine(dto1);  // 1/1/2006 2:00:00 AM +08:00
DateTimeOffset dto2 = TimeZoneInfo.ConvertTime(dto1, tz2);
Debug.WriteLine(dto2);  // 12/31/2005 11:30:00 PM +05:30
DateTimeOffset dto3 = TimeZoneInfo.ConvertTime(dto2, tz1);
Debug.WriteLine(dto3);  // 1/1/2006 3:00:00 AM +09:00

And it's still off. You can see that it thinks the target time should be at +09:00, but Perth didn't switch to that until December 3rd 2006. In January it was clearly still +08:00.

So then I thought... Noda Time to the rescue!

First let's check using the same Windows .NET BCL time zones.

string tzid1 = "W. Australia Standard Time"; // Perth
DateTimeZone tz1 = DateTimeZoneProviders.Bcl[tzid1];

string tzid2 = "Sri Lanka Standard Time"; // Sri Jeyawardenepura
DateTimeZone tz2 = DateTimeZoneProviders.Bcl[tzid2];

LocalDateTime ldt1 = new LocalDateTime(2006, 1, 1, 2, 0, 0);
ZonedDateTime zdt1 = ldt1.InZoneStrictly(tz1);
Debug.WriteLine(zdt1.ToDateTimeOffset()); // 1/1/2006 2:00:00 AM +08:00
ZonedDateTime zdt2 = zdt1.WithZone(tz2);
Debug.WriteLine(zdt2.ToDateTimeOffset()); // 12/31/2005 11:30:00 PM +05:30
ZonedDateTime zdt3 = zdt1.WithZone(tz1);
Debug.WriteLine(zdt3.ToDateTimeOffset()); // 1/1/2006 2:00:00 AM +08:00

Hey, that seems like it fixed it, right? If so, that would mean that the problem isn't with the Windows time zone data, because Noda Time's BCL provider uses the exact same data. So there must be something actually defective in TimeZoneInfo.ConvertTime. There's Whammy #1.

So just to check that it's all good and well, let's try the same thing with IANA TZDB data. It's known to be more accurate after all:

string tzid1 = "Australia/Perth";
DateTimeZone tz1 = DateTimeZoneProviders.Tzdb[tzid1];

string tzid2 = "Asia/Colombo"; // Sri Jeyawardenepura
DateTimeZone tz2 = DateTimeZoneProviders.Tzdb[tzid2];

LocalDateTime ldt1 = new LocalDateTime(2006, 1, 1, 2, 0, 0);
ZonedDateTime zdt1 = ldt1.InZoneStrictly(tz1);
Debug.WriteLine(zdt1.ToDateTimeOffset()); // 1/1/2006 2:00:00 AM +08:00
ZonedDateTime zdt2 = zdt1.WithZone(tz2);
Debug.WriteLine(zdt2.ToDateTimeOffset()); // 1/1/2006 12:00:00 AM +06:00
ZonedDateTime zdt3 = zdt1.WithZone(tz1);
Debug.WriteLine(zdt3.ToDateTimeOffset()); // 1/1/2006 2:00:00 AM +08:00

And there, my friends, is Whammy #2. Notice that the middle time is using a +06:00 offset? I thought this was in error, but when I checked once more here it turns out that the TZDB data is correct. Sri Lanka was at +06:00 at that time. It didn't switch to +05:30 until April.

So to recap the Whammys:

  • The Windows TimeZoneInfo.ConvertTime function appears to be flawed.
  • The Windows Time Zone data for the "Sri Lanka Standard Time" zone is incorrect.

All the better to just use Noda Time and TZDB always!

UPDATE

Thanks to Jon Skeet for helping identify that the first problem is with the way that the "W. Australia Standard Time" zone is being interpreted by the TimeZoneInfo class.

I dug much deeper into the .NET Framework reference source code, and I believe this is happening in the private static method TimeZoneInfo.GetIsDaylightSavingsFromUtc. I believe that they are not taking into account that DST doesn't always start and stop in the same calendar year.

In this case, they are applying the 2006 adjustment rule with the 2005 year, and getting an endTime of 1/2/2005 before the startTime of 12/4/2005. They do attempt to reconcile that this should be in 2006 (by incorrectly adding a year), but they don't consider that data is in reversed order.

This problem will probably show up for any time zones that start their DST in the winter (such as Australia), and it will show up in one form or another any time the transition rule changes - which it did in 2006.

I've raised an issue on Microsoft Connect here.

The "second whammy" I mentioned is just because the historical data for Sri Lanka doesn't exist in the Windows time zone registry keys.

like image 83
Matt Johnson-Pint Avatar answered Oct 02 '22 18:10

Matt Johnson-Pint