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
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: pawaroti at gmail dot com
New email:
PHP Version: OS:

 

 [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: Wed Oct 07 03:00:01 2026 UTC