C#DateTime无法识别时区更改(BST)

时间:2016-04-08 09:49:58

标签: c# datetime dst

几周前,2016年3月27日,英国的钟表前进了一个小时。凌晨1点,时钟跳了起来。前进到02:00

http://www.timeanddate.com/time/dst/events.html

这意味着" 2016年3月27日,01:30",是无效的日期时间,即它不代表实际发生的时间'。

当Java日期时间解析器无法理解我们传递给它的时间时,这最近引起了我们的注意。但是,C#DateTime似乎根本没有任何问题。

DateTime dt = DateTime.Parse("2016-03-27 01:30:00"); 
bool invalid = TimeZoneInfo.Local.IsInvalidTime(dt);

虽然invalid已正确设置为true,但DateTime似乎没有任何问题存储它。

此外,以下声明:

diff = new DateTime(2016, 3, 27, 2, 30, 0) - new DateTime(2016, 3, 27, 0, 30, 0);

导致TimeSpan代表2小时,这是不正确的。

为什么DateTime类型不考虑DST?

5 个答案:

答案 0 :(得分:2)

所以,这里唯一的问题是:

  

为什么DateTime类型不考虑DST?

简答

因为这就是DateTime结构的设计方式。

来自the MSDN docs

  

时区之间的转换操作(例如UTC与本地时间之间或一个时区之间的转换操作)会考虑夏令时,但算术和比较操作则不会。

更长的答案

.NET的DateTime仅跟踪两个逻辑值,TicksKind。在内部,出于性能和兼容性原因,它们合并为一个64位整数,但您可以将它们视为两个单独的值。

  • Ticks跟踪自0001-01-01 00:00:00的纪元值以来100纳秒间隔的数量。

  • Kind跟踪Ticks是用于表示UTC时间,计算机本地时区或其他某些未指定时区的元数据。

    < / LI>

DateTime一起使用的每个函数都应该考虑Kind。框架中的许多人都这样做。有些人没有。许多其他图书馆,甚至一些与时间有关的图书馆,都完全忽视它。

当您致电DateTime.Parse("2016-03-27 01:30:00")时,Kind设置为Unspecified,因为没有上下文。您提供的值不一定在任何特定时区,因此0001-01-01 00:00:00纪元日期也不一定。换句话说,您可以将其视为未固定到UTC或任何DST规则的任何偏移的日期和时间。

请注意,这与Java和JavaScript有很大不同,其中Date对象跟踪自1970-01-01 00:00:00 UTC时代以来的毫秒数。它总是 UTC,其中.NET可能是也可能不是。

有多种方法可以解决这个问题。到目前为止最好的是使用更合理的API,它由Noda Time开源库提供。但是,如果您只想使用.NET内置的功能,请考虑使用DateTimeOffset结构。与DateTime不同,它跟踪其与UTC的偏移量,并在进行数学运算时将其考虑在内。

您仍然需要检查TimeZoneInfo.IsInvalidTime输入是否无效。 .NET内置的API不会在解析时为无效时间抛出异常。但是,如果您为源时区传入无效时间,则会发现TimeZoneInfo上的转换函数(例如ConvertTimeToUtc)确实会引发异常。

您还应该检查TimeZoneInfo.IsAmbiguousTime,因为在两次发生的回退转换期间给出了一个值,例如英国的2016-10-30 01:30,.NET将始终选择标准时间偏移。虽然这可能起初看起来是正确的,但请考虑 daylight 实例首先实际发生 - 这通常是大多数现实场景中的理想行为(无论如何都来自我的体验)。

除此之外,关于您的Java代码,如果您尚未考虑,则应考虑将Joda Time用于Java 7及更低版本,或者将java.time用于Java 8中。您将找到它们与前面提到的Noda Time非常相似。

最后,我将添加我非常自以为是的断言,DateTime结构的设计以多种方式违反SRP。特别是,DateTimeKind是令人厌恶的 - 恕我直言。

答案 1 :(得分:1)

我知道这很旧,但是我碰到了它,并认为其他人可能会对此线程的添加有所帮助。尽管Matt Johnson-Pint给出的答案是全面的,并且确实非常有用,但是有一种简单的方法可以实现对DateTime的必要“调整”,以显示当前的本地时间-我认为这是对实际问题的回答:

fn.bind

在英国BST中,这给出了正确的结果。

有用的链接here

答案 2 :(得分:0)

DateTime具有Kind属性,指示它是本地时间还是UTC或未指定。您的解析格式不允许它设置此类,因此它将是未指定的。我认为您需要将其设置为允许它正确处理DST。

通常,您以UTC格式处理DateTimes,然后在需要向用户显示以解决此问题时转换为本地DateTime。

答案 3 :(得分:0)

我猜微软决定为您提供使用IsInvalidTime方法自行管理无效日期的灵活性。

如果您的申请要求日期有效,那么您应该检查时间是否有效。

答案 4 :(得分:0)

Azure Web Apps具有很好的默认设置,可用于在Azure界面或Visual Studio中更改此设置。 这里有一个很棒的博客,向您展示了如何做: https://www.jasongaylord.com/blog/tip-changing-an-azure-app-service-time-zone