4
respostas

Problema com data e timezone na aplicação do curso - é exibido um dia antes

Na aplicação construída no curso, a data e demais campos preenchidos são incluídos assim, em NegociacaoController:

adiciona(event: Event) {
    event.preventDefault();

    const negociacao = new Negociacao(
        new Date(this._inputData.value.replace('/-/g', '/')),
        parseInt(this._inputQuantidade.value),
        parseFloat(this._inputValor.value)
    );
    this._negociacoes.adiciona(negociacao);
    this._negociacoesView.update(this._negociacoes);
     console.log(negociacao);
}

Ao preencher e incluir as datas 11/11/2011 e 15/01/2020, por exemplo, o log no console exibe:

Negociacao {_data: Thu Nov 10 2011 22:00:00 GMT-0200 (Horário de Verão de Brasília), _quantidade: 1, _valor: 100}
Negociacao {_data: Tue Jan 14 2020 21:00:00 GMT-0300 (Horário Padrão de Brasília), _quantidade: 2, _valor: 200}

E na tabela, também são exibidas as datas de um dia antes do digitado, ou seja, 10/11/2011 e 14/01/2020, pelo código no template() em NegociacaoView:

<td>${negociacao.data.getDate()}/${negociacao.data.getMonth()+1}/${negociacao.data.getFullYear()}</td>

Observando principalmente os detalhes do log, vê-se que as datas recuaram algumas horas referentes ao timezone/fuso horário, e por isso resultaram no dia anterior.

Como tratar adequadamente este problema?

Nota: Vi esse mesmo problema reportado no fórum há uma ano atrás, mas o tópico ficou sem solução porque a situação não foi apresentada com detalhes e código.

4 respostas

Fala ai Márcio, tudo bem? Eu precisaria dar uma olhada eu como você está passando o valor para o new Date().

Eu sugiro você trabalhar com as datas no formato americano, no caso seria: ano-mes-dia, no seguinte formato: YYYY-MM-DD.

Então suas datas visualmente seriam:

  • 10/11/2011
  • 14/01/2020

Mas, na hora de criar o objeto Date, você mandaria:

  • 2011-11-10
  • 2020-01-14

Dessa maneira acredito que não vai haver problemas.

Caso suas datas estejam chegando no formato brasileiro, uma das maneiras que você pode convertê-las para o americano seria da seguinte maneira:

this.inputData.split('/').reverse().join('-')

Ficando:

const negociacao = new Negociacao(
        new Date(this.inputData.split('/').reverse().join('-')),
        parseInt(this._inputQuantidade.value),
        parseFloat(this._inputValor.value)
    );

Espero ter ajudado.

Obrigado pelo retorno, mas a sugestão dada não fez efeito.

Enviando para o console o conteúdo do campo input do tipo "date", o texto como string já é exibido no formato internacional aaaa-mm-dd. Mas quando a data é tratada como objeto, observa-se que ela está com o comportamento de reduzir o horário no número de horas correspondente ao timezone. Veja, executando o seguinte código:

  adiciona(event: Event) {
        event.preventDefault();
        console.log('inputData value: ', this._inputData.value);
        console.log('inputData value: ', this._inputData.valueAsDate);

        const negociacao = new Negociacao(
            new Date(this._inputData.value),
            parseInt(this._inputQuantidade.value),
            parseFloat(this._inputValor.value)
        );
        this._negociacoes.adiciona(negociacao);
        this._negociacoesView.update(this._negociacoes);

        console.log(negociacao);
    }

Sendo que, anteriormente, this._inputData veio do campo de formulário HTML input type="date" id="data", lido assim no código:

this._inputData = <HTMLInputElement>document.querySelector("#data");

A saída do log no console é:

inputData value:  2020-01-15
inputData value:  Tue Jan 14 2020 21:00:00 GMT-0300 (Horário Padrão de Brasília)
Negociacao {_data: Tue Jan 14 2020 21:00:00 GMT-0300 (Horário Padrão de Brasília), _quantidade: 3, _valor: 4}

Note que o valor como texto já é exibido no formato aaaa-mm-dd sem a necessidade de nenhuma conversão, e que a data como objeto já tem algum tipo de conversão de internacionalização e armazena efetivamente 21h do dia anterior, no time zone GMT-3.

Ou seja, creio que o formato da representação textual não é a causa raiz do problema, e sim algum aspecto de internacionalização do objeto do tipo Date e suas consequências no campo de formulário do tipo date e na exibição como da data como texto.

Pesquisando sobre as propriedades e métodos do tipo Date, vi que existem métodos para obter cada informação (dia, mês, ano) em UTC, sem levar em consideração o locale, de forma que se eu substituir no template de exibição da data em um campo de tabela HTML, de:

td>${negociacao.data.getDate()}/${negociacao.data.getMonth()+1}/${negociacao.data.getFullYear()}</td>

Para:

<td>${negociacao.data.getUTCDate()}/${negociacao.data.getUTCMonth()+1}/${negociacao.data.getUTCFullYear()}</td>

É exibida a data correta. Seria essa mesmo a forma correta de lidar com campos data? Se for, seria o caso de atualizar o material do curso...?

Fala ai Márcio, vamos lá:

Primeiro estranho a solução do reverse não ter dado certo, provavelmente é como você disse, achei que os formatos estavam vindo de um jeito mas na verdade eles chegam de outro.

Sobre os pontos:

Seria essa mesmo a forma correta de lidar com campos data? Se for, seria o caso de atualizar o material do curso...?

É como eu gosto de dizer: "Na maioria das vezes vai haver mais de uma solução para dado um problema".

Não existe certo ou errado, apenas são soluções e maneiras diferentes de se obter o resultado esperado.

Se quiser compartilha o projeto comigo, eu dou uma olhada no motivo da solução do curso não estar dando certo. Pode compartilhar através do Github ou Google Drive (zipado).

Espero ter ajudado.