Pourquoi Date.parse donne-t-il des résultats incorrects ?

Case One :

new Date(Date.parse("Jul 8, 2005"));

Sortie :

Fri Jul 08 2005 00:00:00 GMT-0700 (PST)

Case Two :

new Date(Date.parse("2005-07-08"));

Sortie :

Thu Jul 07 2005 17:00:00 GMT-0700 (PST)


Pourquoi la deuxième analyse syntaxique est-elle incorrecte ?

Solution

Jusqu'à la sortie de la 5e édition de la spécification, la méthode Date.parse était complètement dépendante de l'implémentation (new Date(string) est équivalent à Date.parse(string) sauf que ce dernier retourne un nombre plutôt qu'une Date). Dans la 5ème édition de la spécification, la condition a été ajoutée pour supporter une [simplifiée (et légèrement incorrecte) ISO-8601][2] (voir aussi Quelles sont les chaînes de date et d'heure valides en JavaScript ?). Mais à part cela, il n'y avait aucune exigence sur ce que Date.parse / new Date(string) devait accepter, si ce n'est qu'ils devaient accepter la sortie de Date#toString (sans dire ce que c'était).

Depuis l'ECMAScript 2017 (édition 8), les implémentations doivent analyser leur sortie pour Date#toString et Date#toUTCString, mais le format de ces chaînes n'est pas précisé.

À partir de l'ECMAScript 2019 (édition 9), le format de [Date#toString][3] et de [Date#toUTCString][4], a été spécifié comme (respectivement) :

  1. ddd MMM DD YYYY HH:mm:ss ZZ [(nom du fuseau horaire)]
    par exemple Tue Jul 10 2018 18:39:58 GMT+0530 (IST)
  2. ddd, DD MMM YYYY HH:mm:ss Z
    ex. Tue 10 Jul 2018 13:09:58 GMT

fournissant 2 formats supplémentaires que Date.parse devrait analyser de manière fiable dans les nouvelles implémentations (en notant que le support n'est pas omniprésent et que les implémentations non conformes resteront utilisées pendant un certain temps).

Je recommande que les chaînes de date soient analysées manuellement et que le constructeur de date soit utilisé avec les arguments année, mois et jour pour éviter toute ambiguïté :

// parse a date in yyyy-mm-dd format
function parseDate(input) {
  var parts = input.split('-');
  // new Date(year, month [, day [, hours[, minutes[, seconds[, ms]]]]])
  return new Date(parts[0], parts[1]-1, parts[2]); // Note: months are 0-based
}

[2] : http://www.ecma-international.org/ecma-262/5.1/#sec-15.9.1.15 [3] : http://ecma-international.org/ecma-262/9.0/#sec-date.prototype.tostring [4] : http://ecma-international.org/ecma-262/9.0/#sec-date.prototype.toutcstring

Commentaires (8)

Il y a une certaine méthode dans cette folie. En règle générale, si un navigateur peut interpréter une date comme une ISO-8601, il le fera. "2005-07-08&quot ; tombe dans ce camp, et elle est donc analysée en UTC. "8 juillet 2005&quot ; ne le peut pas, et elle est donc analysée en heure locale.

Voir JavaScript and Dates, What a Mess ! pour en savoir plus.

Commentaires (1)

Bien que [CMS ait raison][1] de dire que le passage de chaînes de caractères dans la méthode parse n'est généralement pas sûr, la nouvelle spécification [ECMA-262 5e édition][2] (alias ES5) dans la section 15.9.4.2 suggère que Date.parse() devrait en fait traiter les dates au format ISO. L'ancienne spécification ne faisait pas cette affirmation. Bien sûr, les anciens navigateurs et certains navigateurs actuels ne fournissent toujours pas cette fonctionnalité ES5.

Votre deuxième exemple n&#8217est pas faux. Il s'agit de la date spécifiée en UTC, comme l'implique Date.prototype.toISOString(), mais elle est représentée dans votre fuseau horaire local.

[1] : https://stackoverflow.com/a/2587398 [2] : http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf

Commentaires (2)