Um guia completo para usar a API Temporal do JavaScript para cálculos de intervalos de tempo precisos e intuitivos, cobrindo tudo, desde a criação básica de durações até aritmética avançada e formatação.
Duração Temporal do JavaScript: Dominando Cálculos de Intervalos de Tempo
A API Temporal do JavaScript introduz uma forma moderna e poderosa de lidar com datas, horas e intervalos de tempo. O objeto Temporal.Duration
representa um período de tempo, fornecendo uma abordagem clara e intuitiva para realizar cálculos com intervalos de tempo. Este artigo aprofunda-se nos detalhes de Temporal.Duration
, demonstrando como criar, manipular e formatar durações para vários casos de uso.
O que é Temporal.Duration?
Temporal.Duration
representa um período de tempo, expressando-o em termos de anos, meses, dias, horas, minutos, segundos e frações de segundo (milissegundos, microssegundos, nanossegundos). Ao contrário dos objetos Date
que representam um ponto específico no tempo, Temporal.Duration
representa uma quantidade de tempo. Ele adere ao formato de duração ISO 8601 (por exemplo, P1Y2M10DT2H30M
representa 1 ano, 2 meses, 10 dias, 2 horas e 30 minutos). A API Temporal foi projetada para ser mais intuitiva e menos propensa a erros do que o objeto legado Date
.
Criando Objetos Temporal.Duration
Existem várias maneiras de criar objetos Temporal.Duration
:
1. A partir de um Objeto Simples
Você pode criar uma duração passando um objeto com as propriedades desejadas:
const duration = new Temporal.Duration(1, 2, 10, 2, 30, 0, 0, 0);
console.log(duration.toString()); // Saída: P1Y2M10DT2H30M
Isso cria uma duração de 1 ano, 2 meses, 10 dias, 2 horas e 30 minutos. Note que os argumentos correspondem à seguinte ordem: years
, months
, weeks
, days
, hours
, minutes
, seconds
, milliseconds
, microseconds
, nanoseconds
.
2. A partir de uma String ISO 8601
Você também pode criar uma duração a partir de uma string de duração ISO 8601 usando Temporal.Duration.from()
:
const duration = Temporal.Duration.from("P1Y2M10DT2H30M");
console.log(duration.toString()); // Saída: P1Y2M10DT2H30M
Isso é particularmente útil ao lidar com durações armazenadas em formato de string ou recebidas de uma fonte externa.
3. Usando os métodos add()
e subtract()
com Temporal.Instant
, Temporal.ZonedDateTime
, etc.
Quando você adiciona ou subtrai Temporal.Duration
de outros tipos Temporais (como Temporal.Instant
ou Temporal.ZonedDateTime
), um Temporal.Duration
é retornado representando a diferença entre os dois pontos no tempo, se você então os subtrair. Por exemplo:
const now = Temporal.Now.zonedDateTimeISO();
const later = now.add({ hours: 5 });
const duration = later.since(now);
console.log(duration.toString()); // Saída: PT5H
Acessando Componentes da Duração
Você pode acessar os componentes individuais de um objeto Temporal.Duration
usando suas propriedades:
const duration = Temporal.Duration.from("P1Y2M10DT2H30M");
console.log(duration.years); // Saída: 1
console.log(duration.months); // Saída: 2
console.log(duration.days); // Saída: 10
console.log(duration.hours); // Saída: 2
console.log(duration.minutes); // Saída: 30
console.log(duration.seconds); // Saída: 0
console.log(duration.milliseconds); // Saída: 0
console.log(duration.microseconds); // Saída: 0
console.log(duration.nanoseconds); // Saída: 0
Realizando Aritmética com Durações
Objetos Temporal.Duration
suportam adição e subtração usando os métodos add()
e subtract()
. Esses métodos retornam um novo objeto Temporal.Duration
representando o resultado da operação.
const duration1 = Temporal.Duration.from("P1Y2M");
const duration2 = Temporal.Duration.from("P3M4D");
const addedDuration = duration1.add(duration2);
console.log(addedDuration.toString()); // Saída: P1Y5M4D
const subtractedDuration = duration1.subtract(duration2);
console.log(subtractedDuration.toString()); // Saída: P10M26D
Você também pode encadear esses métodos para cálculos mais complexos:
const duration = Temporal.Duration.from("P1D").add({ hours: 12 }).subtract({ minutes: 30 });
console.log(duration.toString()); // Saída: P1DT11H30M
O método negated()
retorna um novo objeto Temporal.Duration
com todos os componentes negados:
const duration = Temporal.Duration.from("P1Y2M10DT2H30M");
const negatedDuration = duration.negated();
console.log(negatedDuration.toString()); // Saída: -P1Y2M10DT2H30M
O método abs()
retorna um novo objeto Temporal.Duration
com todos os componentes como valores positivos (valores absolutos):
const duration = Temporal.Duration.from("-P1Y2M10DT2H30M");
const absoluteDuration = duration.abs();
console.log(absoluteDuration.toString()); // Saída: P1Y2M10DT2H30M
O método with()
permite que você crie uma nova instância Temporal.Duration
com algumas, ou todas, as propriedades alteradas para novos valores. Se um valor não for especificado no objeto de argumento, então o valor original da duração será usado. Por exemplo:
const duration = Temporal.Duration.from("P1Y2M10DT2H30M");
const newDuration = duration.with({ years: 2, days: 5 });
console.log(newDuration.toString()); // Saída: P2Y2M5DT2H30M
Normalizando Durações
As durações às vezes podem ser expressas de forma não normalizada (por exemplo, P1Y12M
, que poderia ser simplificado para P2Y
). O método normalized()
tenta simplificar uma duração para sua forma mais compacta. No entanto, ele requer uma data de referência para lidar com as complexidades das durações variáveis dos meses. Para normalizar corretamente, você precisará de uma instância Temporal.PlainDate
, Temporal.ZonedDateTime
ou Temporal.Instant
.
Por exemplo, normalizar uma duração envolvendo meses e dias requer uma data de referência:
const duration = Temporal.Duration.from("P1M32D");
const referenceDate = Temporal.PlainDate.from("2024-01-01");
const normalizedDuration = duration.normalized({ relativeTo: referenceDate });
console.log(normalizedDuration.toString()); // Saída: P2M1D
Neste exemplo, a duração P1M32D
é normalizada em relação a 1º de janeiro de 2024, resultando em P2M1D
porque janeiro tem 31 dias.
Se você estiver lidando apenas com componentes de tempo (horas, minutos, segundos, etc.), pode normalizar sem uma data de referência:
const duration = Temporal.Duration.from("PT25H61M");
const normalizedDuration = duration.normalized({ relativeTo: null }); //ou omita o argumento relativeTo
console.log(normalizedDuration.toString()); // Saída: P1DT2H1M
Comparando Durações
Você pode comparar durações usando o método compare()
. Este método retorna:
- -1 se a primeira duração for mais curta que a segunda duração.
- 0 se as durações forem iguais.
- 1 se a primeira duração for mais longa que a segunda duração.
const duration1 = Temporal.Duration.from("P1Y");
const duration2 = Temporal.Duration.from("P6M");
const comparisonResult = Temporal.Duration.compare(duration1, duration2);
console.log(comparisonResult); // Saída: 1
Exemplos Práticos
1. Calculando o Tempo Até um Evento
Suponha que você queira calcular o tempo restante até um evento específico. Usando Temporal.Now.zonedDateTimeISO()
para obter a hora atual e subtraindo a data do evento. Se a data do evento já passou, a saída será negativa.
const eventDate = Temporal.ZonedDateTime.from({ timeZone: 'America/Los_Angeles', year: 2024, month: 12, day: 25, hour: 9, minute: 0, second: 0 });
const now = Temporal.Now.zonedDateTimeISO('America/Los_Angeles');
const durationUntilEvent = eventDate.since(now);
console.log(durationUntilEvent.toString()); // Saída: ex., P262DT14H30M (dependendo da data e hora atuais)
2. Rastreando a Duração de Tarefas de Projeto
No gerenciamento de projetos, você pode usar Temporal.Duration
para rastrear a duração estimada ou real das tarefas.
const task1EstimatedDuration = Temporal.Duration.from("PT8H"); // 8 horas
const task2EstimatedDuration = Temporal.Duration.from("PT16H"); // 16 horas
const totalEstimatedDuration = task1EstimatedDuration.add(task2EstimatedDuration);
console.log(`Duração total estimada: ${totalEstimatedDuration.toString()}`); // Saída: Duração total estimada: P1DT
3. Calculando a Idade
Embora o cálculo preciso da idade exija a consideração de anos bissextos e fusos horários, Temporal.Duration
pode fornecer uma estimativa razoável:
const birthDate = Temporal.PlainDate.from("1990-05-15");
const currentDate = Temporal.PlainDate.from("2024-01-20");
const ageDuration = currentDate.since(birthDate, { smallestUnit: 'years' });
console.log(`Idade estimada: ${ageDuration.years} anos`); // Saída: Idade estimada: 33 anos
4. Exibindo Durações Legíveis por Humanos
Muitas vezes, você precisa exibir durações em um formato legível por humanos. Embora Temporal.Duration
não tenha funções de formatação integradas, você pode criar uma lógica de formatação personalizada:
function formatDuration(duration) {
const parts = [];
if (duration.years) parts.push(`${duration.years} ano${duration.years > 1 ? 's' : ''}`);
if (duration.months) parts.push(`${duration.months} ${duration.months > 1 ? 'meses' : 'mês'}`);
if (duration.days) parts.push(`${duration.days} dia${duration.days > 1 ? 's' : ''}`);
if (duration.hours) parts.push(`${duration.hours} hora${duration.hours > 1 ? 's' : ''}`);
if (duration.minutes) parts.push(`${duration.minutes} minuto${duration.minutes > 1 ? 's' : ''}`);
if (duration.seconds) parts.push(`${duration.seconds} segundo${duration.seconds > 1 ? 's' : ''}`);
return parts.join(', ');
}
const duration = Temporal.Duration.from("P1Y2M10DT2H30M");
const formattedDuration = formatDuration(duration);
console.log(formattedDuration); // Saída: 1 ano, 2 meses, 10 dias, 2 horas, 30 minutos
Uso Avançado e Considerações
1. Manipulação de Fusos Horários
Ao lidar com intervalos de tempo que cruzam limites de fusos horários ou transições de horário de verão, é crucial usar Temporal.ZonedDateTime
para garantir cálculos precisos. Usar Temporal.PlainDate
e Temporal.PlainTime
evitará quaisquer conversões de fuso horário.
2. Menor Unidade e Arredondamento
Os métodos `since()` e `until()` geralmente aceitam opções para definir a menor unidade para a duração resultante. Por exemplo, calcular o tempo *até* um evento e limitar os resultados a dias.
const eventDate = Temporal.PlainDate.from("2024-12-25");
const now = Temporal.PlainDate.from("2024-01-20");
const durationUntilEvent = now.until(eventDate, { smallestUnit: 'days' });
console.log(durationUntilEvent.toString()); //exemplo de saída PT340D
3. Segundos Bissextos
Temporal não leva em conta segundos bissextos nativamente. Se você precisar de extrema precisão, precisará lidar com os segundos bissextos separadamente.
4. Fusos Horários IANA
A API Temporal depende do banco de dados de fusos horários da IANA (Internet Assigned Numbers Authority). Certifique-se de que seu ambiente tenha uma versão atualizada do banco de dados IANA para lidar com precisão as conversões de fuso horário.
Melhores Práticas
- Use o formato ISO 8601 para strings de duração: Isso garante consistência e interoperabilidade.
- Escolha o tipo Temporal apropriado: Use
Temporal.PlainDate
,Temporal.PlainTime
,Temporal.ZonedDateTime
ouTemporal.Instant
com base na necessidade ou não de suporte a fuso horário. - Normalize as durações quando necessário: A normalização simplifica as durações e as torna mais fáceis de comparar.
- Manuseie os fusos horários com cuidado: As conversões de fuso horário podem ser complexas, então use
Temporal.ZonedDateTime
e esteja ciente das transições de horário de verão. - Considere a menor unidade: Ao calcular durações, especifique a menor unidade para obter o nível de precisão desejado.
- Escreva testes unitários: Teste seu código minuciosamente para garantir que os cálculos de duração sejam precisos.
Armadilhas Comuns
- Ignorar fusos horários: Deixar de levar em conta os fusos horários pode levar a cálculos de duração incorretos, especialmente ao lidar com eventos em locais diferentes.
- Usar o objeto legado Date: O objeto legado
Date
é conhecido por suas peculiaridades e inconsistências. Prefira a API Temporal para um tratamento mais confiável de data e hora. - Não normalizar durações: Não normalizar durações pode tornar as comparações e os cálculos mais complexos.
- Formato ISO 8601 incorreto: Usar uma string de duração ISO 8601 inválida pode causar erros.
Casos de Uso do Mundo Real em Diferentes Culturas
A API Temporal pode ser particularmente benéfica em aplicações globais onde as diferenças de fuso horário e as nuances culturais são significativas. Aqui estão alguns exemplos:
- Agendamento Global de Eventos: Agendar eventos com precisão em vários fusos horários, levando em conta as transições de horário de verão. Por exemplo, agendar um webinar que começa às 9:00 AM PST e exibir o horário de início correspondente em vários fusos horários como CET, JST e AEDT.
- Planejamento de Viagens Internacionais: Calcular durações de viagem, incluindo escalas e mudanças de fuso horário. Isso é útil para gerar itinerários и gerenciar horários de voos. Por exemplo, calcular o tempo total de viagem de Nova York a Tóquio, incluindo uma escala em Londres e ajustando para as diferenças de fuso horário.
- E-commerce Global: Exibir tempos de entrega estimados no fuso horário local do usuário. Isso requer considerar o fuso horário de origem, a duração do envio e o fuso horário de destino. Por exemplo, um item enviado de um armazém na Alemanha para um cliente na Austrália, com um tempo de entrega estimado de 7 dias, exibido na hora local do cliente.
- Transações Financeiras Transfronteiriças: Calcular com precisão a acumulação de juros ou prazos de pagamento em diferentes regiões. Isso geralmente envolve considerar diferentes dias úteis e feriados em cada país. Por exemplo, calcular os juros acumulados em um empréstimo em Singapura, levando em conta os feriados públicos de Singapura.
- Aplicações de Calendário Multiculturais: Suportar vários sistemas de calendário, como o calendário islâmico ou hebraico, e calcular com precisão as durações de eventos e lembretes com base nesses calendários.
- Gerenciamento de Projetos Globais: Rastrear durações de tarefas e prazos de projetos em equipes distribuídas, levando em conta diferentes horários de trabalho e fusos horários.
Conclusão
Temporal.Duration
fornece uma maneira robusta e intuitiva de trabalhar com intervalos de tempo em JavaScript. Ao entender suas características e melhores práticas, você pode realizar com confiança cálculos de duração precisos e confiáveis em suas aplicações. Adotar a API Temporal leva a um código mais limpo e de fácil manutenção e reduz o risco de erros associados ao tratamento legado de data e hora.
À medida que você se aprofunda na API Temporal, lembre-se de consultar a documentação oficial и experimentar diferentes cenários para entender completamente suas capacidades. Com seu design moderno e recursos abrangentes, a Temporal está pronta para revolucionar a forma como lidamos com datas, horas e durações em JavaScript.