PHP

Fuso horário no PHP 8.3: log com 3 horas de diferença no servidor

O pedido entrou às 21h de ontem e o relatório mostra 00h de hoje. Não é bug do relatório: o PHP 8.3 está rodando em UTC porque ninguém preencheu date.timezone, e três horas entram ou somem em todo date() do projeto.

Onde setar de verdade

FPM e CLI leem arquivos ini diferentes, e o php -i do terminal só mostra o do CLI. Ajustar um e esquecer o outro deixa o painel certo e o cron errado. O .bak do sed é o seu plano B se o serviço não subir:

php -i | grep '^date.timezone'

sudo sed -i.bak 's|^;?date.timezone =.*|date.timezone = America/Sao_Paulo|' 
  /etc/php/8.3/fpm/php.ini /etc/php/8.3/cli/php.ini
sudo systemctl reload php8.3-fpm

O php.ini da distro entrega a linha comentada, do jeito ;date.timezone =. Sem valor o PHP assume UTC calado: o aviso de fuso indefinido saiu no PHP 7.0. Se a hospedagem não te dá o ini, chame date_default_timezone_set('America/Sao_Paulo') na primeira linha do bootstrap, antes de qualquer formatação de data.

O banco continua em UTC

Resista à vontade de gravar horário de Brasília na coluna. Guarde UTC e converta só na exibição, senão no dia em que o horário de verão voltar você fica com duas horas iguais na mesma tabela. O offset numérico ainda dispensa carregar as tabelas de fuso do MySQL 8:

SELECT id, CONVERT_TZ(date_created_gmt, '+00:00', '-03:00') AS criado_br
FROM wp_wc_orders ORDER BY id DESC LIMIT 5;

Na aplicação vale o mesmo raciocínio: leia como UTC, mostre no fuso de quem está olhando.

$d = new DateTimeImmutable($linha['date_created_gmt'], new DateTimeZone('UTC'));
echo $d->setTimezone(new DateTimeZone('America/Sao_Paulo'))->format('d/m/Y H:i');

Depois do reload, rode php -r 'echo date_default_timezone_get();' no CLI e abra um phpinfo() pelo navegador. Se os dois não devolverem America/Sao_Paulo, o painel bate e o cron da meia-noite não.

Post Recentes

Magento 2 não envia e-mail de pedido: async sending e cron parado

O pedido entra na loja e o e-mail nunca sai: antes de culpar o SMTP, veja o envio assíncrono, a…

21 horas atrás

cron_schedules WordPress: intervalo de 5 minutos no WP-Cron

O WordPress só oferece hourly, twicedaily, daily e weekly. Use o filtro cron_schedules para criar um intervalo de 5 minutos…

2 dias atrás

E-mails do WooCommerce não chegam: como testar o envio de um pedido real

Dispare pela linha de comando o e-mail de um pedido que já existe na loja e descubra se a falha…

2 dias atrás

CodeIgniter 4 tela branca: CI_ENVIRONMENT e o erro que sumiu

Página em branco no CodeIgniter 4, sem nenhuma mensagem? O ambiente está em production e escondeu o erro. Troque o…

2 dias atrás

Google Consent Mode v2 no WordPress: default denied antes do gtag rodar

O Google Ads acusa consentimento ausente porque o gtag sobe antes do banner. Veja como injetar o default denied do…

4 dias atrás

Módulos PHP 8.3 faltando na Saúde do site do WordPress: como instalar

A tela Saúde do site avisa que faltam extensões como intl, imagick ou zip: instale no PHP 8.3, reinicie o…

4 dias atrás