Timestamp em PHP

Artigo que explica o que é um Timestamp (unix time) e como pode ser manipulado no PHP levando-se em conta o fuso horário.

Calendário
Introdução

Há algum tempo escrevi o artigo Aritmética de Datas, que mostrava como manipular datas no PHP e realizar operações sobre elas. Porém, embora tenha citado brevemente sobre Timestamp, não explorei tanto o assunto.

Neste artigo, pretendo explicar melhor o que é o Timestamp e como ele é manipulado no PHP. Também vou destacar algumas características importantes, relacionadas ao fuso horário (timezone).

O que é Timestamp (unix time)?

Timestamp (ou Unix Time) é uma representação de tempo criada para o meio computacional e é formado simplesmente por um número inteiro. O timestamp de uma data qualquer é o número inteiro que representa a quantidade de segundos que se passaram desde o dia 1 de janeiro de 1970 com base no meridiano de Greenwich (GMT), que é o fuso horário 0 (zero).

Então, seguem alguns timestamps de exemplo e suas respectivas datas:

  • 0 = 01/01/1970 00:00:00 GMT
  • 1 = 01/01/1970 00:00:01 GMT
  • 59 = 01/01/1970 00:00:59 GMT
  • 60 = 01/01/1970 00:01:00 GMT
  • 3600 = 01/01/1970 01:00:00 GMT
  • 1405641600 = 18/07/2014 00:00:00 GMT

Por ser um inteiro, o timestamp está atrelado a um limite computacional. Nos computadores de arquitetura 32 bits, os números inteiros normalmente são representados por 32 bits, que variam de -2.147.483.648 até 2.147.483.647, que correspondem às datas "13/12/1901 20:45:52 GMT" até "19/01/2038 03:14:07 GMT". Inclusive, no ano 2038 podemos presenciar um novo "bug do milênio" em função desta limitação, caso os equipamentos que utilizam datas nesta arquitetura não sejam atualizados para uma arquitetura de 64 bits ou superior.

Nos computadores com arquitetura 64 bits, também existe um limite, mas os inteiros podem variar de -9.223.372.036.854.775.808 até 9.223.372.036.854.775.807, que correspondem às datas "27/01/-292277022657 08:29:52 GMT" até "04/12/292277026596 15:30:07 GMT". Considerando que o universo tem aproximadamente 14 bilhões de anos, a arquitetura de 64 bits é capaz de armazenar 20 vezes a idade do universo. Não sei o que vocês acham, mas pra mim é tempo suficiente.

Timestamps e os fusos horários (timezones)

O timestamp é independente de fusos horários. Isso pode soar um pouco estranho, mas a verdade é que a formatação de um timestamp no formato de data é que depende de um fuso horário.

Vamos considerar o timestamp 0 (zero). Ele representa "01/01/1970 00:00:00" no fuso GMT, mas também representa "31/12/1969 21:00:00" no fuso horário de Brasília (-03:00).

Ou seja, o timestamp representa um determinado "instante", e este instante é o mesmo no mundo inteiro. Porém, em cada fuso horário do globo este instante é exibido de forma diferente.

Trabalhando com Timestamp e fusos horários no PHP

Para trabalhar com timestamps corretamente no PHP, levando em consideração o fuso horário, primeiro é necessário que o PHP esteja configurado adequadamente quanto ao fuso horário, ou seja, a diretiva de configuração do php.ini "date.timezone" deve estar preenchida com o nome do fuso horário preferencial do servidor, que pode ser obtido na lista de nomes de fusos horários disponíveis para PHP. Para servidores em São Paulo, por exemplo, esta diretiva deve estar configurada com o valor "America/Sao_paulo".

Também é possível configurar/sobrescrever o fuso horário dinamicamente pelo próprio script PHP:

ini_set('date.timezone', 'America/Sao_paulo');

Uma vez configurado o fuso horário, podemos gerar um timestamp das seguintes formas:

  • chamando a função time para obter o timestamp no instante atual.
  • chamando a função mktime para gerar um timestamp com base em valores relativos ao fuso horário configurado no servidor.
  • chamando a função gmmktime para gerar um timestamp com base em valores relativos ao fuso horário GMT.

Para facilitar o entendimento, vamos ver alguns exemplos:

// Passando: hora, minuto, segundo, mes, dia, ano com base no GMT
$timestamp1 = gmmktime(0, 0, 0, 1, 1, 1970);

// Exibe: 0, pois criamos o timestamp com base no GMT
echo $timestamp1;

// Passando: hora, minuto, segundo, mes, dia, ano com base no fuso -03:00
$timestamp2 = mktime(0, 0, 0, 1, 1, 1970);

// Exibe: 10800, pois criamos o timestamp com base no fuso -03:00
// 01/01/1970 00:00:00 -03:00 == 01/01/1970 03:00:00 GMT
echo $timestamp2;

Ou seja, quando o relógio chegou às 00:00 no dia 01/01/1970 no fuso horário -03:00 (Brasília), já eram 3 da manhã no Meridiano de Greenwich, por isso o timstamp por lá já registrava o valor 10800.

Agora vem o outro lado da história, que é a exibição de um timestamp. Neste caso, podemos formatar um timestamp das seguintes formas:

  • chamando a função date ou strftime para formatar um timestamp com base no fuso horário configurado no servidor.
  • chamando a função gmdate ou gmstrftime para formatar um timestamp com base no fuso horário GMT.

Novamente, vamos ver alguns exemplos:

$timestamp = 0;

// Exibe: 01/01/1970 00:00:00 GMT
echo gmdate('d/m/Y H:i:s T', $timestamp);

// Exibe: 01/01/1970 00:00:00 GMT
echo gmstrftime('%d/%m/%Y %H:%M:%S %Z', $timestamp);

// Exibe: 31/12/1969 21:00:00 BRT
echo date('d/m/Y H:i:s T', $timestamp);

// Exibe: 31/12/1969 21:00:00 BRT
echo strftime('%d/%m/%Y %H:%M:%S %Z', $timestamp);

Ou seja, se formatarmos o timestamp zero em uma data no fuso GMT, ele corresponde exatamente à data 01/01/2970 00:00:00, porém, se formatarmos o mesmo timestamp no fuso horário -03:00, então ele vai exibir 31/12/1969 21:00:00, pois é o horário que marcavam os relógios no Brasil quando o timestamp zero acontecia em Greenwich.


Porém, também podemos manipular datas no PHP utilizando a classe DateTime. No construtor da classe DateTime, passamos a data como primeiro parâmetro e um objeto da classe DateTimeZone como segundo parâmetro. Este segundo parâmetro é opcional e, por padrão, é utilizado o fuso horário configurado no servidor.

Vamos ver um exemplo:

// Criando os objetos que representam fusos horarios diferentes
$fuso_gmt = new DateTimeZone('GMT');
$fuso_sp  = new DateTimeZone('America/Sao_paulo');

// Criando uma data no fuso GMT
$d = new DateTime('01/01/1970 00:00:00', $fuso_gmt);

// Exibe: 01/01/1970 00:00:00 GMT
echo $d->format('d/m/Y H:i:s T');

// Mudando o fuso da data para SP
$d->setTimeZone($fuso_sp);

// Exibe: 31/12/1969 21:00:00 BRT
echo $d->format('d/m/Y H:i:s T');

// Criando uma data no fuso SP (configurado no servidor)
$d2 = new DateTime('01/01/1970 00:00:00');

// Exibe: 01/01/1970 00:00:00 BRT
echo $d2->format('d/m/Y H:i:s T');

// Mudando o fuso da data para GMT
$d2->setTimeZone($fuso_gmt);

// Exibe: 01/01/1970 03:00:00 GMT
echo $d2->format('d/m/Y H:i:s T');

Uma observação é que para realizar operações envolvendo intervalos através da classe DateInterval, o intervalo independe de fuso. Afinal, é uma porção de tempo.

3 comentários

Flavio disse...

Como sempre a sua didática nos artigos do blog é sensacional. Consegui eliminar algumas dúvidas relacionadas a datas no PHP. Seria interessante se você pudesse explorar mais a classe DateTime em outro artigo.

Abraços

Rubens Takiguti Ribeiro (autor do blog) disse...

Olá, Flavio
Na verdade escrevi um pouco mais sobre DateTime no artigo sobre aritmética de datas. Confere aí:
http://rubsphp.blogspot.com.br/2010/11/aritmetica-de-datas.html

Anônimo disse...

Rubens estou usando o wamp e versao do mysql 5.7 quand crio uma tabela com timestamp tipo datanascimento, ele nao deixa eu cadastrar anterior a 31/12/1969. O que poderia ser?