7

Yesterday I ran into an issue with PHP's strtotime not properly adding a month. On '2011-05-31' I ran:

date('Y-m-d',strtotime( '+1 month', strtotime('now')));

Which returns '2011-07-01' when I am expecting '2011-06-30'.

MySQL doesn't have any issue doing this.

I'd rather not reinvent the wheel with this, as it is fairly easy to make mistakes with date calculations from my experience.

Does anyone have a reliable and tested solution for this for PHP 5.1?

Joe Doyle
  • 6,363
  • 3
  • 42
  • 45
Sgraffite
  • 1,898
  • 3
  • 22
  • 29
  • 1
    Have you set the correct locale? – alexn Jun 01 '11 at 20:20
  • If you want better coverage in PHP, the http://php.net/datetime class would be something to venture down. – Jim Jun 01 '11 at 20:28
  • This questions accepted answer looks like it should solve your problem: http://stackoverflow.com/questions/5760262/php-adding-months-to-a-date-while-not-exceeding-the-last-day-of-the-month – Brian Fisher Jun 01 '11 at 20:28
  • This is 100% correct, it is adding 1 month, but there are only 30 days in June therefore the 31st day is August 1st. Concise answer in a question I asked a while back: http://stackoverflow.com/questions/3602405/php-datetimemodify-adding-and-subtracting-months/3602421#3602421 – tplaner Jun 01 '11 at 20:35
  • The DateTime object is PHP 5.2, I specifically asked for a PHP 5.1 solution. My locale is set to the correct timezone. – Sgraffite Jun 01 '11 at 21:11

7 Answers7

5

It certainly is possible in PHP: Check the strtotime manual, especially this comment.

If you have a MySQL connection available, SELECT DATE_ADD( '2011-05-31', INTERVAL 1 MONTH ) would be less redundant since the (correct) functionality is already implemented without you having to implement it yourself.

mabako
  • 1,213
  • 11
  • 19
2

Since this seems to be a fairly confusing topic here is some information on it:

You are actually getting an accurate result it is literally increasing the month by 1, the day remains 31, therefore the date is 2011-06-31. If you do echo date('Y-m-d', strtotime('2011-06-31')); you'll see it displays 2011-07-01.

Here is one method of making this work as "expected" in PHP 5.1 (and before)

function next_month($timestamp)
{
    $next_month = date('m', $timestamp);
    $next_month++;

    $next_year = date('Y', $timestamp);

    if($next_month == 12)
    {
        $next_year++;
    }

    if(date('d', $timestamp) <= date('t', mktime(0, 0, 0, $next_month, 1, $next_year)))
    {
        return date('Y-m-d',strtotime( '+1 month', $timestamp));
    }
    else
    {
        return date('Y-m-d', mktime(0, 0, 0, $next_month, date('t', mktime(0, 0, 0, $next_month, 1, $next_year)), $next_year));
    }
}

echo next_month(strtotime('2011-05-31'));

echo next_month(strtotime('2011-05-01'));

This is modified code from a library I wrote a while ago -- I've never found an elegant solution.

For PHP 5.3+

Refer to PHP DateTime::modify adding and subtracting months for a detailed Q/A on this topic.

Community
  • 1
  • 1
tplaner
  • 8,363
  • 3
  • 31
  • 47
1

Try using:

$date = date_create("1900-01-01"); // Your start date
$new_date = date_add($date, date_interval_create_from_date_string('1 month')); // Your end date
1

You could argue that PHP is doing the right thing, and MySQL the wrong one:

MySQL is clamping the value down back to the last valid date that fits into the year/month definition. PHP is adjust upwards, moving forward to the first proper date that matches the specified day (31-30 = 1 day past, so 2011-06-30 + 1 day = 2011-07-01).

Marc B
  • 356,200
  • 43
  • 426
  • 500
  • If I had to choose a side of MySQl, Sql Server, Javascript, etc vs. PHP in who is correct, I would not choose PHP in this case. – Sgraffite Jun 01 '11 at 20:53
1

Adding +2592000 seconds (60 × 60 × 24 × 30) works the desired way for me.

seriousdev
  • 7,519
  • 8
  • 45
  • 52
1

You could compare the result of strtotime( 'last day of +1 month', strtotime('now')) with strtotime( '+1 month', strtotime('now')), and use whichever one is earlier.

Neil
  • 54,642
  • 8
  • 60
  • 72
0
For other Months : date('Y-m-t',strtotime("2015-05-31T23:59:59 -3 days +1 month"));
Output           : 2015-06-30

For Feb          : date('Y-m-t',strtotime("2015-01-31T23:59:59 -3 days +1 month"));
Output           : 2015-02-28

That will resolve your issue.