O Temporal do JavaScript está chegando
(developer.mozilla.org)- O novo objeto Temporal do JavaScript está começando a entrar em versões experimentais de navegadores, marcando uma mudança para tratar data, hora, duração e calendários de forma mais precisa e consistente com uma API nativa
- O
Dateexistente dificultava o tratamento de fusos horários e a depuração por causa de sua estrutura centrada no horário local do usuário e em UTC, parsing instável e comportamento mutável - O Temporal separa instantes, horário local e durações com tipos como
Temporal.Instant,Temporal.ZonedDateTime,Temporal.PlainDateTime,Temporal.DurationeTemporal.Now, além de oferecer mais de 200 métodos utilitários - Ainda será preciso mais tempo até haver suporte estável entre navegadores, mas no Firefox Nightly já é possível testar o Temporal por trás da configuração
javascript.options.experimental.temporal - Nesta semana, a MDN adicionou mais de 270 páginas de documentação sobre Temporal, e na página de documentação do TC39 com
@js-temporal/polyfillé possível executar os exemplos sem mudar flags
As antigas limitações do Date no JavaScript
- Quando o JavaScript foi criado em 1995, o objeto
Datecopiou a implementação inicial dejava.util.Datedo Java, e embora o Java a tenha substituído em 1997, o JavaScript manteve praticamente a mesma API por quase 30 anos - Os maiores problemas são a falta de suporte a fusos horários e o comportamento instável de parsing
- Só oferece suporte ao horário local do usuário e a UTC
- O próprio
Dateé mutable, o que pode gerar bugs difíceis de rastrear - Também é difícil lidar com cálculos que atravessam o Daylight Saving Time (DST) e mudanças históricas de calendário
- Por causa dessas limitações, muitos desenvolvedores passaram a depender de bibliotecas especializadas como Moment.js ou date-fns para tratar datas e horas em aplicações
Como o Temporal muda o modelo de data e hora
- O Temporal foi projetado como um substituto completo para o objeto
Date, com o objetivo de tornar o gerenciamento de datas e horas mais confiável e previsível - Ele oferece suporte à representação de fusos horários e calendários, além de métodos nativos para conversão, comparação, cálculo e formatação
- A superfície da API tem mais de 200 métodos utilitários, e a documentação do Temporal na MDN recebeu descrições e exemplos
Principais tipos do Temporal
- O Temporal distingue instantes únicos, horário de parede local e durações em tipos diferentes
- As principais estruturas são as seguintes
Temporal.Duration: a diferença entre dois instantesTemporal.Instant: um instante único representado por timestampTemporal.ZonedDateTime: data e hora com fuso horárioTemporal.PlainDateTime: data e hora completas sem fuso horárioTemporal.PlainDate: representa apenas a dataTemporal.PlainYearMonth: ano e mêsTemporal.PlainMonthDay: mês e diaTemporal.PlainTime: representa apenas a hora
Temporal.Now: API para obter a hora atual em instâncias de várias classes ou em formatos específicos
Como usar na prática, com exemplos
- É possível obter a data e a hora atuais como string ISO e passar fusos horários para vários métodos
Temporal.Now.plainDateTimeISO()retorna a data e hora atuais no fuso horário do sistemaTemporal.Now.plainDateTimeISO("America/New_York")retorna a data e hora atuais no fuso horário de New York
- Também é possível trabalhar com calendários além do gregoriano, criando datas em sistemas como o hebraico, chinês e islâmico
- O cálculo do próximo Ano-Novo Chinês usa o dia 1 de
M01no calendário chinês - Na saída de exemplo no momento da escrita, o próximo Ano-Novo Chinês é
1/29/2025
- O cálculo do próximo Ano-Novo Chinês usa o dia 1 de
- Um timestamp Unix Epoch em milissegundos pode ser transformado em instante com
Temporal.Instant.fromEpochMilliseconds()e comparado comTemporal.Now.instant()para calcular o tempo restante- Para o timestamp de exemplo
1851222399924, o tempo a partir de agora é calculado comsmallestUnit: "hour" - A saída de
@js-temporal/polyfillé31,600 hr, enquanto a do Firefox Nightly éPT31600H
- Para o timestamp de exemplo
- A implementação do Firefox para
toLocaleStringatualmente não produz strings sensíveis ao locale- Esse comportamento parece estar mais próximo de uma decisão de design do que de uma limitação técnica, e a formatação de duration em si é possível
- A implementação do polyfill e a do Firefox podem convergir mais tarde
- O método
compare()pode ser usado para ordenar arrays- Com
durations.sort(Temporal.Duration.compare), a ordenação ficaPT1H,PT1H30M,PT1H45M,PT2H
- Com
Suporte em navegadores e como testar
- O suporte ao Temporal está começando a entrar lentamente em versões experimentais de navegadores, e a implementação atual do Firefox parece ser a mais madura
- No Firefox, o Temporal já está sendo compilado por trás da configuração
javascript.options.experimental.temporalna versão Nightly - Os principais issues de navegador para acompanhar a implementação são os seguintes
- Firefox: Build temporal in Nightly by default
- Safari: [JSC] Implement Temporal
- Chrome: Implement the Temporal proposal
- O estado geral de compatibilidade pode ser consultado na seção de compatibilidade de navegadores do objeto Temporal na MDN
- A documentação do Temporal no TC39 inclui
@js-temporal/polyfill, permitindo executar os exemplos no console das ferramentas de desenvolvedor em qualquer navegador sem alterar flags nem configurações
1 comentários
Opiniões do Hacker News
Temporal é excelente. Usei em produção por um bom tempo via polyfill, e ele resolve muitos dos problemas que eu encontrava com a API antiga
Date()Parece que pegou inspiração de boas bibliotecas de tempo, como
chronodo Rust e Joda Time do Java, e juntou tudo em uma API fácil de usarEle é um pouco mais complexo por separar tempo simples, instantes e tempos com fuso horário, mas o próprio tempo é complexo, então o desenvolvedor precisa encarar essa complexidade
Mesmo uma operação como “adicionar um dia a este timestamp” precisa necessariamente decidir se isso é em relação a um fuso horário específico; caso contrário, ficam bugs por causa do horário de verão, de mudanças no fuso horário do usuário ou de diferenças no fuso horário do servidor
Ele também resolve a diferença de serialização entre timestamps com offset fixo (
2025-01-01T00:00+02:00) e um fuso horário específico (Europe/Paris)chrono: https://docs.rs/jiff/latest/jiff/_documentation/comparison/i...Pessoalmente, acho difícil dizer que o Temporal foi fortemente inspirado no
chronodo Rust; parece ter sido mais influenciado por Joda, pelojava.timeatual e por bibliotecas de data e hora em JavaScript como date-fns e Moment.jsElas não vão procurar se
Europe/Parissignifica uma região ampla da França ou apenas Paris; ficam incomodadas porque parece que estão dizendo que moram em ParisIsso foi doloroso ao agendar coisas como eventos de comunidades online. As pessoas querem usar offsets fixos e aceitam expressões como
CET/CEST, mas não gostam de algo comoEurope/suascoordenadasexatasSei que, na prática, a maioria dos fusos horários cobre regiões bem amplas, mas há muita gente que se preocupa com privacidade e, ainda assim, não pensa em pesquisar a diferença entre “hora” e “fuso horário”
chronoe Joda Time são coisas de épocas diferentes. Quando o Rust 1.0 saiu, Java já tinha implementado essa abordagem na biblioteca padrão com java.time, e não era necessária uma biblioteca de terceiros para esse usoDemorei um bom tempo para encontrar isso na documentação, mas Temporal.ZonedDateTime.prototype.withTimeZone() converte de um fuso horário para outro: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
Se você pegar um valor criado com
Temporal.ZonedDateTime.from("2021-08-01T12:00[America/New_York]")e passar parawithTimeZone("Europe/Paris"), ele vira2021-08-01T18:00:00+02:00[Europe/Paris]Conversão de fuso horário e tratamento de durações são recursos centrais que uma biblioteca precisa cobrir, então é bom que o Temporal trate ambos. Porém, parece que
Temporal.Durationnão tem uma funçãoformatpersonalizada para produzir algo como1h03m, por exemploduration.format('H\hmm\m')1 yr,3 hours,3m: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...Já implementei parte disso na biblioteca icu4x
No momento, há várias propostas amadurecendo no TC39, e Temporal é uma das que eu gostaria que fossem lançadas logo
Sei que, para os principais navegadores darem suporte a novos recursos, é necessário esforço de desenvolvimento dos engenheiros do v8, JSC e SpiderMonkey, então sou muito grato a quem está fazendo isso avançar
Do ponto de vista de quem está impaciente, dá vontade de torcer dizendo: “Façam logo Records e Tuples também! Podem pular a guerra da sintaxe de pipes!”
Pelo que entendo, os fornecedores de navegadores já são bastante contrários, neste momento, a adicionar novos tipos primitivos. As dificuldades sobre como a igualdade deveria funcionar são explicadas nesta thread: https://github.com/tc39/proposal-record-tuple/issues/387
No início eu não esperava que BigInt fosse ser tão usado, mas, na prática, continuam surgindo situações em que faz falta uma coleção com igualdade estrutural
Sei que a oposição a adicionar novos tipos primitivos também afeta pattern matching, mas não sei bem o motivo, e tenho acompanhado menos essa proposta
Pipeline, pattern matching e Records+Tuples estão todos em desenvolvimento há mais de 4 anos e ainda estão nos estágios 1 ou 2. No último ano, parece que quase não houve avanço significativo, exceto talvez em pattern matching
Segundo issues no repositório de Records e Tuples, houve resistência à semântica de valor, isto é, a se
===poderia funcionar. Sem semântica de valor, a utilidade da proposta cai bastantePara chegarem ao estágio 3, eles ainda levariam pelo menos mais 1 ou 2 anos, ou talvez nem cheguem lá. Ainda assim, as funções de agrupamento de arrays saíram
Infelizmente, ainda está no estágio 1, então deve levar mais alguns anos
O Dictionary do AS3 era um tipo que usava referências de objetos, strings e números como chaves únicas e permitia associar valores de qualquer tipo. O garbage collector também tratava isso para que, enquanto o próprio objeto de dicionário estivesse vivo, as referências não fossem fracas
Pense no Set do JavaScript, mas usando qualquer tipo de chave especificado de forma fortemente tipada e emitindo erro em tempo de compilação. Sinto falta daquela linguagem
Essas atualizações basicamente quebraram o ecossistema JavaScript, e agora parece que só restaram linguagens que compilam para JS. Quem ainda usa JS vanilla parece alguém fazendo aplicativos em assembly
Tenho curiosidade sobre como os dados de cada fuso horário dentro do Temporal são mantidos atualizados
Fico me perguntando se a estrutura é o TC39 atualizar os dados em algum lugar e cada navegador copiar esses dados internamente e lançar uma nova versão, e se, caso o usuário não tenha atualizado para um navegador com os novos dados, ele verá horários incorretos no meu site
Por exemplo, o México aboliu o horário de verão em 2022: https://en.wikipedia.org/wiki/Time_in_Mexico
Bibliotecas de terceiros como
pytzoumoment-timezonepodem ser atualizadas no lado do servidor, e, se isso for tratado pela biblioteca padrão, basta atualizar a versão da linguagem, mas não sei como isso funciona com Temporal e o navegador do visitanteO computador do usuário também deve ter acesso a esse banco de dados e provavelmente lida com atualizações, mas não tenho certeza. O navegador também poderia baixar e manter esse banco de dados separadamente, e isso deve depender da implementação
Banco de dados relacionado: https://en.wikipedia.org/wiki/Tz_database
Intl, então investigar esse lado provavelmente levará a uma resposta parecidatzdbda IANAParece, em geral, correto dizer que, se o usuário não atualizar o navegador ou o sistema para refletir os novos dados de fuso horário, poderá ver horários incorretos. Porém, isso não difere muito da prática comum atual
A alternativa seria cada aplicação incluir seu próprio
tzdb, e alguns apps fazem isso e têm bons motivos. Mas, em geral, é desperdício, aumenta inconsistências entre aplicações e provavelmente resulta em ciclos de atualização mais lentosÉ preciso adicionar um evento para detectar quando alguém muda de fuso horário
À lista de “falsidades em que programadores acreditam sobre tempo” também poderia entrar “programadores acreditam que o fuso horário permanece fixo durante o uso”. Na realidade, milhões de pessoas atravessam fusos horários todos os dias
Claro, poderia ajudar bibliotecas
É uma pena que
.Nownão seja uma chamada de função. Não deveria ser uma propriedadeSe
.Nowfor avaliado várias vezes dentro de um loop, pode retornar um valor diferente a cada vez, o que é inesperadoC# fez a mesma escolha e não deveria ter feito: https://ericlippert.com/2014/05/19/when-should-i-write-a-pro...
Nowé um namespace para funções que obtêm valores reais, por exemploNow.instant()Gosto muito da proposta do Temporal, mas uma coisa me incomoda. Ela depende de igualdade por referência nas comparações
Ou seja,
Temporal.Instant.from('2020-01-01') != Temporal.Instant.from('2020-01-01')Isso não é ruim por si só, mas na prática elimina a capacidade de usar esses objetos como chaves de
Mapou de reuni-los em umSet. Entendo por que tomaram essa decisão, mas é uma pena que não seja possívelTalvez, se Records e Tuples realmente surgirem algum dia, apareça uma versão baseada neles
==?.epochMillisecondscomo chave ou elemento emMap/Set. Mas se, noMap, você precisar preservar dados de fuso horário ou fazer operações adicionais comInstant, será necessário manter oInstantoriginal no valorNo caso de
Set, dá para usar algo comoMap{v.epochMilliseconds:v}para preservar oInstantNão é ótimo, mas esse é um problema a ser atribuído ao próprio JavaScript, mais do que ao Temporal. O runtime poderia cuidar disso, mas aí o polyfill falharia
Map/Seté parecido com usar números de ponto flutuante emMap/Set, e geralmente é uma má ideiaString()ou'2020-01-01'?Fornecer uma função de comparação que funciona com APIs existentes é um design sólido. Poderia até ser requisito obrigatório ao adicionar novos tipos
Por exemplo, ao passar
Temporal.Duration.compareparasort, dá para ordenar comoPT1H,PT1H30M,PT1H45M,PT2H. Palmas para os designersEntendo que o nome
Temporaltente evitar conflitos com objetos de tempo comuns como Moment e Datetime, mas o nome é ruimQuando vi pela primeira vez, achei que fosse algo como controle de garbage collection
temporalsignifica algo relativo ao tempo em contraste com a eternidade, relativo ao tempo verbal ou a distinções de tempo na gramática, ou relativo ao tempo em oposição ao espaço: https://www.merriam-webster.com/dictionary/temporalParece um bom nome
Para começar,
Temporalnão é um substantivo, é um adjetivo. Tem relação com tempo, mas não encaixa intuitivamenteMais importante: quando se escolhe um nome estranho para reduzir a chance de conflito com código antigo, a linguagem fica mais opaca com o passar do tempo
Quando
PromiseeGeneratorforam adicionados, também havia muitas bibliotecas usando esses nomes de objetos. Ao contrário de palavras reservadas, objetos embutidos podem ser sobrescritos, então isso não foi um grande problemaAcho que, pela saúde da linguagem no longo prazo, o comitê de padronização deveria ter insistido em
TimeClaro, essa discussão já passou, e os fabricantes de navegadores e implementadores de engines JS devem ter chegado a um acordo
DateV2seria melhorEntendo que compatibilidade retroativa seja necessária, mas
Temporalsoa ruim.DateTimenem é um nome existente no padrão JS; não sei por que não usaram isso. Até lá, acho que vou usarconst DateTime = TemporalPosts relacionados:
JavaScript Temporal Is Coming - https://news.ycombinator.com/item?id=42809834 - janeiro de 2025, 18 comentários
Mozilla: Temporal (Limited Availability) - https://news.ycombinator.com/item?id=42776548 - janeiro de 2025, 1 comentário
Is It Time for the JavaScript Temporal API? - https://news.ycombinator.com/item?id=29712118 - dezembro de 2021, 100 comentários
Temporal: Getting started with JavaScript's new date time API - https://news.ycombinator.com/item?id=27661667 - junho de 2021, 194 comentários
JavaScript Temporal - https://news.ycombinator.com/item?id=27395236 - junho de 2021, 1 comentário
JavaScript Proposal Temporal for Dates is now stage 3 - https://news.ycombinator.com/item?id=26432346 - março de 2021, 1 comentário
A frase de que navios grandes demoram para mudar de direção se encaixa perfeitamente