Wow, this is Double Whammy! I just stumbled upon this post and was not going to post anything at all, as it is so old and the OP did not show any code. But then curiosity got the best of me, so I tested it.
Using only .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
Of course, there is a discrepancy described by the OP. At first I thought that this should be due to some kind of DST problem, so I checked Sri Lanka and Perth . Although both options had a transition in 2006, none of them were close to that date. However, I thought I should check with DateTimeOffset
to avoid any ambiguity problems:
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 he believes that the target time should be at +09:00
, but Perth did not switch to it until December 3, 2006. In January, it was clearly still +08:00
.
So, I thought ... Noda Time to the rescue!
First let me 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, this seems to be fixed, right? If this is the case, it will mean that the problem is not with the Windows time zone data, as the Noda Time BCL provider uses accurate data. So there should be something really defective in TimeZoneInfo.ConvertTime
. There is Whammy # 1 .
So, just to make sure that everything is fine and good, try to do the same with IANA TZDB data. In the end, it became more accurate:
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, Whammy # 2 . Note that the average time uses an offset of +06:00
? I thought this was a mistake, but when I checked again here , it turned out that the TZDB data was correct. At that time, Sri Lanka was at +06:00
. He did not switch to +05:30
until April.
So, to indicate Whammys:
- The Windows
TimeZoneInfo.ConvertTime
function appears to be erroneous. - Incorrect data in the Windows time zone for the
"Sri Lanka Standard Time"
zone.
Best to just use Noda Time and TZDB!
UPDATE
Thanks to Jon Skeet for helping to determine that the first problem is that the "W. Australia Standard Time"
zone is interpreted by the TimeZoneInfo
class.
I delved into the source code for the .NET Framework link, and I believe this happens in the TimeZoneInfo.GetIsDaylightSavingsFromUtc
private static method. I believe that they do not take into account that the DST does not always start and stop in the same calendar year.
In this case, they apply the 2006 adjustment rule from 2005 and receive endTime
from 1/2/2005
to startTime
from 12/4/2005
. They are trying to reconcile that this should be in 2006 (by incorrectly adding a year), but they do not believe that the data is in the reverse order.
This problem is likely to be displayed for any time zones that start their DST in the winter (for example, in Australia), and it will be displayed in one form or another at any time when the transition rule changes - which was done in 2006.
I added the problem to Microsoft Connect here .
The “second drunk” that I mentioned is just because historical data for Sri Lanka does not exist in the Windows time zone registry keys.