Como Trabalhar com o Objeto Date em JavaScript?

Neste artigo, iremos conversar um pouco sobre algumas formas de manipular o objeto Date
em JavaScript, explorando maneiras de se construir uma data, e como formatar os dados quando eles chegam, por exemplo, vindos de um formulário html para serem recebidos e processados por esse objeto.
Para começar, simplesmente criando uma instância de Date
, é retornado a data e hora atuais do sistema.
let data = new Date();

Trocando o dia
Para mudar o dia, utilizamos o método setDate()
. Hoje é dia 23, conforme você pode ver na imagem acima.
Vou alterar para dia 22 → data.setDate(22);

O número gigante que foi impresso após o uso do setDate()
é um long, que representa a data. É com este número que o objeto trabalha lá por debaixo dos panos. Tanto é que, se você executar um getTime()
, o verá novamente.

O construtor do Date()
aceita este número para construir uma nova data. Veja:
let ontem = new Date(1574438069430);

Isso quer dizer que, a partir do getTime()
de uma data que você já tem, pode criar um novo objeto do tipo data.
Tratando uma data vinda de um formulário html
Existem várias maneiras de se construir uma data. Uma delas já foi vista acima, que é passando um long, representando uma data, para o construtor de Date()
.
No dia a dia desenvolvendo, frequentemente nos deparamos com a necessidade de se tratar uma data vinda de um input
em um formulário html, semelhante ao que é mostrado na imagem abaixo.

Um input do tipo data, acaba nos trazendo o dado em string, no formato ano, mês e dia, com um traço -
separando os dados. Conforme representado abaixo.
'2019-11-24'
Mas, será que é possível passar para o construtor de Date
essa string diretamente?
Vamos experimentar.

Veja que tivemos problemas. O ano e o mês estão corretos, mas o dia foi descontado em uma unidade.
Bom, vamos então ter que trabalhar este input que recebemos do formulário.
Além do long visto acima, outra forma aceita por este objeto para a construção de uma data é um array, seja ele de strings ou numbers. As duas entradas abaixo são válidas.
new Date(['2019', '11', '24']);

new Date([2019, 11, 24]);

Mas a questão é, como converter a string '2019-11-24'
que está vindo do formulário?
Vamos utilizar o método split()
, quebrando essa string em um array, usando como critério de separação o traço -
.
O split divide um objeto string em um array de strings, obedecendo ao critério de separação informado como parâmetro.
Basta chamar, sobre o input, o método split. Passando como parâmetro, o critério de separação.
'2019-11-24'.split('-');

Passar um array no construtor do objeto data funciona porque, internamente, ele transforma o array recebido em string, usando como separador, a vírgula.
Ou seja, o array de strings ['2019', '11', '24']
ou de números [2019, 11, 24]
, será convertido para a string '2019,11,24'
.
Lá por debaixo dos panos, o objeto Date()
pega o array, por exemplo ['2019', '11', '24']
, e junta tudo novamente em uma string através do método join()
, tendo como critério de junção, a vírgula.
['2019', '11', '24'].join(',');

Por isso que, se for mais cômodo a você, pode simplesmente passar uma string, separando os dados por vírgula.
let amanha = new Date('2019,11,24');

Já que ele aceita uma string com os itens separados por vírgula, outra forma de resolver, seria pegar o input do formulário e aplicar um replace com uma expressão regular.
'2019-11-24'.replace(/-/g, ',');

Nesse caso, simplesmente ajustamos a string para a forma que ele espera receber, substituindo o traço por vírgula.
O objeto Date
também está preparado para receber uma string, com os dados separados por barra /
.
new Date('2019/11/24');

Então se você recebe uma string data no formato 'DD-MM-AAAA'
e deseja passá-la ao construtor de Date no formato 'AAAA/MM/DD'
, uma solução seria:
new Date('24-11-2019' .split('-') .reverse() .join('/'));

Ou seja, com o método split()
transformamos a string em um array de strings, invertemos a ordem do array com o método reverse()
, fazendo com que o ano seja o primeiro elemento e o dia, o último. O mês continua em sua posição original. Por fim, juntamos os elementos do array novamente em uma string com o método join()
, que usou uma barra /
para isolar um dado do outro.
Se quiser tirar a prova, você também pode imprimir a expressão no console.

Construindo uma data a partir de parâmetros independentes
O objeto Date()
também aceita receber, no seu construtor, o ano, mês e dia em forma de parâmetros separados.
Uma vez que já temos o nosso array de strings, podemos lançar mão de um novo recurso, disponível a partir do ECMAScript 6 (ES6) para desmembrar um array, que é o spread operator.
Imprimindo nosso array, nenhuma novidade.

E colocando o spread operator (a reticências) antes do array, os itens serão impressos soltos. Afinal, já não fazem mais parte de um array. Foram desmembrados.

O interessante do spread operator, é que ele tem a capacidade de passar, cada um desses itens do antigo array, como um parâmetro para o construtor de um objeto ou método. Foi, na verdade, exatamente isso o que ele fez no console.log
acima.
A ideia é usar essa mesma lógica para o objeto Date.
let amanha = new Date(...'2019-11-24'.split('-'));

Mas veja que ele entendeu isso como sendo 24 de Dezembro de 2019. Como assim se eu passei 11? Para tirar a prova, vamos experimentar informar os parâmetros manualmente.
let amanha = new Date(2019, 11, 24);

O resultado é o mesmo. Isso quer dizer que não há nada de errado com o nosso spread operator.
Acontece que, nessa forma de criar a data, o mês deve ser passado de 0 a 11, onde 0 é janeiro, 1 é fevereiro, e assim por diante.
Ou seja, se eu quiser criar a data dessa forma, preciso pegar o mês informado e decrementar em uma unidade.
Isso quer dizer que, se estiver vindo a string data '2019-11-24'
, preciso dar um jeito de informar para o construtor do Date, os parâmetros separadamente e com o mês decrescido de uma unidade, algo assim: 2019, 10, 24
.
Para isso, podemos lançar mão de um pouquinho de programação funcional em JavaScript.
Antes de o nosso spread operator desmembrar o array, iremos invocar o método map()
, com o objetivo de decrementar o mês em uma unidade.
O map varre um array e transforma seus itens, seguindo as instruções da função que recebeu como parâmetro. O resultado é um novo array, transformado.
Digamos que eu tenha o seguinte array:
let numeros = [1, 2, 3];
Desejo percorrer este array, multiplicando cada item por 10.
let novosNumeros = numeros.map(item => item * 10); console.log(novosNumeros);

Escrevi a função observando a sintaxe das Arrow Functions.
O map também aceita receber, como segundo parâmetro, o índice do elemento que ele está varrendo.
No índice zero do nosso array, temos o ano. Já o mês, está no índice 1. Assim, através de um if, podemos subtrair em uma unidade o nosso mês.
let amanha = new Date(...'2019-11-24' .split('-') .map((item, indice) => indice == 1 ? item -1 : item)); console.log(amanha);
Optei por escrever um if ternário, enxugando o código.
Podemos ainda evitar este if e ter um código mais sucinto, veja:
Existe na Matemática, o módulo da divisão. Se você pegar o n
e fazê-lo crescer 0, 1, 2, 3 . . .
vai perceber que n módulo de 2
resultará sempre em 0 ou 1.

Isso irá nos permitir fazer: item menos (índice módulo de dois)
. Pois quando o índice é zero, ou seja, a primeira posição do array, o item permanecerá com seu valor original. Já quando o índice for 1 (segunda posição do array, onde está o mês) haverá a subtração.
let amanha = new Date(...'2019-11-24' .split('-') .map((item, indice) => item - indice % 2)); console.log(amanha);
Executando o código abaixo no console do navegador, você verá que a data é criada corretamente.
new Date(...'2019-11-24' .split('-') .map((item, indice) => item - indice % 2));

Consultando o Dia, Mês e Ano de um Objeto Date
Além da saída no console, outra forma de conferir se a data informada foi interpretada da forma desejada, é utilizando os métodos getDate()
, getMonth()
e getFullYear()
deste objeto. Obtendo o dia, mês e ano respectivamente.

Mas não podemos esquecer de que o objeto Date guarda internamente os meses de 0 a 11. Por isso, antes de mostrar o mês ao nosso cliente, devemos somar uma unidade a ele.

Essas formas de tratar dados, bem como de trabalhar com o objeto Date
, foram retiradas do livro Cangaceiro JavaScript, que você pode ler agora iniciando seu mês grátis na Amazon Kindle Unlimited.