2
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
Jason Roell
  • 6,679
  • 4
  • 21
  • 28
  • 1
    Returns `NaN` for the former and `Invalid Date` for the latter when I do it. – John Montgomery Mar 31 '20 at 22:22
  • 2
    At least in a Chromium based browser: You would realize that `Date.parse()` actually ignores anything that comes before the number: `Date.parse('2')` yields the same result as `console.log(Date.parse('COVINGTONOFFICE-2'))`. Chances are, the single number is being evaluated as the month at the turn of the 21st century. The reason why? I have no idea: `Date.parse()` has some internal logic in determining how to parse a badly formatted date, so probably has some heuristics going on. – Terry Mar 31 '20 at 22:22
  • I tested in Chromes console and in node.js (both using v8 internally so I assumed that they would have the same results... but was still curious as to why) – Jason Roell Mar 31 '20 at 22:25
  • 2
    That seems to only work with the V8 engine that comes with Chromium. Firefox, Safari, Edge (non-Chromium) and IE11 all report an invalid date. Chances are, you should never trust `Date.parse()` to parse a string that contains ambiguous date, since browser vendors seem to have non-standardized implementations of the parser internally. – Terry Mar 31 '20 at 22:27

1 Answers1

2

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?

Terry
  • 63,248
  • 15
  • 96
  • 118
  • Thanks Terry... I guess it is just the way it is. So is there a good way to determine if something is a date without writing your own regex? I've updated to question to reflect what I'm trying to achieve. – Jason Roell Mar 31 '20 at 22:36
  • @JasonRoell No problem. It feels like an XY problem to me, since date parsing is extremely tricky and most parsers are therefore extremely lax. However, if you use `'LLLL'` as the format, it might help you to get the desired result: see my updated answer. – Terry Mar 31 '20 at 22:56
  • I appreciate the research and detailed answer. I ended up using that actually, as it seems like my best option other than writing my own regex where I'm sure I will miss an edge case! The data is coming from a data source that I don't have much control over and they are all strings so I was attempting to parse the ones that actually were dates to dates so that I could sort them correctly – Jason Roell Mar 31 '20 at 23:11
  • In quoting MDN you left out probably the most important part: **It is not recommended to use Date.parse…**. Just don't use it. – RobG Mar 31 '20 at 23:15
  • 1
    @RobG I did? "This is inline with the recommendations, that Date.parse() should not be used for strings that are ambiguous or don't look like dates." – Terry Mar 31 '20 at 23:15
  • You've added a qualification that isn't in the reference. For example, "2020-03-31 13:15:22" is not ambiguous nor un–date–like, yet it will return an invalid date in Safari. There are other quirks in various browsers, hence the recommendation to not use the built–in parser (at all). – RobG Mar 31 '20 at 23:19
  • @RobG so what do you recommend using? – Jason Roell Mar 31 '20 at 23:21
  • @RobG Right. Clarified the statement then. – Terry Mar 31 '20 at 23:30