Analisar data sem fuso horário javascript

147

Quero analisar a data sem fuso horário em JavaScript. Eu tentei:

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

Volta a Sex Jul 08 2005 02:00:00 GMT + 0200 (Horário de verão da Europa Central)

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

Retorna o mesmo resultado

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

Retorna o mesmo resultado

Eu quero analisar o tempo:

  1. Sem fuso horário.

  2. Sem chamar o construtor Date.UTC ou nova Data (ano, mês, dia).

  3. Apenas uma passagem simples para o construtor Date (sem abordagens de protótipo).

  4. Eu tenho que Dateobjeto do produto , não String.

Athlan
fonte
3
Você pode simplesmente omitir o Date.parsebtw e passar diretamente a string para o Dateconstrutor.
Bergi 9/07/2013
1
Não sei por que você precisa disso, mas tenho certeza de que o Date sempre tem o fuso horário local do usuário. Se você quer que seu JavaScript para trabalhar com outros fusos horários que você terá que usar um objeto wrapper para Data, talvez isso vai funcionar para você: github.com/mde/timezone-js
HMR
1
Infelizmente, eu tive que copiar o Dateobjeto para obter o objeto correto para comparar as datas no MongoDB:new Date(dateStart.getFullYear(), dateStart.getMonth(), dateStart.getDate())
Athlan
Se você deseja analisar uma data sem uma hora, precisa especificar qual fuso horário deseja assumir, porque "08-07-2005" significa coisas diferentes em fusos horários diferentes. A partir de maio de 2020, a documentação do MDN desaconselhará qualquer recurso de análise da Data de Entrada devido a diferenças na implementação. No entanto, o uso de Date.parse ("2005-07-08") provavelmente retornará um horário das 00:00 UTC. a análise date-fns, por outro lado, retornará 00:00 hora local ao analisar a mesma string de data
Andy

Respostas:

106

A data é analisada corretamente, é apenas paraString que a converte no fuso horário 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())

O objeto Data Javascript são carimbos de data e hora - apenas contêm um número de milissegundos desde a época. Não há informações de fuso horário em um objeto Data. A data do calendário (dia, minutos, segundos) que esse carimbo de data / hora representa é uma questão de interpretação (um dos to...Stringmétodos).

O exemplo acima mostra que a data está sendo analisada corretamente - ou seja, na verdade contém uma quantidade de milissegundos correspondente a "2005-07-08T11: 22: 33" no GMT.

georg
fonte
4
Infelizmente eu tenho que produzir o objeto Date, não String.
Athlan
@ Athlan: acrescentou algumas explicações.
9443 georg
1
Eu tinha verificado. Eu passei a data analisado em consulta MongoDB new Date(Date.parse("2005-07-08T11:22:33+0000")), e data copiado via construtor: new Date(dateStart.getFullYear(), dateStart.getMonth(), dateStart.getDate()). Ambas as soluções, resultados diferentes, segundo correto! Sua resposta foi útil, apenas mencionada em hunlock.com/blogs/Javascript_Dates-The_Complete_Reference . Acima.
Athlan
Funcionou perfeitamente para mim - .toUTCString () foi o ticket que me deu o tempo correto de volta da string original fornecida. ou seja, nova data ("2016-08-22T19: 45: 00.0000000"). toUTCString ()
Michael Giovanni Pumo 18/08/16
38
A raiz de todo o mal nas datas e horas do JavaScript está contida na sua primeira frase ... É apenas paraString que a converte no fuso horário local ... Onde está a responsabilidade única nisso? O método toString deve apenas restringir o resultado e não convertê-lo. Se eu quiser que a data seja convertida, devo ter outros métodos para fazer isso.
anchor
109

Eu tenho o mesmo problema. Recebo uma data como uma String, por exemplo: '2016-08-25T00: 00: 00', mas preciso ter o objeto Date com hora correta. Para converter String em objeto, eu uso getTimezoneOffset:

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

getTimezoneOffset()retornará éter valor negativo ou positivo. Isso deve ser subtraído para funcionar em todos os locais do mundo.

wawka
fonte
6
Eu tenho o mesmo problema e achei útil. No entanto, descobri que isso não lida com compensações de fuso horário devido ao horário de verão. Exemplo: estou no PST, então meu deslocamento atual (em março) do GMT é -8: 00, mas em maio seria -7: 00. Minha solução foi calcularvar userTimezoneOffset = date.getTimezoneOffset()*60000;
mmh02
3
A menos que eu seja um completo idiota, isso realmente retorna na hora errada. getTimezoneOffset()retorna o número de minutos na direção oposta que você pensaria - meu fuso horário é UTC-4 agora, mas getTimezoneOffset()retorna um 240 positivo. Portanto, userTimezoneOffsetdeve ser subtraído de date.getTime(), e não adicionado a ele.
vaindil
1
Concordo com @vaindil que você deve subtrair. A solução da wakwa funciona apenas quando você está do lado correto de Greenwich. Wakwas deveria corrigi-lo.
Janne Harju
1
Ah! falou muito cedo. Não funciona na maioria dos fusos horários. Posso confirmar que ele retorna uma data errada ao compensar os horários AEST e CEST com o horário GMT.
saran3h
1
@vaindil agora o resultado é o mesmo que new Date('2016-08-25T00:00:00Z')eu acho que o ponto foi para manipular new Date('2016-08-25T00:00:00Z')para que a hora local é exibida com o tempo 00:00, mas este código perdeuZ
barbsan
14

Encontrei o mesmo problema e lembrei-me de algo instável sobre um projeto legado em que estava trabalhando e como eles lidaram com esse problema. Eu não entendi na época e realmente não me importei até me deparar com o 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 qualquer motivo, passar a data como '01 -02-2014 'define o fuso horário como zero e ignora o fuso horário do usuário. Pode ser um acaso na classe Date, mas existia há algum tempo e existe hoje. E parece funcionar em vários navegadores. Experimente você mesmo.

Esse código é implementado em um projeto global em que os fusos horários são muito importantes, mas a pessoa que visualiza a data não se importa com o momento exato em que foi introduzida.

Iwnnay
fonte
Eu acho que é intencional, porque o "Z" designa o UTC que JS converte, mas, dado que não há fuso horário, ele não pode convertê-lo, portanto assume essencialmente o fuso horário do usuário. Gostaria de obter alguma confirmação ou melhor explicação embora.
Dsso #
7
O comportamento instável é devido aos traços. Chrome, Firefox e IE11 interpretam 2014/5/31e 2014/05/31são Sáb 31 de maio de 2014 00:00:00 GMT-0600 (Horário de verão das montanhas) `(MDT é meu fuso horário atual). Com traços ... todos os navegadores interpretam 2014-05-31como Sex May 30 2014 18:00:00 GMT-0600 (Horário de verão das montanhas). Estranhamente, com 2014-5-31, o Chrome retorna sábado, o Firefox retorna sexta-feira e o IE11 diz que a data é inválida. Parece que um date.replace('-','/')pode fazer o truque.
atheaos 26/07
6

O Dateobjeto em si conterá o fuso horário de qualquer maneira, e o resultado retornado é o efeito de convertê-lo em string de maneira padrão. Ou seja, você não pode criar um objeto de data sem fuso horário. Mas o que você pode fazer é imitar o comportamento do Dateobjeto, criando o seu próprio. É melhor, porém, ser entregue a bibliotecas como o moment.js .

mishik
fonte
2
Infelizmente eu tenho que produzir o objeto Date, não String.
Athlan
3

solução simples

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
fonte
3

Data em javascript é apenas mantê-lo simples por dentro. portanto, os dados de data e hora são armazenados na época UTC unix (milissegundos ou ms).

Se você deseja ter um horário "fixo" que não seja alterado no fuso horário em que estiver, poderá ajustar o horário no UTC para corresponder ao fuso horário local atual e salvá-lo. E ao recuperá-lo, em qualquer fuso horário local em que você estiver, ele exibirá o horário UTC ajustado com base em quem o salvou e adicionará o deslocamento do fuso horário local para obter o horário "fixo".

Para salvar a data (em 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 a data (em 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
}

Então você pode:

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
fonte
2

Você pode 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
fonte
1
Não acredito que isso leve em consideração o horário de verão
Daniel Thompson
2

Como é realmente um problema de formatação ao exibir a data (por exemplo, exibe na hora local), gosto de usar o novo objeto (ish) Intl.DateTimeFormat para executar a formatação, pois é mais explícito e oferece mais opções de saída:

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 mostrado, ao definir o fuso horário como 'UTC', ele não realizará conversões locais. Como bônus, ele também permite que você crie saídas mais polidas. Você pode ler mais sobre o objeto Intl.DateTimeFormat no Mozilla - Intl.DateTimeFormat .

Editar:

A mesma funcionalidade pode ser alcançada sem a criação de um novo Intl.DateTimeFormatobjeto. Basta passar as opções de localidade e data diretamente para a toLocaleDateString()função.

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
fonte
1

Apenas uma nota genérica. uma maneira de mantê-lo flexível.

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

Podemos usar getMinutes (), mas ele retorna apenas um número nos primeiros 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
fonte
-1

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

Isso terá saída: ter 10 jul 2018 19:07:11

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

Isso terá saída: Sex Jul 08 2005 04:22:33

Nota: O horário retornado dependerá do fuso horário local

xxnations
fonte
-1

Esta é a solução que eu encontrei para esse problema que funciona para mim.


biblioteca usada: momentjs com javascript simples Date class.

Etapa 1. Converter a data da String em objeto de momento (PS: moment retém a data e a hora originais, desde que o toDate()método não seja chamado):

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

Etapa 2. Extrair hourse minutesvalores do objeto de momento criado anteriormente:

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

Etapa 3. Converter momento para data (PS: isso mudará a data original com base no fuso horário do seu navegador / computador, mas não se preocupe e leia a etapa 4.):

  const dateObj = dateMoment.toDate();

Etapa 4. Defina manualmente as horas e minutos extraídos na Etapa 2.

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

A Etapa 5. dateObjagora exibirá a Data original sem nenhuma diferença de fuso horário. Mesmo as alterações do horário de verão não terão efeito no objeto de data, pois estamos definindo manualmente as horas e minutos originais.

Espero que isto ajude.

saran3h
fonte
-7

Existem alguns problemas inerentes à análise de datas que infelizmente não são bem tratados por padrão.

-As datas legíveis por humanos têm fuso horário implícito nelas.
-Há muitos formatos de data amplamente usados ​​na Web que são ambíguos

Para resolver esses problemas de maneira fácil e limpa, seria necessária uma função como esta:

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

Eu procurei por isso, mas não encontrei nada assim!

Então, eu criei: https://github.com/zsoltszabo/timestamp-grabber

Aproveitar!

user2667976
fonte