new Date () establecido en 31 de diciembre de 2014 dice 1 de diciembre en su lugar

80

Estoy tratando de convertir una cadena en un objeto Date, y funciona todos los días excepto el 31 de diciembre, donde el objeto dice 1 de diciembre en lugar de 31. No tengo ni idea de porqué. Aquí está mi JavaScriptcódigo:

var dt = new Date();
dt.setDate("31");
dt.setMonth("11");
dt.setFullYear("2014");

pero mi valor de variable es:

Mon Dec 01 2014 11:48:08 GMT+0100 (Paris, Madrid)

Si hago lo mismo para cualquier otra fecha, mi objeto vuelve al valor apropiado. ¿Tienes idea de lo que hice mal?

usuario2859409
fuente
7
Debe pasar enteros a setMonth, etc., no cadenas.
Funkybro
15
puede usar los Dateparámetros del constructor directamente:new Date(2014, 11, 31)
pomeh
9
por cierto. no es el 11 mes de noviembre?
jnovacho
5
@JuhaUntinen No, la fecha está confusa porque el mes en este momento tiene solo 30 días.
Mr Lister

Respuestas:

85

setMonth debería antes setDate: ( no es seguro durante meses inferiores a 31 días )

var dt = new Date();
dt.setFullYear(2014);
dt.setMonth(11);
dt.setDate(31);

setMonthEl segundo parámetro de And también se puede utilizar para establecer la fecha.

var dt = new Date();
dt.setFullYear(2014);
dt.setMonth(11, 31);


Si no se proporcionan argumentos para el constructor, utilizará la fecha y hora actuales de acuerdo con la configuración del sistema.

Entonces, usar setMonthy por setDateseparado aún causaría un resultado inesperado.

Si los valores establecidos son mayores que su rango lógico , el valor se ajustará automáticamente al valor adyacente .

Por ejemplo, si hoy es 2014-09-30, entonces

var dt = new Date();
dt.setFullYear(2014); /* Sep 30 2014 */
dt.setMonth(1);       /* Mar 02 2014, see, here the auto adjustment occurs! */
dt.setDate(28);       /* Mar 28 2014 */

Para evitar esto, establezca los valores usando el constructor directamente.

var dt = new Date(2014, 11, 31);
xdazz
fuente
1
Lo acabo de descubrir, de hecho, pero realmente no tiene sentido para mí
user2859409
15
@ user2859409 probablemente se deba a que si no configura el mes primero, toma el mes actual y luego, a veces, puede ajustarse al mes siguiente (según la respuesta de Jakub a continuación)
fbstj
3
Dudaría en recomendar ese primer bloque de código durante meses con menos de 31 días. Si, por ejemplo, desea establecer la fecha en el 15 de septiembre, pero hoy es el 31 de agosto, la fecha pasará al siguiente mes y terminará en el 15 de octubre. +1 para el segundo bloque de código: ese es el mejor manera de hacerlo. Ni siquiera sabía que setMonthexistía la forma de 2 argumentos .
Luke Woodward
10
Tenga en cuenta que la configuración del mes anterior al día también puede ser incorrecta. Sin embargo, no en este caso. Si es el 31 de octubre, setMonth (10) establecerá la fecha en el 31 de noviembre, que se ajustará al 1 de diciembre. SetDate (31) y luego resultará en el 31 de diciembre. Por lo tanto, siempre use el setMonth () de 2 argumentos.
Florian F
1
+1 pero me gustaría enfatizar que se prefiere la opción de dos meses para prevenir efectos secundarios.
Brian
120

La cuestión es que, cuando estableces un día primero, todavía estás en el mes actual, es decir, septiembre. Septiembre tiene solo 30 días, así que:

var dt = new Date(); /* today */
dt.setDate("31"); /* 1st Oct 2014 as should be by spec */
dt.setMonth("11"); /* 1st Dec 2014 */
dt.setFullYear("2014"); /* 1st Dec 2014 */
Jakub Michálek
fuente
22
+1 - Este es el tipo de error que permanecerá inactivo durante todo agosto y luego te morderá en el trasero en septiembre;)
Niet the Dark Absol
19
NUNCA es correcto establecer una fecha de un componente a la vez, ya que hay casos de falla con el día primero y el mes primero, y posiblemente con el año primero el 29/2. Debe configurar los tres campos al mismo tiempo.
Jim Garrison
5
+1 y debería ser una respuesta aceptada, porque explica POR QUÉ debería establecer el mes primero. Es un WTF muy javascript
Marinero danubiano
2
Debería ser similar en otros idiomas, por lo que no es un "javascript WTF".
Raidri apoya a Monica
¿Por qué el objeto Fecha no se lanza cuando se establece una fecha incorrecta?
jww
23

Es porque lo primero que haces es

dt.setDate(31)

Esto establece la fecha actual en 31. El mes actual es septiembre, que tiene 30 días, por lo que lo está cerrando.

Si imprimiera la fecha después de este punto, diría 1 de octubre.

funkybro
fuente
12
Lo curioso es que esto solo apareció porque lo probó durante un mes con 30 días. Un mes después y parecía haber funcionado bien.
Peter Remmers
13

Suponiendo que su intención es establecer el año, el mes y la fecha simultáneamente, podría usar el constructor de fecha más larga :

nueva fecha (año, mes, día, hora, minuto, segundo, milisegundo);

[...]

Si se proporcionan al menos dos argumentos, los argumentos faltantes se establecen en 1 (si falta el día) o 0 para todos los demás.

Entonces escribirías:

var dt = new Date(2014, 11, 31);

Como ya se estableció, establecer una parte de la fecha a la vez puede provocar desbordamientos:

var dt = new Date(2012, 1, 29); // Feb 29 2012
dt.setFullYear(2014);           // Mar 01 2014 instead of Feb 28 2014

Además, configurar el mes antes de la fecha aún puede causar un desbordamiento inesperado (las respuestas que recomiendan cambiar el orden de los métodos son incorrectas):

var dt = new Date(2014, 0, 31); // Jan 31 2014
dt.setFullYear(2014);           // Jan 31 2014
dt.setMonth(1);                 // Mar 03 2014 instead of Feb 28 2014
dt.setDate(1);                  // Mar 01 2014
Salman A
fuente
me gusta esta respuesta, porque le da la solución correcta en la parte superior, luego explica por qué la solución rota no funciona ...
Kip
7

Se ha explicado ampliamente el por qué de la conducta y cómo evitarla.

Pero el verdadero error en su código es que no debe usar el constructor predeterminado: new Date (). Su código resultará en una fecha el 13 de diciembre con la hora actual. Dudo que esto sea lo que quieres. Debe usar el constructor de fecha que toma año, mes y día como parámetros.

Florian F
fuente
1
¿Supongo que pretendía ser el comentario sobre la respuesta aceptada?
Marinero del Danubio
Realmente no. Es una respuesta a la pregunta "¿Qué hice mal?"
Florian F
-1

Las respuestas dejaron en claro que el orden correcto para establecer la fecha es:

  • setFullYear ()
  • setMonth ()
  • Establece la fecha()

Solo quiero señalar que también es importante fijar el año en un principio, porque el 29 de febrero en años bisiestos.

Henman
fuente
1
No. El pedido no garantiza que la fecha se establezca correctamente. Vea los comentarios debajo de las respuestas aceptadas y más votadas.
Salman A
1
Si su fecha de inicio es el 31 y la establece en un mes con menos (como 30) días, terminará en el próximo mes. Entonces esto simplemente no es suficiente. Para estar seguro, debe establecer la fecha en un valor no superior a 28 antes de establecer el mes. Y finalmente establezca la fecha nuevamente a su valor final, si es mayor.
Bart
-3
var dt = new Date();
dt.setFullYear(2014);
dt.setMonth(11);
dt.setDate(31);

Pasa el valor como entero, no como cadena ... devolverá el valor correcto ...


Actualización : la descripción anterior no es correcta ... el problema principal era que necesitabas poner estas tres líneas en la secuencia adecuada ... Incluso después de corregir la secuencia, olvidé corregir la descripción ...: P

Deepak Sharma
fuente
No, no es así, aquí está mi prueba en la consola de Chrome: var dt = new Date (); indefinido dt.setDate (31); 1412157761255 dt.setMonth (11); 1417431761255 dt.setFullYear (2014); 1417431761255 dt Lun 01 de diciembre de 2014 12:02:41 GMT + 0100 (París, Madrid)
user2859409
6
No tiene nada que ver con el tipo de argumento y todo que ver con la secuencia. Estás mencionando la secuencia como si fuera algo secundario ...
dee-see
1
Si bien ese código funciona , ha dado una explicación incorrecta , por qué.
Marinero del Danubio