Skip to content Skip to sidebar Skip to footer

Create Date From String

I have a two strings 2017-03-15 (date) and 12:26 (time). I want to create a localised date object from it, without using a library. Remembering that here right now is: Tue Mar 14

Solution 1:

I get the wrong result as the date is considered UTC:

That was actually an error in the ES5 specification (which said that no timezone indicator meant UTC, which is at odds with the ISO-8601 standard it was meant to be a subset of). ES2015 corrected it to say that no timezone indicator meant local time (in keeping with ISO-8601), but that would have caused compatibility problems with existing code when used on date-only strings (like "2018-01-17"). So ES2016 had to update it again, and it's been stable since. If there's no timezone indicator, then:

  • A date-only string (such as "2019-05-20") is parsed in UTC
  • A date/time string (such as "2019-05-20T10:00") is parsed in local time

As a result of this spec confusion, for a while we had a mix of JavaScript engines that used the old ES5 behavior, the ES2015 behavior, or the ES2016 behavior. And one significant platform still has incorrect behavior: iOS.

As of this updated answer on May 20th, 2019:

  • Desktop versions of Chrome, Firefox, Edge, and even IE11 all correctly implement the ES2016+ specification.
  • Safari (desktop or iOS) incorrectly parses date/time strings without timezone indicators in UTC.
  • All current iOS browsers (Safari of course, but also Chrome, Firefox, Brave, Dolphin...) also incorrectly parse date/time strings without timezone indicators in UTC. This is because the iOS JavaScript engine, JavaScriptCore (JSC), implements this incorrectly, and non-Apple iOS applications can't allocate executable memory, so browsers can't use the engines they normally use (Chrome's V8, Firefox's SpiderMonkey, etc.) because those are optimizing engines that need to create executable code at runtime. So they use JSC instead. (Chrome's V8 has recently added a "JIT-less" pure interpreter version, so Chrome may or may not start using that rather than JSC.)

You can check your current browser here:

var may20 = new Date("2019-05-20");
// UTC hours should be 0 if that was parsed as UTC
console.log(may20.getUTCHours() === 0 ? "OK:" : "Error:", may20.toLocaleString());

var may20At10 = new Date("2019-05-20T10:00");
// Local hours should be 10 if that was parsed in local time
console.log(may20At10.getHours() === 10 ? "OK:" : "Error:", may20At10.toLocaleString());

(That check works unless you're in one of the several west African countries that use GMT year-round. It relies on UTC and local time being different from one another on May 20th, 2019. So it works in the UK because although the UK uses GMT much of the year, it's on British Summer Time [GMT+0100] for the date the check uses; and it works in New York because New York is never on GMT; but it doesn't work in Timbuktu because Timbuktu uses GMT year-round.)

However, this will NOT work on Safari (not without the T).

Right. The only date/time format that a JavaScript engine is required to support is the ISO-8601 subset defined here (and also whatever it returns from toString, but that isn't defined in the spec; it just has to be two-way). And as noted above, at least as of this writing on May 20th, 2019, Safari doesn't implement the specification correctly.

But it's just. So. Ugly. Is there a better solution that will work across browsers?

It's not ugly at all. That is, after all, what the Date constructor has to do to figure it out. Put it in your standard library and you're good to go.


Solution 2:

I get the wrong result as the date is considered UTC:

Given:

new Date('2017-03-15T12:26')

IE up to version 8 treats it as an invalid string, IE 9+ treats it as UTC. Firefox 38 treats it as local.

If I use a space … The result is correct

Until you try Safari and get an invalid date.

However, this will NOT work on Safari (not without the T). Safari will actually throw an error (!).

Yes, and both results are consistent with all versions of ECMAScript. Safari is saying "this isn't a valid ISO 8601 string", so returns an invalid date. The others are saying the same, but then falling back to implementation specific heuristics (which they are allowed to do).

The bottom line is do not parse strings with the Date constructor (or Date.parse, they are equivalent for parsing).

So, the only way to do it "right" would be…

Yes, manually parsing the bits. You can use a library for convenience, but they will do exactly the same thing.

Is there a better solution that will work across browsers?

No. Get on the ECMA TC39 committee and beat them over the head until they decide to define a Date object that has a decent parser and formatter. There are plenty of very good existing implementations to choose from, including existing javascript libraries and other languages.

Unfortunately parsing has been virtually ignored and responsibility for formatting has passed to ECMA-402, which is very ordinary for date formatting and is really not suitable.


Post a Comment for "Create Date From String"