为什么在JavaScript的Date构造函数中,month参数的范围从0到11?


128

Date使用以下调用在JavaScript中初始化新对象时,我发现month参数从零开始计数。

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

为什么month参数从0开始?另一方面,每月的天参数(最后一个)是1到31之间的数字。这是否有充分的理由?


96
只是为了让您保持警惕。
SeanJA

4
索引也为零的索引是the Day of the week (integer)0-6
SeanJA

因为它是为机器而不是人类编码的。但是它仍然是漏洞的巨大来源,因为很多代码(仍)是由人类编写的:)
Christophe Roussy

4
@Christophe同样的论点也适用于日和年。
Agnel Kurian

2
@ChristopheRoussy是的,如果它是为机器编码的,那么为什么从1开始索引天呢?
user151496

Answers:


55

在编程世界中,这是一种古老的(可能是不幸的,也许正在消亡)的传统,请参见古老的标准(POSIX)本地时间 C函数http://linux.die.net/man/3/localtime


14
JS Date对象是从Java 1.0移植的,这就是为什么。继承其所有的缺陷... stackoverflow.com/questions/344380/...
C69

1
您是对的,传统通常是完全不一致的,而且常常
不合时宜

1
是2019年,我正在解决一个与此行为有关的问题,因此只要像javascript这样的语言和语言框架都不会弃用它,那么它仍然会发生-请在2025年及以后发表评论;-)
Mauricio Gracia Gutierrez

这是一个传统,总是让我花时间调试日期问题...想知道这种传统造成了多少浪费的工作时间。
Vedmant

102

这个问题的真正答案是,它是从复制的java.util.Date,也有这个怪癖。可以在Twitter上从Brendan Eich那里找到证明-Brendan Eich是最初实现JavaScript(包括Date对象)的人:

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

第一条推文

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

第二条推文

这发生在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.jsdate -fnsjs-joda。但是截至目前,Date该语言仅是内置的。希望这会在不久的将来改变。


24
啊...好的旧的演示驱动开发方法。
阿尔瓦罗·冈萨雷斯

@ÁlvaroGonzález我要怪最初介绍它的原始JDK 1.0开发人员。
barell

30

除月中的某天外,其他所有内容都基于0,请参见此处以获取包含范围的完整列表:)

实际上,这是从1开始的日子,这很奇怪。为什么要这样做?我不知道...但是可能是在他们碰面的同一次会议上发生的,并决定分号是可选的。


1
“基于人”的日子可能是因为没有人在他们的头脑中曾经创建过几天的字符串名称数组(例如{ "first", "second", "third", ..., "twenty-seventh", ... })并尝试通过对其进行索引tm_mday。再说一遍,也许他们只是看到了绝对的效用,可以使一次正常的错误消除
D.Shawley

他们为什么年份不是基于0的?
Vedmant


4

在Java中也是如此。. 可能是将int转换为字符串(0-jan ,, 1-feb),所以用这种方式编码。如果数字从0开始,则映射到月份字符串会容易得多。


3

我知道这并不是对原始问题的真正答案,但我只是想向您展示我对这个问题的首选解决方案,由于它不时出现,所以我似乎从未记住。

较小的功能zerofill可以在需要的地方完成零填充的技巧,并且仅+1添加了月份:

function zerofill(i) {
    return (i < 10 ? '0' : '') + i;
}

function getDateString() {
    const date = new Date();
    const year = date.getFullYear();
    const month = zerofill(date.getMonth()+1);
    const day = zerofill(date.getDate());
    return year + '-' + month + '-' + day;
}

但是,是的,Date具有非常直观的API,当我阅读Brendan Eich的Twitter时我很开心。


2

他们可能认为月份是一个枚举(第一个索引为0),而几天则不是,因为它们没有关联的名称。

或更确切地说,他们认为日期是日期的实际表示形式(以12/31之类的日期表示月份的方式相同),好像您可以使用数字作为变量进行枚举,但实际上从0开始。

因此,实际上,在几个月中,也许他们认为正确的枚举表示形式将是使用月份的名称而不是数字,并且如果日子使用名称表示,他们也会这样做。想象一下,如果我们说是1月5日,1月6日,而不是1月5日,1月6日等,那么也许他们也做了几天从0开始的枚举...

也许在潜意识里,他们想到了一个枚举为{{January,February,...}}几个月,几天为{One,Two,Three,...}的枚举,除了几天以数字而不是名称来访问的日子,例如1对1等,因此不可能从0开始...


您应该对心理学家进行双重培训。他们仍然犯了一个错误,但至少我们现在了解了他们为什么这么做。
Zesty

0

这可能是一个缺陷,但是当您想将月份或星期几表示为字符串时,也可以非常方便使用,您可以创建一个数组,例如['jan,'feb'... etc] [new Date() .getMonth()]代替['','jan',feb ... etc] [new Date()。getMonth()或['jan','feb'... etc] [new Date( ).getMonth()-1]

通常不会指定一个月中的某几天,因此您将不会使用这些名称创建数组。在这种情况下,1-31更易于处理,因此您每次必须减去1 ...


并不是的。您可以轻松地减去一个。它带来的问题比解决的问题多,因为现在当您对日期进行数学运算时,您不得不经常对月份进行特定的操作。
Rey
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.