JavaScript Temporal API: O Fim do Date e Moment.js Esta Proximo
Ola HaWkers, depois de anos de desenvolvimento, a Temporal API esta finalmente chegando aos navegadores principais. Esta nova API nativa promete resolver todos os problemas historicos do objeto Date no JavaScript.
Vamos explorar como usar a Temporal API e preparar seus projetos para essa mudanca.
Por Que Precisamos da Temporal API
Problemas do Date Atual
O objeto Date do JavaScript foi criado em 10 dias em 1995, copiado do Java, e nunca foi corrigido.
Problemas classicos do Date:
// Problema 1: Meses comecam em 0
const date = new Date(2026, 0, 20); // Janeiro, nao Fevereiro
console.log(date.getMonth()); // 0, nao 1
// Problema 2: Anos de 2 digitos
const y2k = new Date(99, 0, 1);
console.log(y2k.getFullYear()); // 1999, nao 99 ou 2099
// Problema 3: Mutabilidade
const original = new Date(2026, 0, 20);
const modified = original;
modified.setMonth(5);
console.log(original.getMonth()); // 5 - original foi alterado!
// Problema 4: Parsing inconsistente
new Date('2026-01-20'); // UTC
new Date('2026/01/20'); // Local
new Date('01-20-2026'); // Invalido em alguns navegadores
// Problema 5: Sem suporte a timezone
// Nao existe forma nativa de trabalhar com fusos horarios
// Problema 6: Sem suporte a duracao
// Nao existe forma de representar "2 horas e 30 minutos"O Que a Temporal Resolve
A Temporal API foi projetada para corrigir todos esses problemas:
Principios da Temporal:
- Imutabilidade: Todos os objetos sao imutaveis
- Clareza: APIs explicitas sem ambiguidade
- Timezones: Suporte completo a fusos horarios
- Precisao: Nanosegundos de precisao
- Tipos separados: Diferentes tipos para diferentes necessidades
Tipos Principais da Temporal
Visao Geral dos Tipos
A Temporal introduz varios tipos especializados:
// Temporal.Instant - momento exato no tempo (UTC)
const instant = Temporal.Instant.from('2026-01-20T15:30:00Z');
// Temporal.ZonedDateTime - data/hora com timezone
const zonedDateTime = Temporal.ZonedDateTime.from({
year: 2026,
month: 1,
day: 20,
hour: 15,
minute: 30,
timeZone: 'America/Sao_Paulo'
});
// Temporal.PlainDateTime - data/hora sem timezone
const plainDateTime = Temporal.PlainDateTime.from({
year: 2026,
month: 1,
day: 20,
hour: 15,
minute: 30
});
// Temporal.PlainDate - apenas data
const plainDate = Temporal.PlainDate.from({
year: 2026,
month: 1,
day: 20
});
// Temporal.PlainTime - apenas hora
const plainTime = Temporal.PlainTime.from({
hour: 15,
minute: 30,
second: 0
});
// Temporal.PlainYearMonth - ano e mes
const yearMonth = Temporal.PlainYearMonth.from({
year: 2026,
month: 1
});
// Temporal.PlainMonthDay - mes e dia (aniversarios)
const monthDay = Temporal.PlainMonthDay.from({
month: 1,
day: 20
});
// Temporal.Duration - duracao de tempo
const duration = Temporal.Duration.from({
hours: 2,
minutes: 30
});Quando Usar Cada Tipo
| Tipo | Caso de Uso | Exemplo |
|---|---|---|
| Instant | Timestamps de eventos | Logs, auditoria |
| ZonedDateTime | Eventos locais | Reunioes, voos |
| PlainDateTime | Eventos sem fuso | Templates |
| PlainDate | Datas apenas | Aniversarios, feriados |
| PlainTime | Horas apenas | Horarios de funcionamento |
| Duration | Intervalos | Tempo de execucao |
Usando a Temporal na Pratica
Criando Datas
// A partir de string ISO
const date1 = Temporal.PlainDate.from('2026-01-20');
// A partir de objeto
const date2 = Temporal.PlainDate.from({
year: 2026,
month: 1,
day: 20
});
// Data atual
const today = Temporal.Now.plainDateISO();
console.log(today.toString()); // "2026-01-20"
// DateTime atual com timezone
const now = Temporal.Now.zonedDateTimeISO('America/Sao_Paulo');
console.log(now.toString());
// "2026-01-20T12:30:00-03:00[America/Sao_Paulo]"Manipulando Datas
const date = Temporal.PlainDate.from('2026-01-20');
// Adicionar tempo (retorna nova instancia)
const nextWeek = date.add({ days: 7 });
console.log(nextWeek.toString()); // "2026-01-27"
// Subtrair tempo
const lastMonth = date.subtract({ months: 1 });
console.log(lastMonth.toString()); // "2025-12-20"
// Modificar campos especificos
const newYear = date.with({ month: 12, day: 31 });
console.log(newYear.toString()); // "2026-12-31"
// Original permanece inalterado (imutabilidade)
console.log(date.toString()); // "2026-01-20"Comparando Datas
const date1 = Temporal.PlainDate.from('2026-01-20');
const date2 = Temporal.PlainDate.from('2026-02-15');
// Comparacao
console.log(Temporal.PlainDate.compare(date1, date2)); // -1 (date1 < date2)
// Igualdade
console.log(date1.equals(date2)); // false
// Diferenca entre datas
const diff = date1.until(date2);
console.log(diff.toString()); // "P26D" (26 dias)
console.log(diff.days); // 26
// Diferenca em unidades especificas
const diffInWeeks = date1.until(date2, { largestUnit: 'weeks' });
console.log(diffInWeeks.toString()); // "P3W5D" (3 semanas e 5 dias)
Trabalhando com Timezones
ZonedDateTime
// Criar datetime com timezone
const meeting = Temporal.ZonedDateTime.from({
year: 2026,
month: 1,
day: 20,
hour: 15,
minute: 0,
timeZone: 'America/Sao_Paulo'
});
console.log(meeting.toString());
// "2026-01-20T15:00:00-03:00[America/Sao_Paulo]"
// Converter para outro fuso
const meetingInTokyo = meeting.withTimeZone('Asia/Tokyo');
console.log(meetingInTokyo.toString());
// "2026-01-21T03:00:00+09:00[Asia/Tokyo]"
// O momento e o mesmo, apenas a representacao muda
console.log(meeting.toInstant().equals(meetingInTokyo.toInstant())); // trueLidando com Horario de Verao
// Temporal lida corretamente com DST
const beforeDST = Temporal.ZonedDateTime.from({
year: 2026,
month: 10,
day: 31,
hour: 23,
minute: 0,
timeZone: 'America/Sao_Paulo'
});
// Adicionar 2 horas atravessa a mudanca de horario
const afterDST = beforeDST.add({ hours: 2 });
console.log(afterDST.hour); // Hora correta considerando DST
// Verificar offset
console.log(beforeDST.offset); // "-03:00"
console.log(afterDST.offset); // "-02:00" (horario de verao)Conversao Entre Sistemas
// De Date para Temporal
const legacyDate = new Date('2026-01-20T15:30:00Z');
const instant = Temporal.Instant.fromEpochMilliseconds(legacyDate.getTime());
const zoned = instant.toZonedDateTimeISO('America/Sao_Paulo');
// De Temporal para Date
const temporal = Temporal.ZonedDateTime.from('2026-01-20T15:30:00-03:00[America/Sao_Paulo]');
const backToDate = new Date(temporal.epochMilliseconds);
Duracoes e Intervalos
Trabalhando com Duration
// Criar duracao
const duration = Temporal.Duration.from({
hours: 2,
minutes: 30,
seconds: 45
});
console.log(duration.toString()); // "PT2H30M45S"
// Aritmetica com duracoes
const doubleDuration = duration.add(duration);
console.log(doubleDuration.toString()); // "PT5H1M30S"
// Negacao
const negativeDuration = duration.negated();
console.log(negativeDuration.toString()); // "-PT2H30M45S"
// Valor absoluto
console.log(negativeDuration.abs().toString()); // "PT2H30M45S"Calculando Diferencas
const startDate = Temporal.PlainDate.from('2026-01-01');
const endDate = Temporal.PlainDate.from('2026-12-31');
// Diferenca padrao (em dias)
const diffDays = startDate.until(endDate);
console.log(diffDays.days); // 364
// Diferenca em meses
const diffMonths = startDate.until(endDate, { largestUnit: 'months' });
console.log(diffMonths.toString()); // "P11M30D"
// Diferenca em anos
const diffYears = startDate.until(endDate, { largestUnit: 'years' });
console.log(diffYears.toString()); // "P0Y11M30D"
// Total em uma unidade especifica
const totalDays = diffDays.total('days');
console.log(totalDays); // 364Arredondamento de Duracoes
const duration = Temporal.Duration.from({
hours: 1,
minutes: 45,
seconds: 30
});
// Arredondar para horas
const roundedHours = duration.round({
largestUnit: 'hours',
smallestUnit: 'hours',
roundingMode: 'halfExpand'
});
console.log(roundedHours.toString()); // "PT2H"
// Arredondar para minutos
const roundedMinutes = duration.round({
smallestUnit: 'minutes',
roundingMode: 'floor'
});
console.log(roundedMinutes.toString()); // "PT1H45M"
Formatacao de Datas
Usando Intl.DateTimeFormat
const date = Temporal.PlainDate.from('2026-01-20');
// Formatacao basica
const formatter = new Intl.DateTimeFormat('pt-BR', {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric'
});
console.log(formatter.format(date));
// "terca-feira, 20 de janeiro de 2026"
// Formatacao de datetime com timezone
const dateTime = Temporal.ZonedDateTime.from({
year: 2026,
month: 1,
day: 20,
hour: 15,
minute: 30,
timeZone: 'America/Sao_Paulo'
});
const fullFormatter = new Intl.DateTimeFormat('pt-BR', {
dateStyle: 'full',
timeStyle: 'long',
timeZone: 'America/Sao_Paulo'
});
console.log(fullFormatter.format(dateTime));
// "terca-feira, 20 de janeiro de 2026 15:30:00 BRT"Formatacao Relativa
const now = Temporal.Now.plainDateISO();
const pastDate = now.subtract({ days: 3 });
const futureDate = now.add({ months: 2 });
// Calcular diferenca
const pastDiff = pastDate.until(now);
const futureDiff = now.until(futureDate);
// Usar Intl.RelativeTimeFormat
const rtf = new Intl.RelativeTimeFormat('pt-BR', { numeric: 'auto' });
console.log(rtf.format(-pastDiff.days, 'day'));
// "ha 3 dias"
console.log(rtf.format(futureDiff.months, 'month'));
// "em 2 meses"
Migrando de Bibliotecas Existentes
Substituindo Moment.js
// Moment.js (antigo)
import moment from 'moment';
const m = moment('2026-01-20');
const added = m.add(7, 'days');
const formatted = m.format('DD/MM/YYYY');
// Temporal (novo)
const t = Temporal.PlainDate.from('2026-01-20');
const addedT = t.add({ days: 7 });
const formattedT = new Intl.DateTimeFormat('pt-BR').format(addedT);
// Comparacao de tamanho de bundle
// Moment.js: ~70KB minificado
// Temporal: 0KB (nativo do navegador)Substituindo date-fns
// date-fns (antigo)
import { addDays, format, differenceInDays } from 'date-fns';
import { ptBR } from 'date-fns/locale';
const date = new Date(2026, 0, 20);
const added = addDays(date, 7);
const formatted = format(date, 'dd/MM/yyyy', { locale: ptBR });
const diff = differenceInDays(new Date(2026, 1, 20), date);
// Temporal (novo)
const t = Temporal.PlainDate.from('2026-01-20');
const addedT = t.add({ days: 7 });
const formattedT = new Intl.DateTimeFormat('pt-BR').format(t);
const diffT = t.until(Temporal.PlainDate.from('2026-02-20')).days;Tabela de Equivalencias
| Operacao | Moment/date-fns | Temporal |
|---|---|---|
| Criar data | moment() / new Date() |
Temporal.Now.plainDateISO() |
| Adicionar dias | .add(7, 'days') |
.add({ days: 7 }) |
| Subtrair meses | .subtract(1, 'month') |
.subtract({ months: 1 }) |
| Formatar | .format('DD/MM/YYYY') |
Intl.DateTimeFormat |
| Diferenca | differenceInDays() |
.until().days |
| Comparar | .isBefore() |
Temporal.PlainDate.compare() |
| Timezone | moment.tz() |
Temporal.ZonedDateTime |
Suporte Atual e Polyfills
Status de Implementacao
Em janeiro de 2026, o suporte esta assim:
| Navegador | Status |
|---|---|
| Chrome | Flag experimental |
| Firefox | Em desenvolvimento |
| Safari | Em desenvolvimento |
| Node.js | Flag --harmony-temporal |
| Deno | Suportado |
| Bun | Suportado |
Usando Polyfill
Enquanto o suporte nativo nao chega, use o polyfill oficial:
npm install @js-temporal/polyfill// Importar polyfill
import { Temporal } from '@js-temporal/polyfill';
// Usar normalmente
const now = Temporal.Now.plainDateISO();
console.log(now.toString());
// Verificar se nativo esta disponivel
if (typeof globalThis.Temporal !== 'undefined') {
console.log('Usando Temporal nativo');
} else {
console.log('Usando polyfill');
}Configuracao TypeScript
// tsconfig.json
{
"compilerOptions": {
"lib": ["ES2022", "DOM"],
"types": ["@js-temporal/polyfill"]
}
}
// Uso com tipos
import { Temporal } from '@js-temporal/polyfill';
function calculateAge(birthDate: Temporal.PlainDate): number {
const today = Temporal.Now.plainDateISO();
const age = birthDate.until(today, { largestUnit: 'years' });
return age.years;
}
const birth = Temporal.PlainDate.from('1990-05-15');
console.log(`Idade: ${calculateAge(birth)} anos`);
Casos de Uso Avancados
Sistema de Agendamento
import { Temporal } from '@js-temporal/polyfill';
interface Appointment {
id: string;
title: string;
start: Temporal.ZonedDateTime;
duration: Temporal.Duration;
timezone: string;
}
class Scheduler {
private appointments: Appointment[] = [];
addAppointment(
title: string,
start: string,
durationMinutes: number,
timezone: string
): Appointment {
const appointment: Appointment = {
id: crypto.randomUUID(),
title,
start: Temporal.ZonedDateTime.from(`${start}[${timezone}]`),
duration: Temporal.Duration.from({ minutes: durationMinutes }),
timezone
};
this.appointments.push(appointment);
return appointment;
}
getEndTime(appointment: Appointment): Temporal.ZonedDateTime {
return appointment.start.add(appointment.duration);
}
hasConflict(newStart: Temporal.ZonedDateTime, duration: Temporal.Duration): boolean {
const newEnd = newStart.add(duration);
return this.appointments.some(apt => {
const aptEnd = this.getEndTime(apt);
// Verifica sobreposicao
return (
Temporal.ZonedDateTime.compare(newStart, aptEnd) < 0 &&
Temporal.ZonedDateTime.compare(newEnd, apt.start) > 0
);
});
}
getAppointmentsForDay(date: Temporal.PlainDate, timezone: string): Appointment[] {
return this.appointments.filter(apt => {
const aptDate = apt.start.withTimeZone(timezone).toPlainDate();
return aptDate.equals(date);
});
}
}
// Uso
const scheduler = new Scheduler();
scheduler.addAppointment(
'Reuniao de equipe',
'2026-01-20T10:00:00',
60,
'America/Sao_Paulo'
);
scheduler.addAppointment(
'Call com cliente internacional',
'2026-01-20T15:00:00',
30,
'America/New_York'
);Calculo de Dias Uteis
function addBusinessDays(
date: Temporal.PlainDate,
days: number
): Temporal.PlainDate {
let result = date;
let remaining = days;
while (remaining > 0) {
result = result.add({ days: 1 });
const dayOfWeek = result.dayOfWeek;
// 6 = Sabado, 7 = Domingo
if (dayOfWeek !== 6 && dayOfWeek !== 7) {
remaining--;
}
}
return result;
}
function getBusinessDaysBetween(
start: Temporal.PlainDate,
end: Temporal.PlainDate
): number {
let count = 0;
let current = start;
while (Temporal.PlainDate.compare(current, end) < 0) {
current = current.add({ days: 1 });
if (current.dayOfWeek !== 6 && current.dayOfWeek !== 7) {
count++;
}
}
return count;
}
// Uso
const today = Temporal.PlainDate.from('2026-01-20'); // Segunda
const deadline = addBusinessDays(today, 5);
console.log(deadline.toString()); // "2026-01-27" (proxima segunda)
const businessDays = getBusinessDaysBetween(today, deadline);
console.log(`${businessDays} dias uteis`); // "5 dias uteis"
Conclusao
A Temporal API representa a maior evolucao no tratamento de datas do JavaScript desde sua criacao. Finalmente temos uma solucao nativa que resolve os problemas historicos do Date.
Pontos principais:
- Objetos imutaveis evitam bugs comuns
- Tipos separados para diferentes necessidades
- Suporte completo a timezones
- Precisao de nanosegundos
- API clara e sem ambiguidades
Recomendacoes:
- Comece a usar o polyfill em novos projetos
- Planeje migracao gradual de Moment.js/date-fns
- Aprenda os diferentes tipos e quando usar cada um
- Acompanhe o progresso de implementacao nos navegadores
A transicao vai levar tempo, mas vale comecar a se familiarizar com a Temporal API agora.
Para mais conteudo sobre JavaScript moderno, leia: Descobrindo o Poder do Async/Await no JavaScript.

