为什么 JavaScript 的 Date 构造函数中的月份参数范围从 0 到 11?

IT技术 javascript datetime date
2021-02-07 04:32:19

Date使用下面的调用在 JavaScript 中初始化一个新对象时,我发现月份参数从零开始计数。

new Date(2010, 3, 1);  // that's the 1st April 2010!

为什么月份参数从 0 开始?另一方面,月份参数(最后一个)是从 1 到 31 的数字。这样做有充分的理由吗?

6个回答

这个问题的真正答案是它是从 复制的java.util.Date,它也有这个怪癖。可以在twitter上找到 Brendan Eich 的证明,他是最初实现 JavaScript 的人:

https://twitter.com/BrendanEich/status/481939099138654209

第一条推文说:“如果它有帮助(对大多数人没有帮助),JS 的 Date 是 Java JDK1.0 (1995) java.util.Date 的副本。让它看起来像 Java...”

https://twitter.com/BrendanEich/status/771006397886533632

第二条推文说:“我们接受了“让它看起来像 Java”的管理命令,我有十天的时间来演示。没有时间发明我们自己的日期 API 甚至修复 Java 的。”

Brendan 还指出 Netscape 的 Ken Smith 是从 Java 移植过来的。

https://twitter.com/BrendanEich/status/771006208949891072

第三条推文说:“只有我没有创建的 Mocha src 文件是 mo_date.c:Netscape 的 Ken Smith 帮助我将 java.util.Date 从 Java 翻译成 C。”

这发生在 1995 年,当时 JDK 1.0 处于测试阶段。它于 1996 年推出。 1997 年,JDK 1.1 出现,弃用了 上的绝大多数功能java.util.Date,将它们移至java.util.Calendar,但即便如此,仍然有从零开始的月份。对此感到厌烦的开发人员创建了Joda-Time库,最终将java.time包嵌入到 Java 8 (2014) 中。

简而言之,Java 花了 18 年的时间才获得正确设计的内置日期/时间 API,但 JavaScript 仍然停留在黑暗时代。我们确实有这样优秀的库力信通 Moment.js日期FNSJS-乔达,等等。但截至目前,除了Date内置于该语言之外,别无他物希望这会在不久的将来随着TC39 临时提案而改变

@Yassir - 这项工作正在进行中。 tc39.es/proposal-temporal/docs
2021-03-23 04:32:19
@ÁlvaroGonzález 我会责怪最初引入它的原始 JDK 1.0 开发人员。
2021-03-23 04:32:19
啊...很好的老演示驱动开发方法。
2021-03-26 04:32:19
@barell 为什么你要责怪为 Java 的第一个版本建模的人,自第一个版本以来,没有一种语言能把它全部弄清楚。Java 实际上修正了他们的 Date api,但 Javascript 仍然坚持旧的,javascript 开发者至少应该给我们一个新的 api,就像 Java 引入 LocalDate 一样。
2021-03-28 04:32:19
注意最后一段:即使在更现代的图书馆中,也并非一切都是美好的。Moment().month()和 date-fngetMonth()仍然是基于 0 的。Luxon 和 js-joda 的月函数似乎是基于 1 的。
2021-04-10 04:32:19

这是编程世界中一个古老的(可能是不幸的,可能正在消亡)传统,请参阅旧标准(POSIX)localtime C 函数http://linux.die.net/man/3/localtime

你是对的,传统通常是完全不一致的,而且常常是不合理的,我真的希望这种“坏”的传统真的正在消亡……
2021-03-11 04:32:19
JSDate对象是从 Java 1.0 移植的,这就是原因。继承它的所有缺陷...... stackoverflow.com/questions/344380/ ......
2021-03-14 04:32:19
永远不会改变。有大量令人难以理解的现有代码假定了这种行为。(我的意思是,在 JavaScript 中。)
2021-04-02 04:32:19
这是一个总是让我花时间调试日期问题的传统......想知道这个传统造成了多少浪费的工作时间。
2021-04-04 04:32:19
是 2019 年,我正在解决与此行为相关的问题,因此只要 javascript 之类的框架和语言不弃用这种情况,它仍然会发生 - 请随时在 2025 年及以后发表评论;-)
2021-04-08 04:32:19

除了一个月中的某一天之外的所有内容都是基于 0 的,请参阅此处以获取包括范围的完整列表:)

它实际上是基于 1 天的天数是这里的怪人......够奇怪了。为什么这样做?我不知道......但可能发生在他们被贴上膏药并决定分号是可选的同一次会议上。

他们为什么年不是0基?
2021-03-15 04:32:19
@Vedmant(出于实际目的)在消极和积极的方向上都有无数年。年份根本不是真正“基于”的,因为它不是一组固定的值。
2021-03-17 04:32:19
“以个为基础”的日子可能是因为没有头脑的人会为日子创建一个字符串名称数组(例如,{ "first", "second", "third", ..., "twenty-seventh", ... })并尝试通过tm_mday. 再说一次,也许他们只是看到了经常发生的一个错误的绝对效用
2021-03-26 04:32:19

2021 年真正的问题是:

如果Date从 JS 的第一天起就被打破了,为什么 26 年(如果从零开始数则是 25 年)它仍然在这里?

JS 有很多不好的部分/怪癖,最糟糕的是其中一些已经几十年没有被修复(有趣的事实:我们正在谈论Date 日期)。

但我们很幸运,看起来末日Date已经临近了。

剧透

new Temporal.PlainDate(2020, 11, 26); // => 2020-11-26

时间(提案)

从提案介绍:

Date一直是 ECMAScript 中长期存在的痛点。这是对 的提议TemporalObject作为顶级命名空间(如Math的全局变量,为 ECMAScript 语言带来了现代日期/时间 API。

正如文档中所报告的那样,它基于“我们检查过的常见用例”,并且针对不同类型的数据具有多种类型:

  • Plain 类型没有时区
  • ZonedDateTime 类型有时区
  • 大多数类型都有日历
  • 许多有用的类型:Absolute, DateTime, Date, Time, TimeZone, ...

这是一个概述Temporal各种类型及其关系的模式 JS 临时提案类型

您可以在可用文档和漂亮的食谱中阅读有关它们的更多信息或者探索当前的问题以寻找开放的问题。

Temporal 何时可用

213 月起,它处于第 3 阶段/草案(请参阅TC39 阶段参考)。请参阅 TC39 21 年 3 月的幻灯片

现在它可以很快包含在 TypeScript 中,因为他们的政策是:

当新功能达到第 3 阶段时,它们就可以包含在 TypeScript 中了。

可能对于 Node 和主要浏览器,我们需要等待更多。

今天开始尝试

同时,您可以使用Temporal polyfill对其进行试验

npm install --save proposal-temporal

// temporal-test.js
const { Temporal } = require('proposal-temporal');

// or as an ES module
// import { Temporal } from 'proposal-temporal/lib/index.mjs';

// 11 means November now!
const date = new Temporal.PlainDate(2020, 11, 26); // => 2020-11-26

const sameDate = Temporal.PlainDate.from(
                {year: 2020, month: 11, day: 26}); // => 2020-11-26

一年总有 12 个月,因此早期的 C 实现可能使用索引为 0..11 的静态固定宽度数组。

Java 日期/日历实现保持对某些日历的额外月份的支持。en.wikipedia.org/wiki/Undecimber
2021-03-14 04:32:19