Error showing next month

0

In this script below it returns me the next month of a specific date and the error only happens on 01/31/2017 and 02/28/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 .... on goes right works perfectly What should I be doing wrong?

    
asked by anonymous 08.12.2016 / 19:55

2 answers

3

This is due to the fact that 1 months in php has 30 days and february have 28 days. it adds 30 days to 1/31 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
?>
    
08.12.2016 / 20:12
2

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&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;            
    }    



}    

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.

    
08.12.2016 / 20:10