• 4

A PHP Error was encountered

Severity: Notice

Message: Undefined index: userid

Filename: views/question.php

Line Number: 191


File: /home/prodcxja/public_html/questions/application/views/question.php
Line: 191
Function: _error_handler

File: /home/prodcxja/public_html/questions/application/controllers/Questions.php
Line: 433
Function: view

File: /home/prodcxja/public_html/questions/index.php
Line: 315
Function: require_once

Looking to create a function that will do this in PHP.

I need to add a number of months to a date, but not exceed the last day of the month in doing so.

For example:

Add 1 month to January (1-28th), 2011, should produce February (1-28th), 2011.
Add 1 month to January 30th, 2011, should produce February 28th, 2011.
Add 3 months to January 31st, 2011, should produce April 30th, 2011.
Add 13 months to January 30th, 2011, should produce February 29th, 2012.
Add 1 month to October 31st, 2011, should produce November 30th, 2011.

If I use date addition in PHP, I get overruns:

Adding 1 month to January 30th, 2011, results in March 2nd, 2011.

My specification doesn't allow me to overrun into a new month.

What's the easiest method to accomplish this?

You can compare the day of the month before and after you add 1 month. If it's not the same, you exceeded the next month.

function add($date_str, $months)
    $date = new DateTime($date_str);

    // We extract the day of the month as $start_day
    $start_day = $date->format('j');

    // We add 1 month to the given date
    $date->modify("+{$months} month");

    // We extract the day of the month again so we can compare
    $end_day = $date->format('j');

    if ($start_day != $end_day)
        // The day of the month isn't the same anymore, so we correct the date
        $date->modify('last day of last month');

    return $date;

$result = add('2011-01-28', 1);   // 2011-02-28
$result = add('2011-01-31', 3);   // 2011-04-30
$result = add('2011-01-30', 13);  // 2012-02-29
$result = add('2011-10-31', 1);   // 2011-11-30
$result = add('2011-12-30', 1);   // 2011-02-28
  • 43
Reply Report
      • 2
    • what about leap-years? what happens if one would like to add a month from the first day of a month? if i'm right: adding a month to Jan 01 would give Jan 30; adding a month to Feb 01 would give Mar 03 with your code - not sure if this is needet, but if it is, this doesn't seem to be right.

this seems to work for me and gives yor desired result:

$date = "2011-01-30";

list($year,$month,$day) = explode("-",$date);

// add month here
// to avoid a month-wrap, set the day to the number of days of the new month if it's too high
$day = min($day,date("t",strtotime($year."-".$month."-01"))); 

$date = $year."-".$month."-".$day;

// 2011-02-28
echo $date;

after reading Crend Kings comemnt, i think we need more information here. whats the desired result in the following cases:

2011-01-30 > 2011-02-28 
2011-01-28 > 2011-02-28 or 2011-02-26 ?
2011-02-01 > 2011-03-01 or 2011-03-03 ?

in words: should the method add the number of days of the next month, wich is what Crend King does and what gives results like 2011-02-26 and 2011-03-03 (wich doesn't seem like the desired results to me) or should this add one month and leave the day as is, instead of a day thats "too high" like my code does? i'm confused...

  • 3
Reply Report
      • 2
    • I don't think this is part of the specification... i think we need more examples to understand this, please see my edit for more information
    • If OP need simply month +1 (e.g. add(Feb 28th) produces Mar 28th), I think your answer is correct for 1 month interval.
      • 2
    • @oezi this does not work if the date was in December month.For ex: if date was 2011-12-30 it gives 2011-13-30

As far as I can tell, this problem is very limited in scope, so you're likely to be best off by testing for one type of error, and fixing it.

All you want to do is make sure that adding "one month" to a late date like the 29th, 30th or 31st does not push you forward to the 1st, 2nd or 3rd of the next-next month.

The way date_modify() works (using it on an example date "2012-01-31" with a string like "+1 months"), is that it first increases the month number by 1, then finds the 31st day from the start of that month. This is why it spills over to March 3rd.

When this is not what you desired, all you have to do is use date_modify() again, now telling it to go back a few days (3 days in this example). Since you only want to go back to the last day of the previous month, the number of days you will want to go back is always the same as the day-of-month in your faulty date.

All that remains is to make sure you don't apply this correction when it is not needed, like when PHP were to improves in future. This is relatively easy, because the scope of the possible problem situations is very limited.

  • (1) The problem only occurs when adding months to dates 29, 30 or 31
  • (2) When the problem occurs, the resulting date is always 1, 2 or 3.

My code below adds "+1 month", checks if that has caused the day-of-month to change wildly from something high to something low, and adjusts the date if that's the case.

//Create the date, store its day-of-month, and add X months
$myDateTimeISO = "2012-01-31";
$addThese = 1;
$myDateTime = new DateTime($myDateTimeISO);
$myDayOfMonth = date_format($myDateTime,'j');
date_modify($myDateTime,"+$addThese months");

//Find out if the day-of-month has dropped
$myNewDayOfMonth = date_format($myDateTime,'j');
if ($myDayOfMonth > 28 && $myNewDayOfMonth < 4){
//If so, fix by going back the number of days that have spilled over
    date_modify($myDateTime,"-$myNewDayOfMonth days");
echo date_format($myDateTime,"Y-m-d");

Results in: 2012-02-29 (yes, this was a leap year).

PS: If you want to add years, the problem and the symptoms are nearly identical. Again, you just need to to check if the day-of-month resulting is 1/2/3 and the day-of-month going in is 29/30/31. If so, you need to go back "-X days" using date_modify, where X is the resulting day-of-month.

  • 3
Reply Report

For anyone interested I made a solid approach as to deal with this issue

 * @var \DateInterval
private $remainder;

 * @param \DateTimeImmutable $date
 * @param string $modifier
 * @return \DateTimeImmutable
private function nextInterval(\DateTimeImmutable $date, $modifier)
    $dayNumber = (int)$date->format('j');
    $next = $date->modify($modifier);
    if (!is_null($this->remainder)) {
        $next = $next->add($this->remainder);
        $dayNumber += $this->remainder->days;
        $this->remainder = null;

    // This should in general only apply to months which do not have the same daynumber in that month after adding
    if ($dayNumber !== (int)$next->format('j')) {
        $n = $next->modify('last day of last month');
        $this->remainder = $n->diff($next);
        $next = $n;

    return $next;




  • 0
Reply Report

You can use this code. The first line accepts a Date in any format, and the later lines split off the month value, adding a month and returning the final value in Y-M-D format.

$year_month = Date("Y-m", strtotime($date));
$year_month_incremented = Date("Y-m", strtotime($year_month . " +1 Month "));
$month_end_dt =strtotime('last day of this month', strtotime($year_month_incremented));
$date = date('Y-m-d', $month_end_dt );
  • 0
Reply Report

Warm tip !!!

This article is reproduced from Stack Exchange / Stack Overflow, please click

Trending Tags

Related Questions