Dates
Escopo: JavaScript. Idiomas específicos deste ecossistema.
Guarde e transmita toda data em UTC; só na hora de exibir converta para o fuso do usuário. Essa única regra elimina a maior fonte de bugs silenciosos de data em JavaScript, porque o tipo Date mistura local time (hora local da máquina) e UTC (Coordinated Universal Time · Tempo Universal Coordenado) sem avisar qual dos dois está usando. O formato de transporte é o ISO 8601 (International Organization for Standardization 8601 · Norma Internacional de Datas): o texto YYYY-MM-DDTHH:mm:ss.sssZ, que qualquer sistema lê do mesmo jeito.
Conceitos fundamentais
| Conceito | O que é |
|---|---|
| UTC (Coordinated Universal Time · Tempo Universal Coordenado) | Referência de tempo sem fuso; formato canônico para armazenar e transmitir |
| ISO 8601 (International Organization for Standardization 8601 · Norma Internacional de Datas) | Formato padrão YYYY-MM-DDTHH:mm:ss.sssZ para datas em texto |
| Temporal (proposta de API moderna) | API que substitui Date no ECMAScript, separa tipos por intenção (instant, zoned, plain) |
| API (Application Programming Interface · Interface de Programação de Aplicações) | Contrato público; Date e Intl.DateTimeFormat são APIs nativas |
UTC vs hora local
new Date() sem argumentos devolve a hora local da máquina que executa o código. Troque a máquina de fuso e o mesmo código passa a dar outro valor. Um servidor em São Paulo e outro em Lisboa gravam horas diferentes para o mesmo instante, e ninguém percebe até o relatório sair errado.
❌ Ruim: captura hora local, comportamento depende do servidor
const createdAt = new Date().toString();
// "Sat Apr 19 2026 11:00:00 GMT-0300": timezone vazando para o valor
✅ Bom: UTC explícito, resultado idêntico em qualquer ambiente
const createdAt = new Date().toISOString();
// "2026-04-19T14:00:00.000Z": inequívoco, portável
Interpretação de texto inconsistente
new Date(string) interpreta o texto de formas diferentes conforme o formato que você passa, e o resultado ainda varia entre engines (motores que executam o JavaScript, como o V8 do Chrome). Dois textos quase iguais podem virar dois instantes distintos.
❌ Ruim: formato ambíguo, resultado local-dependente
const date = new Date("01/15/2026");
// Interpretado como meia-noite local; em UTC-3: "2026-01-15T03:00:00.000Z"
const date2 = new Date("2026-01-15");
// Interpretado como meia-noite UTC: "2026-01-15T00:00:00.000Z"
// Mesmo visual, resultados diferentes
✅ Bom: ISO 8601 completo, sem ambiguidade
const date = new Date("2026-01-15T00:00:00.000Z");
// Sempre meia-noite UTC, qualquer engine, qualquer timezone
Armazenamento vs exibição
Separe o que você guarda do que você mostra. Guardar ou transmitir com toLocaleDateString() embute o fuso dentro do próprio valor, e depois não há como recuperar o instante original. O dado só continua portável se você grava em UTC e formata na camada de exibição.
❌ Ruim: exibição misturada com armazenamento
const order = {
id: "ord_01HV...",
createdAt: new Date().toLocaleDateString("pt-BR"),
// "19/04/2026": timezone implícita, não parseável de volta para Date
};
✅ Bom: armazenar UTC, formatar só na camada de exibição
const order = {
id: "ord_01HV...",
createdAt: new Date().toISOString(), // armazenamento
};
function formatOrderDate(isoString, locale = "pt-BR") {
const date = new Date(isoString);
const formattedDate = new Intl.DateTimeFormat(locale, {
day: "2-digit",
month: "2-digit",
year: "numeric",
timeZone: "America/Sao_Paulo",
}).format(date);
return formattedDate;
}
// "19/04/2026": formatação explícita, locale e timezone declarados
Temporal API
Date é legado. A Temporal API (ES2026) resolve os problemas estruturais com um tipo para cada intenção, sem a ambiguidade de fuso do Date: Temporal.Instant para um instante em UTC, Temporal.PlainDate para uma data sem hora, Temporal.ZonedDateTime para uma data já com o fuso definido.
// Timestamp UTC inequívoco
const now = Temporal.Now.instant();
// Temporal.Instant <2026-04-19T14:00:00Z>
// Data sem hora (sem ambiguidade de timezone)
const birthDate = Temporal.PlainDate.from("1990-08-21");
// Data com timezone explícita
const appointment = Temporal.ZonedDateTime.from(
"2026-04-19T14:00:00[America/Sao_Paulo]"
);
Temporaltem suporte nativo no Chrome 144+ e Firefox 139+; Safari ainda em progresso. Enquanto não há suporte universal,date-fnsouLuxonsão as alternativas recomendadas. Evitemoment.js: descontinuado desde 2020.
DoDocs v3.7.0 · Desenvolvido por @thiagocajadev · Baseado no trabalho de pmndrs/docs · Poimandres.