The 5th Annual China PHP Conference

DateTime::modify

date_modify

(PHP 5 >= 5.2.0, PHP 7)

DateTime::modify -- date_modifyAlters the timestamp

Descrizione

Stile orientato agli oggetti

public DateTime DateTime::modify ( string $modify )

Stile procedurale

DateTime date_modify ( DateTime $object , string $modify )

Alter the timestamp of a DateTime object by incrementing or decrementing in a format accepted by strtotime().

Elenco dei parametri

oggetto

Solo per lo stile procedurale: Un oggetto DateTime restituito da date_create(). La funzione modifica questo oggetto.

modify

Una stringa data/ora. I formati validi sono descritti in Formati di Data e Tempo.

Valori restituiti

Restituisce l'oggetto DateTime per il metodo chaining o FALSE in caso di fallimento.

Log delle modifiche

Versione Descrizione
5.3.6 Absolute date/time statements now take effect. Previously, only relative parts were used.
5.3.0Modificato il valore di ritorno in caso di successo da NULL a DateTime.

Esempi

Example #1 DateTime::modify() example

Stile orientato agli oggetti

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

Stile procedurale

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

I precedenti esempi visualizzeranno:

2006-12-13

Example #2 Beware when adding or subtracting months

<?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";
?>

Il precedente esempio visualizzerĂ :

2001-01-31
2001-03-03

Vedere anche:

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
3 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
5 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
4 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
5 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
3 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