Perché Date.parse dà risultati errati?

Caso uno:

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

Output:

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

Caso due:

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

Output:

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

Traduzione: "Il mio nome e il mio cognome";

Perché il secondo parse non è corretto?

Soluzione

Fino all'uscita delle specifiche della quinta edizione, il metodo Date.parse era completamente dipendente dall'implementazione (new Date(string) è equivalente a Date.parse(string) eccetto che quest'ultimo restituisce un numero piuttosto che una Date). Nella specifica della quinta edizione è stato aggiunto il requisito di supportare un semplificato (e leggermente errato) ISO-8601 (vedi anche Quali sono le stringhe data-ora valide in JavaScript?. Ma a parte questo, non c'era nessun requisito per ciò che Date.parse / new Date(string) doveva accettare oltre al fatto che dovevano accettare qualsiasi output Date#toString (senza dire quale fosse).

A partire da ECMAScript 2017 (edizione 8), le implementazioni erano tenute ad analizzare il loro output per Date#toString e Date#toUTCString, ma il formato di queste stringhe non era specificato.

A partire da ECMAScript 2019 (edizione 9) il formato per Date#toString e Date#toUTCString, sono stati specificati come (rispettivamente):

  1. ddd MMM DD YYYY HH:mm:ss ZZ [(nome del fuso orario)]
    es. Tue Jul 10 2018 18:39:58 GMT+0530 (IST)
  2. ddd, DD MMM YYYY HH:mm:ss Z
    es. Tue 10 Jul 2018 13:09:58 GMT

fornendo altri 2 formati che Date.parse dovrebbe analizzare in modo affidabile nelle nuove implementazioni (notando che il supporto non è onnipresente e le implementazioni non conformi rimarranno in uso per qualche tempo).

Raccomanderei che le stringhe di date siano analizzate manualmente e che il Date constructor sia usato con gli argomenti anno, mese e giorno per evitare ambiguità:

// 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
}
Commentari (8)

C'è un po' di metodo nella follia. Come regola generale, se un browser può interpretare una data come ISO-8601, lo farà. "2005-07-08" rientra in questo campo, e quindi viene analizzato come UTC. "8 luglio 2005" non può, e quindi viene analizzato nell'ora locale.

Vedere JavaScript and Dates, What a Mess! per saperne di più.

Commentari (1)

Mentre CMS è corretto che passare stringhe nel metodo parse è generalmente non sicuro, la nuova specifica ECMA-262 5th Edition (aka ES5) nella sezione 15.9.4.2 suggerisce che Date.parse() dovrebbe effettivamente gestire le date formattate ISO. La vecchia specifica non aveva questa pretesa. Naturalmente, i vecchi browser e alcuni browser attuali ancora non forniscono questa funzionalità ES5.

Il tuo secondo esempio non è sbagliato. È la data specificata in UTC, come sottinteso da Date.prototype.toISOString(), ma è rappresentata nel tuo fuso orario locale.

Commentari (2)