Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I was trying to see if counting on the result of doing a const myNewDate = new Date(dateString) and then using an _.isDate(myNewDate) would be sufficient to validate that it's a "valid date", but then I thought: what can I receive in dateString?

It occurred to me to execute the following: for(i=0;i<110;i++) { console.log(i, new Date(String(i)))}

And this is the result I got:

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

So, just to analyze it a little:

  • from 0 to 4, the value is used for "months" at 6:00
  • 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?)
  • 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?)
  • from 100 to 110 (and even more, I tried 9999 with the same result) it belongs to the year, literally: 100 becomes year 0100. But the time, is set to 5 hours, and minutes and seconds belong to my current computer minutes and seconds (why?)

This is extremely confusing. I'd love to find the source of this.

Techical notes:

  • This is clearly javascript code.
  • I've used node 12.16.3.
  • Same result if I run it in Chrome's console.
  • In Firefox, it returns all as invalid dates.
like image 686
Luis Lobo Borobia Avatar asked Nov 06 '22 00:11

Luis Lobo Borobia


1 Answers

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

The default offset will be your locale which is -6 during these months. According to author Ryan Dahl, "Default year is 0 (=> 2000) for KJS compatibility". You might have noticed that the year changes from 2000 to 2001… I believe this is a bug. See: existing answer

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

DST changes in your locale, which is the default offset

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

Because the string supplied is not a valid month or YYYY it is parsed as DD and a Date with only a day value doesn't make sense. Why it does not default MM or YY is unclear… Speculating, the reason might be ambiguity between YY and DD, when parsing.

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's strptime, Python's datetime.strptime and UNIX C's strptime assume that 00-68 years belong to 2000 and 69-99 belong to 1900. This is intended to be an API convenience, assuming that lower numbers 32:49, closer the current century, are of the current century and that higher numbers 50:99, closer to the previous century, are referring to said century.

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 (when > 99) is literally YYY AD, akin to ISO-years

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

Timezones do change over time, and the locale parsing will try to account for those.

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

However, dates prior to Unix epoch never include 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)'

(The change occurred early noon)

> 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)'
like image 166
Bin Ury Avatar answered Nov 12 '22 19:11

Bin Ury