javascript 中 Date 构造函数对字符串“0”到“110”的字符串解析背后的逻辑是什么?

What is the logic behind the string parsing on the Date constructor in javascript for the strings "0" to "110"?

我试图看看依靠 const myNewDate = new Date(dateString) 然后使用 _.isDate(myNewDate) 的结果是否足以验证它是一个“有效日期”,但后来我想:我可以在 dateString 收到什么?

我想到执行以下操作: for(i=0;i<110;i++) { console.log(i, new Date(String(i)))}

这是我得到的结果:

0 2000-01-01T06:00:00.000Z
1 2001-01-01T06:00:00.000Z
2 2001-02-01T06:00:00.000Z
3 2001-03-01T06:00:00.000Z
4 2001-04-01T06:00:00.000Z
5 2001-05-01T05:00:00.000Z
6 2001-06-01T05:00:00.000Z
7 2001-07-01T05:00:00.000Z
8 2001-08-01T05:00:00.000Z
9 2001-09-01T05:00:00.000Z
10 2001-10-01T05:00:00.000Z
11 2001-11-01T06:00:00.000Z
12 2001-12-01T06:00:00.000Z
13 Invalid Date
14 Invalid Date
15 Invalid Date
16 Invalid Date
17 Invalid Date
18 Invalid Date
19 Invalid Date
20 Invalid Date
21 Invalid Date
22 Invalid Date
23 Invalid Date
24 Invalid Date
25 Invalid Date
26 Invalid Date
27 Invalid Date
28 Invalid Date
29 Invalid Date
30 Invalid Date
31 Invalid Date
32 2032-01-01T06:00:00.000Z
33 2033-01-01T06:00:00.000Z
34 2034-01-01T06:00:00.000Z
35 2035-01-01T06:00:00.000Z
36 2036-01-01T06:00:00.000Z
37 2037-01-01T06:00:00.000Z
38 2038-01-01T06:00:00.000Z
39 2039-01-01T06:00:00.000Z
40 2040-01-01T06:00:00.000Z
41 2041-01-01T06:00:00.000Z
42 2042-01-01T06:00:00.000Z
43 2043-01-01T06:00:00.000Z
44 2044-01-01T06:00:00.000Z
45 2045-01-01T06:00:00.000Z
46 2046-01-01T06:00:00.000Z
47 2047-01-01T06:00:00.000Z
48 2048-01-01T06:00:00.000Z
49 2049-01-01T06:00:00.000Z
50 1950-01-01T06:00:00.000Z
51 1951-01-01T06:00:00.000Z
52 1952-01-01T06:00:00.000Z
53 1953-01-01T06:00:00.000Z
54 1954-01-01T06:00:00.000Z
55 1955-01-01T06:00:00.000Z
56 1956-01-01T06:00:00.000Z
57 1957-01-01T06:00:00.000Z
58 1958-01-01T06:00:00.000Z
59 1959-01-01T06:00:00.000Z
60 1960-01-01T06:00:00.000Z
61 1961-01-01T06:00:00.000Z
62 1962-01-01T06:00:00.000Z
63 1963-01-01T06:00:00.000Z
64 1964-01-01T06:00:00.000Z
65 1965-01-01T06:00:00.000Z
66 1966-01-01T06:00:00.000Z
67 1967-01-01T06:00:00.000Z
68 1968-01-01T06:00:00.000Z
69 1969-01-01T06:00:00.000Z
70 1970-01-01T06:00:00.000Z
71 1971-01-01T06:00:00.000Z
72 1972-01-01T06:00:00.000Z
73 1973-01-01T06:00:00.000Z
74 1974-01-01T06:00:00.000Z
75 1975-01-01T06:00:00.000Z
76 1976-01-01T06:00:00.000Z
77 1977-01-01T06:00:00.000Z
78 1978-01-01T06:00:00.000Z
79 1979-01-01T06:00:00.000Z
80 1980-01-01T06:00:00.000Z
81 1981-01-01T06:00:00.000Z
82 1982-01-01T06:00:00.000Z
83 1983-01-01T06:00:00.000Z
84 1984-01-01T06:00:00.000Z
85 1985-01-01T06:00:00.000Z
86 1986-01-01T06:00:00.000Z
87 1987-01-01T06:00:00.000Z
88 1988-01-01T06:00:00.000Z
89 1989-01-01T06:00:00.000Z
90 1990-01-01T06:00:00.000Z
91 1991-01-01T06:00:00.000Z
92 1992-01-01T06:00:00.000Z
93 1993-01-01T06:00:00.000Z
94 1994-01-01T06:00:00.000Z
95 1995-01-01T06:00:00.000Z
96 1996-01-01T06:00:00.000Z
97 1997-01-01T06:00:00.000Z
98 1998-01-01T06:00:00.000Z
99 1999-01-01T06:00:00.000Z
100 0100-01-01T05:50:36.000Z
101 0101-01-01T05:50:36.000Z
102 0102-01-01T05:50:36.000Z
103 0103-01-01T05:50:36.000Z
104 0104-01-01T05:50:36.000Z
105 0105-01-01T05:50:36.000Z
106 0106-01-01T05:50:36.000Z
107 0107-01-01T05:50:36.000Z
108 0108-01-01T05:50:36.000Z
109 0109-01-01T05:50:36.000Z

所以,稍微分析一下:

这非常令人困惑。我很想找到它的来源。

技术说明:

from 0 to 4, the value is used for "months" at 6:00

默认偏移量将是您的语言环境,在这几个月中为 -6。 根据作者 Ryan Dahl 的说法,“为了 KJS 兼容性,默认年份是 0 (=> 2000)”。 您可能已经注意到年份从 2000 年变为 2001 年……我相信这是一个错误。参见:

from 5 to 10, the value is again used for "months" but at 5:00 (why?)

11 and 12, the value is "months", but back to 6:00

您所在地区的夏令时更改,这是默认偏移量

from 13 to 31 is an invalid date (why?)

因为提供的字符串不是有效的月份或 YYYY,所以它被解析为 DD,而只有日期值的日期没有意义。为什么不默认MM或者YY不清楚……推测,可能是YY和DD在解析的时候有歧义。

from 32 to 49, now the value belongs to the years: 2000 + the value (why?)

from 50 to 99, now the value belongs to the years: 1900 + the value (why?)

PHP的strptime、Python的datetime.strptime和UNIX C的strptime假设00-68年属于2000年,69- 99属于1900。 这是为了 API 方便,假设较小的数字 32:49,更接近当前世纪,是当前世纪,而更大的数字 50:99,更接近上个世纪,是指的是世纪。

from 100 to 110 (and even more, I tried 9999 with the same result) it belongs to the year, literally: 100 becomes year 0100

YYY(当 > 99 时)字面意思是 YYY AD,类似于 ISO 年

But the time, is set to 5 hours, and minutes and seconds belong to my current computer minutes and seconds (why?)

时区确实会随着时间的推移而变化,区域设置解析将尝试考虑这些。

> (new Date("1883-05-31")).getTimezoneOffset()
350
> (new Date("1893-05-31")).getTimezoneOffset()
360
> (new Date("2023-05-31")).getTimezoneOffset()
300

但是,Unix 纪元之前的日期从不包括 the timezone's name, and Dates using a North American locale, prior to November 18, 1883 do not use the modern GMT offset as it was not yet established

> new Date("1883", "10", "18", "12").toString()
'Sun Nov 18 1883 12:00:00 GMT-0550 (Central Standard Time)'
> new Date("1883", "10", "18", "13").toString()
'Sun Nov 18 1883 13:00:00 GMT-0600 (Central Standard Time)'

(变化发生在中午)

> new Date("1883", "10", "18", "12", "09").toString()
'Sun Nov 18 1883 12:09:00 GMT-0550 (Central Standard Time)'
> new Date("1883", "10", "18", "12", "09", "24").toString()
'Sun Nov 18 1883 12:09:24 GMT-0600 (Central Standard Time)'