I made a wee class to help work with dates that does this calculation.
The class follows and examples of how to use it and the output that is generated.
DateHelper.php:
<?php
class DateHelper
{
public $theDay; //dia
public $theMonth; //mês
public $theYear; //ano
public $theHour; //hora
public $theSecond; // segundos - pouco usado
public $timezone;
private $diaSemana; //dia da semana em português
private $mes; //mês escrito como texto em português
/**
* @param string $mydate
*/
public function __construct($mydate=null)
{
if(is_null($mydate)) $mydate = DateHelper::getNow();
$this->setVars($mydate);
}
public function setVars($mydate)
{
//Incializa variáveis
$this->theDay = date("d",strtotime($mydate));
$this->theMonth = date("m",strtotime($mydate));
$this->theYear = date("Y",strtotime($mydate));
$this->theHour = date("H:i",strtotime($mydate));
$this->theSecond = date("s",strtotime($mydate));
$this->timezone = -2; // Brasil = GMT-2
$this->diaSemana = self::getDiaSemana($mydate);
$this->mes = self::getMesNome(intval($this->theMonth));
}
/**
* Dado uma data, retorna o nome do dia da semana em português
* Se não passar nenhuma data, pega o que já passou antes no construtor
* @param date $mydate
*/
public static function getDiaSemana($mydate=0)
{
if($mydate==0)
{
return $this->diaSemana;
}
$diaSemanaN= date("w", strtotime($mydate));
switch($diaSemanaN)
{
case 0:
$diaSemana="Domingo";
break;
case 1:
$diaSemana="Segunda-feira";
break;
case 2:
$diaSemana="Terça-feira";
break;
case 3:
$diaSemana="Quarta-feira";
break;
case 4:
$diaSemana="Quinta-feira";
break;
case 5:
$diaSemana="Sexta-feira";
break;
case 6:
$diaSemana="Sábado";
break;
}
return $diaSemana;
}
/**
* Dado o mês em inteiro, retorna o nome do mês em português
* @param int $theMonth
*/
public static function getMesNome($month)
{
switch($month)
{
case 1:
$mes="Janeiro";
break;
case 2:
$mes="Fevereiro";
break;
case 3:
$mes="Março";
break;
case 4:
$mes="Abril";
break;
case 5:
$mes="Maio";
break;
case 6:
$mes="Junho";
break;
case 7:
$mes="Julho";
break;
case 8:
$mes="Agosto";
break;
case 9:
$mes="Setembro";
break;
case 10:
$mes="Outubro";
break;
case 11:
$mes="Novembro";
break;
case 12:
$mes="Dezembro";
break;
}
return $mes;
}
/**
* Retorna string com a data completa formatada com dia da semana
* Ex: Quarta-feira, 14 de Setembro de 2011
* @return string $formattedDate
*/
public function getFullDatePtBr($strDate=null)
{
if(!is_null($strDate))
{
$diaSemana = $this->getDiaSemana($strDate);
$dia = date("d", strtotime($strDate) );
$mesN = date("m", strtotime($strDate) );
$mes = $this->getMesNome($mesN);
$ano = date("Y", strtotime($strDate) );
$formattedDate = $diaSemana .', '. $dia .' de '. $mes . ' de '.$ano;
}
else
{
$formattedDate = $this->diaSemana .", ". $this->theDay ." de ". $this->mes ." de ". $this->theYear;
}
return $formattedDate;
}
/**
* Retorna string com a data completa formatada sem dia da semana
* Ex: 14 de Setembro de 2011
* @return string $formattedDate
*/
public function getFullDatePtBr2($strDate=null)
{
if(!is_null($strDate))
{
//VOLTAR AQUI
$dia = date("d", strtotime($strDate) );
$mesN = date("m", strtotime($strDate) );
$mes = $this->getMesNome($mesN);
$ano = date("Y", strtotime($strDate) );
$formattedDate = $dia .' de '. $mes .' de '.$ano;
}
else
{
$formattedDate = $this->theDay ." de ". $this->mes ." de ". $this->theYear;
}
return $formattedDate;
}
/**
* Retorna string com a data formatada com dia da semana
* Ex: Quarta-feira, 14 de Setembro
* @return string $formattedDate
*/
public function getDatePtBr($strDate = null)
{
if(!is_null($strDate))
{
$diaSemana = $this->getDiaSemana($strDate);
$dia = date("d", strtotime($strDate) );
$mesN = date("m", strtotime($strDate) );
$mes = $this->getMesNome($mesN);
$formattedDate = $diaSemana .', '. $dia .' de '. $mes;
}
else
{
$formattedDate = $this->diaSemana .", ". $this->theDay ." de ". $this->mes;
}
return $formattedDate;
}
/**
* Retorna string com a data formatada sem dia da semana
* Ex: 14 de Setembro
* @return string $formattedDate
*/
public function getDatePtBr2($strDate = null)
{
if(!is_null($strDate))
{
$dia = date("d", strtotime($strDate) );
$mesN = date("m", strtotime($strDate) );
$mes = $this->getMesNome($mesN);
$formattedDate = $dia .' de '. $mes;
}
else
{
$formattedDate = $this->theDay ." de ". $this->mes;
}
return $formattedDate;
}
/**
* Retorna string com a data abreviada
* Ex: 14/09/2011
* @return string $formattedDate
*/
public function getShortDatePtBr($strDate = null)
{
if(!is_null($strDate))
{
return date("d/m/Y", strtotime($strDate) );
}
else
{
$theDay = str_pad($this->theDay, 2, "0", STR_PAD_LEFT);
$theMonth = str_pad($this->theMonth, 2, "0", STR_PAD_LEFT);
$formattedDate = $theDay ."/". $theMonth ."/". $this->theYear;
return $formattedDate;
}
}
/**
* Retorna string com a data formatada com hora
* Ex: Quarta-feira, 14 de Setembro às 05:26h
* @return string $formattedDate
*/
public function getDatePtBrWithHour($strDate = null)
{
if(!is_null($strDate))
{
$diaSemana = $this->getDiaSemana($strDate);
$dia = date("d", strtotime($strDate) );
$mesN = date("m", strtotime($strDate) );
$mes = $this->getMesNome($mesN);
$hora = date("H:i", strtotime($strDate) );
$formattedDate = $diaSemana .', '. $dia .' de '. $mes .' às '. $hora .'h';
}
else
{
$formattedDate = $this->diaSemana .', '. $this->theDay .' de '. $this->mes .' às '. $this->theHour .'h';
}
return $formattedDate;
}
/**
* Retorna string com a data abreviada com hora
* Ex: 14/09/2011 às 05:26h
* @return string $formattedDate
*/
public function getShortDatePtBrWithHour($strDate = null)
{
if(!is_null($strDate))
{
$shorDatePart = $this->getShortDatePtBr($strDate);
$hora = date("H:i", strtotime($strDate) );
return $shorDatePart .' às '. $hora .'h';
}
else
{
$theDay = str_pad($this->theDay, 2, "0", STR_PAD_LEFT);
$theMonth = str_pad($this->theMonth, 2, "0", STR_PAD_LEFT);
$formattedDate = $theDay .'/'. $theMonth .'/'. $this->theYear .' às '. $this->theHour .'h';
return $formattedDate;
}
}
/**
* @return the $mes
*/
public function getMes() {
return $this->mes;
}
/**
* @return the $theDay
*/
public function getTheDay() {
return $this->theDay;
}
/**
* Importante: Retorna o mês numérico, caso deseje
* escrito por extenso em português utilize getMes() ou getMesNome($mesN)
* @return the $theMonth
*/
public function getTheMonth() {
return $this->theMonth;
}
/**
* @return the $theYear
*/
public function getTheYear() {
return $this->theYear;
}
/**
* @return the $theHour
*/
public function getTheHour() {
return $this->theHour;
}
/**
* Retorna a quantidade de dias do mês
* Criei esse método com base em uma série de métodos com sobrecarga de
* uma classe java que havia feito antes - Por isso tem esse monte de ifs
* $mes pode ser numérico ou nome e $ano pode ser passado ou não
* @param mes
* @param ano (opcional, útil para verificação de ano bissexto)
* @return int_qtd_dias
*/
public function getQtdDias($mes, $ano=null)
{
if(!is_numeric($mes))
{
$mes = $this->getMinMes($mes);
if(!is_null($ano))
{
if(mes.equals("fev") || mes.equals("feb"))
{
return $this->qtdSeFevBi($ano);
}
else
{
return $this->qtdSwitchMes($mes);
}
}
else
{
return $this->qtdSwitchMes($mes);
}
}
elseif(!is_null($ano))
{
if($mes!=2)
{
return $this->getQtdDias($mes);
}
else
{
return $this->qtdSeFevBi($ano);
}
}
else
{
switch($mes)
{
case 1:
return 31;
case 2:
return 28; // se não foi especificado ano, considera 28
case 3:
return 31;
case 4:
return 30;
case 5:
return 31;
case 6:
return 30;
case 7:
return 31;
case 8:
return 31;
case 9:
return 30;
case 10:
return 31;
case 11:
return 30;
case 12:
return 31;
default:
return 0;
}
}
}
/**
* Normaliza o parâmetro mês para as 3 primeiras letras em minúsculo
* @param mes
* @return string_3_caracteres_em_minusculo
*/
private function getMinMes($mes)
{
$mes = strtolower($mes);
return substr($mes,0,3);
}
/**
* Retorna a quantidade de dias com base na string de 3 caracteres fornecida por getMinMes
* @param mes
* @return int_qtd_dias
*/
private function qtdSwitchMes($mesN)
{
switch($mesN)
{
case "jan":
return $this->getQtdDias(1);
case "fev":
return $this->getQtdDias(2);
case "feb":
return $this->getQtdDias(2);
case "mar":
return $this->getQtdDias(3);
case "abr":
return $this->getQtdDias(4);
case "apr":
return $this->getQtdDias(4);
case "mai":
return $this->getQtdDias(5);
case "may":
return $this->getQtdDias(5);
case "jun":
return $this->getQtdDias(6);
case "jul":
return $this->getQtdDias(7);
case "ago":
return $this->getQtdDias(8);
case "aug":
return $this->getQtdDias(8);
case "set":
return $this->getQtdDias(9);
case "sep":
return $this->getQtdDias(9);
case "out":
return $this->getQtdDias(10);
case "oct":
return $this->getQtdDias(10);
case "nov":
return $this->getQtdDias(11);
case "dez":
return $this->getQtdDias(12);
case "dec":
return $this->getQtdDias(12);
default:
return 'erro, o mes '.$mesN.' não existe';
}
}
/**
* Retorna a quantidade de dias de Fevereiro do ano fornecido
* @param ano
* @return int_qtd_dias
*/
private function qtdSeFevBi($ano)
{
// echo "$ano % 4 = " . $ano%4;
if(($ano%400 == 0) || (($ano%4 == 0) && ($ano%100 != 0)))
{
return 29;
}
return 28;
}
public function getProximoDiaSemana($diasemana)
{
switch($diasemana)
{
case "Domingo":
return "Segunda";
case "Segunda":
return "Terça";
case "Terça":
return "Quarta";
case "Quarta":
return "Quinta";
case "Quinta":
return "Sexta";
case "Sexta":
return "Sábado";
case "Sábado":
return "Domingo";
}
return "Erro Dia da Semana";
}
public function getDiaSemanaByCalendarInt($calendarint)
{
switch($calendarint)
{
case 1:
return "Domingo";
case 2:
return "Segunda";
case 3:
return "Terça";
case 4:
return "Quarta";
case 5:
return "Quinta";
case 6:
return "Sexta";
case 7:
return "Sábado";
}
return "Erro Dia da Semana";
}
/**
* Retorna data hora completa de America/Sao_Paulo do momento do processamento
* Requer PHP >= 5.3.0
*/
public static function getNow()
{
/*
$timezone=-2;
$time_now = mktime(date("H"), date("i"), date("s"), date("m"), date("d"), date("Y"));
$now = gmdate("Y-m-d H:i:s", $time_now + 3600*($timezone));
*/
$now = new DateTime('now', new DateTimeZone('America/Sao_Paulo'));
return $now->format('Y-m-d H:i:s');
}
/**
* Data daqui a $qtdDias
*/
public function dataDaquiXdias($qtdDias)
{
$qtdDias = intval($qtdDias);
list($H,$i) = explode(':', $this->theHour);
$time = mktime($H, $i, $this->theSecond, $this->theMonth, $this->theDay + $qtdDias, $this->theYear);
$date = date("Y-m-d H:i:s", $time );
return $date;
}
/**
* Data a $qtdDias atrás
*/
public function dataXdiasAtras($qtdDias)
{
$qtdDias = intval($qtdDias);
list($H,$i) = explode(':', $this->theHour);
$time = mktime($H, $i, $this->theSecond, $this->theMonth, $this->theDay - $qtdDias, $this->theYear);
$date = date("Y-m-d H:i:s", $time );
return $date;
}
/**
* Data após $qtdMeses * 30 dias -> Mês comercial de 30 dias
*/
public function dataDaquiXmeses($qtdMeses)
{
$qtdMeses = intval($qtdMeses);
list($H,$i) = explode(':', $this->theHour);
// ORDEM de mktime: hora, minuto, segundo, MES, DIA, ANO
$time = mktime($H, $i, $this->theSecond, $this->theMonth+$qtdMeses, $this->theDay, $this->theYear);
$date = date("Y-m-d H:i:s", $time );
return $date;
}
/**
* Data $qtdMeses * 30 dias atrás -> Mês comercial de 30 dias
*/
public function dataXmesesAtras($qtdMeses)
{
$qtdMeses = intval($qtdMeses);
list($H,$i) = explode(':', $this->theHour);
$time = mktime($H, $i, $this->theSecond, $this->theMonth - $qtdMeses, $this->theDay, $this->theYear);
$date = date("Y-m-d H:i:s", $time );
return $date;
}
/**
* Data após $qtdAnos
*/
public function dataDaquiXanos($qtdAnos)
{
$qtdAnos = intval($qtdAnos);
list($H,$i) = explode(':', $this->theHour);
$time = mktime($H, $i, $this->theSecond, $this->theMonth, $this->theDay, $this->theYear + $qtdAnos);
$date = date("Y-m-d H:i:s", $time );
return $date;
}
/**
* Data $qtdAnos atrás
*/
public function dataXanosAtras($qtdAnos)
{
$qtdAnos = intval($qtdAnos);
list($H,$i) = explode(':', $this->theHour);
$time = mktime($H, $i, $this->theSecond, $this->theMonth, $this->theDay, $this->theYear - $qtdAnos);
$date = date("Y-m-d H:i:s", $time );
return $date;
}
}
Sample Code Usage:
<?php
require("DateHelper.php");
echo 'Timestamp now(método estático): ' . DateHelper::getNow();
echo '<hr>';
$datehelp = new DateHelper();
echo 'Data formatada do dia atual (se construtor da classe estiver vazio): ' . $datehelp->getShortDatePtBr();
echo '<hr>';
$timestamp_data_daqui_2_meses = $datehelp->dataDaquiXmeses(2);
echo 'Data daqui a 2 meses curta: '.$datehelp->getShortDatePtBr($timestamp_data_daqui_2_meses);
echo '<hr>';
echo 'Data daqui a 2 meses curta com hora: '.$datehelp->getShortDatePtBrWithHour($timestamp_data_daqui_2_meses);
echo '<hr>';
echo 'Data daqui a 2 meses com dia da semana: '.$datehelp->getDatePtBrWithHour($timestamp_data_daqui_2_meses);
echo '<hr>';
echo 'Data completa daqui a 2 meses: '.$datehelp->getFullDatePtBr($timestamp_data_daqui_2_meses);
echo '<hr>';
echo 'Adicionando mais 15 dias ... <br>';
//Modifica a data interna do objeto para poder realizar outros cálculos
$datehelp->setVars($timestamp_data_daqui_2_meses);
$timestamp_2meses_15dias = $datehelp->dataDaquiXdias(15);
echo 'Data completa2 daqui a 2 meses e 15 dias: '.$datehelp->getFullDatePtBr2($timestamp_2meses_15dias);
echo '<hr>';
// ================================================================================
echo '<h2>Cronstruindo o objeto passando uma data</h2>';
$data = '2017-01-10';
echo "Passando dia $data no construtor...<br>";
$datehelp = new DateHelper($data);
echo ' Data simples com dia semana : '. $datehelp->getDatePtBr();
echo '<br>';
echo ' Data simples sem dia semana : '. $datehelp->getDatePtBr2();
echo '<br>';
echo 'Somando um mês a partir dessa data...<br>';
$data_mais_1mes = $datehelp->dataDaquiXmeses(1);
echo '*** Data mais um mês: '.$datehelp->getDatePtBr($data_mais_1mes);
echo '<br>';
echo '*** Data mais 30 dias a partir da data do objeto('.$datehelp->getShortDatePtBr().'): ';
$data_mais_30dias = $datehelp->dataDaquiXdias(30);
echo $datehelp->getDatePtBr($data_mais_30dias);
echo '<hr>';
$data_mais_2meses = $datehelp->dataDaquiXmeses(2);
echo '*** Data ('.$datehelp->getShortDatePtBr().') mais dois meses: '.$datehelp->getDatePtBr($data_mais_2meses);
echo '<br>';
echo '*** Data mais 60 dias a partir da data do objeto('.$datehelp->getShortDatePtBr().'): ';
$data_mais_60dias = $datehelp->dataDaquiXdias(60);
echo $datehelp->getDatePtBr($data_mais_60dias);
echo '<hr>';
//Modifica a data interna do objeto para poder realizar outros cálculos
$datehelp->setVars($data_mais_60dias);
$data_menos_5dias = $datehelp->dataXdiasAtras(5);
echo $datehelp->getShortDatePtBr() . ' menos 5 dias: '.$datehelp->getShortDatePtBr($data_menos_5dias);
echo '<br>';
$data_menos_20dias = $datehelp->dataXdiasAtras(20);
echo $datehelp->getShortDatePtBr() . ' menos 20 dias: '.$datehelp->getShortDatePtBr($data_menos_20dias);
echo '<br>';
$data_menos_5anos = $datehelp->dataXanosAtras(5);
echo '***'.$datehelp->getShortDatePtBr() . ' menos 5 anos: '.$datehelp->getShortDatePtBr($data_menos_5anos);
echo '<br>';
$data_menos_5x365dias = $datehelp->dataXdiasAtras(5*365);
echo '***'.$datehelp->getShortDatePtBr() . ' menos 5 * 365 dias: '.$datehelp->getShortDatePtBr($data_menos_5x365dias);
echo '<br><br><b>Repare nas diferenças nas linhas marcadas com ***<br>
A contagem de meses, dias e anos tem diferenças e
você deve escolher o método que for melhor para o seu negócio.</b>';
Output generated by the example:
Timestamp now (static method): 2016-12-09 12:33:30
Formatted date of the current day (if class constructor is empty): 12/09/2016
Date 2 months short: 09/02/2017
Date within 2 months short with time: 09/02/2017 at 12: 33h
Date from 2 months to the day of the week: Thursday, February 9 at 12: 33h
Full date in 2 months: Thursday, February 09, 2017
Adding another 15 days ...
Full date2 in 2 months and 15 days: February 24, 2017
Building the object passing a date
Spending 2017-01-10 day in the constructor ...
Simple date with week day: Tuesday, January 10
Simple date without day week: January 10
Adding a month from that date ...
Date one more month: Friday, February 10
Date plus 30 days from object date (10/01/2017): Thursday, February 9
Date (10/01/2017) plus two months: Friday, March 10
Date plus 60 days from object date (10/01/2017): Saturday, March 11
11/03/2017 at 5 days: 3/6/2017
11/03/2017 less 20 days: 2/19/2017
11/03/2017 at least 5 years: 11/03/2012
11/03/2017 at 5 x 365 days: 12/03/2012
The count of months, days and years have differences and you should choose the method that is best for your business.