JavaScript: Which browsers support parsing of ISO-8601 Date String with Date.parse


I failed to parse an ISO-8601 date "2011-04-26T13:16:50Z" on IE8 and Safari 5, but it worked on Chrome 10, FF4. Support seems to be quite mixed?

Does anyone know the actual status of which browsers can parse this format? I assume IE6, and 7 will fail too.

var d = Date.parse("2011-04-26T13:16:50Z");

I had this issue today. I found momentjs was a good way of parsing ISO 8601 dates in a cross browser manor.

momentjs can also be used to output the date in a different format.


I say shim it only if needed via a few tests,

here is one I already written:

(function() {

var d = window.Date,
    regexIso8601 = /^(\d{4}|\+\d{6})(?:-(\d{2})(?:-(\d{2})(?:T(\d{2}):(\d{2}):(\d{2})\.(\d{1,3})(?:Z|([\-+])(\d{2}):(\d{2}))?)?)?)?$/;

if (d.parse('2011-11-29T15:52:30.5') !== 1322581950500 ||
    d.parse('2011-11-29T15:52:30.52') !== 1322581950520 ||
    d.parse('2011-11-29T15:52:18.867') !== 1322581938867 ||
    d.parse('2011-11-29T15:52:18.867Z') !== 1322581938867 ||
    d.parse('2011-11-29T15:52:18.867-03:30') !== 1322594538867 ||
    d.parse('2011-11-29') !== 1322524800000 ||
    d.parse('2011-11') !== 1320105600000 ||
    d.parse('2011') !== 1293840000000) {

    d.__parse = d.parse;

    d.parse = function(v) {

        var m = regexIso8601.exec(v);

        if (m) {
            return Date.UTC(
                m[1],
                (m[2] || 1) - 1,
                m[3] || 1,
                m[4] - (m[8] ? m[8] + m[9] : 0) || 0,
                m[5] - (m[8] ? m[8] + m[10] : 0) || 0,
                m[6] || 0,
                ((m[7] || 0) + '00').substr(0, 3)
            );
        }

        return d.__parse.apply(this, arguments);

    };
}

d.__fromString = d.fromString;

d.fromString = function(v) {

    if (!d.__fromString || regexIso8601.test(v)) {
        return new d(d.parse(v));
    }

    return d.__fromString.apply(this, arguments);
};

})();

and in your code just always use Date.fromString(...) instead of new Date(...)

test a browser to see if the shim will be used:

http://jsbin.com/efivib/1/edit

works in all major browsers, used these references:

http://dev.w3.org/html5/spec/common-microsyntaxes.html

http://www.ecma-international.org/ecma-262/5.1/#sec-15.9.1.15

http://msdn.microsoft.com/en-us/library/windows/apps/ff743760(v=vs.94).aspx

http://msdn.microsoft.com/en-us/library/windows/apps/wz6stk2z(v=vs.94).aspx

http://msdn.microsoft.com/en-us/library/windows/apps/k4w173wk(v=vs.94).aspx

!- microsoft connect requires a log in to view:

IE9 was failing on milliseconds with digit counts other than 3: (fixed in IE10) https://connect.microsoft.com/IE/feedback/details/723740/date-parse-and-new-date-fail-on-valid-formats

IE10 is still (as of 1/17/2013) failing when the time zone is omitted (according to ECMA, this should defalt to Z or UTC, not local): https://connect.microsoft.com/IE/feedback/details/776783/date-parse-and-new-date-fail-on-valid-formats

-- Read this if you care about where the standard is now / going in the future and why I can't get the IE team to recognize that their IE10 implementation is technically incorrect:

ECMAScript-262 v6.0 is going to move to the slightly more iso8601 compliant version of "if time zone indicator is omitted, assume local time"... so now there is a discrepancy, this implementation, chrome, mobile safari and opera all follow ECMAScript-262 v5.1, whereas IE10, firefox, desktop safari all seem to be following the more iso8601 compliant ECMAScript-262 v6.0 specification... this is confusing to say the least. When chrome or mobile safari pull the trigger and move to the ES6 implementation, I think this implementation should go with it leaving ES5.1 in the minority. I've read that this is listed in the "errata" of version 5.1 though I haven't found it. I'm more of the opinion that it's a little early to be pulling the trigger on ES6 just yet, but I'm also of the opinion that code needs to be practical, not ideal and move to where the browser makers move to. That said, it seems to be a 50/50 decision right now, so below is the "future" version of this code...

I should also mention that either version of the code will normalize "non-compliant" browsers to match the behavior of the other one, since that's what shims do ;)

HERE IS AN ADAPTED VERSION COMPATIBLE WITH ECMAScript-262 v6.0 (JavaScript Future)

see relevant sections here: (this is the only online html version of the spec I could find) http://people.mozilla.org/~jorendorff/es6-draft.html#sec-15.9.1.15

(function() {

    var d = window.Date,
        regexIso8601 = /^(\d{4}|\+\d{6})(?:-(\d{2})(?:-(\d{2})(?:T(\d{2}):(\d{2}):(\d{2})\.(\d{1,})(Z|([\-+])(\d{2}):(\d{2}))?)?)?)?$/,
        lOff, lHrs, lMin;

    if (d.parse('2011-11-29T15:52:30.5') !== 1322599950500 ||
        d.parse('2011-11-29T15:52:30.52') !== 1322599950520 ||
        d.parse('2011-11-29T15:52:18.867') !== 1322599938867 ||
        d.parse('2011-11-29T15:52:18.867Z') !== 1322581938867 ||
        d.parse('2011-11-29T15:52:18.867-03:30') !== 1322594538867 ||
        d.parse('2011-11-29') !== 1322524800000 ||
        d.parse('2011-11') !== 1320105600000 ||
        d.parse('2011') !== 1293840000000) {

        d.__parse = d.parse;

        lOff = -(new Date().getTimezoneOffset());
        lHrs = Math.floor(lOff / 60);
        lMin = lOff % 60;

        d.parse = function(v) {

            var m = regexIso8601.exec(v);

            if (m) {
                return Date.UTC(
                    m[1],
                    (m[2] || 1) - 1,
                    m[3] || 1,
                    m[4] - (m[8] ? m[9] ? m[9] + m[10] : 0 : lHrs) || 0,
                    m[5] - (m[8] ? m[9] ? m[9] + m[11] : 0 : lMin) || 0,
                    m[6] || 0,
                    ((m[7] || 0) + '00').substr(0, 3)
                );
            }

            return d.__parse.apply(this, arguments);

        };
    }

    d.__fromString = d.fromString;

    d.fromString = function(v) {

        if (!d.__fromString || regexIso8601.test(v)) {
            return new d(d.parse(v));
        }

        return d.__fromString.apply(this, arguments);
    };

})();

hope this helps -ck


Simple function to parse ISO8601 date format in any browser:

function dateFromISO8601(isoDateString) {
  var parts = isoDateString.match(/\d+/g);
  var isoTime = Date.UTC(parts[0], parts[1] - 1, parts[2], parts[3], parts[4], parts[5]);
  var isoDate = new Date(isoTime);

  return isoDate;
}

Yes, Date.parse is not consistent for different browsers. You could:


Some older browsers return the wrong date (and not NaN)if you parse an ISO date string.

You can use your own method across all browsers, or use Date.parse if it is implemented correctly- check a known timestamp.

Date.fromISO= (function(){
    var diso= Date.parse('2011-04-26T13:16:50Z');
    if(diso=== 1303823810000) return function(s){
        return new Date(Date.parse(s));
    }
    else return function(s){
        var day, tz, 
        rx= /^(\d{4}\-\d\d\-\d\d([tT][\d:\.]*)?)([zZ]|([+\-])(\d\d):(\d\d))?$/, 
        p= rx.exec(s) || [];
        if(p[1]){
            day= p[1].split(/\D/).map(function(itm){
                return parseInt(itm, 10) || 0;
            });
            day[1]-= 1;
            day= new Date(Date.UTC.apply(Date, day));
            if(!day.getDate()) return NaN;
            if(p[5]){
                tz= parseInt(p[5], 10)*60;
                if(p[6]) tz += parseInt(p[6], 10);
                if(p[4]== "+") tz*= -1;
                if(tz) day.setUTCMinutes(day.getUTCMinutes()+ tz);
            }
            return day;
        }
        return NaN;
    }
})()

The ES5 spec deviates from the ISO8601 spec, especially when it comes to the treatment of dates without a timezone indicator / offset. There is a bug ticket at https://bugs.ecmascript.org/show_bug.cgi?id=112 describing the problem and it looks like it will be fixed in ES6.

For now, I recommend looking at https://github.com/csnover/js-iso8601 for a cross-browser implementation. I use https://github.com/csnover/js-iso8601/tree/lax which doesn't conform to the ES5 spec but has better interoperability with other JSON serialisation libraries such as JSON.NET.


I found ckozl answer really useful and interesting, but the regexp is not perfect and it didn't work in my case.

Apart from the fact that dates without minutes, secs or milisecs are not parsed, ISO 8501 spec says that the '-' and ':' separators are optional, so "2013-12-27" and "20131227" are both valid. In my case, this is important because I'm setting the server date and time in a JavaScript variable from PHP:

var serverDate = new Date(Date.parse("<?php date(DateTime::ISO8601); ?>"));

This code generates something like this:

<script>
var serverDate = new Date(Date.parse("2013-12-27T15:27:34+0100"));
</script>

The important part is the time zone designator "+0100" where the ':' is missing. Although Firefox parses that string correctly, IE (11) fails (if the ':' is added, then IE also works). The headache about the zonetime and the ECMAScript specifications described by ckozl is unimportant in my case, because PHP always add the time zone designator.

The RegExp I'm using, instead of that one from ckozl is:

var regexIso8601 = /^(\d{4}|\+\d{6})(?:-?(\d{2})(?:-?(\d{2})(?:T(\d{2})(?::?(\d{2})(?::?(\d{2})(?:(?:\.|,)(\d{1,}))?)?)?(Z|([\-+])(\d{2})(?::?(\d{2}))?)?)?)?)?$/;

Keep in mind that this regexp is not perfect either. ISO 8501 allows week specification (2007-W01-1 for monday, 1 Jan 2007), or decimal fractions in hours and minutes (18.50 for 18:30:00, or 18:30.25 for 18:30:15). But they are quite unusual.

P.D. This answer should be, I imagine, a comment to the original chozl answer, but I do not have reputation enough :(


As mentioned previously ISO 8601 style dates were added in ECMAScript version 5, where implementation is not consistent, and not available in all browsers. There are a number of script stubs available, but you may wish to simply add your own Date.parse* method.

(function() {
  //ISO-8601 Date Matching
  var reIsoDate = /^(\d{4})-(\d{2})-(\d{2})((T)(\d{2}):(\d{2})(:(\d{2})(\.\d*)?)?)?(Z|[+-]00(\:00)?)?$/;
  Date.parseISO = function(val) {
    var m;

    m = typeof val === 'string' && val.match(reIsoDate);
    if (m) return new Date(Date.UTC(+m[1], +m[2] - 1, +m[3], +m[6] || 0, +m[7] || 0, +m[9] || 0, parseInt((+m[10]) * 1000) || 0));

    return null;
  }

  //MS-Ajax Date Matching
  var reMsAjaxDate = /^\\?\/Date\((\-?\d+)\)\\?\/$/;
  Date.parseAjax = function(val) {
    var m;

    m = typeof val === 'string' && val.match(reMsAjaxDate);
    if (m) return new Date(+m[1]);

    return null;
  }
}();

I use the above method for JSON.parse hydration of dates...

JSON.parse(text, function(key, val) {
  return Date.parseISO(val) || Date.parseAjax(val) || val;
});

ISO 8601 date formats were added with ECMAScript-262 v5. So if a browser is not v5 compatible, you simply cannot expect to be capable of handling ISO 8601 formats.

Browsers not being v5 compatible may use any implementation specific date formats they want. Most of them do at least support RFC822/RFC1123 date formats, though. Example:

var d = Date.parse("Wed, 26 Apr 2011 13:16:50 GMT+0200");

Microsoft Sharepoint 2013 is ALSO using a different notation eg "2013-04-30T22:00:00Z"

If you want to use the REST services from sharepoint 2013 in combination with Internet Explorer 8 ( IE8 ) , then the solution from ckozl is NOT working. Youll get the NaN

change the regex line TO:

regexIso8601 = /^(\d{4}|\+\d{6})(?:-(\d{2})(?:-(\d{2})(?:T(\d{2}):(\d{2}):(\d{2})(\.(\d{1,3}))?(?:Z|([\-+])(\d{2}):(\d{2}))?)?)?)?$/;

this will make the microseconds bit optional !

cheerio, Leo