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.

Quer mergulhar em tecnologia e aprendizagem?

Receba a newsletter que o nosso CEO escreve pessoalmente, com insights do mercado de trabalho, ciência e desenvolvimento de software