PHP Datas e Horas

Quase todo sistema lida com datas: a data do pedido, o prazo de entrega, a idade do cliente, quantos dias faltam para o Natal. O PHP tem dois jeitos de trabalhar com elas: as funções clássicas (date, time, strtotime), curtas e diretas, e os objetos DateTime, mais completos para cálculos. E tem uma pegadinha que pega todo brasileiro no primeiro dia: o fuso horário.

Você vai aprender
  • Mostrar a data e a hora com date(), e as letras de formato (d/m/Y H:i…).
  • Acertar o fuso: date_default_timezone_set('America/Sao_Paulo'), e por que a hora sai 3 horas adiantada sem ele.
  • O que é o timestamp (time()), e como criar datas com mktime e strtotime ('+1 week', 'next monday').
  • Usar DateTime e DateTimeImmutable, e por que preferir o segundo.
  • Ler datas no formato brasileiro (25/12/2026) sem cair em armadilhas.
  • Calcular diferenças com diff (a idade de alguém, dias até uma data).
  • Escrever os nomes dos meses e dias em português, e validar datas com checkdate.

A primeira data: date()

date ("data") devolve a data e a hora de agora, formatadas do jeito que você pedir. O formato é um texto em que cada letra vira um pedaço da data:

<?php
echo date('d/m/Y H:i:s'), "\n";
echo date_default_timezone_get(), "\n";
d
Dia com dois dígitos (16, 07).
/
Não é letra de formato: sai como está.
m
Mês com dois dígitos (10).
Y
Ano com quatro dígitos (2026). Maiúscula! O y minúsculo dá só 26.
H:i:s
Hora (0 a 23), minutos e segundos, com dois dígitos. Atenção: minuto é i, e não m (que é o mês).

A Ana rodou o programa às 20h56 de uma sexta-feira, em Campinas, e comparou com o relógio do sistema (o comando date do terminal):

$ cd datas
$ date
sex 16 out 2026 20:56:29 -03
$ php agora.php
16/10/2026 23:56:29          « 3 horas a mais!
UTC

O fuso horário

O PHP não sabe onde você está. Se ninguém disser, ele usa o fuso UTC (o "horário universal", de Londres no inverno), que está 3 horas à frente do horário de Brasília. Note que ele não avisa nada: só mostra a hora errada. (Versões muito antigas, até o PHP 5, mostravam um aviso; hoje, silêncio.) Há duas formas de consertar:

  1. No código, no começo do programa:
    <?php
    date_default_timezone_set('America/Sao_Paulo');
    echo date('d/m/Y H:i:s'), "\n";
    echo date_default_timezone_get(), "\n";
    
    $ php fuso.php
    16/10/2026 20:56:29          « agora bate com o relógio
    America/Sao_Paulo
  2. No php.ini (a configuração do PHP, veja Tipos de Erro), valendo para todos os programas: date.timezone = America/Sao_Paulo.

O nome do fuso segue o padrão "Continente/Cidade" (o banco de dados de fusos da IANA). Para o Brasil, os mais usados são America/Sao_Paulo (Brasília, Sul, Sudeste, parte do Nordeste), America/Manaus, America/Cuiaba, America/Rio_Branco, America/Fortaleza, America/Recife, America/Belem e America/Noronha. Escreva exatamente assim, com sublinhado no lugar do espaço. Um nome errado dá aviso e o fuso não muda:

$ php fuso-errado.php      « date_default_timezone_set('America/Sao Paulo');

Notice: date_default_timezone_set(): Timezone ID 'America/Sao Paulo' is invalid in /home/ana/datas/fuso-errado.php on line 2
bool(false)
UTC
$ php -d date.timezone=Brasil agora.php      « um valor inválido no php.ini

Warning: PHP Startup: Invalid date.timezone value 'Brasil', using 'UTC' instead in Unknown on line 0
16/10/2026 23:56:30
UTC

Experimente: rode e compare as duas linhas com o relógio do seu computador. A primeira usa o fuso padrão do PHP; a segunda, o de Brasília. Troque o fuso por America/Manaus ou Europe/Lisbon e veja a hora mudar.

<?php
echo "Padrão (" . date_default_timezone_get() . "): " . date('d/m/Y H:i') . "\n";
date_default_timezone_set('America/Sao_Paulo');
echo "Brasília: " . date('d/m/Y H:i') . "\n";

As letras de formato

Para a tabela abaixo, a Ana usou sempre a mesma data, sábado, 7 de março de 2026, 14:05:09, passando um segundo argumento ao date (você vai entender esse número na próxima seção). Saídas reais:

LetraSignificaSaída
dDia, 2 dígitos07
jDia, sem zero7
DDia da semana, abreviado (inglês)Sat
l (L minúsculo)Dia da semana, completo (inglês)Saturday
wDia da semana, número (0 = domingo … 6 = sábado)6
NDia da semana, ISO (1 = segunda … 7 = domingo)6
zDia do ano (começa em 0)65
WSemana do ano (ISO)10
mMês, 2 dígitos03
nMês, sem zero3
M / FMês, abreviado / completo (inglês)Mar / March
tQuantos dias o mês tem31
LAno bissexto? (1 ou 0)0
Y / yAno, 4 / 2 dígitos2026 / 26
H / GHora 00–23 / 0–2314 / 14
h / gHora 01–12 / 1–1202 / 2
a / Aam/pmpm / PM
iMinutos05
sSegundos09
eNome do fusoAmerica/Sao_Paulo
T / PAbreviação / diferença para o UTC-03 / -03:00
UTimestamp1772903109
cData completa ISO 86012026-03-07T14:05:09-03:00
rData no formato de e-mail (RFC 2822)Sat, 07 Mar 2026 14:05:09 -0300

Para escrever uma letra sem que ela vire formato, ponha uma barra invertida antes (\h, \d\e):

$ php formatos.php       « (final do programa)
…
07/03/2026 às 14h05                       « date('d/m/Y \à\s H\hi', $ts)
Saturday, 07 de March de 2026             « date('l, d \d\e F \d\e Y', $ts): nomes em inglês!

Os nomes de dias e meses do date saem sempre em inglês. A solução em português está mais adiante, em Meses e dias em português.


O timestamp: time() e mktime()

Por dentro, o PHP (e quase todo sistema) guarda um momento como um número inteiro: quantos segundos se passaram desde a meia-noite de 1º de janeiro de 1970, no fuso UTC. Esse número se chama timestamp ("carimbo de tempo") ou "tempo Unix". A função time() devolve o timestamp de agora, e date aceita um timestamp como segundo argumento:

<?php
date_default_timezone_set('America/Sao_Paulo');
var_dump(time());
echo date('d/m/Y H:i', 0), "\n";
echo date('d/m/Y H:i', 1000000000), "\n";
$natal = mktime(0, 0, 0, 12, 25, 2026);
echo $natal, "\n";
echo date('d/m/Y', mktime(0, 0, 0, 13, 1, 2026)), "\n";
echo date('d/m/Y', mktime(0, 0, 0, 3, 0, 2026)), "\n";
$ php time.php
int(1792194990)            « segundos desde 1970 (no momento em que a Ana rodou)
31/12/1969 21:00           « o timestamp 0, no horário de Brasília
08/09/2001 22:46           « o timestamp 1 bilhão
1798167600                 « o Natal de 2026, meia-noite
01/01/2027                 « "mês 13 de 2026" = janeiro de 2027
28/02/2026                 « "dia 0 de março" = último dia de fevereiro
mktime(hora, minuto, segundo, mês, dia, ano)
make time, "fabricar o tempo": monta o timestamp de uma data. Cuidado com a ordem estranha: mês antes do dia (herança do formato americano).
valores "fora do lugar"
O mktime não reclama de mês 13 ou dia 0: ele "transborda" para o mês seguinte ou anterior. Isso é útil (o dia 0 de março dá o último dia de fevereiro) e perigoso (uma data errada vira outra data sem aviso).

Com timestamps, comparar datas e fazer contas é fácil, porque são só números: o maior é o mais recente, e um dia tem 86 400 segundos. Mas contas "na mão" erram em horário de verão e meses de tamanhos diferentes. Para somar dias, semanas e meses, use strtotime ou DateTime.


strtotime: datas escritas em inglês

strtotime ("texto para tempo") lê uma data escrita em texto, inclusive expressões relativas em inglês, e devolve o timestamp (ou false se não entender). O segundo argumento é o "ponto de partida"; sem ele, é agora. A Ana usou como base a sexta-feira 16/10/2026 às 10:00:

<?php
date_default_timezone_set('America/Sao_Paulo');
$base = mktime(10, 0, 0, 10, 16, 2026);   // sexta, 16/10/2026 10:00
foreach (['tomorrow', '+1 day', '+1 week', '+2 weeks 3 days', 'next monday', 'last friday', 'first day of next month', 'last day of this month', '2026-12-25', '2026-12-25 18:30', '12/25/2026', '05/12/2026', '25/12/2026', 'amanhã'] as $t) {
    $r = strtotime($t, $base);
    echo str_pad("'$t'", 28), ' => ', $r === false ? 'false' : date('D d/m/Y H:i', $r), "\n";
}
$ php strtotime.php
'tomorrow'                   => Sat 17/10/2026 00:00     « amanhã, meia-noite
'+1 day'                     => Sat 17/10/2026 10:00     « 24 horas depois, mesma hora
'+1 week'                    => Fri 23/10/2026 10:00
'+2 weeks 3 days'            => Mon 02/11/2026 10:00
'next monday'                => Mon 19/10/2026 00:00     « a próxima segunda
'last friday'                => Fri 09/10/2026 00:00     « a sexta anterior (não hoje)
'first day of next month'    => Sun 01/11/2026 10:00
'last day of this month'     => Sat 31/10/2026 10:00
'2026-12-25'                 => Fri 25/12/2026 00:00     « formato ISO: o mais seguro
'2026-12-25 18:30'           => Fri 25/12/2026 18:30
'12/25/2026'                 => Fri 25/12/2026 00:00     « com barras = mês/dia/ano (americano)
'05/12/2026'                 => Tue 12/05/2026 00:00     « PERIGO: virou 12 de MAIO
'25/12/2026'                 => false                    « não existe mês 25
'amanhã'                    => false                    « só entende inglês
Nunca passe uma data brasileira com barras para strtotime

Com barras, o PHP entende mês/dia/ano. 25/12/2026 falha (ainda bem, você percebe), mas 05/12/2026 vira 12 de maio, sem erro nenhum, e o bolo é entregue sete meses depois. Para ler datas no formato dd/mm/aaaa, use DateTimeImmutable::createFromFormat('d/m/Y', …), que você vai ver daqui a pouco. Para guardar datas (em arquivos e bancos), use o formato ISO 2026-12-25.


Objetos de data: DateTime e DateTimeImmutable

As funções acima trabalham com números soltos. Os objetos DateTime guardam a data e o fuso juntos, e têm métodos para formatar, somar, comparar e calcular diferenças. (Objetos e métodos são assunto do Nível 3; aqui basta a receita: new cria, -> chama um método.)

<?php
date_default_timezone_set('America/Sao_Paulo');
$d = new DateTime('2026-10-16 14:30');
echo $d->format('d/m/Y H:i'), "\n";
$d->modify('+1 day');
echo $d->format('d/m/Y H:i'), "\n";
$e = $d;
$e->modify('+1 month');
echo $d->format('d/m/Y'), " e ", $e->format('d/m/Y'), "\n";
TrechoO que faz
new DateTime('2026-10-16 14:30')Cria a data. Aceita os mesmos textos do strtotime ('now', 'tomorrow', '+1 week'…). Sem argumento, é agora.
->format('d/m/Y H:i')Formata com as mesmas letras do date.
->modify('+1 day')Muda a data do próprio objeto.
$e = $d;Não copia a data: $e e $d passam a ser o mesmo objeto.
$ php datetime.php
16/10/2026 14:30
17/10/2026 14:30
17/11/2026 e 17/11/2026      « mexer em $e mudou $d também!

Esse último resultado é a fonte de muitos bugs: você calcula o prazo de entrega a partir da data do pedido e, sem querer, muda a data do pedido. Por isso existe o DateTimeImmutable ("imutável"): os métodos dele nunca mudam o objeto; eles devolvem uma data nova.

<?php
date_default_timezone_set('America/Sao_Paulo');
$pedido = new DateTimeImmutable('2026-10-16');
$entrega = $pedido->modify('+3 days');
echo "Pedido:  ", $pedido->format('d/m/Y'), "\n";
echo "Entrega: ", $entrega->format('d/m/Y'), "\n";
$prazo = $pedido->add(new DateInterval('P1M'));
echo "Prazo:   ", $prazo->format('d/m/Y'), "\n";
var_dump($entrega > $pedido);
$ php immutable.php
Pedido:  16/10/2026          « intacto
Entrega: 19/10/2026
Prazo:   16/11/2026
bool(true)                   « datas se comparam com < > == direto
$entrega = $pedido->modify('+3 days');
Com o imutável, guarde o resultado: $pedido->modify(…) sozinho, sem atribuir, não faz nada.
new DateInterval('P1M')
Um "intervalo": P (período) + 1M (1 mês). Outros: P3D (3 dias), P1Y2M (1 ano e 2 meses), PT2H (2 horas; o T separa as horas).
->add(…) / ->sub(…)
Somam ou subtraem um intervalo.
Qual usar?

Em código novo, prefira DateTimeImmutable. Ele faz tudo o que o DateTime faz, sem o risco de mudar uma data sem querer. Para só mostrar "agora" numa página, date('d/m/Y') continua ótimo.

Missão: o prazo de entrega da lojinha é de 3 dias. O programa abaixo mostra a data do pedido errada (ela mudou junto com a entrega). Troque DateTime por DateTimeImmutable e guarde o resultado do modify em $entrega, para mostrar Pedido: 16/10/2026 e Entrega: 19/10/2026.

<?php
date_default_timezone_set('America/Sao_Paulo');
$pedido = new DateTime('2026-10-16');
$entrega = $pedido;
$entrega->modify('+3 days');
echo "Pedido: " . $pedido->format('d/m/Y') . "\n";
echo "Entrega: " . $entrega->format('d/m/Y') . "\n";
<?php
date_default_timezone_set('America/Sao_Paulo');
$pedido = new DateTimeImmutable('2026-10-16');
$entrega = $pedido->modify('+3 days');
echo "Pedido: " . $pedido->format('d/m/Y') . "\n";
echo "Entrega: " . $entrega->format('d/m/Y') . "\n";

Ler uma data brasileira: createFromFormat

Quando a data vem de um formulário como 25/12/2026, diga ao PHP qual é o formato:

<?php
date_default_timezone_set('America/Sao_Paulo');
$d = DateTimeImmutable::createFromFormat('d/m/Y', '25/12/2026');
echo $d->format('Y-m-d'), "\n";
$x = DateTimeImmutable::createFromFormat('d/m/Y', '31/02/2026');
echo $x->format('d/m/Y'), "\n";
print_r(DateTimeImmutable::getLastErrors());
$y = DateTimeImmutable::createFromFormat('d/m/Y', 'ontem');
var_dump($y);
$ php fromformat.php
2026-12-25                    « entendeu dia/mês/ano
03/03/2026                    « 31 de fevereiro "transbordou" para 3 de março!
Array
(
    [warning_count] => 1
    [warnings] => Array
        (
            [10] => The parsed date was invalid      « mas ficou um aviso guardado
        )

    [error_count] => 0
    [errors] => Array
        (
        )

)
bool(false)                   « texto que não segue o formato: false

Os dois pontos de atenção: createFromFormat devolve false quando o texto não tem o formato pedido, e aceita datas impossíveis como 31/02, "transbordando" para março. Para recusar datas impossíveis, confira com checkdate (no fim da aula) ou com getLastErrors(). E o :: em DateTimeImmutable::createFromFormat chama um método da classe, sem objeto (um método estático).

Já o new DateTime('25/12/2026') não tenta adivinhar: lança uma exceção:

$ php malformed.php      « $d = new DateTime('25/12/2026');

Fatal error: Uncaught DateMalformedStringException: Failed to parse time string (25/12/2026) at position 0 (2): Unexpected character in /home/ana/datas/malformed.php:2
Stack trace:
#0 /home/ana/datas/malformed.php(2): DateTime->__construct('25/12/2026')
#1 {main}
  thrown in /home/ana/datas/malformed.php on line 2

"Falha ao interpretar o texto de data". A exceção DateMalformedStringException existe desde o PHP 8.3+ (antes era uma Exception comum, com a mesma mensagem).


Diferença entre datas: diff (e a idade)

$a->diff($b) calcula o intervalo entre duas datas, em anos, meses e dias de calendário (levando em conta meses de 28, 30 ou 31 dias e anos bissextos). É o jeito certo de calcular uma idade:

<?php
date_default_timezone_set('America/Sao_Paulo');
$nascimento = new DateTimeImmutable('1997-03-15');
$hoje = new DateTimeImmutable('2026-10-16');
$diff = $nascimento->diff($hoje);
echo "Idade: {$diff->y} anos\n";
echo $diff->format('%y anos, %m meses e %d dias'), "\n";
echo "Dias vividos: {$diff->days}\n";
echo $diff->format('%a dias'), "\n";
$natal = new DateTimeImmutable('2026-12-25');
echo "Faltam ", $hoje->diff($natal)->days, " dias para o Natal\n";
var_dump($natal->diff($hoje)->invert);
$ php idade.php
Idade: 29 anos
29 anos, 7 meses e 1 dias        « o format não sabe fazer plural: "1 dias"
Dias vividos: 10807
10807 dias
Faltam 70 dias para o Natal
int(1)                           « 1 = o intervalo é "para trás" (a 2ª data é anterior)
No intervaloO que éNo format
->y, ->m, ->dAnos, meses e dias "de calendário"%y, %m, %d
->h, ->i, ->sHoras, minutos, segundos%h, %i, %s
->daysTotal de dias entre as datas%a
->invert1 se a segunda data é anterior à primeira%R mostra + ou -

Num programa de verdade, $hoje seria new DateTimeImmutable('today'). Aqui a Ana fixou a data para o resultado não mudar a cada dia.


Meses e dias em português

O date e o format só escrevem em inglês. O jeito mais simples (e que funciona em qualquer PHP) é ter os nomes num array e usar os números que o format dá: n (mês de 1 a 12) e w (dia da semana de 0 a 6, começando no domingo).

<?php
date_default_timezone_set('America/Sao_Paulo');
$meses = [1 => 'janeiro', 'fevereiro', 'março', 'abril', 'maio', 'junho',
          'julho', 'agosto', 'setembro', 'outubro', 'novembro', 'dezembro'];
$dias = ['domingo', 'segunda-feira', 'terça-feira', 'quarta-feira',
         'quinta-feira', 'sexta-feira', 'sábado'];
$d = new DateTimeImmutable('2026-10-16');
echo $dias[$d->format('w')] . ', ' . $d->format('j') . ' de '
   . $meses[$d->format('n')] . ' de ' . $d->format('Y') . "\n";
$ php meses.php
sexta-feira, 16 de outubro de 2026
[1 => 'janeiro', 'fevereiro', …]
O 1 => faz o array começar na chave 1; os próximos ganham 2, 3… Assim $meses[10] é 'outubro', sem precisar subtrair 1.
$dias
Começa em 0 (domingo), igual ao w.
E a extensão intl?

O PHP tem uma extensão de internacionalização, a intl, com a classe IntlDateFormatter, que escreve datas em qualquer idioma. Ela não vem em toda instalação: no Ubuntu/Debian é o pacote php-intl. O php que a Ana usa no dia a dia (e o do editor do guia) não tem:

$ php intl.php      « var_dump(extension_loaded('intl')); new IntlDateFormatter(…);
bool(false)

Fatal error: Uncaught Error: Class "IntlDateFormatter" not found in /home/ana/datas/intl.php:3
Stack trace:
#0 {main}
  thrown in /home/ana/datas/intl.php on line 3

A Ana tem, na mesma máquina, uma segunda instalação do PHP com mais extensões, que ela chama pelo comando php-completo. Nela, a intl existe:

<?php
var_dump(extension_loaded('intl'));
$data = new DateTimeImmutable('2026-10-16', new DateTimeZone('America/Sao_Paulo'));
$fmt = new IntlDateFormatter('pt_BR', IntlDateFormatter::FULL, IntlDateFormatter::NONE, 'America/Sao_Paulo');
echo $fmt->format($data), "\n";
$fmt = new IntlDateFormatter('pt_BR', IntlDateFormatter::LONG, IntlDateFormatter::SHORT, 'America/Sao_Paulo');
echo $fmt->format($data), "\n";
$fmt = new IntlDateFormatter('pt_BR', IntlDateFormatter::NONE, IntlDateFormatter::NONE, 'America/Sao_Paulo', null, "EEEE, d 'de' MMMM");
echo $fmt->format($data), "\n";
$fmt = new IntlDateFormatter('pt_BR', IntlDateFormatter::NONE, IntlDateFormatter::NONE, 'America/Sao_Paulo', null, 'MMM/yy');
echo $fmt->format($data), "\n";
$ php-completo intl2.php
bool(true)
sexta-feira, 16 de outubro de 2026          « FULL: data completa, sem hora (NONE)
16 de outubro de 2026 às 00:00              « LONG para a data, SHORT para a hora
sexta-feira, 16 de outubro                  « um modelo próprio (letras do padrão ICU, diferentes das do date!)
out./26

Os argumentos são: o idioma ('pt_BR'), o estilo da data, o estilo da hora (FULL, LONG, MEDIUM, SHORT ou NONE), o fuso e, opcionalmente, o calendário e um modelo. Cuidado: os modelos da intl usam outras letras (EEEE = dia da semana, MMMM = mês por extenso, yy = ano com 2 dígitos).

Confira sempre com extension_loaded('intl') antes, ou fique com o array, que funciona em qualquer lugar.


Validar: checkdate e conversão de fusos

checkdate(mês, dia, ano) responde se a data existe de verdade (de novo, mês antes do dia):

<?php
var_dump(checkdate(2, 29, 2026));
var_dump(checkdate(2, 29, 2028));
var_dump(checkdate(4, 31, 2026));
var_dump(checkdate(12, 25, 2026));
$ php checkdate.php
bool(false)     « 2026 não é bissexto
bool(true)      « 2028 é
bool(false)     « abril tem 30 dias
bool(true)

E para mostrar o mesmo momento em outro fuso (o cliente de Manaus, a fornecedora em Lisboa), use setTimezone:

<?php
$sp = new DateTimeImmutable('2026-10-16 14:30', new DateTimeZone('America/Sao_Paulo'));
echo $sp->format('d/m/Y H:i T P'), "\n";
echo $sp->setTimezone(new DateTimeZone('Europe/Lisbon'))->format('d/m/Y H:i T P'), "\n";
echo $sp->setTimezone(new DateTimeZone('America/Manaus'))->format('d/m/Y H:i T P'), "\n";
echo $sp->setTimezone(new DateTimeZone('UTC'))->format('d/m/Y H:i T P'), "\n";
$ php zonas.php
16/10/2026 14:30 -03 -03:00
16/10/2026 18:30 WEST +01:00     « horário de verão de Portugal (outubro)
16/10/2026 13:30 -04 -04:00
16/10/2026 17:30 UTC +00:00

Quando dá errado

A hora sai 3 horas adiantada

O que significa: o PHP está usando o fuso UTC (o padrão, sem aviso).

Como consertar: date_default_timezone_set('America/Sao_Paulo'); no começo do programa (ou num arquivo de configuração incluído por todas as páginas), ou date.timezone = America/Sao_Paulo no php.ini.

"Timezone ID 'America/Sao Paulo' is invalid"
Notice: date_default_timezone_set(): Timezone ID 'America/Sao Paulo' is invalid in /home/ana/datas/fuso-errado.php on line 2

Como consertar: o nome tem sublinhado: America/Sao_Paulo. Com new DateTimeZone('Brasil/Campinas') o erro é uma exceção: Fatal error: Uncaught DateInvalidTimeZoneException: DateTimeZone::__construct(): Unknown or bad timezone (Brasil/Campinas). A lista completa sai de DateTimeZone::listIdentifiers().

Dia e mês trocados (05/12 virou 12 de maio)

O que significa: strtotime ou new DateTime receberam uma data com barras, que eles leem como mês/dia/ano.

Como consertar: DateTimeImmutable::createFromFormat('d/m/Y', $texto), conferindo se o resultado não é false.

"Failed to parse time string"
Fatal error: Uncaught DateMalformedStringException: Failed to parse time string (25/12/2026) at position 0 (2): Unexpected character in /home/ana/datas/malformed.php:2

O que significa: o texto passado a new DateTime(…) não é uma data que o PHP entenda ("posição 0, caractere 2: inesperado").

Como consertar: use o formato ISO (2026-12-25) ou createFromFormat; se o texto vem do usuário, trate a exceção com try/catch (veja Exceções).


Referência

ItemO que faz
date($formato, $ts)Formata o timestamp (padrão: agora).
time()Timestamp de agora (segundos desde 1970).
mktime(h, i, s, mês, dia, ano)Monta um timestamp.
strtotime($texto, $base)Texto (em inglês) → timestamp, ou false.
checkdate(mês, dia, ano)A data existe?
date_default_timezone_set($fuso) / _get()Define / mostra o fuso padrão.
new DateTimeImmutable($texto, $fuso)Cria uma data imutável.
DateTimeImmutable::createFromFormat('d/m/Y', $t)Lê uma data num formato conhecido.
->format($f)Formata (mesmas letras do date).
->modify('+1 week'), ->add(new DateInterval('P3D')), ->sub(…)Somam/subtraem (no imutável, devolvem uma data nova).
$a->diff($b)Intervalo: ->y, ->m, ->d, ->days, ->invert.
->setTimezone(new DateTimeZone('…'))O mesmo momento em outro fuso.
->getTimestamp()O timestamp do objeto.

Exercícios

1. Formato brasileiro

Complete para mostrar algo como 16/10/2026:

echo date('');

2. O fuso de Brasília

Complete:

date_default_timezone_set('');

3. Uma semana depois

Complete para calcular a data uma semana depois de $pedido (um DateTimeImmutable):

$retorno = $pedido->modify('');

4. No date, qual letra mostra os minutos?

5. O que strtotime('05/12/2026') devolve?

6. Com $a = new DateTimeImmutable('2026-10-16'); $a->modify('+1 day'); echo $a->format('d');, o que aparece?

Missão final: complete a função ficha. Ela recebe o nome e a data de nascimento no formato brasileiro e, considerando que hoje é 16/10/2026: (1) se a data não existir, mostra Data inválida: 31/02/2026; (2) senão, mostra a idade (Bia tem 29 anos), o próximo aniversário por extenso em português (Aniversário: segunda-feira, 15 de março de 2027) e quantos dias faltam (Faltam 150 dias). Dica: explode('/', $texto) separa dia, mês e ano para o checkdate; o próximo aniversário é a data de nascimento com o ano de hoje, ou do ano seguinte se já passou.

<?php
date_default_timezone_set('America/Sao_Paulo');
$meses = [1 => 'janeiro', 'fevereiro', 'março', 'abril', 'maio', 'junho',
          'julho', 'agosto', 'setembro', 'outubro', 'novembro', 'dezembro'];
$dias = ['domingo', 'segunda-feira', 'terça-feira', 'quarta-feira',
         'quinta-feira', 'sexta-feira', 'sábado'];
$hoje = new DateTimeImmutable('2026-10-16');

function ficha(string $nome, string $nascimento): void
{
    global $meses, $dias, $hoje;
    // seu código aqui
}

ficha('Bia', '15/03/1997');
ficha('Caio', '31/02/2026');
<?php
date_default_timezone_set('America/Sao_Paulo');
$meses = [1 => 'janeiro', 'fevereiro', 'março', 'abril', 'maio', 'junho',
          'julho', 'agosto', 'setembro', 'outubro', 'novembro', 'dezembro'];
$dias = ['domingo', 'segunda-feira', 'terça-feira', 'quarta-feira',
         'quinta-feira', 'sexta-feira', 'sábado'];
$hoje = new DateTimeImmutable('2026-10-16');

function ficha(string $nome, string $nascimento): void
{
    global $meses, $dias, $hoje;
    [$d, $m, $a] = array_map('intval', explode('/', $nascimento));
    if (!checkdate($m, $d, $a)) {
        echo "Data inválida: $nascimento\n";
        return;
    }
    $nasc = DateTimeImmutable::createFromFormat('!d/m/Y', $nascimento);
    echo "$nome tem {$nasc->diff($hoje)->y} anos\n";

    $aniv = $nasc->setDate((int) $hoje->format('Y'), $m, $d);
    if ($aniv < $hoje) {
        $aniv = $aniv->modify('+1 year');
    }
    echo "Aniversário: " . $dias[$aniv->format('w')] . ', ' . $aniv->format('j')
       . ' de ' . $meses[$aniv->format('n')] . ' de ' . $aniv->format('Y') . "\n";
    echo "Faltam {$hoje->diff($aniv)->days} dias\n";
}

ficha('Bia', '15/03/1997');
ficha('Caio', '31/02/2026');

Na solução aparecem dois detalhes novos: o ! no começo do formato ('!d/m/Y') zera a hora: sem ele, a data recebe a hora do momento em que o programa roda (quando a Ana testou, createFromFormat('d/m/Y', '15/03/2027') deu 15/03/2027 20:59:04); misturar datas com e sem hora deixa comparações como $aniv < $hoje difíceis de prever, e setDate(ano, mês, dia) troca a data mantendo o resto. O global deixa a função usar as variáveis de fora (veja Escopo); num programa maior, você passaria esses valores como parâmetros.


Resumo

  • date('d/m/Y H:i') mostra data e hora; cada letra é um pedaço (minuto é i; ano com 4 dígitos é Y).
  • Sem fuso definido, o PHP usa UTC (3 horas à frente de Brasília) e não avisa: use date_default_timezone_set('America/Sao_Paulo') ou o php.ini.
  • Timestamp = segundos desde 1970: time(), mktime() (mês antes do dia!).
  • strtotime entende inglês ('+1 week', 'next monday'), mas lê 05/12/2026 como 12 de maio.
  • Prefira DateTimeImmutable: format, modify, add, diff, e guarde sempre o resultado.
  • Datas brasileiras: createFromFormat('d/m/Y', …) + checkdate.
  • Nomes em português: um array de meses e dias (ou IntlDateFormatter, se a extensão intl existir).

Próxima aula: Tipos de Erro, para entender os Warning, Notice e Fatal error que apareceram até aqui.