【问题标题】:DateTime difference operator considers daylight saving?DateTime 差异运算符考虑夏令时?
【发布时间】:2010-10-23 01:47:48
【问题描述】:

据我所知,DateTime 类型的差分运算符考虑闰年:所以

new DateTime(2008, 3, 1) - new DateTime(2008, 2, 1) // should return 29 days
new DateTime(2009, 3, 1) - new DateTime(2009, 2, 1) // should return 28 days

但是夏令时呢?

【问题讨论】:

    标签: .net datetime operator-overloading dst


    【解决方案1】:

    .NET 无法正确处理夏令时,即使它提供了您想要的答案。你想要错误的答案。

    短版:

    • .NET 怎么知道由于能源危机,1977 年夏时制是全年有效的?

    • 当以色列议会逐年制定规则时,.NET 如何知道以色列的夏令时规则?

    • .NET 如何知道美国在二战期间全年都使用 DST,而从 1945 年到 1966 年,DST 规则因地区而异,而且规则仍然因地区而异。

    .NET 尝试逃避,并使用当前的夏令时规则,即使它们没有或将要生效。结果是,您得到的答案虽然是您认为自己想要的,但却是不正确的。

    来自Raymond Chen的博客,Why Daylight Savings Time is nonintuitive

    为什么 (win32) 时区转换函数不使用适合一年中时间的时区?

    ...

    Win32 不会尝试猜测哪个 时区规则当时生效 其他时间。所以 Win32 说,“星期四, 太平洋标准时间 2002 年 10 月 17 日上午 8:45:38"。

    注意:太平洋标准时间。甚至 虽然 10 月 17 日是在太平洋 Daylight时间,Win32显示时间 作为标准时间,因为那是什么 时间是现在

    .NET 说,“好吧,如果 现在的效果也对 2003 年 10 月 17 日,那将是 白天时间”,所以它显示 “2003 年 10 月 17 日,星期四,上午 9 点 45 分 PDT" - 白天时间。

    所以你得到的答案是错误的。但既然你期望得到错误的答案,那就是你得到的。

    【讨论】:

      【解决方案2】:

      我认为不会。 The documentation 只是说 DateTime 存储为自 0001 年 1 月 1 日午夜 12:00:00 以来的滴答数,但它没有说明午夜实际上是在哪个时区 - 我不得不假设如果它总是在内部存储在 UTC 中,他们会这么说。

      您可以轻松解决这个问题:只需这样做:

      var difference = Dt1.ToUniversalTime() - Dt2. ToUniversalTime()
      

      转换为 UTC 将考虑夏令时

      【讨论】:

      • 不,这不是一个有效的解决方法。看我的帖子。要正确存储适合转换为 UTC 时间的本地时间,您必须指定所有应用的 UTC 偏移量(包括时区以及 DST 是否生效)。由于 DateTime 从不输入 DST 在给定本地时间是否处于活动状态,因此每个本地时间值本质上都是不完整/有缺陷的,因此不适合转换。 Windows 甚至搞砸了从 UTC 到 Local 的转换,因为它似乎根据它是否在方法调用时间而不是在给定时间有效来应用 DST 偏移量,这是 asinine。
      • 您说“转换为 UTC 将考虑夏令时”,但这是不可能的,因为 DateTime 构造函数从不询问您 DST 是否生效,因此它不可能知道它是否在11 月 2 日凌晨 1 点和 2 点(无论如何在美国)。转换 DateTime 允许您存储的不存在的本地时间也会有问题,当我们提前设置时钟时我们会跳过。
      • 其实挺有趣的。 ToUniversalTime 将在全年的 2 天工作,除了 2 小时。同时,相应的 ToLocalTime(和底层 API)会导致 Windows 显示错误的文件修改时间 5 到 7 个月!!!年,取决于文件是否在其 DST“模式”(活动或非活动)与当前日期匹配的日期范围内被修改。真是个错误。
      • 要对此进行测试,请将文件放在桌面上并且一年内不要修改它。写下修改日期。在一年中的 5 到 7 个月内,您记下的日期将与 Windows 资源管理器显示的日期不匹配。大声笑。
      【解决方案3】:

      夏令时比一般的 12 个时区和使用它们的国家更具体。

      不同的国家或国家组使用不同的 DST 日期。

      真的有点痛苦,更不用说不这样做的国家或国家的部分地区了。

      例如,澳大利亚昆士兰州没有夏令时,而该国其他地区则有。

      如果它不这样做我不会感到惊讶,如果它这样做的话,至少没有文化信息 9 就无法做到。

      【讨论】:

        【解决方案4】:

        它不会而且实际上不能,因为它既不会强制您使用 UTC 来构造 DateTime,也不会允许您指定 DST 是否有效当您使用本地时间值构造 DateTime 时。此外,它允许“未指定”模式(LT 或 UTC),这就是 asinine。

        通过允许从本地时间值构造 DateTime 值,可以构造一个不明确的 DateTime 值(指定为本地时间)(例如,美国 11 月 2 日凌晨 1 点到 2 点之间的任何时间,当本地时间小时重复)并且不能确定性地转换回 UTC,除非构造函数提供了一个参数来指定 DST 在给定的本地时间是否有效

        由于没有提供这样的参数,DateTime 类的设计是不完整且有缺陷的,未能考虑正确指定本地时间所需的所有参数。

        我认为这就是他们创建 DateTimeOffset 类的原因,它......如果你对为什么存在这样一个看似多余的类感到困惑......这就是原因。

        因此,您绝不应该对未设置为 DateTimeMode.Utc 的任何 DateTime 实例进行任何类型的计算。仅使用 UTC。您实际上无法转换为 LT 或从 LT 转换,因为它被两个不同的错误破坏了,两种方式。 1. 从 LT 到 UTC 失败了,因为如前所述,它不允许您指定 DST 是否在 LT 的那个模棱两可的小时内有效。哦,它还允许您指定一个基本上不可能的本地时间,例如我们在时钟提前设置时跳过的时间。 2. 将过去的 UTC 值转换为本地时间时,Windows 会根据 DST 是否现在生效,而不是给定时间,这会严重愚蠢。当然,当您以文件名记录、存储或使用的修改时间,有一天在 Windows 资源管理器中显示为 HOUR OFF 时,您可能已经注意到了这个问题。不,你没疯,Windows 只是有一个严重的错误,他们从来没有时间在 DOS 和最新的 .NET 框架(约 2 年)之间修复它!当然,这个错误会影响 CVS 系统和任何跟踪修改时间的东西。 FAT 文件系统将时间存储为本地时间,这意味着它完全被搞砸了。

        【讨论】:

          【解决方案5】:

          测试一下看看!

          编写测试就像编写 DST 案例和闰年案例一样容易。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2011-08-14
            • 2013-09-22
            • 1970-01-01
            • 2011-07-25
            • 2012-05-01
            • 2018-01-01
            • 2012-07-03
            相关资源
            最近更新 更多