关于.net:夏令时转换开始时间测试在Windows上的“GTB标准时间”失败

Daylight Saving Time transition start time tests fail for 'GTB Standard Time' on Windows

我写了几个测试,用于将时间从特定时区转换为UTC。

规则规定,在欧洲,时钟在01:00 UTC转发,对于'GTB标准时间',这意味着+ 2 UTC,例如03:00:00

但是,我发现使用TimeZoneInfo.IsDaylightSavingTime(dateTime)方法在不同平台(Linux与Windows)的测试中存在差异。

我为DST过渡日期和时间创建了一个新的测试对象:

1
2
var testDate = new DateTime(2019, 03, 31, 03, 20, 00); //20 minutes after Daylight Saving Time start
...

并将其传递给TimeZoneInfo'timeZone'对象,其中时区设置为'GTB标准时间':

1
2
3
4
...
    var timeZone = TimeZoneInfo.FindSystemTimeZoneById("GTB Standard Time");
    return timeZone.IsDaylightSavingTime(testDate);
}

这返回False,虽然2019-03-31本地03:20:00夏令时应该已经开启。这应该返回True。

我设法仅在Windows上使用.Net时区的内置数据库重复此测试。使用tzdata db(例如NodaTime)为此测试返回True。

令人困惑的是那个
我手动为timeZone对象抛出一个错误,看看来自TimeZoneInfo对象的额外信息,发现DST start实际上是正确的:

1
timeZone.GetAdjustmentRules().First().DaylightTransitionStart.TimeOfDay

返回03:00:00

有人可以确认这一点,还有办法检查Windows在DST时间的位置吗?我可以在不使用任何外部库的情况下在Windows和Linux上进行当前测试通过吗?


该时区的当地时间从当天的02:59:59到04:00:00,因此3:20:00无效。它落入了前进过渡所造成的差距。

根据TimeZoneInfo.IsDaylightSavingTime(DateTime)的文档(强调我的)

If the dateTime parameter specifies an invalid time, the method call throws an ArgumentException if the value of the dateTime parameter's Kind property is DateTimeKind.Local; otherwise, the method returns false.

如果可以,请改为使用DateTimeOffset类型,或者使用DateTimeDateTimeKind.Utc。无论哪种方式,都不可能存在无效或模糊的当地时间。

如果您不能这样做,那么使用TimeZoneInfo对象上的IsInvalidTimeIsAmbiguousTime测试输入值,然后您可以在代码中决定如何处理结果。例如,您可能希望将该实例的3:20移至4:20。

在模糊时间的情况下,请注意TimeZoneInfo(IsDaylightSavingTimeGetUtcOffset等)上的所有方法都将默认采用标准时间,顺序为第二。在这些场景中,人们几乎总是想要白天时间。您可以通过调用GetAmbiguousTimeOffsets获取两个可用的偏移量,然后选择较大的偏移量。

此外,你提到了Noda Time - 一个更好的API,恕我直言。在那里,这样的事情由"解析器"处理。如果你调用LocalDateTime.InZoneLeniently,则使用默认的"宽松"解析器。还有其他解析器,您可以指定自己的解析器。从这里开始查看文档。