php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #69468 DateTime->add problem for 2015-01-31
Submitted: 2015-04-16 10:37 UTC Modified: 2015-04-16 11:30 UTC
From: pawaroti at gmail dot com Assigned:
Status: Not a bug Package: Date/time related
PHP Version: 5.5.24RC1 OS: Windows 7
Private report: No CVE-ID: None
 [2015-04-16 10:37 UTC] pawaroti at gmail dot com
Description:
------------
Adding 1 month using DateInterval('P1M') sets date to 2015-03-03 if adding from DateTime('2015-01-31')

+1 month = 2015-03-03
+2 months = 2015-03-31
+3 months = 2015-05-01
+4 months = 2015-05-31
+5 months = 2015-07-01
+6 months = 2015-07-31
+7 months = 2015-08-31
+8 months = 2015-10-01
+9 months = 2015-10-31
+10 months = 2015-12-01
+11 months = 2015-12-31
+12 months = 2016-01-31

BEFORE:
object(DateTime)[5]
  public 'date' => string '2015-01-31 00:00:00.000000' (length=26)
  public 'timezone_type' => int 3
  public 'timezone' => string 'Europe/Warsaw' (length=13)

AFTER
object(DateTime)[5]
  public 'date' => string '2015-03-03 00:00:00.000000' (length=26)
  public 'timezone_type' => int 3
  public 'timezone' => string 'Europe/Warsaw' (length=13)

INTERVAL
object(DateInterval)[6]
  public 'y' => int 0
  public 'm' => int 1
  public 'd' => int 0
  public 'h' => int 0
  public 'i' => int 0
  public 's' => int 0
  public 'weekday' => int 0
  public 'weekday_behavior' => int 0
  public 'first_last_day_of' => int 0
  public 'invert' => int 0
  public 'days' => boolean false
  public 'special_type' => int 0
  public 'special_amount' => int 0
  public 'have_weekday_relative' => int 0
  public 'have_special_relative' => int 0

Test script:
---------------
for($i=0; $i<=12; $i++)
{
$data = new DateTime('2015-01-31');
echo $data->add(new DateInterval('P'.$i.'M'))->format('Y-m-d').'<br />';
}

Expected result:
----------------
2015-02-28
2015-03-31
2015-04-30
2015-05-31
2015-06-30
2015-07-31
2015-08-31
2015-09-30
2015-10-31
2015-11-30
2015-12-31
2016-01-31

Actual result:
--------------
2015-03-03
2015-03-31
2015-05-01
2015-05-31
2015-07-01
2015-07-31
2015-08-31
2015-10-01
2015-10-31
2015-12-01
2015-12-31
2016-01-31

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2015-04-16 11:30 UTC] requinix@php.net
-Status: Open +Status: Not a bug
 [2015-04-16 11:30 UTC] requinix@php.net
P1M means "increment the month number by 1". Jan 31 + 1 month = Feb 31, which is invalid and overflows into March, becoming Mar 3. Similarly for other months with <31 days.

You need to decide what result you want to get, understand why you want to get it, and then write code to support it. You may find that the logic is easier to express using the procedural functions. For example, if you wanted to use the last day of the month if the date overflowed,

  // extract month, day, and year components
  $start = date_parse("2015-01-31");
  // use month+1 and allow for overflow
  $target = mktime(0, 0, 0, $start["month"] + 1, $start["day"], $start["year"]);
  // end day < start day promises that the date must have overflowed
  if (getdate($target)["mday"] < $start["day"]) {
    // use underflow with month+2
    $target = mktime(0, 0, 0, $start["month"] + 2, 0, $start["year"]);
  }

http://3v4l.org/Y3CHG
 
PHP Copyright © 2001-2026 The PHP Group
All rights reserved.
Last updated: Tue Oct 06 21:00:01 2026 UTC