Problem adding month to date with php

0

I'm having a problem adding months to php, I had done using modify but as in own documentation already informs that of the error, hence I tried 3 other functions that I found and hence the 3 and I bring the same error, when a date starts on days 29, 30 or 31 January, for example, in February comes all to the (28, 30 or 31) and not always on the 28th.

How can I resolve this?

Here's an example with one of these functions:

$date=new DateTime();
$date->setDate(2017,1,31);

addMonths($date, 1);
echo $date->format('d/m/Y');

echo "<br>";

addMonths($date, 1);
echo $date->format('d/m/Y');

echo "<br>";

addMonths($date, 1);
echo $date->format('d/m/Y');

function addMonths($date,$months)
{
    $init=clone $date;
    $modifier=$months.' months';
    $back_modifier =-$months.' months';

    $date->modify($modifier);
    $back_to_init= clone $date;
    $back_to_init->modify($back_modifier);

    while($init->format('m')!=$back_to_init->format('m')){
        $date->modify('-1 day')    ;
        $back_to_init= clone $date;
        $back_to_init->modify($back_modifier);
    }
}

result

28/02/2017
28/03/2017
28/04/2017

while the expected result would be

28/02/2017
31/03/2017
30/04/2017
    
asked by anonymous 25.04.2017 / 16:39

1 answer

3

In short, the problem is that you are changing the original instance of the start date, so in this way, when you add 1 month to the start date, it will be 28/02, that is $date will become 28 / 02; when added another month, the day will be March 28, as it would be adding a month on 2/28 instead of two months on 1/31. To not change the object, clone the input object and modify it, returning its instance to the end:

function add_months(DateTime $date, int $months)
{
    // Clona o objeto $date para mantê-lo inalterado
    $future = clone $date;

    // Define o modificador
    $modifier = "{$months} months";

    // Modifica a data $future
    $future->modify($modifier);

    // Clona o objeto $future para corrigir o limite dos dias
    $pass = clone $future;
    $pass->modify("-{$modifier}");

    // Enquanto o mes atual for diferente do mês do passado do futuro
    while ($date->format('m') != $pass->format('m'))
    {
        // Modifica as datas em -1 dia
        $future->modify("-1 day");
        $pass->modify("-1 day");
    }

    // Retorna a data desejada
    return $future;
}

// Define a data inicial
$date = new DateTime();
$date->setDate(2017, 1, 31);

// Adiciona 1 mês à data inicial
echo add_months($date, 1)->format("d/m/Y"), PHP_EOL;

// Adiciona 2 meses à data inicial
echo add_months($date, 2)->format("d/m/Y"), PHP_EOL;

// Adiciona 3 meses à data inicial
echo add_months($date, 3)->format("d/m/Y"), PHP_EOL;

In this way, the output will be as expected:

28/02/2017
31/03/2017
30/04/2017

Note that instead of adding several times a month, you should add the correct amount of months, otherwise the problem will persist.

    
25.04.2017 / 17:42