O que é o Intl.RelativeTimeFormat
O Intl.RelativeTimeFormat e uma API nativa do JavaScript que formata durações relativas no estilo 'ha 2 horas', 'em 3 dias' ou 'ha 1 mes', com suporte completo a internacionalização. Ela faz parte da especificação ECMAScript Internationalization API (ECMA-402) e esta disponível em todos os navegadores modernos desde 2020.
Antes dessa API existir, a solução padrão era instalar uma biblioteca como date-fns, moment.js ou dayjs somente para formatar esse tipo de string. Isso adicionava kilobytes desnecessários ao bundle e dependência de manutenção externa para algo que o próprio ambiente já suporta.
A API faz parte da família Intl, que cobre formatação de números, moedas, datas absolutas e muito mais. Se você já usou Intl.NumberFormat ou Intl.DateTimeFormat, o padrão e idêntico.
Como funciona por dentro
O Intl.RelativeTimeFormat recebe dois argumentos no construtor: o locale (como 'pt-BR') e um objeto de opcoes. Ele expõe o método format(value, unit), onde value e um número (positivo para futuro, negativo para passado) e unit e a unidade de tempo.
Internamente, a API usa os dados de localização do próprio motor JavaScript (V8, SpiderMonkey, JavaScriptCore), que por sua vez seguem o padrão CLDR (Common Locale Data Repository) do Unicode. Isso significa que a formatação esta sempre alinhada com as convenções reais do idioma, sem você precisar manter strings de tradução.
A grande diferença em relação a bibliotecas externas: a API não calcula a diferença entre duas datas. Ela só formata. Você passa o número e a unidade, ela devolve a string. O calculo fica por sua conta, o que é intencional - deixa a API simples e composavel.
Principais recursos e opcoes
Veja o que você pode configurar no construtor:
- numeric: 'auto' - usa palavras naturais quando possível ('ontem', 'amanha') em vez de '1 dia atrás'. Recomendado para UX.
- numeric: 'always' - sempre usa número ('ha 1 dia'). Útil para consistência visual.
- style: 'long' - forma completa: 'ha 2 horas'.
- style: 'short' - abreviado: 'ha 2 h.'.
- style: 'narrow' - mínimo: 'ha 2 h' (varia por idioma).
As unidades disponíveis são: year, quarter, month, week, day, hour, minute, second. Cada uma aceita singular e plural automaticamente.
Use numeric: 'auto' para interfaces em português. Em vez de 'ha 1 dia', o usuário le 'ontem' - muito mais natural.
Como começar: exemplos passo a passo
Sem instalar nada. Abra o console do navegador ou o Node.js e teste:
const rtf = new Intl.RelativeTimeFormat('pt-BR', { numeric: 'auto' }); rtf.format(-2, 'hour'); // 'ha 2 horas' rtf.format(1, 'day'); // 'amanha' rtf.format(-1, 'day'); // 'ontem' rtf.format(-3, 'month'); // 'ha 3 meses' rtf.format(5, 'minute'); // 'em 5 minutos'Para calcular a diferença entre duas datas e passar o valor correto, use um helper simples:
function timeAgo(date) { const seconds = Math.round((date - Date.now()) / 1000); const rtf = new Intl.RelativeTimeFormat('pt-BR', { numeric: 'auto' }); if (Math.abs(seconds) < 60) return rtf.format(seconds, 'second'); if (Math.abs(seconds) < 3600) return rtf.format(Math.round(seconds / 60), 'minute'); if (Math.abs(seconds) < 86400) return rtf.format(Math.round(seconds / 3600), 'hour'); if (Math.abs(seconds) < 2592000) return rtf.format(Math.round(seconds / 86400), 'day'); if (Math.abs(seconds) < 31536000) return rtf.format(Math.round(seconds / 2592000), 'month'); return rtf.format(Math.round(seconds / 31536000), 'year');} timeAgo(new Date('2026-08-05')); // 'ha 2 dias'Exemplo prático: feed de posts com timestamps
Imagine um componente React que exibe quando cada post foi publicado. Antes, você importava date-fns. Agora:
// Sem nenhum import externo function PostCard({ title, publishedAt }) { const rtf = new Intl.RelativeTimeFormat('pt-BR', { numeric: 'auto' }); const diff = Math.round((new Date(publishedAt) - Date.now()) / 3600000); const label = Math.abs(diff) < 24 ? rtf.format(Math.round(diff), 'hour') : rtf.format(Math.round(diff / 24), 'day'); return {title}
; }O componente acima não tem nenhuma dependência externa. O bundle final e menor, sem impacto no tempo de carregamento. Para um blog ou feed com centenas de cards, isso se multiplica.
Instanciar new Intl.RelativeTimeFormat() dentro de um loop ou render frequente pode ter custo de performance. Crie a instância fora da função e reutilize.
Comparação com alternativas
Quando usar cada opcao:
- Intl.RelativeTimeFormat (nativo): ideal quando você só precisa formatar durações relativas, sem manipulação complexa de datas. Zero dependência, zero bundle extra.
- date-fns (formatDistanceToNow): continua valendo quando você já usa date-fns para outras operações no projeto (parse, add, subtract). Não faz sentido instalar só para relativo.
- dayjs (plugin relativeTime): mesma lógica do date-fns. Se já esta no projeto, use. Do contrario, prefira o nativo.
- moment.js: legado. Pesado, imutável no package. Não adicionar em projetos novos.
O critério e simples: se o projeto já tem a biblioteca por outro motivo, use ela para consistência. Se você ia instalar só para o relativo, use o nativo.
Pontos positivos e limitações
Positivos: zero dependência, zero bundle, suporte nativo a dezenas de idiomas via CLDR, comportamento consistente entre plataformas. Funciona no Node.js (v12+) e em todos os navegadores modernos.
Limitações: a API não calcula a diferença entre datas - você precisa passar o valor calculado. Para casos complexos (fusos horários, calendarioshebraicos, etc.), uma biblioteca completa ainda e mais ergonómica. Também não ha opcao de personalizar o texto da string diretamente.
No Internet Explorer 11, a API Intl.RelativeTimeFormat não existe. Se você ainda precisa suportar IE11 (raro em 2026, mas acontece em sistemas legados), use um polyfill ou mantenha a biblioteca.
Casos de uso reais
Feed de noticias ou blog: timestamps do tipo 'ha 3 horas' ou 'ontem' em cada card de post. Caso clássico onde o nativo substitui date-fns completamente.
Chat ou notificações: exibir quando foi a última mensagem ('ha 2 min', 'ha 1 semana'). A API lida com todas as unidades necessárias.
Dashboard de dados: mostrar quando foi a última atualização de um gráfico ou métrica ('atualizado ha 5 minutos'). Sem biblioteca, sem overhead.
Apps multilingue: o mesmo código funciona para pt-BR, en-US, es-ES, já-JP e mais de 100 outros locales. Só mude o locale no construtor ou derive do navigator.language.
Dicas e boas práticas
Reutilize a instância do Intl.RelativeTimeFormat fora dos loops. Criar a instância e mais caro que chamar .format() - faca uma vez e chame múltiplas vezes.
Use navigator.language no browser (ou o header Accept-Language no servidor) como locale dinâmico. Assim o timestamp aparece no idioma do usuário sem configuração extra.
Combine com Intl.DateTimeFormat para um tooltip: o texto do card mostra 'ha 2 dias' (relativo), e ao passar o mouse aparece a data completa formatada ('07 de agosto de 2026 as 14h30'). Tudo nativo, zero biblioteca.
Vale a pena?
Se você esta instalando date-fns, dayjs ou qualquer outra biblioteca exclusivamente para formatar timestamps relativos, sim - vale muito a pena migrar para o Intl.RelativeTimeFormat. Você remove uma dependência, reduz o bundle e ganha suporte nativo a internacionalização.
Se a biblioteca já esta no projeto por outros motivos, não ha urgência - mantenha a consistência. A API nativa não substitui tudo que date-fns faz, só a parte de formatação relativa.
O próximo passo e abrir o projeto atual, buscar por formatDistanceToNow, fromNow() ou similares, e avaliar se da para trocar pelo nativo. Na maioria dos casos, da.
Comentários
Deixar um comentárioVocê precisa ter uma conta no CuritibaBlog para comentar.