某些时区中 DST 开头的日期值错误

警告

已停用、不受支持的 Internet Explorer 11 桌面应用程序在某些版本的 Windows 10 上已通过 Microsoft Edge 更新永久禁用。 有关详细信息,请参阅 Internet Explorer 11 桌面应用停用常见问题解答

本文介绍从标准时间转换为夏令时(DST)时的错误报告,并提供解决方案。

原始产品版本: Internet Explorer 11、Internet Explorer 10、Internet Explorer 9
原始 KB 数: 2410734

现象

当你使用 JavaScript Date 对象计算某些情况下的日期时,用户可能会看到明显不正确的结果。 如果满足以下条件,则会发生此行为:

  • 日期和时间设置配置的时区在午夜从标准时间转换为 DST。
  • 日期算术使用不带 Date 小时和分钟的对象(或使用 0 的小时和分钟),并且仅使用从标准时间转换到 DST 的日期。

例如,尝试构造 2010 年 10 月 17 日的日期将生成 10/16 的日期:

var dt = new Date(2010, 9,17);
// ...
console.log(dt.toString()); // evaluates to 'Sat Oct 16 23:00:00 UTC-0300 2010'
dt.getDate(); // evaluates to 16

原因

这是在对象初始化为 DST 开始的时间时 Date() 发生的问题的一个特定实例。

用于构造 Date 对象的值表示标准时间结束时间点之后的时间,但早于本地时钟在 DST 开始后显示。 欧洲计算机制造商协会脚本(ECMAScript)语言规范指定计算时间值时减去 1 小时的 DST 调整,即对象的内部表示形式 Date 。 但是,这最终表示 DST 开始之前的一段时间。 对于巴西,这种情况发生在午夜,因此对象 Date 最终表示前一天的时间。

解决方法

此行为符合 ECMAScript 标准,因此是设计使然。

如果只关注日、月和年,则可以通过使用不为零的小时值(即安全大于夏令时调整的小时值)构造日期对象来解决此问题。

详细信息

可以在 ECMAScript 2016 语言规范中找到 ECMAScript® 标准。

第 20.3.2 节定义如何解释 Date 构造函数,包括将时间值转换为协调世界时(UTC)的事实。

第 20.3.1.10 节定义了本地时间和 UTC 时间之间的转换,并指出这些转换不一定相互反转。

此转换的公式如下所示:

UTC( t ) = t - LocalTZA - DaylightSavingTA(t - LocalTZA)

如果针对 DST 的开始执行此操作,可以查看如何减去小时。 此示例适用于太平洋时间,因此实际日期不会更改。 入手:

t = <Sun Mar 13 02:00:00 Pacific 2011>
LocalTZA = -8
The expression t - LocalTZA occurs twice in this equation; it evaluates to <Sun Mar 13 10:00:00 UTC 2011>. This is the exact moment when DST starts in the Pacific time zone. This is the key fact during conversion of this time to UTC:
UTC( <Sun Mar 13 02:00:00 Pacific 2011> )
= <Sun Mar 13 02:00:00 Pacific 2011> - LocalTZA - DaylightSavingTA( <Sun Mar 13 02:00:00 Pacific 2011> - LocalTZA )
= <Sun Mar 13 10:00:00 UTC 2011> -DaylightSavingTA( <Sun Mar 13 10:00:00 UTC 2011> )
= <Sun Mar 13 10:00:00 UTC 2011>- 1
= <Sun Mar 13 9:00:00 UTC 2011>