PNWPHP 2017 CfP

DateTime::modify

date_modify

(PHP 5 >= 5.2.0, PHP 7)

DateTime::modify -- date_modifyタイムスタンプを変更する

説明

オブジェクト指向型

public DateTime DateTime::modify ( string $modify )

手続き型

DateTime date_modify ( DateTime $object , string $modify )

strtotime() 形式で加算あるいは減算することによって DateTime オブジェクトのタイムスタンプを変更します。

パラメータ

object

手続き型のみ: date_create() が返す DateTime オブジェクト。 この関数は、このオブジェクトを変更します。

modify

日付/時刻 文字列。有効な書式については 日付と時刻の書式 で説明しています。

返り値

メソッドチェインに使う DateTime オブジェクトを返します。失敗した場合に FALSE を返します。

変更履歴

バージョン 説明
5.3.6 日付/時刻の絶対指定も効果を及ぼすようになりました。 これまでは、相対指定部分だけを用いていました。
5.3.0成功した場合の返り値が NULL から DateTime に変更されました。

例1 DateTime::modify() の例

オブジェクト指向型

<?php
$date 
= new DateTime('2006-12-12');
$date->modify('+1 day');
echo 
$date->format('Y-m-d');
?>

手続き型

<?php
$date 
date_create('2006-12-12');
date_modify($date'+1 day');
echo 
date_format($date'Y-m-d');
?>

上の例の出力は以下となります。

2006-12-13

例2 月の加減算には注意

<?php
$date 
= new DateTime('2000-12-31');

$date->modify('+1 month');
echo 
$date->format('Y-m-d') . "\n";

$date->modify('+1 month');
echo 
$date->format('Y-m-d') . "\n";
?>

上の例の出力は以下となります。

2001-01-31
2001-03-03

参考

add a note add a note

User Contributed Notes 10 notes

up
20
jenspj at msn dot com
5 years ago
These functions makes sure that adding months or years always ends up in the month you would expect.  Works for positive and negative values

<?php
     
      
    $date
=new DateTime();
   
$date->setDate(2008,2,29);
   
    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);   
        }
       
       
/*
        if($months<0&&$date->format('m')>$init->format('m'))
        while($date->format('m')-12-$init->format('m')!=$months%12)
        $date->modify('-1 day');
        else
        if($months>0&&$date->format('m')<$init->format('m'))
        while($date->format('m')+12-$init->format('m')!=$months%12)
        $date->modify('-1 day');
        else
        while($date->format('m')-$init->format('m')!=$months%12)
        $date->modify('-1 day');
        */
       
   
}
    
    function
addYears($date,$years){
       
       
$init=clone $date;
       
$modifier=$years.' years';
       
$date->modify($modifier);
       
        while(
$date->format('m')!=$init->format('m'))
       
$date->modify('-1 day');
       
       
    }
   
   
   
   
addMonths($date,-1);
    
addYears($date,3);
   
   
    echo
$date->format('F j,Y');
    

?>
up
8
Anonymous
1 year ago
I cant believe this is in official PHPDOC, such an incredible retarded bug, and, best of all, No explanation at all... this is the kind of things that make PHPCore developers look like fools.

<?php
$date
= new DateTime('2000-12-31');

$date->modify('+1 month');
echo
$date->format('Y-m-d') . "\n";

$date->modify('+1 month');
echo
$date->format('Y-m-d') . "\n";
?>

Result:

2001-01-31
2001-03-03
up
5
www dot wesley at gmail dot com
1 year ago
This is an improvement of @jenspj's answer

<?php

$d
= new DateTime('2007-12-31');

function
addMonths($date, $months)
{
   
$years = floor(abs($months / 12));
   
$leap = 29 <= $date->format('d');
   
$m = 12 * (0 <= $months?1:-1);
    for (
$a = 1;$a < $years;++$a) {
       
$date = addMonths($date, $m);
    }
   
$months -= ($a - 1) * $m;
   
   
$init = clone $date;
    if (
0 != $months) {
       
$modifier = $months . ' months';
       
       
$date->modify($modifier);
        if (
$date->format('m') % 12 != (12 + $months + $init->format('m')) % 12) {
           
$day = $date->format('d');
           
$init->modify("-{$day} days");
        }
       
$init->modify($modifier);
    }
   
   
$y = $init->format('Y');
    if (
$leap && ($y % 4) == 0 && ($y % 100) != 0 && 28 == $init->format('d')) {
       
$init->modify('+1 day');
    }
    return
$init;
}

function
addYears($date, $years)
{
    return
addMonths($date, 12 * $years);
}

echo
$d->format('F j,Y') . ' N<br />';
$d = addMonths($d, +1);
echo
$d->format('F j,Y') . ' +1M<br />';
$d = addMonths($d, +1);
echo
$d->format('F j,Y') . ' +1M<br />';
$d = addYears($d, +60);
echo
$d->format('F j,Y') . ' +60Y<br />';
$d = addYears($d, -59);
echo
$d->format('F j,Y') . ' -59Y<br />';
up
4
jay dot removethis at grooveshark dot com
3 years ago
Due to DST and the way DateTime internally handles dates, it's possible to get stuck in a time loop.

For example:

<?php
$dt
= new DateTime('2012-03-11 3:00AM');
echo
$dt->format('YmdH') . "\n";
$dt->modify("-1 hour");
echo
$dt->format('YmdH') . "\n";
$dt->modify("-1 hour");
echo
$dt->format('YmdH') . "\n";
?>

prints out:

2012031103
2012031103
2012031103

if your timezone is set to America/New_York.
up
1
admin at wmfoi dot com dot br
2 years ago
The changelog says: "5.3.0 - Changed the return value on success from NULL to DateTime".

That means that you can't do a Fluid Interface design with it in PHP 5.2.

In other words, this will not work in 5.2:

<?php
$DateTime
=new DateTime();
echo
$DateTime->modify('+1 day')->format('d');
?>
up
2
Jenny jsimonds@atomic jet packs dot com
4 years ago
Note: This method modifies the object in-place. So if you want to calculate a new date but assign the new value to a different object, this will NOT work:

<?php
$numMinutes
= 25;
$oDateA = new DateTime('2012-01-01 12:00:00');

print
"
Original:<br>
oDateA = 
{$oDateA->format('Y-m-d H-i-s')}<br>
"
;

$oDateB = $oDateA->modify ("+{$numMinutes} minutes");

print
"
plus
{$numMinutes} minutes:<br>
oDateA = 
{$oDateA->format('Y-m-d H-i-s')}<br>
oDateB = 
{$oDateB->format('Y-m-d H-i-s')}<br>
"
;
?>
...produces this:
oDateA = 2012-01-01 12-00-00
plus 25 minutes:
oDateA = 2012-01-01 12-25-00
oDateB = 2012-01-01 12-25-00

Use something like this instead:
<?php
$numMinutes
= 25;
$oDateA = new DateTime('2012-01-01 12:00:00');

print
"
<p>
Original:<br>
oDateA = 
{$oDateA->format('Y-m-d H-i-s')}<br>
"
;

$oDateB = clone $oDateA;
$oDateB->modify ("+{$numMinutes} minutes");

print
"
plus
{$numMinutes} minutes:<br>
oDateA = 
{$oDateA->format('Y-m-d H-i-s')}<br>
oDateB = 
{$oDateB->format('Y-m-d H-i-s')}<br>
"
;
?>

... produces this:
oDateA = 2012-01-01 12-00-00
plus 25 minutes:
oDateA = 2012-01-01 12-00-00
oDateB = 2012-01-01 12-25-00
up
1
mangotonk at gmail dot com
2 months ago
a slightly more compact way of getting the month shift

<?php

     
/**
     * correctly calculates end of months when we shift to a shorter or longer month
     * workaround for http://php.net/manual/en/datetime.add.php#example-2489
     *
     * Makes the assumption that shifting from the 28th Feb +1 month is 31st March
     * Makes the assumption that shifting from the 28th Feb -1 month is 31st Jan
     * Makes the assumption that shifting from the 29,30,31 Jan +1 month is 28th (or 29th) Feb
     *
     *
     * @param DateTime $aDate
     * @param int $months positive or negative
     *
     * @return DateTime new instance - original parameter is unchanged
     */

   
function MonthShifter (DateTime $aDate,$months){
       
$dateA = clone($aDate);
       
$dateB = clone($aDate);
       
$plusMonths = clone($dateA->modify($months . ' Month'));
       
//check whether reversing the month addition gives us the original day back
       
if($dateB != $dateA->modify($months*-1 . ' Month')){
           
$result = $plusMonths->modify('last day of last month');
        } elseif(
$aDate == $dateB->modify('last day of this month')){
           
$result $plusMonths->modify('last day of this month');
        } else {
           
$result = $plusMonths;
        }
        return
$result;
    }

//TEST

$x = new DateTime('2017-01-30');
echo(
$x->format('Y-m-d')." past end of feb, but not dec<br>");
echo(
'b ' . MonthShifter($x,1)->format(('Y-m-d'))."<br>");
echo(
'c ' . MonthShifter($x,-1)->format(('Y-m-d'))."<br>");

$x = new DateTime('2017-01-15');
echo(
"<br>" . $x->format('Y-m-d')." middle of the month <br>");
echo(
'd ' . MonthShifter($x,1)->format(('Y-m-d'))."<br>");
echo(
'e ' . MonthShifter($x,-1)->format(('Y-m-d'))."<br>");

$x = new DateTime('2017-02-28');
echo(
"<br>" . $x->format('Y-m-d')." end of Feb<br>");
echo(
'f ' . MonthShifter($x,1)->format(('Y-m-d'))."<br>");
echo(
'g ' . MonthShifter($x,-1)->format(('Y-m-d'))."<br>");

$x = new DateTime('2017-01-31');
echo(
"<br>" $x->format('Y-m-d')." end of Jan<br>");
echo(
'h ' . MonthShifter($x,1)->format(('Y-m-d'))."<br>");
echo(
'i ' . MonthShifter($x,-1)->format(('Y-m-d'))."<br>");

$x = new DateTime('2017-01-31');
echo(
"<br>" $x->format('Y-m-d')." end of Jan +/- 1 years diff, leap year respected<br>");
echo(
'j ' . MonthShifter($x,13)->format(('Y-m-d'))."<br>");
echo(
'k ' . MonthShifter($x,-11)->format(('Y-m-d'))."<br>");

//returns

2017-01-30 past end of feb, but not dec
b 2017
-02-28
c 2016
-12-30

2017
-01-15 middle of the month
d 2017
-02-15
e 2016
-12-15

2017
-02-28end of Feb
f 2017
-03-31
g 2017
-01-31

2017
-01-31end of Jan
h 2017
-02-28
i 2016
-12-31

2017
-01-31end of Jan +/- 1 years diff, leap year respected
j 2018
-02-28
k 2016
-02-29
up
1
sinus at sinpi dot net
4 months ago
A very simple way to ensure we do not cross over month boundaries when adding months is to just go back a few days if the day number got reset:

<?php
function addMonths($date,$months) {
 
$orig_day = $date->format("d");
 
$date->modify("+".$months." months");
  while (
$date->format("d")<$orig_day && $date->format("d")<5) {
   
$date->modify("-1 day");
  }
}

for (
$i=0;$i<5;$i++) {
 
$d = new DateTime("2000-01-10");
 
addmonths($d,$i);
  echo
$d->format("Y-m-d")."<br>";
}
for (
$i=0;$i<5;$i++) {
 
$d = new DateTime("2000-01-31");
 
addmonths($d,$i);
  echo
$d->format("Y-m-d")."<br>";
}
?>

prints:
2000-01-10
2000-02-10
2000-03-10
2000-04-10
2000-05-10
2000-01-31
2000-02-29
2000-03-31
2000-04-30
2000-05-31
up
0
66Ton99
2 years ago
Extension for DateTime class which solves problem of adding or subtracting months

https://gist.github.com/66Ton99/60571ee49bf1906aaa1c
up
0
php at lanar dot com dot au
3 years ago
modify() ignores any timezone information in the data while the DateTime constructor does not.

$dt = new DateTime( '2013-10-26T11:00:00+11:00' )
will create a +11 timezone while
$dt->modify( '2013-10-26T11:00:00+02:00' )
does not change the timezone or the time.

<?php
$dt
= new DateTime( '2013-10-26T15:00:00Australia/Melbourne' ) ;
echo
"\n", $dt->format( "c" ) ;
echo
"\nTimezone '", $dt->getTimezone()->getName() . "'." ;
// modify $dt to 1 am new york which is 3 pm melbourne
$dt->modify( '2013-10-26T01:00:00America/New_York' ) ;
// result is 1 am melbourne time, not 3 pm
echo "\n", $dt->format( "c" ) ;
echo
"\nTimezone '", $dt->getTimezone()->getName() . "'." ;
?>
Output
2013-10-26T15:00:00+11:00
Timezone 'Australia/Melbourne'.
2013-10-26T01:00:00+11:00
Timezone 'Australia/Melbourne'.
To Top