Why does Date.parse('COVINGTONOFFICE-2') return a real date?

2020-04-01 javascript node.js
console.log(Date.parse('COVINGTONOFFICE-2')) // 981003600000
console.log(new Date('COVINGTONOFFICE-2').toDateString()) // Thu Feb 01 2001

Why does this return a valid date? What am I missing?

And if I want to parse a string such as 'Mon Nov 26 2018 18:03:33 GMT-0500 (Eastern Standard Time)' and have it be parsed to a date correctly but then have the above 'COVINGTONOFFICE-2' fail the date test, how would I go about that the correct way without hacking together my own regex?

Here is what I've tried:

console.log(moment('COVINGTONOFFICE-2').isValid()) // true
console.log(moment.isDate('COVINGTONOFFICE-2')) // false... good!
// so now I want to make sure that a date that has been stringified is still able to be parsed as valid date
console.log(Date.parse('Mon Nov 26 2018 18:03:33 GMT-0500 (Eastern Standard Time)')) // true
console.log(moment.isDate('Mon Nov 26 2018 18:03:33 GMT-0500 (Eastern Standard Time)')) // false... damn

Answers

Just to consolidate my findings as they're in the comments and might be difficult for others to read or find:

  • Chromium engine seems to return the same result for Date.parse('COVINGTONOFFICE-2') and Date.parse('2'). They both return the month counting from the start of the 21st century, i.e. 2 will give you Feb 1st, 2001. This only works up to 12: any number beyond that is invalid.
  • Date.parse('COVINGTONOFFICE-2') returns invalid date for other browsers that I have tested

Chances are is that Chromium's V8 engine has some internal heuristics that determine how to parse strings that look like dates: and makes a best effort in attempting to guess it. For other browsers, they simply give up.

This is inline with the recommendations, that the use of Date.parse() should be avoided. By extension, it should not even be used for strings that are ambiguous or don't look like dates. Browsers have different internal heuristics/implementations to perform the parsing, as MDN docs have pointed out:

There are still many differences in how different hosts parse date strings, therefore date strings should be manually parsed (a library can help if many different formats are to be accommodated).

I have compiled a quick ASCII table showing my findings so far:

+---------------------------------+--------------------+---------+-----------------+---------+---------------------+
|             Browser             | Chrome/Brave/Opera | Firefox |     Safari      |  IE11   | Edge (non-Chromium) |
+---------------------------------+--------------------+---------+-----------------+---------+---------------------+
| Date.parse('COVINGTONOFFICE-2') | Thu Feb 01 2001    | Invalid | Invalid         | Invalid | Invalid             |
| Date.parse('2')                 | Thu Feb 01 2001    | Invalid | Tue Jan 01 0002 | Invalid | Invalid             |
| Date.parse(2)                   | Thu Jan 01 1970    | NaN     | Thu Jan 01 1970 | NaN     | NaN                 |
+---------------------------------+--------------------+---------+-----------------+---------+---------------------+

As a response to your add-on question: I think the problem you face with the native date parser is the same as Moment.js moment(...) parser. Both are rather forgiving, so they will probably interpret 'COVINGTONOFFICE-2' as a valid string based on browser implementations.

Moment.js does offer the possibility to manually specify the format of a date string, but it does not support any tokens for week of the day in locale format (i.e. Mon, Tue, Wed...). The closest you can achieve is to do specify LLLL as the format: it seems to work well with dates printed out using the new Date().toString() method:

// true
console.log(moment('Mon Nov 26 2018 18:03:33 GMT-0500 (Eastern Standard Time)', 'LLLL').isValid());

// false
console.log(moment('COVINGTONOFFICE-2', 'LLLL').isValid());
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>

This feels more and more like an XY problem to me: is there a reason why you have to parse a string as a date? Is there no other way to retrieve a ISO-valid date format?

Related