【问题标题】:Is there a flaw in Windows 7 Timezone rules [duplicate]Windows 7时区规则是否存在缺陷[重复]
【发布时间】:2019-01-15 18:34:20
【问题描述】:

英国夏令时每年都会在 3 月和 10 月调整时钟。在 1968 年至 1971 年期间,英国尝试将 BST 作为永久选项,因此时钟在 1968 年 3 月调高 1 小时,直到 1971 年 10 月才恢复。

我正在用 Javascript 创建日期,将它们序列化为 JSON 并发布到 WebApi。

目前使用 Windows 7 作为开发环境,Windows 不认为那个时期是 BST。例如 01/01/1970 应该是夏令时,但是

new System.DateTime(1970, 01, 01, 00, 00, 00).IsDaylightSavingTime();

返回 false。

还有……

System.TimeZone.CurrentTimeZone.GetDaylightChanges(1970)
{System.Globalization.DaylightTime}
    Delta: {01:00:00}
    End: {25/10/1970 02:00:00}
    Start: {29/03/1970 01:00:00}

1970 年应该有一个涵盖全年的规则,因为全年都是 BST。

是否有补丁可以纠正 Windows 中的缺陷?

【问题讨论】:

  • 没有。没有 BST - 它只是一个非正式的首字母缩略词。您的代码虽然没有显示任何使用 specific 时区的尝试。它隐含地使用 current ,我敢打赌没有这样的规则。
  • 时区的实际标准是 IANA 时区数据库。对于伦敦,时区是Europe/London。如果时区很重要,您应该使用像 NodaTime 这样的库,其中包括 IANA 数据库
  • 就是这样;时区无关紧要,客户端和服务器位于同一时区,因此序列化和反序列化时间应该遵循相同的规则,但它们不是。对于 1968 - 1971 年期间内的日期,日期被序列化和反序列化(在同一台机器上)可能会损失一个小时。
  • 你为什么认为你的当前时区有这样的规则?还是时区规则可以追溯到那么远?这与序列化或反序列化无关,除非您忘记包含偏移量或 IANA 时区名称
  • 如果你关心偏移量不要假设。不要使用 DateTime,使用 DateTimeOffset。序列化时使用 ISO8601 格式 with 偏移量。如果您关心时间 zones,请使用 IANA 时区名称和支持它们的库。规则可以追溯到 1800 年代

标签: c# windows timezone timezone-offset


【解决方案1】:

更新

毕竟有一个错误,或者更确切地说GMT Standard Time 不包含英国特定的规则。 1968 年至 1970 年间,英国的偏移量变为 +1:00,并且没有 DST。

真正的 问题是,offset 在那个时期对英国来说是错误的:

var date= new DateTime(1970,1,1,0,0,0,DateTimeKind.Local);
var tzi = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
var offset=tzi.GetUtcOffset(date);

offset00:00:00。哎呀!

对于 1970-08-01,偏移量为 01:00:00IsDaylightSavingTime() 返回 True。

PS: SQL Server 的AT TIME ZONE 使用Windows 时区名称。这可能是历史数据问题的更大根源。

原创

没有错误。当全年有一个单一偏移时,谈论夏令时是没有意义的。

IANA 时区数据库显示 1970-01-01没有使用 DST。偏移量为 +1:00。使用 NodaTime :

var london = DateTimeZoneProviders.Tzdb["Europe/London"];

// Time zone conversions
var localDate = new LocalDateTime(1970, 1, 1, 0, 0, 00);
var before = london.AtStrictly(localDate);

Console.WriteLine($"{before} {before.IsDaylightSavingTime()} {before.Offset}");

这会返回:

1970-01-01T00:00:00 Europe/London (+01) DST:False +01

对于 1971-11-01,结果是:

1971-11-01T00:00:00 Europe/London (+00) DST:False +00

此时,偏移量从 +1:00 变为 +00:00,并且重新引入了 DST 规则。

夏季日期的结果更有趣。

1971-07-30 返回:

1971-07-30T00:00:00 Europe/London (+01) DST:False +01

这是正确的 - 在该日期没有有效的 DST 规则。偏移量固定为 +1。

1972-07-30 返回:

1972-07-30T00:00:00 Europe/London (+01) DST:True +01

偏移量相同,因为 DST 规则在该日期生效。

【讨论】:

  • 这不是错误,只是 Windows 没有这么久的历史数据。请参阅重复链接。此外,一般来说,Windows 时区数据仅保证从 2010 年开始可靠(在 MS DST/TZ 政策页面here 中提到)。有些区域可能有更早的数据,但不能保证它们都会。
  • @MattJohnson 更有理由在 SQL Server 中使用 Windows 时区,旅行社开发人员说。无论如何,没有 GDS 报告 Windows tz 名称。 AT TIME ZONE 如何在 Linux 上的 SQL Server 上工作?
  • @MattJohnson 或者更确切地说,为了避免支付机票退款,GDS 和旅行社将避免像瘟疫一样的 Windows 时区。如果它导致责任,它必须被视为一个错误
【解决方案2】:

Windows 没有针对英国的单独时区。 Windows 在英国使用的时区(“GMT 标准时间”)与爱尔兰和葡萄牙共享。

这就是为什么只适用于英国的历史偏差没有得到反映。

即使在过去 200 年中,国家的边界​​也发生了很大变化,直到最近(仅在几十年前),欧洲的非常小的地区都有自己的时区定义,并且经常变化。 Windows 无法反映这些复杂的信息。如果您需要这些信息,则需要使用专用数据库。

【讨论】:

    【解决方案3】:

    正如 cmets 中所述,您提供的代码使用的是您正在运行该代码的计算机上的当前时区。这可能是英国,但假设不是一个好主意。下面的代码考虑了上面的 cmets:

    var tzi = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
    var dt = new DateTime(1970, 1, 2, 0, 0, 0, DateTimeKind.Utc);
    
    var isDlt = tzi.IsDaylightSavingTime(dt);
    

    尽管如此,这也返回 false,因此您所说的错误确实存在。我非常怀疑是否有补丁,但如果您愿意,您可以很容易地编写一个扩展方法,使用 IANA 数据库来确定给定日期是否在夏令时。

    您可能还想查看 TimeZoneInfo.GetAdjustmentRules 的文档 - https://msdn.microsoft.com/en-us/library/system.timezoneinfo.getadjustmentrules(v=vs.110).aspx

    【讨论】:

    • 我没有指定时区的原因是因为无论如何它将是英国的;所以不需要。这绝对是一个缺陷,我只是看不出我以前从未遇到过它,或者 MS 没有修复它。
    • 另外,这是在 Microsoft 的 GetDayLightChanges() 文档中:“由于 TimeZone 类仅支持一个夏令时调整规则,因此 GetDaylightChanges 方法将当前调整规则应用于任何一年,无论是否调整规则实际上适用于那一年。”
    • @ChrisWyatt 如果全年使用相同的偏移量,则没有 DST。那个时期的偏移量是+1:00而不是00:00。没有错误
    • 这就是语义问题。 IANA 碰巧认为它是带有偏移的标准时间,但至少在政治上它被称为夏令时。
    • @ChrisWyatt 当它让你失去你的航班时,它不是语义。只需对任何在线旅行社说Russia - 过去 5 年中的 3 次规则更改。它变得更糟。 Windows 上的 SQL Server 至少为 AT TIME ZONE 表达式使用 Windows 时区名称。这对上述旅行社来说有点没用
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-09
    • 2012-03-06
    • 2014-11-12
    • 1970-01-01
    • 2019-04-09
    • 1970-01-01
    相关资源
    最近更新 更多