¿Es el objeto de fecha Javascript siempre un día libre?

238

En mi aplicación Java Script tengo la fecha almacenada en un formato como este:

2011-09-24

Ahora, cuando trato de usar el valor anterior para crear un nuevo objeto Fecha (para poder recuperar la fecha en un formato diferente), la fecha siempre regresa un día libre. Vea abajo:

var doo = new Date("2011-09-24");
console.log(doo);

registros:

Fri Sep 23 2011 20:00:00 GMT-0400 (Eastern Daylight Time)
levi
fuente
11
La clase Fecha de Javascript no representa una fecha, representa una marca de tiempo (lo mismo en Java). Para que sea una fecha, utiliza una zona horaria y esa es la causa de su problema. Lo analiza con la zona horaria GMT / UTC (24 de septiembre de 2011, 00 : 00 UTC) y luego lo genera con una zona horaria diferente de 4 horas (23 de septiembre de 2011, 20 : 00 GMT-0400).
Codo
2
Obtengo "fecha inválida". Reemplace los caracteres '-' con los caracteres '/' e intente nuevamente. O divida la fecha en sus bits y configure los componentes individualmente (si lo hace, reste 1 del número del mes).
RobG
@Codo: sí, buena respuesta. Se aplica ECMA-262 15.9.1.15. El OP debe usar "2011-09-24T20: 00: 00-04: 00" o similar.
RobG
1
Descubrí que el formato "24 de septiembre de 2011" devolverá la fecha correcta. Consulte aquí para obtener una explicación: stackoverflow.com/questions/2587345/javascript-date-parse
christurnerio

Respuestas:

98

Observe que es el horario de verano del este -4 hoursy que las horas en la fecha en que regresará son 20.

20h + 4h = 24h

que es la medianoche del 2011-09-24. La fecha se analizó en UTC (GMT) porque proporcionó una cadena de solo fecha sin ningún indicador de zona horaria. Si hubiera dado una cadena de fecha / hora sin un indicador en su lugar ( new Date("2011-09-24T00:00:00")), se habría analizado en su zona horaria local. (Históricamente ha habido inconsistencias allí, sobre todo porque la especificación cambió más de una vez, pero los navegadores modernos deberían estar bien; o siempre puede incluir un indicador de zona horaria).

Está obteniendo la fecha correcta, nunca especificó la zona horaria correcta.

Si necesita acceder a los valores de fecha, puede usar getUTCDate()o cualquiera de las otras getUTC*()funciones :

var d,
    days;
d = new Date('2011-09-24');
days = ['Sun', 'Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat'];
console.log(days[d.getUTCDay()]);
zzzzBov
fuente
24
¿Cómo se "especifica la zona horaria correcta"? El constructor de fecha siempre interpreta la cadena de fecha como UTC, pero luego la ajusta para la zona horaria. Incluso puedo hacer `nueva fecha ('2012-01-02 EDT') y aún así volver al día anterior debido a la aplicación de la compensación para el horario de verano, lo que no tiene sentido porque si te dijera que esa es la fecha según la zona horaria local actual de EDT, luego no aplique una compensación adicional. Le dije que la zona horaria era EDT, pero aún aplica un desplazamiento adicional que la mueve un día.
AaronLS
1
@AaronLS, EDTes el horario de verano (también conocido como horario de verano) , ESTes la zona horaria que se aplica en enero.
zzzzBov
1
Lo que me gustaría hacer sería crearlo solo como UTC a partir de una cadena, de ahí que pregunte "¿Cómo" especifica la zona horaria correcta? con respecto a dónde declaró "simplemente nunca especificó la zona horaria correcta". Si lo hago new Date('2012-01-01 GMT'), todavía aplica un desplazamiento, ya que lo convierte a la fecha y hora local del usuario.
AaronLS
77
@AaronLS, si se ve obligado a utilizar los get*métodos y necesita que devuelva la fecha / hora correcta, incluido el desplazamiento de zona horaria desconocida, simplemente agregue el desplazamiento de zona horaria desconocida: d = new Date('2013-01-08 GMT'); d.setMinutes(d.getMinutes() + d.getTimezoneOffset());esto normalizará la fecha a la ubicación del usuario para que los .get*métodos vuelvan El valor esperado. Los .getUTC*métodos serán incorrectos, así que tenga cuidado.
zzzzBov
1
Hay una diferencia entre definir el comportamiento para proporcionar una referencia y usarlo como un escape cuando los implementadores no pudieron implementar algo correctamente. Y es que no la misma representación si los datos no se alinea con las expectativas.
Rabia disidente
252

Hay varias cosas locas que suceden con un objeto JS DATE que convierte cadenas, por ejemplo, considere la siguiente fecha que proporcionó

Nota: Los siguientes ejemplos pueden o no ser UN DÍA DE DESCUENTO dependiendo de SU zona horaria y hora actual.

new Date("2011-09-24"); // Year-Month-Day
// => Fri Sep 23 2011 17:00:00 GMT-0700 (MST) - ONE DAY OFF.

Sin embargo, si reorganizamos el formato de cadena a Mes-Día-Año ...

new Date("09-24-2011");
=> // Sat Sep 24 2011 00:00:00 GMT-0700 (MST) - CORRECT DATE.

Otro extraño

new Date("2011-09-24");
// => Fri Sep 23 2011 17:00:00 GMT-0700 (MST) - ONE DAY OFF AS BEFORE.

new Date("2011/09/24"); // change from "-" to "/".
=> // Sat Sep 24 2011 00:00:00 GMT-0700 (MST) - CORRECT DATE.

Podríamos cambiar fácilmente los guiones en su fecha "2011-09-24" al hacer una nueva fecha

new Date("2011-09-24".replace(/-/g, '\/')); // => "2011/09/24".
=> // Sat Sep 24 2011 00:00:00 GMT-0700 (MST) - CORRECT DATE.

¿Qué pasaría si tuviéramos una cadena de fecha como "2011-09-24T00: 00: 00"?

new Date("2011-09-24T00:00:00");
// => Fri Sep 23 2011 17:00:00 GMT-0700 (MST) - ONE DAY OFF.

Ahora cambie el guión a barra diagonal como antes; ¿lo que pasa?

new Date("2011/09/24T00:00:00");
// => Invalid Date

Normalmente tengo que administrar el formato de fecha 2011-09-24T00: 00: 00, así que esto es lo que hago.

new Date("2011-09-24T00:00:00".replace(/-/g, '\/').replace(/T.+/, ''));
// => Sat Sep 24 2011 00:00:00 GMT-0700 (MST) - CORRECT DATE.

ACTUALIZAR

Si proporciona argumentos separados para el constructor Fecha, puede obtener otras salidas útiles como se describe a continuación

Nota: los argumentos pueden ser de tipo Número o Cadena. Mostraré ejemplos con valores mixtos.

Obtenga el primer mes y día de un año determinado

new Date(2011, 0); // Normal behavior as months in this case are zero based.
=> // Sat Jan 01 2011 00:00:00 GMT-0700 (MST)

Obtenga el último mes y día del año

new Date((2011 + 1), 0, 0); // The second zero roles back one day into the previous month's last day.
=> // Sat Dec 31 2011 00:00:00 GMT-0700 (MST)

Ejemplo de número, argumentos de cadena. Tenga en cuenta que el mes es marzo porque de nuevo los meses basados ​​en cero.

new Date(2011, "02"); 
=> // Tue Mar 01 2011 00:00:00 GMT-0700 (MST)

Si hacemos lo mismo pero con un día de cero, obtenemos algo diferente.

new Date(2011, "02", 0); // again the zero roles back from March to the last day of February.
=> // Mon Feb 28 2011 00:00:00 GMT-0700 (MST)

Agregar un día cero a cualquier argumento de año y mes obtendrá el último día del mes anterior. Si continúa con números negativos, puede continuar retrocediendo otro día

new Date(2011, "02", -1);
=> // Sun Feb 27 2011 00:00:00 GMT-0700 (MST)
SoEzPz
fuente
12
Esto realmente me ayudó lo mejor. Acabo de agregar .replace (/ - / g, '\ /'). Replace (/ T. + /, '') Al final de mis datos cuando hice una nueva fecha. ¡Muy facil!
Devin Prejean
64
Wow: javascript es terriblemente inconsistente.
psparrow
2
Las llamadas .replace () realmente ayudaron esta noche.
desuso el
2
Sí, he probado todo esto, y es realmente extraño.
chintan adatiya
27
Todo esto se debe al comportamiento del Date.parse () subyacente que intenta seguir ISO 8601. Cuando la cadena de fecha sigue el formato aaaa-mm-dd, se supone que es ISO 8601 con UTC 00:00 implícito. Cuando la cadena se desvía del formato (por ejemplo, mm-dd-aaaa o barra inclinada en lugar de guión), vuelve al analizador más flexible de acuerdo con RFC 2822, que utiliza la hora local cuando la zona horaria está ausente. Es cierto que todo esto será bastante arcano para una persona promedio.
Mizstik
71

Para normalizar la fecha y eliminar el desplazamiento no deseado (probado aquí: https://jsfiddle.net/7xp1xL5m/ ):

var doo = new Date("2011-09-24");
console.log(  new Date( doo.getTime() + Math.abs(doo.getTimezoneOffset()*60000) )  );
// Output: Sat Sep 24 2011 00:00:00 GMT-0400 (Eastern Daylight Time)

Esto también logra lo mismo y el crédito a @tpartee (probado aquí: https://jsfiddle.net/7xp1xL5m/1/ ):

var doo = new Date("2011-09-24");
console.log( new Date( doo.getTime() - doo.getTimezoneOffset() * -60000 )  );
AaronLS
fuente
Esto lo hizo por mí: tuve que trabajar con fechas de una API y luego ordenarlas / compararlas, por lo que simplemente agregar el desplazamiento de zona horaria funciona mejor.
chakeda
Esto funcionó para mí, excepto que tuve que restar el timeZoneOffset, no agregarlo
ErikAGriffin
@ErikAGriffin ¿Está en una zona horaria positiva, IE GMT + 0X00 en lugar de GMT-0X00?
AaronLS
Hice algo similar:doo.setMinutes(doo.getMinutes() + doo.getTimezoneOffset())
Dissident Rage
2
@AaronLS Estabas en el camino correcto pero con una lógica ligeramente incorrecta. Para compensar el desplazamiento de TZ, la lógica correcta es: console.log (new Date (doo.getTime () - doo.getTimezoneOffset () * -60000)); - El signo del desplazamiento es importante y no se puede eliminar por completo, pero también necesita el signo inverso para la corrección, por lo que multiplicamos el desplazamiento por -60000 para que se aplique el signo inverso.
tpartee
28

Si desea obtener la hora 0 de alguna fecha en la zona horaria local, pase las partes de la fecha individual al Dateconstructor.

new Date(2011,08,24); // month value is 0 based, others are 1 based.
Lincoln
fuente
26

Solo quiero agregar que aparentemente agregar un espacio al final de la cadena usará UTC para la creación.

new Date("2016-07-06")
> Tue Jul 05 2016 17:00:00 GMT-0700 (Pacific Daylight Time)

new Date("2016-07-06 ")
> Wed Jul 06 2016 00:00:00 GMT-0700 (Pacific Daylight Time)

Editar: Esta no es una solución recomendada, solo una respuesta alternativa. No utilice este enfoque, ya que no está muy claro lo que está sucediendo. Hay varias formas en que alguien podría refactorizar esto causando accidentalmente un error.

Kyle Shrader
fuente
Para el ejemplo con el espacio al final, la consola devuelve "Fecha inválida = $ 2"
Brian Risk
1
funciona muy bien! nueva Fecha (data.Date + "") .toLocaleDateString ("en-US")
Nakres
Para ser justos, esta fue solo una respuesta alternativa, y no es una solución recomendada.
Kyle Shrader
25

Creo que tiene que ver con el ajuste de la zona horaria. La fecha que ha creado está en GMT y la hora predeterminada es medianoche, pero su zona horaria es EDT, por lo que resta 4 horas. Prueba esto para verificar:

var doo = new Date("2011-09-25 EDT");
PescadoCanasta
fuente
3
Esta es la mejor respuesta aquí. + 1 millón para usar las cadenas de localización de zona horaria incorporadas en lugar de convertir mediante programación.
blearn
2
Este ayuda. Funciona así: $ scope.dat = new Date (datetring + 'EDT'). Sin embargo
tenga en
No sé qué sucede detrás de escena, pero funciona perfectamente.
the_haystacker
Esto diría que es la respuesta más simplista y menos reformateo de código.
Michael
Gracias, considero la mejor manera para mí.
Janderson Constantino
11

Su problema es específicamente con la zona horaria. Nota GMT-0400: es decir, estás 4 horas detrás de GMT. Si agrega 4 horas a la fecha / hora mostrada, obtendrá exactamente la medianoche del 24/09/2011. Utilice el toUTCString()método en su lugar para obtener la cadena GMT:

var doo = new Date("2011-09-24");
console.log(doo.toUTCString());
Aleks G
fuente
7

Probablemente esta no sea una buena respuesta, pero solo quiero compartir mi experiencia con este problema.

Mi aplicación usa globalmente utc date con el formato 'AAAA-MM-DD', mientras que el plugin datepicker que uso solo acepta js date, es difícil para mí considerar utc y js. Entonces, cuando quiero pasar una fecha con formato 'AAAA-MM-DD' a mi selector de fechas, primero la convierto al formato 'MM / DD / AAAA' usando moment.js o lo que desee, y la fecha se muestra en datepicker ahora correcto. Por su ejemplo

var d = new Date('2011-09-24'); // d will be 'Fri Sep 23 2011 20:00:00 GMT-0400 (EDT)' for my lacale
var d1 = new Date('09/24/2011'); // d1 will be 'Sat Sep 24 2011 00:00:00 GMT-0400 (EDT)' for my lacale

Al parecer, d1 es lo que quiero. Espero que esto sea útil para algunas personas.

Jie Zhang
fuente
1
Solo cambiar los formatos como lo hiciste, funcionó igual para mí. Tan raro.
jAC
5

Esto a través de mí para un bucle, +1 en la respuesta de zzzBov. Aquí hay una conversión completa de una fecha que funcionó para mí usando los métodos UTC:

//myMeeting.MeetingDate = '2015-01-30T00:00:00'

var myDate = new Date(myMeeting.MeetingDate);
//convert to JavaScript date format
//returns date of 'Thu Jan 29 2015 19:00:00 GMT-0500 (Eastern Standard Time)' <-- One Day Off!

myDate = new Date(myDate.getUTCFullYear(), myDate.getUTCMonth(), myDate.getUTCDate());
//returns date of 'Fri Jan 30 2015 00:00:00 GMT-0500 (Eastern Standard Time)' <-- Correct Date!
cmartin
fuente
4

Significa 2011-09-24 00:00:00 GMT, y ya que estás en GMT -4, será 20:00el día anterior.

Personalmente, entiendo 2011-09-24 02:00:00, porque estoy viviendo en GMT +2.

pimvdb
fuente
3

Aunque en el caso del OP la zona horaria es EDT, no hay garantía de que el usuario que ejecuta su script esté en la zona horaria EDT, por lo que codificar el desplazamiento no necesariamente funcionará. La solución que encontré divide la cadena de fecha y usa los valores separados en el constructor de fecha.

var dateString = "2011-09-24";
var dateParts = dateString.split("-");
var date = new Date(dateParts[0], dateParts[1] - 1, dateParts[2]);

Tenga en cuenta que debe tener en cuenta otra parte de la rareza de JS: el mes está basado en cero.

Brian Risk
fuente
2

Encontré este problema exacto donde mi cliente estaba en hora estándar del Atlántico. El valor de la fecha que el cliente recuperó fue "2018-11-23" y cuando el código lo pasó a new Date("2018-11-23")la salida para el cliente fue para el día anterior. Creé una función de utilidad como se muestra en el fragmento que normalizó la fecha, dando al cliente la fecha esperada.

date.setMinutes(date.getMinutes() + date.getTimezoneOffset());

var normalizeDate = function(date) {
  date.setMinutes(date.getMinutes() + date.getTimezoneOffset());
  return date;
};

var date = new Date("2018-11-23");

document.getElementById("default").textContent = date;
document.getElementById("normalized").textContent = normalizeDate(date);
<h2>Calling new Date("2018-11-23")</h2>
<div>
  <label><b>Default</b> : </label>
  <span id="default"></span>
</div>
<hr>
<div>
  <label><b>Normalized</b> : </label>
  <span id="normalized"></span>
</div>

Gabriel Gates
fuente
2

si solo está buscando asegurarse de que las partes individuales de la fecha se mantengan igual para fines de visualización, * esto parece funcionar, incluso cuando cambio mi zona horaria:

var doo = new Date("2011-09-24 00:00:00")

simplemente agregue los ceros allí.

En mi código hago esto:

let dateForDisplayToUser = 
  new Date( `${YYYYMMDDdateStringSeparatedByHyphensFromAPI} 00:00:00` )
  .toLocaleDateString( 
    'en-GB', 
    { day: 'numeric', month: 'short', year: 'numeric' }
  )

Y cambio mi zona horaria en mi computadora y la fecha sigue siendo la misma que la cadena de fecha aaaa-mm-dd que obtengo de la API.

Pero me estoy perdiendo algo / ¿es una mala idea?

* al menos en cromo. ¡Esto no funciona en Safari! a partir de este escrito

Timothy Mitchell
fuente
Cuando lo haces .toISOString(), vuelve 1 día atrás.
vivek_23
new Date('2019/11/18 05:30:00').toISOString();funcionó para mí
vivek_23 12/12/19
1

La mejor manera de manejar esto sin usar más métodos de conversión,

 var mydate='2016,3,3';
 var utcDate = Date.parse(mydate);
 console.log(" You're getting back are 20.  20h + 4h = 24h :: "+utcDate);

Ahora solo agregue GMT en su fecha o puede agregarlo.

 var  mydateNew='2016,3,3'+ 'GMT';
 var utcDateNew = Date.parse(mydateNew);
 console.log("the right time that you want:"+utcDateNew)

Live: https://jsfiddle.net/gajender/2kop9vrk/1/

Gajender Singh
fuente
1

Me enfrenté a un problema como este. Pero mi problema fue el conjunto al obtener la fecha de la base de datos.

esto se almacena en la base de datos y está en formato UTC.

2019-03-29 19: 00: 00.0000000 +00: 00

Entonces, cuando llego de la base de datos y verifico la fecha, agrega un desplazamiento con ella y la envío de vuelta a JavaScript.

ingrese la descripción de la imagen aquí

Está agregando +05: 00 porque esta es la zona horaria de mi servidor. Mi cliente está en una zona horaria diferente +07: 00.

2019-03-28T19: 00: 00 + 05: 00 // esto es lo que obtengo en javascript.

Así que aquí está mi solución, lo que hago con este problema.

var dates = price.deliveryDate.split(/-|T|:/);
var expDate = new Date(dates[0], dates[1] - 1, dates[2], dates[3], dates[4]);
var expirationDate = new Date(expDate);

Entonces, cuando la fecha proviene del servidor y tiene un desplazamiento del servidor, así que divido la fecha y elimino el desplazamiento del servidor y luego lo convierto en fecha. Resuelve mi problema.

Uxmaan Ali
fuente
1

si necesita una solución simple para esto, vea:

new Date('1993-01-20'.split('-')); 

ingrese la descripción de la imagen aquí

Sebastiao Marcos
fuente
0

Está utilizando el formato de cadena de fecha ISO que, de acuerdo con esta página , hace que la fecha se construya utilizando la zona horaria UTC:

Nota: no se recomienda analizar las cadenas de fecha con el constructor Fecha (y Date.parse, son equivalentes) debido a las diferencias e inconsistencias del navegador. El soporte para cadenas de formato RFC 2822 es solo por convención. La compatibilidad con los formatos ISO 8601 difiere en que las cadenas de solo fecha (por ejemplo, "1970-01-01") se tratan como UTC, no locales.

Si formatea el texto de manera diferente, por ejemplo "Jan 01 1970", (al menos en mi máquina) usa su zona horaria local.

Paul Wintz
fuente
0

Intentando agregar mis 2 centavos a este hilo (elaborando sobre la respuesta de @ paul-wintz).

Me parece que cuando el constructor de fecha recibe una cadena que coincide con la primera parte del formato ISO 8601 (parte de fecha), realiza una conversión de fecha precisa en la zona horaria UTC con 0 hora. Cuando esa fecha se convierte a la hora local, puede ocurrir un cambio de fecha si la medianoche UTC es una fecha anterior en la zona horaria local.

new Date('2020-05-07')
Wed May 06 2020 20:00:00 GMT-0400 (Eastern Daylight Time)

Si la cadena de fecha está en cualquier otro formato "más flexible" (usa "/" o la fecha / mes no está rellenada con cero), crea la fecha en la zona horaria local, por lo que no hay problema de cambio de fecha.

new Date('2020/05/07')
Thu May 07 2020 00:00:00 GMT-0400 (Eastern Daylight Time)
new Date('2020-5-07')
Thu May 07 2020 00:00:00 GMT-0400 (Eastern Daylight Time)
new Date('2020-5-7')
Thu May 07 2020 00:00:00 GMT-0400 (Eastern Daylight Time)
new Date('2020-05-7')
Thu May 07 2020 00:00:00 GMT-0400 (Eastern Daylight Time)

Entonces, una solución rápida, como se mencionó anteriormente, es reemplazar "-" con "/" en su cadena de fecha con formato ISO solamente.

new Date('2020-05-07'.replace('-','/'))
Thu May 07 2020 00:00:00 GMT-0400 (Eastern Daylight Time)
Florin D
fuente
0

Para almacenar yyyy-mm-dden formato de fecha MySql, debe hacer lo siguiente:

const newDate = new Date( yourDate.getTime() + Math.abs(yourDate.getTimezoneOffset()*60000) );
console.log(newDate.toJSON().slice(0, 10)); // yyyy-mm-dd
Paulo Henrique Guimarães
fuente
-1

Su registro genera GMT, por lo que desea especificar su zona horaria:

var doo = new Date("2011-09-24 EST");
bmacx7
fuente
3
Esta pregunta ya tiene muchas respuestas. Si de todos modos quiere responder la pregunta, debe mencionar algo nuevo que las otras respuestas no. La respuesta principal ya explica el problema con la zona horaria con mucho mayor detalle.
Calvin Godfrey el
Esta respuesta es casi exactamente la misma que stackoverflow.com/a/7556642/8828658
un arácnido de piedra el
A quién le importa si su explicación es más profunda ... su código sigue siendo diferente al mío. La mía es mucho más simple. Y sí, arácnido de piedra, tienes razón. Culpa mía.
bmacx7
-3

no importa, no noté el GMT -0400, que hace que la fecha sea ayer

Puede intentar establecer un "tiempo" predeterminado para que sea 12:00:00

ChrisH
fuente
Sí, fui un poco rápido con mi respuesta, lo siento. Revisé mi respuesta.
ChrisH
-3

Lo siguiente funcionó para mí:

    var doo = new Date("2011-09-24").format("m/d/yyyy");
Venu
fuente
Todavía no funcionará mientras no juegues con la zona horaria.
Gar