Formatação de Datas e Números com a API Intl
Você já usou Intl.DateTimeFormat e Intl.NumberFormat antes. Mas se o seu modelo mental remonta a alguns anos atrás, você provavelmente está perdendo capacidades significativas—particularmente em relação aos controles de arredondamento do Intl.NumberFormat e como Temporal e Intl funcionam juntos em runtimes do final de 2025.
Este artigo fornece uma visão técnica atualizada da internacionalização em JavaScript através da API Intl, focando no que mudou e no que desenvolvedores experientes frequentemente erram.
Principais Conclusões
- A API Intl formata valores em strings sensíveis ao locale, mas não analisa, calcula ou armazena dados—mantenha a apresentação separada da lógica da aplicação.
Intl.NumberFormatagora suporta controles avançados de arredondamento incluindoroundingMode,roundingIncrementetrailingZeroDisplay.- Os tipos Temporal lidam com sua própria formatação
toLocaleString()enquantoIntl.DateTimeFormatcontinua a formatar objetosDate. - Sempre reutilize instâncias de formatadores para performance e evite codificar strings de saída esperadas em testes.
O Que a Intl Realmente Faz
O namespace Intl lida com formatação de valores sensível ao locale. Ele não analisa, calcula ou manipula dados—ele transforma valores em strings legíveis para humanos de acordo com convenções culturais.
Dois pontos críticos:
- Intl formata; não armazena ou computa. A lógica da sua aplicação permanece separada da apresentação.
- A saída varia por runtime. Os dados de locale subjacentes vêm de bibliotecas ICU empacotadas com navegadores e Node.js. Strings exatas podem diferir ligeiramente entre Chrome e Safari, ou entre versões do Node.
Nunca codifique strings de saída esperadas em testes. Use formatToParts() ou asserções estruturais em vez disso.
Intl.DateTimeFormat: Além das Opções Básicas
Formatando Objetos Date
Intl.DateTimeFormat permanece a forma padrão de formatar objetos Date do JavaScript:
const formatter = new Intl.DateTimeFormat('de-DE', {
dateStyle: 'long',
timeStyle: 'short',
timeZone: 'Europe/Berlin'
});
formatter.format(new Date()); // "27. Juni 2025 um 14:30"
As opções dateStyle e timeStyle fornecem configurações predefinidas. Quando você precisa de controle granular, use opções individuais como weekday, month, hour e timeZoneName.
Tipos Temporal e Formatação Sensível ao Locale
Temporal está sendo ativamente implementado em motores JavaScript modernos, mas ainda não possui suporte amplo em todos os navegadores e ambientes. Onde disponível, Temporal.PlainDate, Temporal.ZonedDateTime e outros tipos Temporal formatam a si mesmos via toLocaleString(), em vez de serem passados diretamente para Intl.DateTimeFormat.prototype.format().
const date = Temporal.PlainDate.from('2025-06-27');
date.toLocaleString('ja-JP', { dateStyle: 'full' });
// "2025年6月27日金曜日"
Intl.DateTimeFormat aceita objetos Date. Os tipos Temporal lidam com sua própria lógica de formatação e podem delegar comportamento sensível ao locale internamente, mas não são formatados pelo próprio Intl.DateTimeFormat. Esta distinção importa ao projetar APIs que aceitam entradas de data.
Intervalos de Datas com formatRange
Para exibir intervalos de datas, use formatRange():
const start = new Date(2025, 5, 27);
const end = new Date(2025, 6, 3);
new Intl.DateTimeFormat('en-US', { dateStyle: 'medium' })
.formatRange(start, end);
// "Jun 27 – Jul 3, 2025"
O formatador colapsa inteligentemente partes redundantes com base nas convenções do locale.
Discover how at OpenReplay.com.
Controles de Arredondamento e Exibição do Intl.NumberFormat
Opções Modernas de Arredondamento
O comportamento de arredondamento do Intl.NumberFormat expandiu significativamente nas especificações recentes, com suporte variando por runtime. Além de minimumFractionDigits e maximumFractionDigits, você agora tem:
roundingMode: Controla como os valores arredondam (ceil,floor,halfExpand,halfEven, etc.)roundingIncrement: Arredonda para incrementos específicos (5, 10, 50, etc.)trailingZeroDisplay: Controla se zeros à direita aparecem (autooustripIfInteger)
const formatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
roundingMode: 'halfEven',
maximumFractionDigits: 2
});
formatter.format(2.225); // "$2.22" (arredondamento bancário)
formatter.format(2.235); // "$2.24"
Padrões de Formatação de Números Sensíveis ao Locale
Para notação compacta e formatação de unidades:
// Notação compacta
new Intl.NumberFormat('en-US', {
notation: 'compact',
compactDisplay: 'short'
}).format(1234567); // "1.2M"
// Formatação de unidades
new Intl.NumberFormat('de-DE', {
style: 'unit',
unit: 'kilometer-per-hour',
unitDisplay: 'short'
}).format(120); // "120 km/h"
Considerações Práticas
Reutilize Instâncias de Formatadores
Criar formatadores tem overhead. Armazene-os em cache ao formatar múltiplos valores:
// Faça isso
const priceFormatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
});
prices.map(p => priceFormatter.format(p));
// Não isso
prices.map(p => new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
}).format(p));
Detecção de Recursos
Verifique opções mais recentes programaticamente:
try {
new Intl.NumberFormat('en', { roundingMode: 'halfEven' });
// Recurso suportado
} catch (e) {
// Recorra ao arredondamento padrão
}
Locale vs. Timezone
Estes são conceitos independentes. Um locale (en-GB) determina convenções de formatação. Um timezone (Europe/London) determina o horário do relógio exibido. Você pode formatar uma data em convenções alemãs enquanto mostra o horário de Tóquio.
Conclusão
A API Intl para formatação de datas e formatação de números sensível ao locale amadureceu substancialmente. A especificação agora inclui modos de arredondamento, controles de exibição e formatação de intervalos que eliminam a maioria das razões para bibliotecas externas.
Os tipos Temporal existem ao lado da Intl—eles lidam com suas próprias chamadas toLocaleString() enquanto Intl.DateTimeFormat continua a formatar objetos Date. Construa seu modelo mental em torno desta separação, teste sem expectativas de strings codificadas e reutilize instâncias de formatadores para performance.
Perguntas Frequentes
Não. Intl.DateTimeFormat.prototype.format() aceita apenas objetos Date. Tipos Temporal como PlainDate e ZonedDateTime têm seus próprios métodos toLocaleString(). Eles não são formatados pelo próprio Intl.DateTimeFormat, mesmo que possam usar dados de locale similares internamente.
Intl depende de dados de locale ICU empacotados com cada runtime. Chrome, Safari, Firefox e Node.js podem distribuir diferentes versões do ICU com pequenas variações na saída. Evite codificar strings esperadas em testes. Use formatToParts() ou asserções estruturais para verificar o comportamento de formatação de forma confiável.
Arredondamento bancário (halfEven) arredonda valores intermediários em direção ao dígito par mais próximo, reduzindo viés cumulativo de arredondamento. É comumente usado em contextos financeiros e contábeis, mas resultados exatos ainda podem ser afetados pela representação de ponto flutuante binário.
Tente construir um formatador com a opção habilitada. Se o runtime não suportá-la, pode lançar um RangeError ou silenciosamente ignorar a opção, dependendo do motor. Sempre inclua uma estratégia de fallback.
Complete picture for complete understanding
Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.
Check our GitHub repo and join the thousands of developers in our community.