Analizar fecha sin zona horaria javascript

147

Quiero analizar la fecha sin zona horaria en JavaScript. Yo he tratado:

new Date(Date.parse("2005-07-08T00:00:00+0000"));

Vuelve viernes 08 de julio de 2005 02:00:00 GMT + 0200 (horario de verano de Europa Central)

new Date(Date.parse("2005-07-08 00:00:00 GMT+0000"));

Devuelve el mismo resultado

new Date(Date.parse("2005-07-08 00:00:00 GMT-0000"));

Devuelve el mismo resultado

Quiero analizar el tiempo:

  1. Sin zona horaria.

  2. Sin llamar al constructor Date.UTC o nueva fecha (año, mes, día).

  3. Simplemente pasa una cadena al constructor de fecha (sin enfoques prototipo).

  4. Tengo que Dateobjetar producto , no String.

Athlan
fuente
3
Simplemente puede omitir el Date.parseBTW y pasar directamente la cadena al Dateconstructor.
Bergi
1
No estoy seguro de por qué necesita esto, pero estoy bastante seguro de que Date siempre tiene la zona horaria local del usuario. Si desea que su JavaScript funcione con otras zonas horarias que no sean las que tendrá que usar un objeto contenedor para Date, tal vez esto funcione para usted: github.com/mde/timezone-js
HMR
1
Desafortunadamente, tuve que copiar el Dateobjeto para obtener el objeto correcto para comparar fechas en MongoDB:new Date(dateStart.getFullYear(), dateStart.getMonth(), dateStart.getDate())
Athlan
Si desea analizar una fecha sin hora, debe especificar qué zona horaria desea asumir, porque "2005-07-08" significa cosas diferentes en diferentes zonas horarias. A partir de mayo de 2020, la documentación de MDN desaconseja cualquier función de análisis de fechas incorporada debido a las diferencias en la implementación. Sin embargo, usar Date.parse ("2005-07-08") probablemente devolverá una hora de 00:00 UTC. el análisis de fecha-fns, por otro lado, devolverá las 00:00 hora local al analizar la misma cadena de fecha
Andy

Respuestas:

106

La fecha se analiza correctamente, solo toString lo convierte a su zona horaria local:

let s = "2005-07-08T11:22:33+0000";
let d = new Date(Date.parse(s));

// this logs for me 
// "Fri Jul 08 2005 13:22:33 GMT+0200 (Central European Summer Time)" 
// and something else for you

console.log(d.toString()) 

// this logs
// Fri, 08 Jul 2005 11:22:33 GMT
// for everyone

console.log(d.toUTCString())

Los objetos de fecha de Javascript son marcas de tiempo, simplemente contienen varios milisegundos desde la época. No hay información de zona horaria en un objeto Date. La fecha del calendario (día, minutos, segundos) que representa esta marca de tiempo depende de la interpretación (uno de los to...Stringmétodos).

El ejemplo anterior muestra que la fecha se analiza correctamente, es decir, en realidad contiene una cantidad de milisegundos correspondiente a "2005-07-08T11: 22: 33" en GMT.

georg
fuente
44
Desafortunadamente, tengo que producir el objeto Date, no String.
Athlan
@Athlan: agregó algunas explicaciones.
georg
1
Lo había comprobado. He pasado la fecha analizado en consulta MongoDB new Date(Date.parse("2005-07-08T11:22:33+0000")), y la fecha copiado a través de constructor: new Date(dateStart.getFullYear(), dateStart.getMonth(), dateStart.getDate()). Ambas soluciones, resultados diferentes, segundo correcto! Su respuesta fue útil, solo mencionada en hunlock.com/blogs/Javascript_Dates-The_Complete_Reference . Arriba.
Athlan
Funcionó perfectamente para mí: .toUTCString () fue el ticket que me devolvió la hora correcta de la cadena original dada. es decir, nueva fecha ("2016-08-22T19: 45: 00.0000000"). toUTCString ()
Michael Giovanni Pumo
38
La raíz de todo mal en las fechas y la hora de JavaScript está contenida en su primera oración ... Es solo a String que lo CONVIERTE en su zona horaria local ... ¿Dónde está la responsabilidad única en esto? El método toString solo debe clasificar en cadena el resultado y no convertirlo. Si quiero convertir la fecha, debería tener otros métodos para hacerlo.
ancla
109

Tengo el mismo problema. Obtengo una fecha como String, por ejemplo: '2016-08-25T00: 00: 00', pero necesito tener un objeto Date con la hora correcta. Para convertir String en objeto, uso getTimezoneOffset:

var date = new Date('2016-08-25T00:00:00')
var userTimezoneOffset = date.getTimezoneOffset() * 60000;
new Date(date.getTime() - userTimezoneOffset);

getTimezoneOffset()devolverá el valor negativo o positivo del éter. Esto debe restarse para que funcione en todos los lugares del mundo.

wawka
fuente
66
Tengo el mismo problema y me pareció útil. Sin embargo, descubrí que esto no maneja las compensaciones de zona horaria debido al horario de verano. Ejemplo: estoy en PST, así que mi compensación actual (en marzo) de GMT es -8: 00, pero en mayo sería -7: 00. Mi solución fue calcularvar userTimezoneOffset = date.getTimezoneOffset()*60000;
mmh02
3
A menos que sea un completo idiota, esto realmente devuelve el momento equivocado. getTimezoneOffset()devuelve el número de minutos en la dirección opuesta a la que pensarías: mi zona horaria es UTC-4 en este momento pero getTimezoneOffset()devuelve un 240 positivo. Por userTimezoneOffsetlo tanto, se debe restar de él date.getTime(), no agregarlo.
vaindil
1
Estoy de acuerdo con @vaindil que debes restar. La solución de wakwa solo funciona cuando estás en el lado correcto de Greenwich. Wakwas debería corregirlo.
Janne Harju
1
Ah! habló demasiado pronto No funciona para la mayoría de las zonas horarias. Puedo confirmar que devuelve una fecha incorrecta al compensar las horas AEST y CEST con la hora GMT.
saran3h
1
@vaindil ahora el resultado es el mismo new Date('2016-08-25T00:00:00Z')que creo que el punto era manipular new Date('2016-08-25T00:00:00Z')para que la hora local se muestre con la hora 0:00 pero este código se perdióZ
barbsan
14

Me encontré con el mismo problema y luego recordé algo extraño sobre un proyecto heredado en el que estaba trabajando y cómo manejaron este problema. No lo entendí en ese momento y realmente no me importó hasta que me encontré con el problema.

var date = '2014-01-02T00:00:00.000Z'
date = date.substring(0,10).split('-')
date = date[1] + '-' + date[2] + '-' + date[0]

new Date(date) #Thu Jan 02 2014 00:00:00 GMT-0600

Por alguna razón, pasar la fecha como '01 -02-2014 'establece la zona horaria en cero e ignora la zona horaria del usuario. Esto puede ser una casualidad en la clase Fecha pero existió hace algún tiempo y existe hoy. Y parece funcionar entre navegadores. Pruébalo por ti mismo.

Este código se implementa en un proyecto global donde las zonas horarias importan mucho, pero a la persona que mira la fecha no le importa el momento exacto en que se introdujo.

Iwnnay
fuente
Creo que es intencional porque la "Z" designa UTC que JS luego convierte, pero dado que no hay zona horaria, no puede convertirlo, por lo que esencialmente asume la zona horaria del usuario. Sin embargo, me encantaría obtener alguna confirmación o una mejor explicación.
dlsso
77
El comportamiento inestable se debe a los guiones. Chrome, Firefox e IE11 interpretan 2014/5/31y 2014/05/31son sábados el 31 de mayo de 2014 00:00:00 GMT-0600 (Mountain Daylight Time) `(MDT es mi zona horaria actual). Con guiones ... todos los navegadores interpretan el 2014-05-31viernes 30 de mayo de 2014 18:00:00 GMT-0600 (Mountain Daylight Time). Curiosamente, con 2014-5-31Chrome regresa el sábado, Firefox regresa el viernes e IE11 dice que la fecha no es válida. Parece que un date.replace('-','/')poder haría el truco.
ateos
6

El Dateobjeto en sí contendrá la zona horaria de todos modos, y el resultado devuelto es el efecto de convertirlo a una cadena de forma predeterminada. Es decir, no puede crear un objeto de fecha sin zona horaria. Pero lo que puede hacer es imitar el comportamiento del Dateobjeto creando uno propio. Sin embargo, es mejor entregarlo a bibliotecas como moment.js .

mishik
fuente
2
Desafortunadamente, tengo que producir el objeto Date, no String.
Athlan
3

Solución simple

const handler1 = {
  construct(target, args) {
    let newDate = new target(...args);
    var tzDifference = newDate.getTimezoneOffset();
    return new target(newDate.getTime() + tzDifference * 60 * 1000);
  }
};

Date = new Proxy(Date, handler1);
alexey
fuente
3

La fecha en javascript es simple por dentro. entonces los datos de fecha y hora se almacenan en UTC unix epoch (milisegundos o ms).

Si desea tener una hora "fija" que no cambie en la zona horaria que se encuentre en la Tierra, puede ajustar la hora en UTC para que coincida con su zona horaria local actual y guardarla. Y cuando lo recupere, en la zona horaria local en la que se encuentre, mostrará la hora UTC ajustada según la persona que la guardó y agregará el desplazamiento de la zona horaria local para obtener la hora "fija".

Para guardar la fecha (en ms)

toUTC(datetime) {
  const myDate = (typeof datetime === 'number')
    ? new Date(datetime)
    : datetime;

  if (!myDate || (typeof myDate.getTime !== 'function')) {
    return 0;
  }

  const getUTC = myDate.getTime();
  const offset = myDate.getTimezoneOffset() * 60000; // It's in minutes so convert to ms
  return getUTC - offset; // UTC - OFFSET
}

Para recuperar / mostrar fecha (en ms)

fromUTC(datetime) {
  const myDate = (typeof datetime === 'number')
    ? new Date(datetime)
    : datetime;

  if (!myDate || (typeof myDate.getTime !== 'function')) {
    return 0;
  }

  const getUTC = myDate.getTime();
  const offset = myDate.getTimezoneOffset() * 60000; // It's in minutes so convert to ms
  return getUTC + offset; // UTC + OFFSET
}

Entonces tú puedes:

const saveTime = new Date(toUTC(Date.parse("2005-07-08T00:00:00+0000")));
// SEND TO DB....

// FROM DB...
const showTime = new Date(fromUTC(saveTime));
DRBendanillo
fuente
2

Puedes usar este código

var stringDate = "2005-07-08T00:00:00+0000";
var dTimezone = new Date();
var offset = dTimezone.getTimezoneOffset() / 60;
var date = new Date(Date.parse(stringDate));
date.setHours(date.getHours() + offset);
deype0
fuente
1
No creo que esto tenga en cuenta el horario de verano
Daniel Thompson
2

Dado que es realmente un problema de formato cuando se muestra la fecha (por ejemplo, se muestra en la hora local), me gusta usar el nuevo objeto (ish) Intl.DateTimeFormat para realizar el formateo, ya que es más explícito y proporciona más opciones de salida:

const dateOptions = { timeZone: 'UTC', month: 'long', day: 'numeric', year: 'numeric' };

const dateFormatter = new Intl.DateTimeFormat('en-US', dateOptions);
const dateAsFormattedString = dateFormatter.format(new Date('2019-06-01T00:00:00.000+00:00'));

console.log(dateAsFormattedString) // "June 1, 2019"

Como se muestra, al configurar la zona horaria en 'UTC' no realizará conversiones locales. Como beneficio adicional, también le permite crear salidas más pulidas. Puede leer más sobre el objeto Intl.DateTimeFormat de Mozilla - Intl.DateTimeFormat .

Editar:

Se puede lograr la misma funcionalidad sin crear un nuevo Intl.DateTimeFormatobjeto. Simplemente pase las opciones de configuración regional y fecha directamente a la toLocaleDateString()función.

const dateOptions = { timeZone: 'UTC', month: 'long', day: 'numeric', year: 'numeric' };
const myDate = new Date('2019-06-01T00:00:00.000+00:00');
today.toLocaleDateString('en-US', dateOptions); // "June 1, 2019"
John Galt
fuente
1

Solo una nota genérica. Una forma de mantenerlo flexible.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date

Podemos usar getMinutes (), pero solo devuelve un número durante los primeros 9 minutos.

let epoch = new Date() // Or any unix timestamp

let za = new Date(epoch),
    zaR = za.getUTCFullYear(),
    zaMth = za.getUTCMonth(),
    zaDs = za.getUTCDate(),
    zaTm = za.toTimeString().substr(0,5);

console.log(zaR +"-" + zaMth + "-" + zaDs, zaTm)

Date.prototype.getDate()
    Returns the day of the month (1-31) for the specified date according to local time.
Date.prototype.getDay()
    Returns the day of the week (0-6) for the specified date according to local time.
Date.prototype.getFullYear()
    Returns the year (4 digits for 4-digit years) of the specified date according to local time.
Date.prototype.getHours()
    Returns the hour (0-23) in the specified date according to local time.
Date.prototype.getMilliseconds()
    Returns the milliseconds (0-999) in the specified date according to local time.
Date.prototype.getMinutes()
    Returns the minutes (0-59) in the specified date according to local time.
Date.prototype.getMonth()
    Returns the month (0-11) in the specified date according to local time.
Date.prototype.getSeconds()
    Returns the seconds (0-59) in the specified date according to local time.
Date.prototype.getTime()
    Returns the numeric value of the specified date as the number of milliseconds since January 1, 1970, 00:00:00 UTC (negative for prior times).
Date.prototype.getTimezoneOffset()
    Returns the time-zone offset in minutes for the current locale.
Date.prototype.getUTCDate()
    Returns the day (date) of the month (1-31) in the specified date according to universal time.
Date.prototype.getUTCDay()
    Returns the day of the week (0-6) in the specified date according to universal time.
Date.prototype.getUTCFullYear()
    Returns the year (4 digits for 4-digit years) in the specified date according to universal time.
Date.prototype.getUTCHours()
    Returns the hours (0-23) in the specified date according to universal time.
Date.prototype.getUTCMilliseconds()
    Returns the milliseconds (0-999) in the specified date according to universal time.
Date.prototype.getUTCMinutes()
    Returns the minutes (0-59) in the specified date according to universal time.
Date.prototype.getUTCMonth()
    Returns the month (0-11) in the specified date according to universal time.
Date.prototype.getUTCSeconds()
    Returns the seconds (0-59) in the specified date according to universal time.
Date.prototype.getYear()
    Returns the year (usually 2-3 digits) in the specified date according to local time. Use getFullYear() instead. 
NVRM
fuente
-1

(new Date().toString()).replace(/ \w+-\d+ \(.*\)$/,"")

Esto tendrá salida: martes 10 de julio de 2018 19:07:11

(new Date("2005-07-08T11:22:33+0000").toString()).replace(/ \w+-\d+ \(.*\)$/,"")

Esto tendrá salida: Vie 08 de julio 2005 04:22:33

Nota: El tiempo devuelto dependerá de su zona horaria local.

xxnations
fuente
-1

Esta es la solución que se me ocurrió para este problema que funciona para mí.


biblioteca utilizada: momentjs con JavaScript simple Clase de fecha.

Paso 1. Convertir la fecha de cadena en objeto de momento (PS: momento conserva la fecha y hora originales siempre que toDate()no se llame al método):

const dateMoment = moment("2005-07-08T11:22:33+0000");

Paso 2. Extraer hoursy minutesvalores del objeto de momento creado previamente:

  const hours = dateMoment.hours();
  const mins = dateMoment.minutes();

Paso 3. Convierta el momento a la fecha (PD: esto cambiará la fecha original según la zona horaria de su navegador / máquina, pero no se preocupe y lea el paso 4):

  const dateObj = dateMoment.toDate();

Paso 4. Establezca manualmente las horas y minutos extraídos en el Paso 2.

  dateObj.setHours(hours);
  dateObj.setMinutes(mins);

El paso 5 dateObjahora mostrará la fecha original sin ninguna diferencia de zona horaria. Incluso los cambios de horario de verano no tendrán ningún efecto en el objeto de fecha, ya que estamos configurando manualmente las horas y minutos originales.

Espero que esto ayude.

saran3h
fuente
-7

Hay algunos problemas inherentes con el análisis de fechas que desafortunadamente no se abordan bien de manera predeterminada.

-Las fechas legibles para humanos tienen una zona horaria implícita en ellas
-Hay muchos formatos de fecha ampliamente utilizados en la web que son ambiguos

Para resolver estos problemas de manera fácil y limpia, se necesitaría una función como esta:

>parse(whateverDateTimeString,expectedDatePattern,timezone)
"unix time in milliseconds"

¡He buscado esto, pero no encontré nada como eso!

Entonces creé: https://github.com/zsoltszabo/timestamp-grabber

¡Disfrutar!

usuario2667976
fuente