web-dev-qa-db-fra.com

JavaScript: quels navigateurs prennent en charge l'analyse de la chaîne de date ISO-8601 avec Date.parse

J'ai échoué à analyser une date ISO-8601 "2011-04-26T13: 16: 50Z" sur IE8 et Safari 5, mais cela a fonctionné sur Chrome 10, FF4. Le support semble être assez mélangé ?

Quelqu'un connaît-il l'état réel des navigateurs qui peuvent analyser ce format? Je suppose que IE6 et 7 échoueront également.

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

J'ai eu ce problème aujourd'hui. J'ai trouvé momentjs était un bon moyen d'analyser les dates ISO 8601 dans un manoir multi-navigateur.

momentjs peut également être utilisé pour afficher la date dans un format différent.

17
asgeo1

Je dis shim seulement si nécessaire via quelques tests,

en voici une que j'ai déjà écrite:

(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);
};

})();

et dans votre code, utilisez toujours Date.fromString(...) au lieu de new Date(...)

testez un navigateur pour voir si la cale sera utilisée:

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

fonctionne dans tous les principaux navigateurs, a utilisé ces références:

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 nécessite une connexion pour voir:

IE9 échouait en millisecondes avec un nombre de chiffres différent de 3: (corrigé dans IE10) https://connect.Microsoft.com/IE/feedback/details/723740/date-parse-and-new-date-fail -sur-formats-valides

IE10 échoue toujours (au 17/01/2013) lorsque le fuseau horaire est omis (selon l'ECMA, cela devrait être défini sur Z ou UTC, pas local): https://connect.Microsoft.com/ IE/feedback/details/776783/date-parse-and-new-date-fail-on-valid-formats

- Lisez ceci si vous vous souciez de la situation actuelle ou future de la norme et pourquoi je ne peux pas faire en sorte que l'équipe IE reconnaisse que son implémentation IE10 est techniquement incorrect:

ECMAScript-262 v6.0 va passer à la version légèrement plus conforme à iso8601 de "si l'indicateur de fuseau horaire est omis, supposez l'heure locale" ... alors maintenant il y a un écart, cette implémentation, chrome, safari mobile et opera tous suivent ECMAScript-262 v5.1, tandis qu'IE10, firefox, desktop safari semblent tous suivre la spécification ECMAScript-262 v6.0 la plus conforme à iso8601 ... c'est pour le moins déroutant. Lorsque chrome ou safari mobile appuyez sur la gâchette et passe à l'implémentation ES6, je pense que cette implémentation devrait aller de pair avec ES5.1 minoritaire. J'ai lu que cela est répertorié dans les "errata" de la version 5.1 bien que je ne l'ai pas trouvé. Je suis plus d'avis qu'il est encore un peu tôt pour appuyer sur la gâchette sur ES6, mais je suis également d'avis que le code doit être pratique, pas idéal et aller là où les fabricants de navigateurs vont. Cela dit, il semble que ce soit une décision 50/50 en ce moment, donc voici la "future" version de ce code ...

Je dois également mentionner que l'une ou l'autre version du code normalisera les navigateurs "non conformes" pour correspondre au comportement de l'autre, puisque c'est ce que font les shims;)

ICI IS UNE VERSION ADAPTÉE COMPATIBLE AVEC ECMAScript-262 v6.0 (JavaScript Future)

voir les sections pertinentes ici: (c'est la seule version html en ligne de la spécification que j'ai pu trouver) 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);
    };

})();

j'espère que cela aide -ck

32
ckozl

Fonction simple pour analyser le format de date ISO8601 dans n'importe quel navigateur:

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;
}
18
Oleksandr Tsurika

Oui, Date.parse n'est pas cohérent pour différents navigateurs. Vous pourriez:

  • Utilisez plutôt Date.UTC , ce qui décompose la chaîne de date en entrées distinctes
  • Utilisez une bibliothèque wrapper comme parseDate de jQuery
6
Vik David

Certains navigateurs plus anciens renvoient la date erronée (et non NaN) si vous analysez une chaîne de date ISO.

Vous pouvez utiliser votre propre méthode sur tous les navigateurs, ou utiliser Date.parse si elle est implémentée correctement - vérifiez un horodatage connu.

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;
    }
})()
4
kennebec

La spécification ES5 s'écarte de la spécification ISO8601, notamment en ce qui concerne le traitement des dates sans indicateur/décalage de fuseau horaire. Il y a un ticket de bogue à https://bugs.ecmascript.org/show_bug.cgi?id=112 décrivant le problème et il semble qu'il sera corrigé dans ES6.

Pour l'instant, je recommande de regarder https://github.com/csnover/js-iso8601 pour une implémentation multi-navigateur. J'utilise https://github.com/csnover/js-iso8601/tree/lax qui n'est pas conforme à la spécification ES5 mais a une meilleure interopérabilité avec d'autres bibliothèques de sérialisation JSON telles que JSON.NET.

4
Will Holley

Comme mentionné précédemment, les dates de style ISO 8601 ont été ajoutées dans ECMAScript version 5, où l'implémentation n'est pas cohérente et n'est pas disponible dans tous les navigateurs. Il existe un nombresur stubs de script disponibles, mais vous pouvez simplement ajouter votre propre méthode Date.parse *.

(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;
  }
}();

J'utilise la méthode ci-dessus pour l'hydratation JSON.parse des dattes ...

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

J'ai trouvé la réponse ckozl vraiment utile et intéressante, mais l'expression régulière n'est pas parfaite et cela n'a pas fonctionné dans mon cas.

Mis à part le fait que les dates sans minutes, secs ou milisecs ne sont pas analysées, la spécification ISO 8501 indique que les séparateurs "-" et ":" sont facultatifs, donc "2013-12-27" et "20131227" sont tous deux valides. Dans mon cas, cela est important car je configure la date et l'heure du serveur dans une variable JavaScript de PHP:

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

Ce code génère quelque chose comme ceci:

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

La partie importante est l'indicateur de fuseau horaire "+0100" où le ':' est manquant. Bien que Firefox analyse correctement cette chaîne, IE (11) échoue (si le ':' est ajouté, alors IE fonctionne également). Le mal de tête à propos du zonetime et les spécifications ECMAScript décrites par ckozl n'ont pas d'importance dans mon cas, car PHP ajoutez toujours l'indicateur de fuseau horaire.

Le RegExp que j'utilise, au lieu de celui de ckozl est:

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

Gardez à l'esprit que cette expression rationnelle n'est pas parfaite non plus. ISO 8501 permet une spécification de semaine (2007-W01-1 pour le lundi 1er janvier 2007) ou des fractions décimales en heures et minutes (18,50 pour 18:30:00 ou 18: 30,25 pour 18:30:15). Mais ils sont assez inhabituels.

P.D. Cette réponse devrait être, j'imagine, un commentaire de la réponse chozl d'origine, mais je n'ai pas assez de réputation :(

2
Googol

ISO 8601 les formats de date ont été ajoutés avec ECMAScript-262 v5. Donc, si un navigateur n'est pas compatible v5, vous ne pouvez tout simplement pas vous attendre à être capable de gérer les formats ISO 8601.

Les navigateurs non compatibles avec la v5 peuvent utiliser les formats de date spécifiques à l'implémentation qu'ils souhaitent. La plupart d'entre eux prennent au moins en charge les formats de date RFC822 / RFC112 . Exemple:

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

Microsoft Sharepoint 2013 utilise également une notation différente, par exemple "2013-04-30T22: 00: 00Z"

Si vous souhaitez utiliser les services REST de sharepoint 2013 en combinaison avec Internet Explorer 8 (IE8), la solution de ckozl ne fonctionne PAS. Vous obtiendrez le NaN

changez la ligne d'expression régulière À:

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

cela rendra le bit de microsecondes facultatif!

cheerio, Leo

0
leo