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); ?>
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
Muito bom a função parabéns.
Ó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!
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!
Muito bom o post… ajudou bastante.. para simplificar eu já tinha uma função que fazia as conversões para o timestamp
valeu
Show, muito bom…
Ó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’);
Boa Samuel, contribuições são bem-vindas.
Valeu, abraços.
Exclareceu e ao mesmo tempo meu ajudou bastante em um projeto. Parabéns!
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
Samuel Peixoto, sensacional, era o que precisava. Fiz um lance de expirar link com isso, perfeito, obrigado.
VALEU GAROTO!
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
Amigo, você postou a linha do erro, é preciso informar o erro para eu poder ajuda-lo.
abs
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 ?
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!
Aê Alcides, valeu cara. Conto com pessoas como você que compartilham as experiências para ajudar ao amigos. vlw
Desculpe, Rafael.
A pressa sempre é inimiga!!
O que pegou?
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” ?
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));
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.
ERRO NA LINA 27 ???????????????????????????
Que erro?
Ola pessoal. ótima função.
Porem estou com o mesmo problema na linha de return alguém pode ajudar?
Encontrei o erro.
o Sinal de subtração, redigite-o…
vai entender????
Excelente sacada, obrigado, estava com o mesmo problema.
Boa.. Obrigado
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.
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
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
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
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.’);
}
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.
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 🙂
Vejam os exemplos de DateTime::diff, talvez ajude
http://www.php.net/manual/en/datetime.diff.php
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 =]
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!
Idéia genial. Parabéns e obrigado!
Ó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…
Não funcionou comigo…
“A non well formed numeric value encountered” no return…
Gustavo, não consegui simular o erro, você poderia postar como ficou a linha que você utilizou para tentar calcular as datas?
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.
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
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.
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