Back

Formatação de Datas e Números com a API Intl

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.NumberFormat agora suporta controles avançados de arredondamento incluindo roundingMode, roundingIncrement e trailingZeroDisplay.
  • Os tipos Temporal lidam com sua própria formatação toLocaleString() enquanto Intl.DateTimeFormat continua a formatar objetos Date.
  • 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:

  1. Intl formata; não armazena ou computa. A lógica da sua aplicação permanece separada da apresentação.
  2. 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.

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 (auto ou stripIfInteger)
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.

OpenReplay