Error Showing Next Month

Asked

Viewed 120 times

0

In this script below it returns me the next month of a specific date and the error only happens on 31/01/2017 and 28/02/2017

  echo $mes = date('m', strtotime('+1 months', strtotime(date('2017-01-31'))));
  echo('<br>');
  echo $mes = date('m', strtotime('+1 months', strtotime(date('2017-02-28'))));

 no caso 31/01/2017  ele me retorna mes 3 (mais teria que ser 2)
 no caso 28/02/2017  ele me retorna mes 3 (que seria o correto)

month 03/2017 04/2017.... onwards will correct works perfectly What I must be doing wrong?

2 answers

3

This is due to the fact that 1 months in php have 30 days and February have 28 days. it adds 30 days to 31/01 and goes straight to month 3

<?php

 echo $mes = date('m',strtotime(date('2017-01-31'))) +1;
  echo('<br>');
echo $mes = date('m',strtotime(date('2017-02-28'))) +1
?>

2

I made a small class to help work with dates that make this calculation.

Follow the class and then 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&ccedil;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&aacute;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&ccedil;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 .' &agrave;s '. $hora .'h';
        }
        else
        {
            $formattedDate = $this->diaSemana .', '. $this->theDay .' de '. $this->mes .' &agrave;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 .' &agrave;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 .' &agrave;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;            
    }    



}    

Example code of use:

<?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

Current day formatted date (if class constructor is empty): 12/09/2016

Date in 2 short months: 09/02/2017

Date in 2 months short with time: 09/02/2017 at 12:33h

Date 2 months from now with day of the week: Thursday, February 9 at 12:33h

Full date in 2 months: Thursday, February 09, 2017

Adding another 15 days ...

Completed in 2 months and 15 days: February 24, 2017

Chronicling the object by passing a date

Spending day 2017-01-10 at the builder...

Simple date with weekday : Tuesday, January 10

Simple Date No Day Week : January 10th

Adding one month from that date...

Date one more month: Friday, February 10

Date more 30 days from Object date(10/01/2017): Thursday, 09 of February

Date (10/01/2017) two more months: Friday, March 10

Date more 60 days from Object date(10/01/2017): Saturday, 11 of March

11/03/2017 less 5 days: 06/03/2017

11/03/2017 less 20 days: 19/02/2017

11/03/2017 less 5 years: 11/03/2012

11/03/2017 less 5 x 365 days: 12/03/2012

The count of months, days and years has differences and you should choose the method that is best for your business.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.