mdn / content

The content behind MDN Web Docs
https://developer.mozilla.org
Other
9.2k stars 22.49k forks source link

Update "Non-standard date strings" section of `Date.parse` JS reference #30363

Open vinnydiehl opened 12 months ago

vinnydiehl commented 12 months ago

MDN URL

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse#non-standard_date_strings

What specific section or headline is this issue about?

Non-standard date strings

What information was incorrect, unhelpful, or incomplete?

As discovered in #30235, the content in this section is somewhat out of date. A lot of work has been done to Date.parse recently in SpiderMonkey, especially with regard to supporting new formats and achieving parity with Chrome's format support.

What did you expect to see?

More up-to-date information about implementation-specific date formats.

Do you have any supporting links, references, or citations?

30234, #30235, and the Bugzilla bugs referenced in those PRs.

Josh-Cena commented 12 months ago

This section was rewritten a couple of months ago. I've just tested on all three browsers:

Please let me know if there's any other case we should update, or any case you wish to add.

Josh-Cena commented 12 months ago

I think a better way would be to use table layout instead of code for this section. I will try to rewrite it and make the case more exhaustive.

vinnydiehl commented 11 months ago

A few initial suggestions off the top of my head, just based on the formats already in the docs:

Input JavaScriptCore SpiderMonkey V8
Date.parse("0") -62167219200000 NaN 946710000000
Date.parse("31") -61188912000000 NaN NaN
Date.parse("999") -30641760000000 NaN -30641733102000
Date.parse("1000") -30610224000000 -30610224000000 -30610224000000
Input JavaScriptCore SpiderMonkey V8
Date.parse("1970-01-01") 0 0 0
Date.parse("1970-1-01") NaN 25200000 25200000
Date.parse("1970,01,01") NaN 25200000 25200000
Date.parse("1970 01 01") NaN 25200000 25200000
Input JavaScriptCore SpiderMonkey V8
Date.parse("12-01-01") -61788528000000 1007190000000 1007190000000
Date.parse("31-01-01") -61188912000000 NaN NaN
Date.parse("49-01-01") -60620832000000 2493097200000 2493097200000
Date.parse("50-01-01") -60589296000000 -631126800000 -631126800000
Input JavaScriptCore SpiderMonkey V8
Date.parse("12/01/01") 1007190000000 1007190000000 1007190000000
Date.parse("31/01/01") NaN NaN NaN
Date.parse("49/01/01") 2493097200000 2493097200000 2493097200000
Date.parse("50/01/01") -631126800000 -631126800000 -631126800000
> eshost -te 'Date.parse("2014-02-30")'
Engine Result
JavaScriptCore NaN
SpiderMonkey 1393743600000
V8 1393718400000

It's late and I'm sure I'll think of more stuff moving forward as I've gotten quite familiar with the behavior or this function across engines... also see the Bugzilla links referenced in #30234 and #30235 for more examples of our findings and advances during recent development.

If it helps, I did all of this testing and generated all of these tables automatically via a tool that I made which wraps eshost.

For example, the first chart in this post was generated with the command mdhost -f 'Date.parse("#{}")' 0 31 999 1000, which prints the results from eshost and copies a markdown chart of the results to your clipboard. Maybe this will help you with quickly generating at least some starting point for the documentation.

vinnydiehl commented 11 months ago

Also, while I understand that this documentation is for Date.parse and not the Date constructor, displaying these results as UTC timestamps is pretty confusing. The eshost output from the constructor paints a much clearer picture of what these formats are being parsed as, and the constructor runs the same function under the hood as Date.parse.

Another potential source of confusion that should be documented is that some of these date formats are assumed local time rather than GMT so these results won't even be consistent across different user locations.

Josh-Cena commented 11 months ago

Thanks for the information! I think a lot of the examples are incorporated already, just not in an exhaustive way. Also, the current code is generated by eshost too :)

vinnydiehl commented 11 months ago

No problem! Here's a few more...

Input JavaScriptCore SpiderMonkey V8
Date.parse("Thu Jan 01 1970") 25200000 25200000 25200000
Date.parse("Mon Jan 01 1970") 25200000 25200000 25200000
Date.parse("foo bar Jan 01 1970") 25200000 25200000 25200000
Date.parse("Jan Thurs 01 1970") NaN 25200000 25200000
Date.parse("Jan foo bar 01 1970") NaN 25200000 25200000
Input JavaScriptCore SpiderMonkey V8
Date.parse("1970-01-01") 0 0 0
Date.parse("Thu 1970-01-01") NaN 25200000 25200000
Date.parse("Thu Jan.01.1970") NaN 25200000 25200000
Input JavaScriptCore SpiderMonkey V8
Date.parse("Ja 01 1970") NaN NaN NaN
Date.parse("Jan 01 1970") 25200000 25200000 25200000
Date.parse("Janxxx 01 1970") 25200000 25200000 25200000
Input JavaScriptCore SpiderMonkey V8
new Date("-002022-01-01") Sat Dec 31 -2023 16:31:42 GMT-0728 (Mountain Standard Time) Sat Dec 31 -2023 16:31:42 GMT-0728 (Mountain Standard Time) Sat Dec 31 -2023 16:31:42 GMT-0728 (Mountain Standard Time)
new Date("01 01 -2022") Invalid Date Sun Jan 01 -2022 00:00:00 GMT-0728 (Mountain Standard Time) Invalid Date
new Date("Jan 1 -2022") Sun Jan 01 -2022 00:00:00 GMT-0728 (Mountain Standard Time) Sun Jan 01 -2022 00:00:00 GMT-0728 (Mountain Standard Time) Invalid Date
Input JavaScriptCore SpiderMonkey V8
new Date("1970-01-01 01::02") Invalid Date Thu Jan 01 1970 01:02:00 GMT-0700 (Mountain Standard Time) Thu Jan 01 1970 01:00:02 GMT-0700 (Mountain Standard Time)
new Date("05:Jan:2000") Invalid Date Invalid Date Sat Jan 01 2000 05:00:00 GMT-0700 (Mountain Standard Time)
Josh-Cena commented 11 months ago

What I dread the most is time representations containing English... Like, theoretically you could exhaust all time formats containing dashes, slashes, spaces, etc. but once you have English letters there start to be infinite possibilities.

I tried to read the parser source for Firefox, but no my brain could not generate the formal grammar supported by that parser; I really hope each browser can document the formal syntax of their date strings ๐Ÿ˜ž

vinnydiehl commented 11 months ago

It would be really nice if the spec would go further in depth than the current date time string format, rather than telling engines to basically "figure it out". In theory the formal spec would be enough, but in practice a lot of developers use non-standard date formats and then people complain when a website breaks on some browsers.

I agree that coming up with a formal grammar for the current behavior of any given engine is an absolute nightmare, and not even limited to alpha characters which could at least be adequately explained, but once you start getting into the edge cases and the subtle differences in behavior between different formats that appear to display the same date, thar be dragons.

Thankfully, the behavior surrounding different delimiters has vastly improved in FF, but it's still not perfect; '-' behaves slightly differently than its friends '.', '/', and ' '.

Anyway, I think a table with a shit ton of examples is our best bet here, rather than trying to dive into the weeds of defining a grammar which would end up being overly complex and TL;DR for a casual MDN reader just looking to see what formats are supported where.

Josh-Cena commented 11 months ago

No we explicitly don't want it to be exhaustive or nearly soโ€”doing so is a nightmare for both us and the readers ๐Ÿ˜„ Neither would we mention formal syntax, no chance. That was just for my own intellectual curiosity and maybe to save some time of shooting in the dark. My plan is still only to present a few typical cases, showcasing exactly why using non-standard datestrings is a nightmare and why you always need to conduct cross-browser tests before relying on anything. That's the sole purpose. We are not trying to write it as a compatibility data. If you really entertain the idea, maybe you can put it up as a gist or a blog post, and I will definitely link to it.

vinnydiehl commented 11 months ago

Agreed. And, I think it'd be appropriate to add a blurb at the top of the section stressing that the non-standard dates are for reference only and that readers should avoid using them at all costs in favor of the spec format. It would literally be more reliable to have an LLM guess what date a user is trying to enter than to feed their input to some random implementation of Date.parse. ๐Ÿ˜…

vinnydiehl commented 11 months ago

By the way, I've added a couple of features to mdhost to help make the tables a bit cleaner for documentation, such as:

So, now we can do:

mdhost -b -f 'Date.parse("#{}")' -t '"#{}"' "1970-01-01" "Thu 1970-01-01" "Thu Jan.01.1970"

The args after the options are formatted in place of the #{}. The generated table copied to the clipboard in this example looks like:

Input Safari Firefox Chrome
"1970-01-01" 0 0 0
"Thu 1970-01-01" NaN 25200000 25200000
"Thu Jan.01.1970" NaN 25200000 25200000

It's on RubyGems (gem install mdhost) if you'd like to give it a whirl ^.^

vinnydiehl commented 10 months ago

This change in 123 is relevant here: https://bugzilla.mozilla.org/show_bug.cgi?id=1870434

CdTgr commented 6 months ago

Another case, maybe related to this ticket.

Any string that ends with a -[number] is a valid date.

new Date('something-10')      // valid date "2001-09-30T22:00:00.000Z"
Date.parse('hello-10')        // also valid "1001887200000"
Date.parse('this-one-too-5')  // also valid "988668000000"
vinnydiehl commented 6 months ago

@CdTgr A number of other delimiters (`,.,,,-,/`) also work here, see bug 1881930.