¿Por qué Date.parse da resultados incorrectos?

Caso Uno:

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

Output:

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

Caso 2:

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

Output:

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


¿Por qué el segundo parse es incorrecto?

Solución

Hasta la aparición de la 5ª edición de la especificación, el método Date.parse era completamente dependiente de la implementación (new Date(string) es equivalente a Date.parse(string) excepto que este último devuelve un número en lugar de una Date). En la 5ª edición de la especificación se añadió el requisito de soportar una ISO-8601 simplificada (y ligeramente incorrecta) (ver también ¿Qué son las cadenas de fecha y hora válidas en JavaScript?). Pero aparte de eso, no había ningún requisito sobre lo que Date.parse / new Date(string) debía aceptar, aparte de que tenían que aceptar cualquier salida de Date#toString (sin decir cuál era).

A partir de ECMAScript 2017 (edición 8), las implementaciones debían analizar su salida para Date#toString y Date#toUTCString, pero no se especificaba el formato de esas cadenas.

A partir de ECMAScript 2019 (edición 9) el formato para Date#toString y Date#toUTCString, se ha especificado como (respectivamente):

  1. ddd MMM DD YYYY HH:mm:ss ZZ [(nombre de la zona horaria)]
    por ejemplo, Tue Jul 10 2018 18:39:58 GMT+0530 (IST)
  2. ddd, DD MMM YYYY HH:mm:ss Z
    e.g. Tue 10 Jul 2018 13:09:58 GMT

proporcionando 2 formatos más que Date.parse debería analizar de forma fiable en las nuevas implementaciones (teniendo en cuenta que el soporte no es omnipresente y que las implementaciones no conformes seguirán en uso durante algún tiempo).

Yo recomendaría que las cadenas de fecha se analicen manualmente y que se utilice el constructor de fecha con argumentos de año, mes y día para evitar ambigüedades:

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

Hay algo de método en esta locura. Como regla general, si un navegador puede interpretar una fecha como ISO-8601, lo hará. "2005-07-08" cae en este campo, y por lo tanto se analiza como UTC. "8 de julio de 2005" no puede, y por lo tanto se analiza en la hora local.

Véase JavaScript y las fechas, ¡qué lío! para más información.

Comentarios (1)

Mientras que CMS es correcto que pasar cadenas al método parse es generalmente inseguro, la nueva especificación ECMA-262 5th Edition (también conocida como ES5) en la sección 15.9.4.2 sugiere que Date.parse() debería manejar fechas con formato ISO. La antigua especificación no hacía tal afirmación. Por supuesto, los navegadores antiguos y algunos actuales todavía no proporcionan esta funcionalidad de ES5.

Tu segundo ejemplo no es incorrecto. Es la fecha especificada en UTC, como implica Date.prototype.toISOString(), pero está representada en su zona horaria local.

Comentarios (2)