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)
levi
fonte
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()]);
zzzzBov
fonte
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)
SoEzPz
fonte
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 )  );
AaronLS
fonte
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.
Lincolnk
fonte
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.

Kyle Shrader
fonte
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");
FishBasketGordo
fonte
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());
Aleks G
fonte
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.

Jie Zhang
fonte
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!
cmartin
fonte
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.

pimvdb
fonte
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.

Brian Risk
fonte
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>

Gabriel Gates
fonte
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

Timothy Mitchell
fonte
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/

Gajender Singh
fonte
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.

Uxmaan Ali
fonte
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

Sebastiao Marcos
fonte
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.

Paul Wintz
fonte
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)
Florin D
fonte
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
Paulo Henrique Guimarães
fonte
-1

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

var doo = new Date("2011-09-24 EST");
bmacx7
fonte
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

ChrisH
fonte
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");
Venu
fonte
Ainda não funcionará, desde que você não tenha mexido com o fuso horário.
15776 Gar