Percursos
/
JavaScript
JavaScript
/
Exercícios
/
Hora da consulta
Hora da consulta

Hora da consulta

Exercício de aprendizagem

Introdução

O JavaScript tem um objeto incorporado, Date, que armazena a data e a hora e fornece métodos para as gerir.

Caution

Baseava-se na classe java.util.Date do Java, que foi substituída no início da década de 2010, mas, por compatibilidade com versões anteriores, o Date do JavaScript continua a existir.

Devido à dificuldade geral de trabalhar com datas e ao facto de o tratamento de fusos horários ser mau ou inexistente, existem muitas bibliotecas, como moment.js, day.js, date-fns e luxon. Nenhuma delas está disponível no Exercism.

Nos teus próprios projetos, não uses um pacote obsoleto ou sem manutenção como o moment.js; usa antes alternativas mais modernas, como o luxon, ou o Temporal, que ainda não está amplamente disponível. Este exercício centra-se no Date, que continuará a ser relevante até ao fim do JavaScript.

Criação

Um objeto Date é uma instância da classe Date. Pode ser criado sem passar quaisquer argumentos à função construtora. Isto resulta num objeto Date que representa a data e a hora atuais:

const now = new Date();
// => Thu Apr 14 2022 11:46:08 GMT+0530 (India Standard Time)
// Shows current day, date and time (in your time zone).

Timestamp Unix (número)

Se for passado um número, este será interpretado como um timestamp. Um timestamp é um número inteiro que representa o número de milissegundos decorridos desde 1 de janeiro de 1970 UTC+0.

const epoch = new Date(0);
// Thu Jan 01 1970 01:00:00 GMT+0100 (Central European Standard Time)

const another = new Date(1749508766627);
// Tue Jun 10 2025 00:39:26 GMT+0200 (Central European Summer Time)

Podes esperar que new Date(0) gere o objeto de data "mais antigo", mas o JavaScript converte a data para o teu fuso horário local, o que significa que só quem está num fuso horário GMT / UTC+0 é que obtém realmente o valor do Unix epoch.

Timestamp ISO 8601 (string)

Podes passar um valor do tipo string que representa uma data à função construtora Date. O único formato consistente entre implementações é a versão simplificada das chamadas strings de timestamp ISO 8601, reconhecidas e normalizadas internacionalmente.

Um momento no tempo em UTC tem este aspeto:

YYYY-MM-DDTHH:mm:ss.mssZ
YYYYMMDDTHHmmss.mssZ

Em que ocorrem as seguintes substituições:

Chave Descrição Predefinição
YYYY O ano civil, representado com 4 dígitos
MM O mês civil, representado com 2 dígitos 01
DD O dia civil, representado com 2 dígitos 01
T Uma letra T literal, que separa a data da hora
HH As horas num relógio de 24 horas, com 2 dígitos 00
mm Os minutos, com 2 dígitos 00
ss Os segundos, com 2 dígitos 00
mss Os milissegundos, com 3 dígitos 000
Z Uma letra Z literal, ou um desvio +/-HH:mm

A letra Z literal indica UTC (sem fuso horário, sem horário de verão).

Como existem valores predefinidos para a maioria dos componentes, é válido omitir partes no fim:

YYYY-MM-DD

Por predefinição, assume a hora 00:00:00.000.

Se o timestamp não terminar em Z nem terminar com +HH:mm ou -HH:mm (que indicam um desvio de fuso horário), por razões históricas aplica-se o seguinte:

Quando o desvio de fuso horário está ausente, as formas apenas com data são interpretadas como uma hora UTC e as formas com data e hora são interpretadas como uma hora local. A interpretação como hora UTC deve-se a um erro histórico da especificação, que não era coerente com a ISO 8601, mas que não pôde ser alterado devido à compatibilidade com a web. Vê Broken Parser: um problema de realidade da web.

Caution

Outros formatos aceites por Date.parse podem ou não funcionar. Ao trabalhar com datas em JavaScript, usa sempre um timestamp ISO 8601 ao converter uma string para um Date.

As formas apenas com data são permitidas, mas nem todos os formatos ISO 8601 são suportados. Consulta a página de explicação da versão simplificada na MDN.

Objeto Date

Também podes usar um objeto de data já existente como argumento da função construtora. Isto cria uma cópia do objeto Date existente, com a mesma data e a mesma hora.

const t1 = new Date();
const t2 = new Date(t1);
// Values of t1 and t2 will be the same.

Fornecer valores individuais dos componentes de data e hora

Podes criar um objeto de data que representa apenas uma data passando três números. Podes criar um objeto de data que representa uma data e uma hora passando 6 números.

const date1 = new Date(95, 11, 17);
// Creates Date for Dec 17 1995 00:00 if your local timezone is equivalent to UTC.

const date2 = new Date(2013, 12, 5, 13, 24, 0);
// Creates Date for Jan 5 2014 13:24 if your local timezone is equivalent to UTC.

O segundo valor é o month, que começa em 0 para janeiro e vai até 11 para dezembro.

Date.parse()

Podes encontrar menções ou referências a uma função de análise de datas, Date.parse. Como esta função tem apenas alguns invariantes (verdades) e como o resto da implementação não está especificado (e, por isso, não é padrão), não deves usá-la.

Acesso aos componentes de Date

Existem vários métodos nos objetos de data que devolvem os componentes da data:

getFullYear(); // Get the year (4 digits)
getMonth(); // Get the month, from 0 to 11.
getDate(); // Get the day of month, from 1 to 31.
getHours(); // Get the hour in a 24 clock, from 0 to 23
getMinutes(); // Get the minutes, from 0 to 59
getSeconds(); // Get the seconds, from 0 to 59
getMilliseconds(); // Get the milliseconds, from 0 and 999
getDay(); // Get the day of week, from 0 (Sunday) to 6 (Saturday).

Cada um destes tem uma variante set correspondente (por exemplo, setFullYear) para atualizar o valor. Qualquer valor que transborde passa para o componente seguinte:

const date = new Date('2025-02-28T12:42:00Z');
// => Fri Feb 28 2025 13:42:00 GMT+0100 (Central European Standard Time)

date.setDate(29);
// there was no February 29th in 2025.

date.getDate();
// => 1

date.toString();
// => Sat Mar 01 2025 13:42:00 GMT+0100 (Central European Standard Time)

Existem variantes UTC de todos os métodos, que ignoram o fuso horário local.

Converter a partir de uma data

Os objetos de data têm um método getTime() que devolve o timestamp UNIX em milissegundos, ou seja, o número de milissegundos desde a meia-noite do início de 1 de janeiro de 1970, UTC. Além disso, existe o método toISOString(), que converte um objeto de data numa string de timestamp ISO 8601.

Comparar datas

Os operadores maior que (>), maior ou igual (>=), menor que (<) e menor ou igual (<=) podem ser usados diretamente entre duas datas, ou entre uma data e um número. Isto funciona porque o JavaScript tenta converter a data num valor primitivo.

Advanced

Ao fazer uma comparação entre duas datas, ou entre uma data e um número, o JavaScript chama [Symbol.toPrimitive]("number"), que por sua vez chama date.valueOf(). Esta última é equivalente a chamar date.getTime().

Se não quiseres depender deste comportamento, converte primeiro num número com getTime().

Não é possível comparar datas com os operadores de igualdade (== e ===), mas podes comparar o resultado de .getTime().

Instruções

Neste exercício vais trabalhar com algumas funções para gerir marcações. O sistema guarda tudo em strings formatadas em ISO 8601, mas não é assim que as pessoas usam o calendário. São necessárias várias funções para converter entre os diferentes formatos.

1. Cria uma marcação

Cria uma marcação daqui a n dias, à hora atual. A função recebe n dias e devolve a hora da marcação daqui a n dias.

createAppointment(4, now);
// Given now is Sun Oct 05 2022 23:28:43 GMT+0600 (Bangladesh Standard Time)
// => Sun Oct 09 2022 23:28:43 GMT+0600 (Bangladesh Standard Time)

Se o segundo parâmetro now não for usado, deve ser usada a hora atual.

2. Converte uma data num timestamp

Várias ferramentas só funcionam com o formato ISO 8601, normalizado internacionalmente. Escreve a função getAppointmentTimestamp, que recebe uma data e devolve uma string nesse formato.

const appointment = new Date(Date.UTC(2010, 6, 16, 12, 42, 0, 0));

getAppointmentTimestamp(appointment);
// => '2010-07-16T12:42:00.000Z'

3. Obtém os detalhes de uma marcação

Os timestamps são difíceis de ler; uma função para obter os detalhes da marcação deve ajudar nisso. A função getAppointmentDetails recebe um timestamp no formato ISO 8601 e devolve o ano, o mês, o dia, a hora e os minutos.

getAppointmentDetails('2022-04-24T08:15:00.000');
// => { year: 2022, month: 3, date: 24, hour: 8, minute: 15 }

4. Atualiza uma marcação com as opções indicadas

A função recebe como primeiro argumento a hora da marcação e como segundo argumento um objeto com algumas opções. Tens de atualizar a marcação de acordo com as opções do objeto e devolver a nova data da marcação. O objeto de opções pode ter várias opções.

updateAppointment('2022-02-09T09:20:00.000', { month: 6 });
// => { year: 2022, month: 6, date: 9, hour: 10, minute: 20 }

5. Obtém o tempo disponível entre duas marcações

A função recebe duas marcações (timestamps) como argumentos. Tens de devolver a diferença entre esses dois momentos em segundos.

Como meio segundo é quase irrelevante, arredonda o número antes de o devolver.

timeBetween('2022-12-12T09:20:00.000', '2022-12-18T08:30:00.000');
// => 515400

6. Verifica se uma marcação é válida ou não

Por fim, quando a marcação é criada, o sistema precisa de verificar se é válida. Por outras palavras, a marcação tem de estar no futuro e não no passado.

Escreve a função isValid, que recebe dois argumentos, um timestamp de marcação (string) e a hora atual como timestamp (string), e devolve true se a marcação estiver no futuro, dada a hora atual.

isValid('2022-02-11T23:00:00.000', '2022-02-08T23:00:00.000');
// => true
Editar via GitHub A ligação abre numa nova janela ou separador
JavaScript Exercism

Estás pronto para começar Hora da consulta?

Inscreve-te no Exercism para aprenderes e dominares JavaScript com 37 conceitos159 exercícios, e mentoria humana real, tudo grátis.