System.DateTimeOffset 个实例报告了 1883 年 11 月 19 日之前日期的令人惊讶的 UTC 偏移

Surprising UTC offset reported by System.DateTimeOffset instances for dates before 19 Nov 1883

注意:为方便起见,使用 PowerShell 来演示行为,但问题是关于 System.DateTimeOffset .NET 类型的行为。

注意:正如 Matt Johnson 指出的那样,有问题的行为 只发生在 类 Unix 平台 (macOS, Linux,使用 .NET Core)。

看起来,当 System.DateTimeOffset 转换本地日期时,生成的 时区偏移量(与 UTC 的偏移量)与 1883 年 11 月 19 日之前的日期不同

考虑以下 PowerShell 命令:

([datetime] '1883-11-18'), ([datetime] '1883-11-19') |
  ForEach-Object { ([datetimeoffset] $_).Offset.ToString() }

Eastern Time Zone 中调用时会产生:

-04:57:00
-05:00:00

(DST(夏令时)直到 1918 年才开始使用。)

我怀疑这与以下内容有关,摘录from Wikipedia,重点补充:

[...] had brought the US railway companies to an agreement which led to standard railway time being introduced at noon on 18 November 1883 across the nation.

Searching for 1883 in the entire .NET documentation yields just the following, passing reference:

[...] the U.S. Eastern Standard Time zone from 1883 to 1917, before the introduction of daylight saving time in the United States

在类Unix平台(Linux、OSX等)上运行时,操作系统中的时区数据来源于IANA time zone database。此数据集中的早期日期由其本地平均时间 (LMT) 引用,该时间是根据参考城市的纬度和经度计算得出的。在这种情况下,America/New_York 代表的美国东部时间有一个 LMT 条目与您报告的结果一致。

来自tzdb

# Zone  NAME              GMTOFF    RULES  FORMAT  [UNTIL]
Zone    America/New_York  -4:56:02  -      LMT     1883 Nov 18 12:03:58
                          -5:00     US     E%sT    1920
                          -5:00     NYC    E%sT    1942
                          -5:00     US     E%sT    1946
                          -5:00     NYC    E%sT    1967
                          -5:00     US     E%sT

请注意,由于 DateTimeOffset 支持的偏移精度,偏移中的秒数在导入时被截断。

您可以在 tz 数据库的 the theory file 中阅读有关 LMT(以及更多)的更多信息。

在 Windows,您不会看到此行为,因为 Windows 没有早于 2006-2007 转换的 Eastern Standard Time 时区的时区数据。因此早于 1987 年的日期可能会被错误地转换。如果这对您很重要,您将需要另一个时区信息来源,例如 Noda Time.

中包含的 tzdb 副本

另请注意,本地时间隐含在从 DateTimeDateTimeOffset 的转换中,但仅当输入值的 .KindDateTimeKind.LocalDateTimeKind.Unspecified 时.相反,如果它是 DateTimeKind.Utc,则结果 DateTimeOffset 将具有零偏移量。