Temporal API

A API Temporal do JavaScript: um substituto moderno de Date

O JavaScript Date está estragado de formas bem conhecidas há décadas. O TC39 Temporal — Stage 4 desde o início de 2025, já nos navegadores modernos e no Node.js — separa de forma limpa os instantes, as datas de relógio de parede e as datas-hora com fuso. Este guia explica os novos tipos, como se relacionam com os timestamps Unix e como migrar.

Temporal vs Date num relance

O Date embutido do JavaScript é uma fonte conhecida de bugs há décadas: é mutável, só entende o fuso local e o UTC, os seus meses são indexados a zero e o seu parsing está vagamente especificado. O Temporal é o substituto normalizado — Stage 4 e parte do ECMAScript 2026 — e corrige cada um desses problemas com tipos imutáveis feitos de propósito. A tabela abaixo é o contraste geral; o resto deste guia cobre os tipos e como se relacionam com os timestamps Unix.

AspetoDate (legado)Temporal
MutabilidadeMutávelImutável
PrecisãoMilissegundosNanossegundos
Fusos horáriosSó local + UTCQualquer fuso IANA (ZonedDateTime)
Indexação dos mesesBase 0 (0 = janeiro)Base 1 (1 = janeiro)
ParsingPermissivo, definido pela implementaçãoISO 8601 / RFC 9557 estrito
Instante vs relógio de paredeConfundidos num só tipoTipos separados

Porque existe o Temporal

O JavaScript Date confunde vários conceitos distintos: um instante exato, uma hora de relógio de parede e uma data-hora com fuso. O Date também tem peculiaridades de parsing bem conhecidas, um único fuso (o do utilizador) e precisão de milissegundos. O Temporal expõe os conceitos subjacentes como tipos separados e suporta precisão de nanossegundos, fusos IANA arbitrários e sistemas de calendário explícitos.

  • Stage 4 desde o início de 2025; lançado primeiro por omissão no Firefox 139
  • Agora disponível no Chrome 144+, Firefox 139+ e Node.js 26+
  • Os polyfills (@js-temporal/polyfill) funcionam em qualquer ambiente moderno
  • Concebido para coexistir com o Date — existem métodos de interoperabilidade nos dois sentidos

Os tipos essenciais do Temporal

Um pequeno conjunto de tipos cobre de forma limpa o problema das datas-hora. Cada um tem uma forma de cadeia canónica (ISO 8601, estendida pela RFC 9557 para o tipo com fuso):

TipoRepresentaCadeia de exemplo
Temporal.InstantUm instante exato, como um timestamp Unix (precisão ns)2026-01-01T00:00:00Z
Temporal.ZonedDateTimeInstante + fuso IANA + calendário2026-01-01T09:00:00+09:00[Asia/Tokyo]
Temporal.PlainDateTimeData + hora, sem fuso2026-01-01T09:00:00
Temporal.PlainDateUma data de calendário (p. ex. um aniversário)2026-01-01
Temporal.PlainTimeUma hora de relógio de parede09:00:00
Temporal.DurationUma duração, ciente das unidadesP3DT4H10M

Trabalhar com timestamps Unix

O Temporal.Instant é o tipo timestamp Unix. A API publicada só expõe conversões epoch em milissegundos e nanossegundos — os métodos anteriores fromEpochSeconds e fromEpochMicroseconds foram removidos antes do Stage 4 — por isso converte segundos Unix multiplicando por 1000. Usa Instant para armazenamento e transporte, e ZonedDateTime quando precisares de uma vista de relógio de parede num fuso específico.

  • Temporal.Now.instant() — o momento exato atual
  • Temporal.Instant.fromEpochMilliseconds(Date.now()) — a partir de um timestamp JS em milissegundos
  • Temporal.Instant.fromEpochMilliseconds(1700000000 * 1000) — a partir de segundos Unix (× 1000)
  • Temporal.Instant.fromEpochNanoseconds(1700000000000000000n) — a partir de nanossegundos (BigInt)
  • instant.epochMilliseconds e instant.epochNanoseconds — reler o valor epoch
  • instant.toZonedDateTimeISO("America/New_York") — uma vista de relógio de parede num fuso

Fusos e DST tratados corretamente

O ZonedDateTime transporta um fuso IANA, por isso as transições de DST, as horas de buraco e as horas de sobreposição são todas tratadas explicitamente. A opção de desambiguação deixa-te escolher uma política para horas locais ambíguas, e o formato de cadeia canónico é a RFC 9557 (um timestamp ISO 8601 com o fuso entre parênteses retos).

  • zdt.timeZoneId — o nome IANA (p. ex. America/Los_Angeles)
  • zdt.add({ hours: 1 }) — aritmética ciente do DST em termos de relógio de parede
  • zdt.until(zdt2) — distância entre duas datas-hora com fuso
  • Opções de desambiguação: "earlier", "later", "compatible" (por omissão — posterior para o buraco, anterior para a sobreposição), "reject"
  • Ida e volta: instante ↔ data-hora com fuso é sem perdas

Padrões de migração a partir de Date

A estratégia de migração mais simples é introduzir o Temporal primeiro nas fronteiras (parsing da entrada, formatação da saída) e mover gradualmente a lógica interna.

  • Date → Instant: Temporal.Instant.fromEpochMilliseconds(date.getTime())
  • Instant → Date: new Date(instant.epochMilliseconds)
  • Para código novo, prefere o Temporal em todo o lado e converte para Date só nas bordas da API
  • O date-fns e o Luxon têm ambos modos / adaptadores cientes do Temporal
  • JSON: Temporal.Instant.prototype.toJSON devolve uma cadeia ISO 8601

Suporte em navegadores e runtimes

O Temporal foi lançado em 2025 e o suporte nativo já é amplo, mas ainda não universal. O polyfill é o caminho mais seguro enquanto os navegadores antigos e o Safari estável ainda estiverem em serviço.

  • Firefox 139+: o primeiro a lançá-lo, ativado por omissão (maio de 2025)
  • Chrome 144+: ativado por omissão (janeiro de 2026)
  • Node.js 26+: ativado por omissão (maio de 2026)
  • Safari: disponível em Technology Preview, ainda não numa versão estável
  • Polyfill: @js-temporal/polyfill ou temporal-polyfill — mesma API, qualquer ambiente moderno

Referências relacionadas

FAQ

O Temporal é um substituto de Date?
Sim — o Temporal foi concebido para substituir totalmente o Date em código novo. O Date permanece na linguagem por compatibilidade retroativa, e os dois interoperam via milissegundos epoch.
Como converto um timestamp Unix para Temporal?
Usa Temporal.Instant.fromEpochMilliseconds(). Para segundos Unix, multiplica por 1000: Temporal.Instant.fromEpochMilliseconds(seconds * 1000). A API publicada só tem fromEpochMilliseconds e fromEpochNanoseconds — o método mais antigo fromEpochSeconds foi removido antes de o Temporal atingir o Stage 4.
O Temporal suporta nanossegundos?
Sim. O Temporal.Instant tem precisão de nanossegundos internamente e expõe epochNanoseconds como um BigInt.
Posso usar o Temporal no Node.js hoje?
No Node.js 26+ o Temporal está ativado por omissão. Em versões anteriores do Node, instala @js-temporal/polyfill — a superfície da API é idêntica.
Que navegadores suportam o Temporal?
O Firefox 139+ (maio de 2025), o Chrome 144+ (janeiro de 2026) e o Node.js 26+ (maio de 2026) incluem o Temporal por omissão. O Safari tem-no em Technology Preview. Para algo mais antigo, usa o @js-temporal/polyfill.
Como é que o Temporal trata o buraco do DST?
Os construtores e a aritmética de ZonedDateTime aceitam uma opção de desambiguação. "compatible" (por omissão) escolhe o instante posterior para os buracos e o anterior para as sobreposições; "reject" lança um erro se a hora local for ambígua.