Dates
Escopo: JavaScript. Idiomas específicos deste ecossistema.
Datas são uma das maiores fontes de bugs silenciosos em JavaScript. Date mistura local time e UTC (Coordinated Universal Time, Tempo Universal Coordenado) de forma imprevisível. A regra é simples: armazenar e transmitir sempre em UTC ISO 8601 (International Organization for Standardization 8601, Norma Internacional de Datas), converter para o fuso local só na exibição.
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 local time
new Date() sem argumentos retorna a hora local da máquina. Em servidores com timezones diferentes, o mesmo código produz resultados diferentes.
❌ 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
Parsing inconsistente
O comportamento de new Date(string) muda conforme o formato passado e varia entre engines.
❌ 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** (International Organization for Standardization, Organização Internacional de Normalização) 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
Armazenar ou transmitir com toLocaleDateString() embute o fuso no valor: impossível reverter
depois. Separar armazenamento de exibição mantém o dado portável.
❌ 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 tipos explícitos: Temporal.Instant para timestamps UTC,
Temporal.PlainDate para datas sem hora, Temporal.ZonedDateTime para datas com timezone.
// 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: deprecated desde 2020.
Desenvolvido por @thiagocajadev · Fork baseado no repositório pmndrs/docs · Poimandres.