IntlDateFormatter: data por extenso em pt-BR sem array de meses

Toda vez que preciso imprimir “31 de agosto de 2026” aparece de novo aquele array com os doze meses no meio do template. Dá para apagar essa herança: a extensão intl já sabe escrever data em português, e o IntlDateFormatter aceita um pattern seu no lugar dos formatos prontos.

$tz  = new DateTimeZone('America/Sao_Paulo');
$fmt = new IntlDateFormatter(
    'pt_BR',
    IntlDateFormatter::NONE,
    IntlDateFormatter::NONE,
    $tz,
    IntlDateFormatter::GREGORIAN,
    "d 'de' MMMM 'de' y"
);

echo $fmt->format(new DateTimeImmutable('2026-08-31', $tz));
// 31 de agosto de 2026

As aspas simples dentro do pattern marcam texto literal do ICU, por isso o “de” sai como palavra e não como código de campo. MMMM é o mês por extenso, MMM abrevia para “ago.” (com ponto, em pt-BR) e EEEE traz o dia da semana. Os dois NONE no meio existem porque, com pattern explícito, os estilos prontos de data e hora ficam fora do jogo. O mês vem minúsculo: se precisar de “Agosto” no começo da frase, resolva com mb_convert_case() na saída, não trocando o pattern.

A pegadinha do fuso

date_default_timezone_get();  // UTC na maioria dos servidores

$fmt->format(new DateTimeImmutable('2026-08-31'));
// 30 de agosto de 2026  <- um dia a menos

$fmt->format(new DateTimeImmutable('2026-08-31', $tz));
// 31 de agosto de 2026

Data sem hora vira meia-noite no fuso padrão do PHP. Se o servidor roda em UTC e o formatter converte para São Paulo, aquelas três horas a menos jogam o resultado para o dia anterior. Passe o mesmo DateTimeZone na criação e na formatação e o problema some. Vale o mesmo cuidado ao formatar um post_date vindo do MySQL, que é hora local sem fuso nenhum embutido.

Antes de subir isso para produção rode php -m | grep intl. Sem a extensão instalada a classe nem existe e o deploy quebra com Error: Class “IntlDateFormatter” not found.

Dúvidas? Faça um comentário logo abaixo ou envie uma mensagem clicando aqui.

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *