Calcular diferença entre 2 datas com PHP

  • Autor do post:
  • Categoria do post:PHP DEV

Calcular diferença entre 2 datas com PHP

Olá, estou atualizando o post “Calcular Diferença Entre 2 Datas”, usaremos uma função mais simples para calcular diferença entre Anos, Meses, Dias, Horas, Minutos e Segundos.

A função recebe 3 ou 4 parâmetros.

1º  Parâmetro é o data inicial
2º  Parâmetro é a data final
3º  Parâmetro é o que se deseja calcular, ex. Ano, Mes, Dia, Hora, Minuto. Sendo o parâmetro a primeira letra ( ‘A’ = ano, ‘M’ = meses, etc …)
4º  Parâmetro é opcional e só precisa ser passado se o separador for diferente de “-” (ex: 2010/04/10 neste caso deve ser passado o separador no parâmetro).

O formato da data deve ser “Ano-Mês-Dia”, ex  2010-12-31, ou seja, $d1 = “2010-12-31”.

<?php

function diffDate($d1, $d2, $type='', $sep='-')
{
 $d1 = explode($sep, $d1);
 $d2 = explode($sep, $d2);
 switch ($type)
 {
 case 'A':
 $X = 31536000;
 break;
 case 'M':
 $X = 2592000;
 break;
 case 'D':
 $X = 86400;
 break;
 case 'H':
 $X = 3600;
 break;
 case 'MI':
 $X = 60;
 break;
 default:
 $X = 1;
 }
 return floor( ( ( mktime(0, 0, 0, $d2[1], $d2[2], $d2[0]) – mktime(0, 0, 0, $d1[1], $d1[2], $d1[0] ) ) / $X ) );
}

?>

Exemplos de uso:
Calcular diferença entre Dias (3º parâmetro D).

<?php

$d1 = "2011-01-01";
$d2 = "2011-01-10";
echo diffDate($d1,$d2,'D');

?>

Calcular diferença entre Meses (3º parâmetro M).

<?php

$d1 = "2011-01-01";
$d2 = "2011-02-01";
echo diffDate($d1,$d2,'M');

?>

Calcular diferença em Minutos (3º parâmetro MI).

<?php

$d1 = "2011-01-01";
$d2 = "2011-02-01";
echo diffDate($d1,$d2,'MI');

?>

Calcular diferença entre Anos (3º parâmetro A).

<?php

$d1 = "2010-01-01";
$d2 = "2011-01-01";
echo diffDate($d1,$d2,'A');

?>

Calcular diferença em Horas (3º parâmetro H).

<?php

$d1 = "2011-01-01";
$d2 = "2011-02-01";
echo diffDate($d1,$d2,'H');

?>

Calcular diferença em Dias com separador “/”  (3º parâmetro D e 4º parâmetro / ).

<?php

$d1 = "2011/01/01";
$d2 = "2011/02/01";
echo diffDate($d1,$d2,'D',"/");

?>

Calcular diferença em Segundos (omitindo o 3º e 4º parâmetro ).

<?php

$d1 = "2011-01-01";
$d2 = "2011-02-01";
echo diffDate($d1,$d2);

?>

Este post tem 46 comentários

  1. Fábio Ferreira

    Boas Rafael,
    Que boa função de diferença entre datas 😉 tenho de dar uma vista de olhos na que tinha postado aqui á uns tempos .
    Mais uma vez um Grande Obrigado pela partilha de conhecimento 🙂

    Aguardo com ansiedade os próximos post PHP + JQuery

    Valeu, Bom Ano

  2. Joel Backschat

    Muito bom a função parabéns.

  3. Márcio

    Ótimo função, Rafael!

    Não achei função tão boa nem nas “googladas” pelos sites gringos.

    Apenas uma colaboração, para manter a sua lógica e a diferença entre as datas não ficar negativa, o return deve ficar assim:

    return floor( ( ( mktime(0, 0, 0, $d2[1], $d2[2], $d2[0]) – mktime(0, 0, 0, $d1[1], $d1[2], $d1[0] ) ) / $X ) );

    Pois do jeito que você colocou ele está subtraindo a data maior da data menor, então está gerando dias negativos. Nada que tire o brilho da função!

    Um abraço!

    1. Rafael Clares

      Márcio, é verdade, muito obrigado pela contribuição, assim fica fácil pra mim hehehehe!

      Anteriormente, digo, quando foi escrita a function ao invés de :
      diffDate($d1, $d2, $type=”, $sep=’-‘)
      era
      diffDate($d2, $d1, $type=”, $sep=’-‘)

      Para mim o correto seria informar primeiro a maior data dia 10 menos dia 05… quando fui postar me apeguei ao fator ordem, achei que confundiria, alterei os params mas não o resto função… que burro dá zero pra ele kas kas kas
      Foi mancada minha mesmo…
      Valeu,
      forte abraço!

  4. dayane

    Muito bom o post… ajudou bastante.. para simplificar eu já tinha uma função que fazia as conversões para o timestamp

    valeu

  5. Leo

    Show, muito bom…

  6. Samuel Peixoto

    ÓTIMA A FUNÇÃO

    Não sou expert mas presento uma variação que pode ser útil:

    Calcula ‘2011-05-02 08:00:00’ e ‘2011-05-01 09:55:00′

    function diffDate($d1, $d2, $type=”, $sep=’-‘)

    {

    if(strstr($d1,’:’)){
    $dh1 = explode(‘ ‘, $d1);
    $d1 = explode($sep, $dh1[0]);
    $d1_h = explode(‘:’, $dh1[1]);
    } else{
    $d1 = explode($sep, $d1);
    $d1_h[0] = $d1_h[1] = $d1_h[2]= 0;}

    if(strstr($d2,’:’)){
    $dh2 = explode(‘ ‘, $d2);
    $d2 = explode($sep, $dh2[0]);
    $d2_h = explode(‘:’, $dh2[1]);
    } else{
    $d2 = explode($sep, $d2);
    $d2_h[0] = $d2_h[1] = $d2_h[2]= 0;}

    switch ($type)
    {
    case ‘A’:
    $X = 31104000;
    break;
    case ‘M’:
    $X = 2592000;
    break;
    case ‘D’:
    $X = 86400;
    break;
    case ‘H’:
    $X = 3600;
    break;
    case ‘MI’:
    $X = 60;
    break;
    default:
    $X = 1;
    }
    return (((mktime($d1_h[0],$d1_h[1],$d1_h[2],$d1[1],$d1[2],$d1[0])-mktime($d2_h[0],$d2_h[1],$d2_h[2],$d2[1],$d2[2],$d2[0]))/$X));
    }

    $d1 = ‘2011-05-02 08:00:00’;
    $d2 = ‘2011-05-01 09:55:00′;

    echo diffDate($d1, $d2,’MH’);

    1. Rafael Clares

      Boa Samuel, contribuições são bem-vindas.
      Valeu, abraços.

  7. Wallison

    Exclareceu e ao mesmo tempo meu ajudou bastante em um projeto. Parabéns!

  8. Samuel Peixoto

    Pessoal, tive uma dificuldade e creio que outros também podem ter.
    Para somar horas, exemplo: 08:00:00 quero adicionar 01:00:00 hora, podemos usar a seguinte função:

    function somaHora($d1, $d2, $sep=’:’)

    {
    $d1_h = explode($sep, $d1);
    $d2_h = explode($sep, $d2);
    $d1_h[0]+$d2_h[0].’:’.$d1_h[1]+$d2_h[1].’:’.$d1_h[2]+$d2_h[2];

    $novo_horario = mktime(((int)$d1_h[0] + (int)$d2_h[0]), ((int)$d1_h[1] + (int)$d2_h[1]), ((int)$d1_h[2] + (int)$d2_h[2]));

    return date(“H:i:s”, $novo_horario);
    }

    Ao somar: echo somaHora(’08:00:00′, ’01:00:00′);
    O resultado é: 09:00:00

    Ao somar: echo somaHora(’08:00:00′, ’00:35:00′);
    O resultado é: 08:35:00

    Espero poder ajudar.

    Att. Samuel Peixoto

  9. John

    Samuel Peixoto, sensacional, era o que precisava. Fiz um lance de expirar link com isso, perfeito, obrigado.

  10. Guilherme

    VALEU GAROTO!

  11. Wallace

    O meu deu o seguinte erro
    Parse error: parse error in C:xampp…………php on line 27

    A linha 27 é bem no return o que pode se ?
    Valeuu

    1. Rafael Clares

      Amigo, você postou a linha do erro, é preciso informar o erro para eu poder ajuda-lo.
      abs

  12. odaieromar

    Olá, Ragael.

    Tenho também um problema de erro:
    PHP Parse error: syntax error, unexpected T_STRING in testa_data.php on line 28
    e a linha 28 do ‘testa_data.php’ é
    return floor( ( ( mktime(0, 0, 0, $d2[1], $d2[2], $d2[0]) – mktime(0, 0, 0, $d1[1], $d1[2], $d1[0] ) ) / $X ) );

    (copiei e colei seu script em um arquivo que chamei de testa_data.php)
    A sintaxe me parece correta. Não vi o erro. Pode me ajudar ?

    1. Alcides Junior

      esse erro também ocorreu comigo basta vc apagar o – que está entre os mktime não sei pq mas quando fiz isso ele rodou blz!

      1. Rafael Clares

        Aê Alcides, valeu cara. Conto com pessoas como você que compartilham as experiências para ajudar ao amigos. vlw

  13. odaieromar

    Desculpe, Rafael.

    A pressa sempre é inimiga!!

  14. marcelo

    Colega Clares pode me elucidar em uma questão?
    o sistema cadastra uma data no bd como que eu faço para que 3 dias antes de chegar a essa data cadastrada me exibir uma msg na tela. “Faltam 3 dias para o evento tal” ?

    1. Rafael Clares

      Marcelo tente o seguinte:

      if(date(‘d/m/Y’,mktime(0,0,0,date(‘m’),date(‘d’)+3,date(‘Y’))) <= date('d/m/Y'))
      {
      echo "faltam 3 dias…"
      }

      onde o +3 é a quantidade de dias (hoje + 3)
      outros exemplos

      //PARA DESCOBRIR QUAL DATA SERÁ DAQUI A 5 DIAS
      echo date('d/m/Y',mktime(0,0,0,date('m'),date('d')+5,date('Y')));

      //PARA DESCOBRIR QUAL SERÁ O DIA AMANHÃ
      echo date('d/m/Y',mktime(0,0,0,date('m'),date('d')+1,date('Y')));

      //PARA MÊS QUE VEM
      echo date('d/m/Y',mktime(0,0,0,date('m') + 1,date('d'),date('Y')));

      //PARA ANO QUE VEM
      echo date('d/m/Y',mktime(0,0,0,date('m'),date('d'),date('Y') + 1));

      1. Higo rocha

        ou então, pegar a data de hoje, calcular a diferença com a data cadastrada, verificar se é igual a 3 e mandar a msg, me corrijam se eu estiver enganado.

  15. neisjbDINEI

    ERRO NA LINA 27 ???????????????????????????

  16. Luiz Vinicius

    Ola pessoal. ótima função.
    Porem estou com o mesmo problema na linha de return alguém pode ajudar?

  17. Luiz Vinicius

    Encontrei o erro.
    o Sinal de subtração, redigite-o…
    vai entender????

    1. Felipe Oliveira

      Excelente sacada, obrigado, estava com o mesmo problema.

    2. Lucas

      Boa.. Obrigado

  18. Pedro Torres

    Olá Rafael…

    Primeiramente, parabéns e obrigado pelo post.

    Percebi que esta utilizando:

    09 case ‘A’:
    10 $X = 31536000;

    12 case ‘M’:
    13 $X = 2592000;

    Portanto, esta supondo que todos os anos que estão sendo comparados possuem 365 dias.
    E que todos os meses possuem 30 dias.

    O resultado dessa diferença não esta errado, se levarmos em consideração anos bissestos e meses com quantidade de dias diferentes de 30 ?

    Estou tentando achar uma função que analíse tudo isso, mas esta difícil de achar.

    Abraços.

    1. Rafael Clares

      Pedro, o único mês que tem 1 dia a mais é fevereiro nos anos bisextos, neste caso é preciso verificar se o ano é bisexto antes de definir $X para ano e mês.
      Então segue a alteração.

      function diffDate($d1, $d2, $type=”, $sep=’-‘)
      {
      $d1 = explode($sep, $d1);
      $d2 = explode($sep, $d2);
      switch ($type)
      {
      case ‘A’:
      $X = 31536000;
      if (days_in_month(date(‘D’), date(‘Y’)) == 29)
      {
      $X = 31536000 + 86400;
      }
      break;
      case ‘M’:
      $X = 2592000;
      if (days_in_month(date(‘D’), date(‘Y’)) == 29)
      {
      $X = 2592000 + 86400;
      }
      break;
      case ‘D’:
      $X = 86400;
      break;
      case ‘H’:
      $X = 3600;
      break;
      case ‘MI’:
      $X = 60;
      break;
      default:
      $X = 1;
      }
      return floor(( ( mktime(0, 0, 0, $d2[1], $d2[2], $d2[0]) – mktime(0, 0, 0, $d1[1], $d1[2], $d1[0]) ) / $X));
      }

      function days_in_month($month, $year)
      {
      return $month == 2 ? ($year % 4 ? 28 : ($year % 100 ? 29 : ($year % 400 ? 28 : 29))) : (($month – 1) % 7 % 2 ? 30 : 31);
      }
      ?>

      Agora você pode testar com:

      $d1 = “2012-02-01”;
      $d2 = “2012-03-01”;
      echo diffDate($d1, $d2, ‘D’);

      e

      $d1 = “2011-02-01”;
      $d2 = “2011-03-01”;
      echo diffDate($d1, $d2, ‘D’);

      Verá que o resultado de dias será diferente já de 2012 é bisexto.

      Abs

      1. Pedro Torres

        Obrigado pelo esclarecimento rafael.

        Mais uma ajuda. Eu que não estou entendendo direito, ou estamos assumindo que todos os meses possuem 30 dias? Resolvido no caso de fevereiro. Mas e no caso dos meses com 31 dias?

        Abs

        1. Rafael Clares

          Pedro, a idéia é essa que eu te passei, utilizar a function days_in_month() para saber quantos dias tem o mês…
          A partir daí acredito que você possa implementar o restante do código.
          Por ex: ao receber data_1 e data_2 você pode verificar quantos dias tem nelas utilizando a funcao,… abs

  19. Pedro Torres

    Ok Rafael, obrigado. Abaixo mostro a maneira com que realizarei a comparação entre as datas.

    Pessoal, como aprendi conceitos por aqui, deixo o código que finalizei pra que possam aproveitar.

    // Aa datas/horas são passadas no formato: “dd/mm/aaaa 00:00:00” ou apenas “dd/mm/aaaa”
    public function getDiferencaEntreDatasHoras( $dataHoraInicial, $dataHoraFinal )
    {
    // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
    // 1 3 / 0 6 / 1 9 8 6 1 4 : 3 5 : 0 0

    $diaI = substr($dataHoraInicial,0,2);
    $mesI = substr($dataHoraInicial,3,2);
    $anoI = substr($dataHoraInicial,6,4);
    $horI = substr($dataHoraInicial,11,8);
    $datetime1 = date_create($anoI.”-“.$mesI.”-“.$diaI.$horI);

    $diaF = substr($dataHoraFinal,0,2);
    $mesF = substr($dataHoraFinal,3,2);
    $anoF = substr($dataHoraFinal,6,4);
    $horF = substr($dataHoraFinal,11,8);
    $datetime2 = date_create($anoF.”-“.$mesF.”-“.$diaF.$horF);

    $interval = date_diff($datetime1, $datetime2);

    return $interval->format(‘A diferença entre as datas é de: %y anos, %m meses, %d dias, %h horas, %i minutos e %s segundos.’);
    }

    1. Pedro Torres

      E reparem que se a data for passada no formato “aaaa-mm-dd” ou “aaaa-mm-dd 00:00:00”, boa parte do código deverá ser inutilizado.
      Abs.

  20. _JF

    A partir da versão 5.3.0 do PHP foi introduzida uma classe para cálculo de datas e tempo, é a DateTime, vale a pena dar uma estudada nela, é bem fácil e tem total suporte a timezone e daylight (horário de verão), como sugestão fica a dica de fazer novo artigo abordando esta classe, seria uma atualização natural deste artigo 🙂

  21. Felipe Oliveira

    Excelente amigo, tive o mesmo problema do Return como outros tiveram. Graças ao amigo Vinícius que sacou que era só redigitar o sinal de subtração agora está tudo certo. Obrigado =]

  22. DOUGBRAG

    Parabéns Rafael! Estou começando no PHP e a sua função de calculo de data foi muito útil. Terás mais um seguidor a partir de agora. Abraço!

  23. Tiago Botega

    Idéia genial. Parabéns e obrigado!

  24. João Paulo Guedes Miranda

    Ótima função parabéns….
    Fiz uns ajustes.

    function diffDate($d1,$d2,$type=’D’)
    {
    $d1 = reset(explode(‘ ‘, $d1)); //separa por espaço , caso passe data e hora
    $d2 = reset(explode(‘ ‘, $d2));

    //convertendo caso não esteja no formato da W3C

    if(!preg_match(‘/([0-9]{4})[/|-]([0-9]{2})[/|-]([0-9]{2})/’,$d1,$arr))
    {
    $d1 = data($d1);
    }

    if(!preg_match(‘/([0-9]{4})[/|-]([0-9]{2})[/|-]([0-9]{2})/’,$d2,$arr))
    {
    $d2 = data($d2);
    }

    $d1 = explode(‘-‘,$d1);
    $d2 = explode(‘-‘,$d2);

    switch ($type)
    {
    case ‘A’://Anos
    $X = (days_in_month(date(‘D’), date(‘Y’)) == 29) ? 31536000 + 86400 : 31536000;// Se for bissexto adiciona + 1 dia
    break;
    case ‘M’://Meses
    $X = (days_in_month(date(‘D’), date(‘Y’)) == 29) ? 2592000 + 86400 : 2592000;// Se for bissexto adiciona + 1 dia
    break;
    case ‘D’://Dias
    $X = 86400;
    break;
    case ‘H’://Horas
    $X = 3600;
    break;
    case ‘MI’://Minutos
    $X = 60;
    break;
    default://Segundos
    $X = 1;
    }

    return floor(((mktime(0, 0, 0, $d2[1], $d2[2], $d2[0]) – mktime(0, 0, 0, $d1[1], $d1[2], $d1[0] ) )/$X));
    }

    function days_in_month($month,$year)
    {
    return $month == 2 ? ($year % 4 ? 28 : ($year % 100 ? 29 : ($year % 400 ? 28 : 29))) : (($month – 1) % 7 % 2 ? 30 : 31);
    }

    function data($str = ”,$lk = false)
    {
    if(!empty($str))
    {
    $array = explode(‘ ‘,$str);

    $data = $array[0];
    $hora = $array[1];

    return (preg_match(‘/([0-9]{4})[/|-]([0-9]{2})[/|-]([0-9]{2})/’,$data,$arr) ? $arr[3].’/’.$arr[2].’/’.$arr[1].(($lk === true) ? ‘ ‘.$hora : ”) :
    (preg_match(‘/([0-9]{2})[/|-]([0-9]{2})[/|-]([0-9]{4})/’,$data,$arr) ? $arr[3].’-‘.$arr[2].’-‘.$arr[1].’ ‘.$hora :’DATE UNDEFINED’));
    }
    else
    {
    $verao = date(‘I’) === 1 ? 3:4;
    $timestamp = mktime(date(‘H’)-$verao, date(‘i’), date(‘s’), date(‘m’), date(‘d’), date(‘Y’));
    return gmdate(‘Y-m-d H:i:s’, $timestamp);
    }
    }//by: JPGM

    Valeu…

  25. Gustavo

    Não funcionou comigo…
    “A non well formed numeric value encountered” no return…

    1. Rafael Clares

      Gustavo, não consegui simular o erro, você poderia postar como ficou a linha que você utilizou para tentar calcular as datas?

  26. Diego Guedes

    Para resolver o problema de erro na linha “return floor(((mktime(0, 0, 0, $d2[1], $d2[2], $d2[0]) – mktime(0, 0, 0, $d1[1], $d1[2], $d1[0] ) )/$X));” apague a subtração “-” e digite novamente.

  27. Bruno Sotto

    Olá, gostei muito da sua função, foi muito util pra mim, mas tava dando diferença de um dia aqui. acontece que mudou o horario de verão estes dias, e como testei um periodo com inicio em fim deixando a mudança no meio apareceu esta diferença

  28. Bruno Sotto

    pra corrigir a questão que levantei do horário de verão coincidir entre a data inicio e final usei round ou invés de floor. ficou perfeito.

  29. Angelo Augusto

    Estou com uma dúvida se por acaso eu tenho dois campos datas e quero fazer que por exemplo se o campo2 atingir 90 dias ao campo1 ele me retorne sei la atingir 90 dia como poderei aplicar ?
    Queria pedir obrigado a todos e otimo forum

Os comentários estão encerrados.