Consider the following tests:
[Test]
public void CanHandleBaseOffsetChange_Tzdb()
{
var tz = DateTimeZoneProviders.Tzdb["Europe/Moscow"];
var dt = Instant.FromUtc(2013, 6, 1, 0, 0, 0).InZone(tz).LocalDateTime;
var expected = new LocalDateTime(2013, 6, 1, 4, 0, 0);
Assert.AreEqual(expected, dt);
}
[Test]
public void CanHandleBaseOffsetChange_Bcl()
{
var tz = DateTimeZoneProviders.Bcl["Russian Standard Time"];
var dt = Instant.FromUtc(2013, 6, 1, 0, 0, 0).InZone(tz).LocalDateTime;
var expected = new LocalDateTime(2013, 6, 1, 4, 0, 0);
Assert.AreEqual(expected, dt);
}
[Test]
public void CanHandleBaseOffsetChange_Tzi()
{
var tz = TimeZoneInfo.FindSystemTimeZoneById("Russian Standard Time");
var dt = TimeZoneInfo.ConvertTimeFromUtc(new DateTime(2013, 6, 1), tz);
var expected = new DateTime(2013, 6, 1, 4, 0, 0);
Assert.AreEqual(expected, dt);
}
Only the TZDB test pases. The TZI test fails due to the fact that
TimeZoneInfo.AdjustmentRule doesn't track year-to-year changes to the base
offset. This is reported in https://support.microsoft.com/kb/3012229 and fixed
in .Net 4.6 preview (coreclr).
NodaTime's BclDateTimeZone implementation has the same issue, because it loads
its data from TimeZoneInfo. In order to work around the issue, we would need
to load BCL data either using Win32 APIs, or by reading directly from the
registry.
The base offset changes ARE in the registry, so there's no reason that we would
need to rely on the TZI fix. Even if we did, we'd have to use reflection to
get at the new internal field that was added to TimeZoneInfo.AdjustmentRule.
Original issue reported on code.google.com by
mj1856on 8 Feb 2015 at 6:46