O objeto de data Javascript sempre tem um dia de folga?


238

No meu aplicativo Java Script, tenho a data armazenada em um formato assim:

2011-09-24

Agora, quando tento usar o valor acima para criar um novo objeto Date (para recuperar a data em um formato diferente), a data sempre volta um dia de folga. Ver abaixo:

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

Histórico:

Fri Sep 23 2011 20:00:00 GMT-0400 (Eastern Daylight Time)

11
A classe Date do Javascript não representa uma data, representa um carimbo de data / hora (o mesmo em Java). Para torná-lo uma data, ele usa um fuso horário e essa é a causa do seu problema. Ele o analisa com o fuso horário GMT / UTC (24 de setembro de 2011, 00 : 00 UTC) e o envia com um fuso horário diferente de 4 horas (23 de setembro de 2011, 20 : 00 GMT-0400).
— Codo 26/09

2
Recebo "data inválida". Substitua os caracteres '-' por '/' e tente novamente. Ou divida a data em seus bits e defina os componentes individualmente (se você fizer isso, subtraia 1 do número do mês).
— RobG

@Codo - sim, boa resposta. É aplicável o ECMA-262 15.9.1.15. O OP deve usar "2011-09-24T20: 00: 00-04: 00" ou semelhante.
— RobG

1
Descobri que o formato "24 de setembro de 2011" retornará a data correta. Veja aqui para uma explicação: stackoverflow.com/questions/2587345/javascript-date-parse
— christurnerio

Respostas:


98

Observe que o horário de verão oriental é -4 hourse que as horas na data em que você está voltando são 20.

20h + 4h = 24h

que é meia-noite de 24/09/2011. A data foi analisada no UTC (GMT) porque você forneceu uma sequência apenas de data sem nenhum indicador de fuso horário. Se você forneceu uma string de data / hora sem um indicador ( new Date("2011-09-24T00:00:00")), ela teria sido analisada no fuso horário local. (Historicamente, houve inconsistências por lá, principalmente porque as especificações foram alteradas mais de uma vez, mas os navegadores modernos devem estar bem; ou você sempre pode incluir um indicador de fuso horário.)

Você está obtendo a data certa, apenas nunca especificou o fuso horário correto.

Se você precisar acessar os valores da data, poderá usar getUTCDate()ou qualquer uma das outras getUTC*()funções :

var d,
    days;
d = new Date('2011-09-24');
days = ['Sun', 'Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat'];
console.log(days[d.getUTCDay()]);

24
Como você "especifica o fuso horário correto"? O construtor de data sempre interpreta a sequência de datas como UTC, mas depois ajusta o fuso horário. Eu posso até fazer `new Date ('2012-01-02 EDT') e ainda voltar ao dia anterior devido à aplicação do deslocamento para o horário de verão, o que não faz sentido, porque se eu lhe disser que é a data conforme o fuso horário local atual da EDT, não aplique um deslocamento adicional a ele. Eu disse que o fuso horário era EDT, mas ainda aplica um deslocamento adicional , retornando um dia.
— AaronLS

1
@AaronLS, EDTé o horário de verão (também conhecido como horário de verão) , ESTé o fuso horário que se aplica a janeiro.
— precisa saber é o seguinte

1
Criá-lo como apenas UTC a partir de uma string seria o que eu gostaria de fazer, por isso perguntei "Como você" especifica o fuso horário correto "?" em relação ao local em que você declarou "você nunca especificou o fuso horário correto". Se eu fizer new Date('2012-01-01 GMT')isso, ainda aplicará um deslocamento, pois o converterá na hora local da data do usuário.
— precisa saber é o seguinte

7
@AaronLS, se você for forçado a usar os get*métodos e precisar que ele retorne a data / hora correta, incluindo o deslocamento de fuso horário desconhecido, basta adicionar o deslocamento de fuso horário desconhecido: d = new Date('2013-01-08 GMT'); d.setMinutes(d.getMinutes() + d.getTimezoneOffset());Isso normalizará a data para a localidade do usuário, para que os .get*métodos retornem o valor esperado. Os .getUTC*métodos estarão incorretos, portanto, tenha cuidado.
— precisa saber é o seguinte

1
Há uma diferença entre definir o comportamento para fornecer uma referência e usá-lo como escape quando os implementadores falharam ao implementar algo corretamente. E é não a mesma representação se os dados não se alinha às expectativas.
— Raiva Dissident

252

Existem várias coisas malucas que acontecem com um objeto JS DATE que convertem seqüências de caracteres, por exemplo, considere a data seguinte que você forneceu

Nota: Os exemplos a seguir podem ou não ter UM DIA DE DESCONTO, dependendo do SEU fuso horário e da hora atual.

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

No entanto, se reorganizarmos o formato da string para Mês-Dia-Ano ...

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

Outro estranho

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.

Poderíamos alterar facilmente hífens na sua data "24/09/2011" ao fazer uma nova data

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

E se tivéssemos uma sequência de datas 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.

Agora mude o hífen para avançar a barra como antes; o que acontece?

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

Normalmente, tenho que gerenciar o formato da data 2011-09-24T00: 00: 00, então é isso que faço.

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

ATUALIZAR

Se você fornecer argumentos separados para o construtor Date, poderá obter outras saídas úteis, conforme descrito abaixo

Nota: os argumentos podem ser do tipo Número ou String. Vou mostrar exemplos com valores mistos.

Obter o primeiro mês e dia de um determinado ano

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

Obter o último mês e dia do ano

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)

Exemplo de número, argumentos de sequência. Observe que o mês é março porque zero meses com base novamente.

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

Se fizermos a mesma coisa, mas com um dia zero, obteremos 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)

Adicionar um dia zero a qualquer argumento de ano e mês obterá o último dia do mês anterior. Se você continuar com números negativos, poderá continuar revertendo outro dia

new Date(2011, "02", -1);
=> // Sun Feb 27 2011 00:00:00 GMT-0700 (MST)

12
Isso realmente me ajudou o melhor. Acabei de adicionar o .replace (/ - / g, '\ /'). Replace (/ T. + /, '') Ao final dos meus dados quando fiz uma nova data. Super fácil!
— Devin Prejean

64
Uau - o javascript é terrivelmente inconsistente.
— Psrrow

2
As chamadas .replace () realmente ajudaram muito nesta noite.
— Disuse

2
Sim, eu testei tudo isso, e é realmente estranho.
— adatiya Chintan

27
Tudo isso se deve ao comportamento do Date.parse () subjacente que tenta seguir a ISO 8601. Quando a sequência de datas segue o formato aaaa-mm-dd, presume-se que seja a ISO 8601 com UTC 00:00 implícito. Quando a string se desvia do formato (por exemplo, mm-dd-aaaa ou barra em vez de hífen), ela volta ao analisador mais flexível, de acordo com a RFC 2822, que usa a hora local quando o fuso horário está ausente. É certo que tudo isso será bastante misterioso para uma pessoa comum.
— Mizstik 04/07/19

71

Para normalizar a data e eliminar o deslocamento indesejado (testado aqui: 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)

Isso também realiza o mesmo e crédito para @tpartee (testado aqui: https://jsfiddle.net/7xp1xL5m/1/ ):

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

Isso foi o que fiz para mim - tive que trabalhar com datas de uma API e depois classificá-las / compará-las, simplesmente adicionando o deslocamento de fuso horário funciona melhor.
— chakeda

Isso funcionou para mim, exceto que eu tinha para subtrair o timezoneOffset, não adicioná-lo
— ErikAGriffin

@ErikAGriffin Você está em um fuso horário positivo, ou seja, GMT + 0X00 em vez de GMT-0X00?
— AaronLS

Fiz algo semelhante: #doo.setMinutes(doo.getMinutes() + doo.getTimezoneOffset())
— Dissident Rage

2
@AaronLS Você estava no caminho certo, mas com uma lógica um pouco errada. Para compensar o deslocamento da TZ, a lógica correta é: console.log (nova Data (doo.getTime () - doo.getTimezoneOffset () * -60000)); - O sinal do deslocamento é importante e não pode ser eliminado, mas você também precisa do sinal inverso para correção, por isso multiplicamos o deslocamento por -60000 para que o sinal inverso seja aplicado.
— precisa saber é

28

Se você deseja obter a hora 0 de alguma data no fuso horário local, passe as partes individuais da data para o Dateconstrutor.

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

26

Só quero acrescentar que, aparentemente, adicionar um espaço no final da string usará o UTC para criação.

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)

Edit: Esta não é uma solução recomendada, apenas uma resposta alternativa. Por favor, não use essa abordagem, pois não está claro o que está acontecendo. Existem várias maneiras pelas quais alguém poderia refatorar isso acidentalmente, causando um erro.


Para o exemplo com o espaço no final, o console retorna "Data Inválida = $ 2"
— Brian Risk

1
funciona muito bem! new Date (data.Date + "") .toLocaleDateString ("en-US")
— quarta

Para ser justo, essa foi apenas uma resposta alternativa e não é uma solução recomendada.
— Kyle Shrader

25

Eu acredito que isso tem a ver com o ajuste de fuso horário. A data que você criou é GMT e o horário padrão é meia-noite, mas seu fuso horário é EDT, portanto, subtrai 4 horas. Tente isto para verificar:

var doo = new Date("2011-09-25 EDT");

3
Esta é a melhor resposta aqui. + 1 milhão para usar as cadeias de localização de fuso horário embutidas em vez de converter programaticamente.
— blearn

2
Este ajuda. Funciona assim: $ scope.dat = new Date (datestring + 'EDT'). Observe a diferença entre EDT e EST: link
— Weihui Guo

Não sei o que está acontecendo nos bastidores, mas funciona perfeitamente.
— 2341818

Isso eu diria que é a mais simplista das respostas e menos reformatação de código.
— Michael

Obrigado, considero o melhor caminho para mim.
— Janderson Constantino

11

Seu problema está especificamente no fuso horário. Observe a parte GMT-0400- você está 4 horas atrás do GMT. Se você adicionar 4 horas à data / hora exibida, receberá exatamente meia-noite 24/09/2011. Use o toUTCString()método para obter a sequência GMT:

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

7

Provavelmente, essa não é uma boa resposta, mas quero compartilhar minha experiência com esse problema.

Meu aplicativo usa globalmente utc date com o formato 'AAAA-MM-DD', enquanto o plug-in datepicker que eu uso somente aceita data js, é difícil para mim considerar utc e js. Então, quando eu quero passar uma data no formato 'AAAA-MM-DD' para o meu datepicker, primeiro a converto no formato 'MM / DD / AAAA' usando moment.js ou o que você quiser, e a data é exibida no datepicker agora corrigir. Para o seu exemplo

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

Aparentemente, d1 é o que eu quero. Espero que isso seja útil para algumas pessoas.


1
Apenas mudar os formatos como você fez, funcionou da mesma forma para mim. Tão estranho.
— JAC

5

Isto através de mim para um loop, +1 na resposta do zzzBov. Aqui está uma conversão completa de uma data que funcionou para mim usando os 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!

4

Isso significa que 2011-09-24 00:00:00 GMT, e como você está GMT -4, será20:00 no dia anterior.

Pessoalmente, entendo 2011-09-24 02:00:00, porque estou morando GMT +2.


3

Embora, no caso do OP, o fuso horário seja EDT, não há garantia de que o usuário que está executando seu script seja no fuso horário EDT, portanto, a codificação codificada do deslocamento não funcionará necessariamente. A solução que encontrei divide a string de data e usa os valores separados no construtor Date.

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

Observe que você deve dar conta de outra parte da estranheza do JS: o mês é baseado em zero.


2

Encontrei esse problema exato em que meu cliente estava no horário padrão do Atlântico. O valor da data que o cliente recuperou foi "23/11/2018" e quando o código passou para new Date("2018-11-23")a saída do cliente foi para o dia anterior. Criei uma função de utilitário, como mostrado no trecho que normalizou a data, fornecendo ao cliente a data 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>


2

se você apenas deseja garantir que as partes individuais da data permaneçam as mesmas para fins de exibição, * isso parece funcionar, mesmo quando eu mudo o fuso horário:

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

basta adicionar os zeros lá.

No meu código eu faço isso:

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

E alterno meu fuso horário no meu computador e a data permanece a mesma que a sequência de datas aaaa-mm-dd que recebo da API.

Mas estou faltando alguma coisa / isso é uma má idéia?

* pelo menos em cromo. Isso não funciona no Safari! no momento da redação deste


Quando você faz .toISOString(), ele volta 1 dia atrás.
— vivek_23

new Date('2019/11/18 05:30:00').toISOString();trabalhou para mim
— vivek_23

1

A melhor maneira de lidar com isso sem usar mais métodos de conversão,

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

Agora basta adicionar GMT à sua data ou você pode anexá-la.

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

Ao vivo: https://jsfiddle.net/gajender/2kop9vrk/1/


1

Eu enfrentei um problema como este. Mas o meu problema foi deslocado ao obter a data do banco de dados.

isso está espalhado no banco de dados e está no formato UTC.

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

Então, quando eu chegar do banco de dados e verificar a data, ele está adicionando deslocamento com ele e enviar de volta para javascript.

insira a descrição da imagem aqui

Ele está adicionando +05: 00 porque este é o fuso horário do meu servidor. Meu cliente está em um fuso horário diferente +07: 00.

2019-03-28T19: 00: 00 + 05: 00 // isto é o que recebo em javascript.

Então, aqui está a minha solução, o que faço com esse 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);

Então, quando a data vier do servidor e tiver o deslocamento do servidor, divido a data e removo o deslocamento do servidor e depois os converto para a data. Isso resolve meu problema.


1

se você precisar de uma solução simples para isso, consulte:

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

insira a descrição da imagem aqui


0

Você está usando o formato de sequência de datas ISO que, de acordo com esta página , faz com que a data seja construída usando o fuso horário UTC:

Nota: a análise de seqüências de datas com o construtor Date (e Date.parse, eles são equivalentes) é altamente desencorajada devido a diferenças e inconsistências do navegador. O suporte para seqüências de caracteres de formato RFC 2822 é apenas por convenção. O suporte para os formatos ISO 8601 difere porque as seqüências de data somente (por exemplo, "1970-01-01") são tratadas como UTC, e não local.

Se você formatar o texto de maneira diferente, como "Jan 01 1970"(pelo menos na minha máquina), ele usará o fuso horário local.


0

Tentando adicionar meus 2 centavos a este tópico (elaborando a resposta em @ paul-wintz).

Parece-me que, quando o construtor Date recebe uma string que corresponde à primeira parte do formato ISO 8601 (parte da data), ele faz uma conversão precisa da data no fuso horário UTC com 0 hora. Quando essa data é convertida para a hora local, pode ocorrer uma mudança de data se a meia-noite UTC for uma data anterior no fuso horário local.

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

Se a sequência de datas estiver em qualquer outro formato "mais flexível" (usa "/" ou a data / mês não for preenchida com zero), ela criará a data no fuso horário local, portanto, nenhum problema de alteração de data.

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)

Portanto, uma solução rápida, como mencionado acima, é substituir "-" por "/" na sua string Data somente no formato ISO.

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

0

Armazenando yyyy-mm-ddno formato MySql Date, você deve fazer o seguinte:

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

-1

Seu log gera GMT e você deseja especificar seu fuso horário:

var doo = new Date("2011-09-24 EST");

3
Esta pergunta já tem muitas respostas. Se você quiser responder à pergunta de qualquer maneira, mencione algo novo que as outras respostas não. A resposta principal já explica o problema com o fuso horário com muito mais detalhes.
— Calvin Godfrey

Esta resposta é quase exatamente o mesmo que stackoverflow.com/a/7556642/8828658
— uma pedra aracnídeo

Quem se importa se a explicação dele é mais aprofundada ... o código dele ainda é diferente do meu. O meu é muito mais simples. E sim aracnídeo de pedra, você está correto. Foi mal.
— bmacx7

-3

deixa pra lá, não percebeu o GMT -0400, o que faz com que a data seja ontem

Você pode tentar definir um "horário" padrão como 12:00:00


Sim, eu fui um pouco rápido com a minha resposta, desculpe por isso. Revisei minha resposta.
— ChrisH

-3

O seguinte funcionou para mim -

    var doo = new Date("2011-09-24").format("m/d/yyyy");

Ainda não funcionará, desde que você não tenha mexido com o fuso horário.
— 15776 Gar
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.