Datas e horas
Nesta aula, você aprenderá a trabalhar com datas e horas em PHP usando as classes DateTime e DateTimeImmutable, além de explorar formatação, intervalos e fusos horários. O conteúdo inclui exemplos práticos, boas práticas e exercícios para fixação.
Datas e horas são fundamentais em quase todo sistema web, desde a simples exibição da data atual até o cálculo de prazos, agendamentos e fusos horários. O PHP oferece um conjunto robusto de classes para lidar com esses conceitos, sendo as principais DateTime e DateTimeImmutable. Nesta aula, você vai dominar a criação, manipulação, formatação e comparação de datas, além de entender como trabalhar com intervalos e fusos horários de forma eficiente.
Vamos começar com uma visão geral das classes, depois mergulhar em formatação, intervalos e fusos. Ao final, você terá uma base sólida para implementar funcionalidades relacionadas a tempo em seus projetos.
DateTime e DateTimeImmutable
As classes DateTime e DateTimeImmutable representam um ponto específico no tempo. A diferença crucial é que DateTime é mutável, ou seja, métodos como modify() alteram o objeto original. Já DateTimeImmutable retorna um novo objeto com as alterações, preservando o original. Isso evita efeitos colaterais e é recomendado para evitar bugs.
Para criar uma instância, basta chamar o construtor com uma string de data/hora. Se nenhum argumento for passado, a data/hora atual é usada. Veja exemplos:
$date = new DateTime(); // data e hora atual
$date2 = new DateTime('2025-03-15 10:30:00');
$immutable = new DateTimeImmutable('now'); // imutável
echo $date->format('Y-m-d H:i:s'); // ex.: 2025-03-15 10:30:00
echo $immutable->format('Y-m-d'); // ex.: 2025-03-15Métodos comuns incluem format(), modify(), setDate(), setTime(), getTimestamp() e diff(). Com DateTimeImmutable, lembre-se de sempre capturar o retorno dos métodos que modificam o objeto:
$immutable = new DateTimeImmutable('2025-03-15');
$newImmutable = $immutable->modify('+1 day');
echo $immutable->format('Y-m-d'); // 2025-03-15
echo $newImmutable->format('Y-m-d'); // 2025-03-16Use DateTimeImmutable sempre que possível, especialmente em funções que recebem datas como parâmetro, para garantir que o valor original não seja alterado.
Formatação
A formatação é feita com o método format(), que aceita uma string de formato com caracteres especiais. Os mais comuns são: d dia com dois dígitos, m mês com dois dígitos, Y ano com quatro dígitos, H hora 24h, i minutos, s segundos. Você pode combinar esses caracteres com separadores arbitrários.
$date = new DateTime('2025-03-15 10:30:00');
echo $date->format('d/m/Y'); // 15/03/2025
echo $date->format('H:i'); // 10:30
echo $date->format('l, j \d\e F \d\e Y'); // sábado, 15 de março de 2025Note que para caracteres literais no formato, é preciso escapá-los com uma barra invertida. Para uma lista completa, consulte a documentação oficial.
Outra forma de formatar é usando strftime(), mas ela está obsoleta desde o PHP 8.1. Prefira format().
Para exibir datas em português, você pode usar IntlDateFormatter ou manipular o formato com arrays de nomes. Exemplo com IntlDateFormatter:
$date = new DateTime('2025-03-15');
$formatter = new IntlDateFormatter('pt_BR', IntlDateFormatter::LONG, IntlDateFormatter::NONE);
echo $formatter->format($date); // 15 de março de 2025Isso requer a extensão intl, que geralmente vem habilitada.
Intervalos
Intervalos representam uma duração de tempo, como '1 dia', '2 horas', '3 meses'. A classe DateInterval é usada com add() e sub() para modificar datas, e diff() para calcular a diferença entre duas datas.
Para criar um intervalo, use o construtor com uma string no formato ISO 8601, como 'P1D' para 1 dia, 'PT1H' para 1 hora, 'P2M' para 2 meses. Exemplos:
$date = new DateTime('2025-03-15');
$interval = new DateInterval('P1D'); // 1 dia
$date->add($interval);
echo $date->format('Y-m-d'); // 2025-03-16Para calcular a diferença entre duas datas, use diff():
$date1 = new DateTime('2025-03-15');
$date2 = new DateTime('2025-03-20');
$diff = $date1->diff($date2);
echo $diff->days; // 5
echo $diff->format('%d dias'); // 5 diasO objeto DateInterval tem propriedades como y, m, d, h, i, s, e days (total de dias). Cuidado: days só é preenchido quando o diff é feito entre duas datas, não em intervalos criados manualmente.
Para criar intervalos mais complexos, você pode usar DateInterval::createFromDateString():
$interval = DateInterval::createFromDateString('2 weeks + 3 days');
echo $interval->format('%d dias'); // 17 dias (2 semanas = 14 dias + 3)Fusos horários
Fusos horários são essenciais para aplicações que lidam com usuários em diferentes regiões. O PHP usa a base de dados da IANA (Olson). Você pode definir o fuso horário no php.ini ou dinamicamente com date_default_timezone_set().
Ao criar um objeto DateTime, você pode especificar o fuso horário no construtor ou com setTimezone():
$date = new DateTime('2025-03-15 10:00:00', new DateTimeZone('America/Sao_Paulo'));
echo $date->format('Y-m-d H:i:s P'); // 2025-03-15 10:00:00 -03:00
// Convertendo para outro fuso
$date->setTimezone(new DateTimeZone('UTC'));
echo $date->format('Y-m-d H:i:s P'); // 2025-03-15 13:00:00 +00:00Para listar todos os fusos suportados, use DateTimeZone::listIdentifiers().
Uma boa prática é armazenar datas em UTC no banco de dados e converter para o fuso do usuário apenas na exibição. Isso evita problemas com horário de verão e mudanças de fuso.
Exemplo de conversão:
$utc = new DateTime('2025-03-15 10:00:00', new DateTimeZone('UTC'));
$utc->setTimezone(new DateTimeZone('America/Sao_Paulo'));
echo $utc->format('Y-m-d H:i:s'); // 2025-03-15 07:00:00Lembre-se de que alguns fusos têm horário de verão, e o PHP já lida com isso automaticamente.
Boas práticas e observações finais
Sempre prefira DateTimeImmutable para evitar mutações inesperadas. Use o fuso horário UTC para armazenamento e converta para o fuso do usuário na exibição. Ao formatar datas para usuários, considere usar IntlDateFormatter para localização. Evite usar timestamps inteiros quando precisar de operações complexas, pois as classes DateTime são mais expressivas.
Referências
- Documentação oficial: DateTime
- Documentação oficial: DateTimeImmutable
- Documentação oficial: DateInterval
- Documentação oficial: DateTimeZone
- date_default_timezone_set
- Formatação de datas
- IntlDateFormatter
Exercícios
- Crie um objeto
DateTimeImmutablepara a data '2025-12-31 23:59:59' e exiba o dia da semana em português. - Calcule a diferença entre '2025-01-01' e '2025-12-31' e exiba o número de dias.
- Adicione 3 meses e 10 dias à data '2025-03-15' e exiba o resultado.
- Converta a data/hora '2025-03-15 10:00:00' do fuso 'America/Sao_Paulo' para 'UTC' e exiba.
- Crie um objeto
DateTimea partir de um timestamp (ex.: 1742000000) e exiba a data formatada.
$date = new DateTimeImmutable('2025-12-31 23:59:59');
$formatter = new IntlDateFormatter('pt_BR', IntlDateFormatter::LONG, IntlDateFormatter::NONE);
echo $formatter->format($date); // quarta-feira, 31 de dezembro de 2025$start = new DateTime('2025-01-01');
$end = new DateTime('2025-12-31');
$diff = $start->diff($end);
echo $diff->days; // 364$date = new DateTime('2025-03-15');
$date->add(new DateInterval('P3M10D'));
echo $date->format('Y-m-d'); // 2025-06-25$date = new DateTime('2025-03-15 10:00:00', new DateTimeZone('America/Sao_Paulo'));
$date->setTimezone(new DateTimeZone('UTC'));
echo $date->format('Y-m-d H:i:s'); // 2025-03-15 13:00:00$timestamp = 1742000000;
$date = new DateTime('@' . $timestamp);
echo $date->format('Y-m-d H:i:s'); // 2025-03-15 00:53:20 (depende do fuso)