DEV Community

Discussion on: Oh Javascript... šŸ™„

Collapse
 
variadicism profile image
Connor Davey

Firstly, thank you very much for making this post before it tripped me up at some point! This seems like something that I would spend way too much time debugging.

Now then...

This Date behavior is not just unintuitive; it is incorrect.

I suspect that your supposition is correct that a - causes the date to be parsed as ISO 8601. However, even if this is the case, using ISO 8601 does not imply that the date time is in UTC. In the absence of a time zone designation, ISO 8601 is supposed to assume local time zone, not UTC. If the date time is in UTC, ISO 8601 expects a standard time zone definition like "+0:00" or the special "Z" designation appended to the end.

Wait! It gets worse! If you add a time to this date, it no longer assumes UTC time!

new Date('1995-12-17')
> Sat Dec 16 1995 17:00:00 GMT-0700 (MST)
new Date('1995-12-17T00:00:00')
> Sun Dec 17 1995 00:00:00 GMT-0700 (MST)

In conclusion, a - separator does not in any way, shape, or form imply UTC time... except in JavaScript's Date library and only if no time is provided. This is bad behavior.

Collapse
 
kspeakman profile image
Kasey Speakman

Wow, it is much worse than I thought! I think it is fair to categorize this in "the truly awful parts" of Javascript.

For the most part, I avoid working with dates in JS. In client-server apps I deal with them on the server and send dates back only as display strings for the client where possible. But in this case, I am doing a client-side-only app which needs to process dates and schedules. So I have to try to use the "least bad parts". I'm half-tempted to port moment.js or NodaTime to Elm.

Collapse
 
variadicism profile image
Connor Davey

At my company, we use moment.js. My colleagues recommend that.

Thread Thread
 
squgeim profile image
Shreya Dahal

Using moment does not solve this issue. Initializing date with a string that is not strictly ISO 8601 is inconsistent in the specification itself and depends on the browser.

On Safari:

> new Date('2018-3-14')
ā‹– Invalid Date
> moment('2018-3-14')
ā‹– Invalid Date

This works on Chrome, though. :D

More about the moment issue here: github.com/moment/moment/issues/1407

I have a more thorough write-up on this with a lot more caveats here: blog.lftechnology.com/date-ing-jav...

Thread Thread
 
kspeakman profile image
Kasey Speakman

Thanks for the link. That is a great article on many of the JS Date caveats.

Collapse
 
squgeim profile image
Shreya Dahal

Here's a quote from the ECMAScript 5 specification:

All numbers must be base 10. If the MM or DD fields are absent ā€œ01ā€ is used as the value. If the HH, mm, or ss fields are absent ā€œ00ā€ is used as the value and the value of an absent sss field is ā€œ000ā€. The value of an absent time zone offset is ā€œZā€.

So a lack of timezone offset is treated as UTC.

Collapse
 
variadicism profile image
Connor Davey

Thanks for the reference! This explains the behavior described in the original post.

However, I then argue that this standard is bad. Though I'm having trouble finding any truly official documentation, everything I do find (e.g., Wikipedia and this document) says that according to ISO 8601, in the absence of a time zone, local time should be used, not UTC. So, the browser is behaving correctly with these bare dates, but based on what I argue is a flawed standard that conflicts with ISO 8601.

Even more bothersome, though, is that this still doesn't explain why adding an explicit time switches to local time instead of UTC! I looked at the document linked, not just the quote, but still as far as I can tell, the standard you linked seems to indicate that new Date('1995-12-17T00:00:00') should still be considered UTC and result in Sat Dec 16 1995 17:00:00 GMT-0700 (MST), but it is read in local time instead!

This makes me sad. I don't understand why this is.

Thread Thread
 
squgeim profile image
Shreya Dahal

What's more troublesome is that that is inconsistent across different browsers: new Date('1995-12-17T00:00:00') is parsed as UTC on Safari.

According to the specs, strings that do not confirm to ISO 8601 are open for interpretation by difference implementation (like April 13 is April 13 2001 on Chrome, but doesn't work on other browsers). So my first guess was that this string just did not register as ISO 8601 on Chrome and it fell back to its own Interpretation.

I went to the latest ES7 specs and it has changed:

When the time zone offset is absent, date-only forms are interpreted as a UTC time and date-time forms are interpreted as a local time.

So we can have different results based on what version of the browser we are using.