迹忆客 专注技术分享

当前位置:主页 > 学无止境 > WEB前端 > JavaScript >

Javascript 的Date的许多异常点

作者:迹忆客 最近更新:2022/09/08 浏览次数:

Javascript Date 很奇怪。 众所周知,Brendan Eich 在 10 天内编写了 Javascript 的第一个版本 - Date 函数本身也不例外。 它是基于最终在 Java 中被弃用的代码。

这意味着 Javascript 继承了一个 Date 函数,该函数在 Java 中被发现是错误的和有问题的,因此它充满了问题。 我们甚至可能自己也遇到过一些问题。 那么,大家可能想知道,“这有什么奇怪的?”。 让我们看看 Javascript 的 Date 构造函数的所有异常和常见缺陷,从而避免它们。

Javascript 实际上不支持日期

这听起来和直觉不符,因为主要的 Javascript 日期构造函数为 Date,但 Javascript 实际上并不支持日期。 Javascript 仅支持日期时间。 所有 Javascript 日期都是下面的 Unix 时间戳。 这意味着如果我们尝试创建一个日期,我们实际上是在创建一个日期时间。 所有未指定时间的 Javascript 日期默认为该给定日期的午夜。

let date = new Date(2011, 1, 22);
// 请注意,生成的日期附有时间:
// Tue Feb 22 2011 00:00:00 GMT+0000 (Greenwich Mean Time)

解析日期

如果我们知道月份从 0 开始,那么像我们上面所做的那样解析日期可以正常工作,但是解析日期字符串在不同浏览器之间会有很大差异。 强烈建议不要解析日期字符串。 在 ECMAScript 5 规范之前,从未定义过 Date 解析字符串日期的方式,并且不同的浏览器有许多历史问题,使其非常不可靠。

根据当前规范,只有符合 ISO-8601 标准的字符串才能被 Javascript 解析,任何其他日期都应该返回 NaN,即:

let parseMyDate = Date.parse('2022-03-21T11:00:01+00:00');

然而,事实并非如此。 许多浏览器允许在此格式之外进行日期解析。 这就是它有可能令人困惑的地方。 假设我们要解析标准 dd/mm/yyyy 格式的日期格式。 我们采用标准日期,并将其传递给 parse() 函数:

let myDate = new Date("5/1/2022");
console.log(myDate);

在所有现代浏览器中,它使用美国日期格式,即 mm/dd/yyyy - 这意味着它返回 5 月 1 日,而不是 1 月 5 日,从而导致意外结果。

解析日期默认为 UTC

假设我们有一个没有时间或时区与之关联的日期:

let myDate = Date.parse('01 Jan 1999');
console.log(myDate);

我们可能会认为这并没有什么令人困惑的地方——它代表了一个固定的时间日期。 然而:

  • 如果我们的时区是 UTC,这将返回 915148800000。
  • 如果我们的时区是 UTC+3:00,这将返回 915138000000,即多 3 小时。
  • 如果我们的时区是 UTC-5:00,这将返回 915166800000,即减少 5 小时。

因此,如果我们的时区在 UTC 以西,例如 -5:00,则 Javascript 会从 Unix 时间戳中减去 5 小时。 由于日子从午夜开始。

这意味着如果我们尝试将此时间戳与不同的时区一起使用,例如,在后端系统中,我们不会得到 1999 年 1 月 1 日,而是 1998 年 12 月 31 日! 所有这一切都是因为 Javascript 没有实现日期——每个日期都有一个与之关联的时间——在这种情况下是午夜。

Javascript 日期中的月份从 0 开始

如果我们想在 Javascript 中创建一个日期,我们可以解析代表年、月和日的数字。 例如,如果我们想为 2011 年 2 月 22 日创建一个日期,我们会这样写

let date = new Date(2011, 2, 22);

只是,这给了我们 2011 年 3 月 22 日星期二 00:00:00 GMT+0000(格林威治标准时间)。 这是因为 Javascript 中的月份从 0 开始计数,所以二月是 1,而不是 2:

let date = new Date(2011, 1, 22);

不正确的日期跳到下个月

假设我们不小心创建了一个错误的日期,例如 2022 年 2 月 31 日。我们错误地将其从数据库或 API 传递到日期函数中:

let date = new Date(2022, 1, 31);

我们可能认为这只会返回 Invalid Date 或 NaN,但我们错了。 Javascript 跳到 3 月 3 日! 由于 2011 年 2 月只有 28 天,而且还有 3 天,所以这些天被添加到月底。 换句话说,我们不能相信 Date 在所有不正确的日期上都返回错误。

字符串不解析为数字

最奇怪的行为是当我们不给 Javascript 解析整个字符串时。 例如:

let myDate = new Date("0");
console.log(myDate);

我们可能认为这将返回 0 年,或者可能是 unix 纪元,但它实际上返回 2000 年 - Sat Jan 01 2000 00:00:00 GMT+0000(格林威治标准时间)。

然而,更奇怪的是,如果我们试图增加它,它会在几个月内开始计算:

console.log(new Date("5")); // Tue May 01 2001 00:00:00 GMT+0100 (British Summer Time)
console.log(new Date("11")); // Thu Nov 01 2001 00:00:00 GMT+0000 (Greenwich Mean Time)
console.log(new Date("4")); // Sun Apr 01 2001 00:00:00 GMT+0100 (British Summer Time)

最重要的是,如果我们尝试执行 new Date("13") ,我们将得到 Invalid Date 作为结果,因为没有第 13 个月。

使用时间戳可能会混淆日期

如果我们只将一个数字传递给 new Date(),它会将其视为 Unix 时间戳 - 但是,它不会针对时区进行调整。 例如,在 UTC 中,以下代码返回 Thu Jan 01 1970 00:00:00 GMT+0000(格林威治标准时间)

console.log(new Date(0));

这是有道理的,因为它是 Unix 时代,如果特定时间对我们很重要,那可能没问题。 但是,如果我们在 UTC-5:00 中,该代码将返回不同的日期,即 1969 年 12 月 31 日星期三 19:00:00 GMT-0500(东部标准时间) - 即 5 小时前。 这意味着如果我们使用时间戳代替日期,因为 Javascript 不直接支持日期,当使用 Date().toLocaleString() 之类的方法时,我们会立即遇到问题。 最终,我们可以使用 .toUTCString() 方法解决这个问题——但这种复杂性并不完全明显。

年份不一致

你可能认为我们很轻松,只有时间戳和时区被破坏 - 但即使是年份也是不一致的。 如果我们想为 0 年的 1 月 1 日创建一个日期,你可能会认为我们会这样写:

console.log(new Date(0, 0, 0));

由于月份从 0 开始,这看起来是正确的——但实际上,如果年份小于 100,则 0 表示 1900 年。好吧,你可能会想,我想这应该返回 1900 年 1 月 1 日——但这实际上也是错误的——因为 天数从 1 开始索引,而不是 0。上面的代码返回 Sun Dec 31 1899 00:00:00 GMT+0000(格林威治标准时间) - 因为该月的第 0 天算作上个月的最后一天。 以下是一些其他示例:

console.log(new Date(0, 0, 0)); // Sun Dec 31 1899 00:00:00 GMT+0000 (Greenwich Mean Time)
console.log(new Date(50, 0, 0)); // Sat Dec 31 1949 00:00:00 GMT+0000 (Greenwich Mean Time)
console.log(new Date(30, 0, 0)); // Tue Dec 31 1929 00:00:00 GMT+0000 (Greenwich Mean Time)
console.log(new Date(24, 0, 0)); // Mon Dec 31 1923 00:00:00 GMT+0000 (Greenwich Mean Time)

一旦超过 100 年,它就会回到正常计算年份。 所以下面的代码实际上给了我们 101 年,而不是 2001 年:

console.log(new Date(101, 0, 0)); // Fri Dec 31 0100 00:00:00 GMT-0001 (Greenwich Mean Time)

如果我们使用的是 1900 年之后的几年,这可能会很有用,但对于之前的任何事情来说,这都是令人难以置信的违反直觉的。

为什么没有人修复 Javascript 日期?

Javascript Date 函数从根本上在许多方面都被破坏了——这就是为什么大多数人使用像 Moment.js 这样的工具,但为什么它没有得到修复?

它们没有得到修复的主要原因是因为大多数 Web 都是基于考虑到 Date 缺陷的代码构建的。 因此,现在更改将导致许多网站容易崩溃。

为了解决这种情况,Javascript 引入了一套全新的标准,称为 Temporal,它将占用与 Date 不同的命名空间,并将解决本文中描述的大部分问题。 在那之前,我们一直被 Javascript Dates 产生的异常所困扰。

转载请发邮件至 1244347461@qq.com 进行申请,经作者同意之后,转载请以链接形式注明出处

本文地址:

相关文章

在 Angular 中上传文件

发布时间:2023/04/14 浏览次数:71 分类:Angular

本教程演示了如何在 Angular 中上传任何文件。我们还将介绍如何在文件上传时显示进度条,并在上传完成时显示文件上传完成消息。

Angular 2 中的复选框双向数据绑定

发布时间:2023/04/14 浏览次数:139 分类:Angular

本教程演示了如何一键标记两个复选框。这篇有 Angular 的文章将着眼于执行复选框双向数据绑定的不同方法。

在 AngularJs 中加载 spinner

发布时间:2023/04/14 浏览次数:107 分类:Angular

我们将介绍如何在请求加载时添加加载 spinner,并在 AngularJs 中加载数据时停止加载器。

在 Angular 中显示和隐藏

发布时间:2023/04/14 浏览次数:78 分类:Angular

本教程演示了 Angular 中的显示和隐藏。在开发商业应用程序时,我们需要根据用户角色或条件隐藏一些数据。我们必须根据该应用程序中的条件显示相同的数据。

在 Angular 中下载文件

发布时间:2023/04/14 浏览次数:104 分类:Angular

本教程演示了如何在 angular 中下载文件。我们将介绍如何通过单击按钮在 Angular 中下载文件并显示一个示例。

扫一扫阅读全部技术教程

社交账号
  • https://www.github.com/onmpw
  • qq:1244347461

最新推荐

教程更新

热门标签

扫码一下
查看教程更方便