DateTime::modify

date_modify

(PHP 5 >= 5.2.0)

DateTime::modify -- date_modifyИзменение временной метки

Описание

Объектно-ориентированный стиль

public DateTime DateTime::modify ( string $modify )

Процедурный стиль

DateTime date_modify ( DateTime $object , string $modify )

Изменяет метку времени объекта DateTime путем добавления или вычитания времени в формате, принятом для функции strtotime().

Список параметров

object

Только для процедурного стиля: Объект DateTime, возвращаемый date_create(). Функция изменяет этот объект.

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

Смотрите также

  • strtotime() - Преобразует текстовое представление даты на английском языке в метку времени Unix
  • DateTime::add() - Добавляет заданное количество дней, месяцев, лет, часов, минут и секунд к объекту DateTime
  • DateTime::sub() - Вычитает заданное количество дней, месяцев, лет, часов, минут и секунд из времени объекта DateTime
  • DateTime::setDate() - Установка даты
  • DateTime::setISODate() - Установка ISO даты
  • DateTime::setTime() - Установка времени
  • DateTime::setTimestamp() - Устанавливает дату и время, основываясь на метке времени Unix

Коментарии

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');
     
 
?>
2012-02-20 16:34:55
http://php5.kiev.ua/manual/ru/datetime.modify.html
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
2012-04-16 00:04:34
http://php5.kiev.ua/manual/ru/datetime.modify.html
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'.
2013-10-26 09:50:21
http://php5.kiev.ua/manual/ru/datetime.modify.html
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.
2013-10-29 07:46:44
http://php5.kiev.ua/manual/ru/datetime.modify.html
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');
?>
2014-04-08 23:22:00
http://php5.kiev.ua/manual/ru/datetime.modify.html
Автор:
Extension for DateTime class which solves problem of adding or subtracting months

https://gist.github.com/66Ton99/60571ee49bf1906aaa1c
2014-05-13 18:31:46
http://php5.kiev.ua/manual/ru/datetime.modify.html
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 * (<= $months?1:-1);
    for (
$a 1;$a $years;++$a) {
       
$date addMonths($date$m);
    }
   
$months -= ($a 1) * $m;
   
   
$init = clone $date;
    if (
!= $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) == && ($y 100) != && 28 == $init->format('d')) {
       
$init->modify('+1 day');
    }
    return 
$init;
}

function 
addYears($date$years)
{
    return 
addMonths($date12 $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 />';
2015-07-04 23:31:31
http://php5.kiev.ua/manual/ru/datetime.modify.html
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
2016-11-30 00:54:10
http://php5.kiev.ua/manual/ru/datetime.modify.html
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 datetime.add#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*-' 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 febbut 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 diffleap year respected
j 2018
-02-28
k 2016
-02-29
2017-01-24 07:55:03
http://php5.kiev.ua/manual/ru/datetime.modify.html
function subMonths(\Datetime $dateTime, int $months)
{
    if ($invert = $months < 0) {
        $months *= -1;
    }

    for ($i=0; $i<$months; $i++) {
        $daysOfMonth = cal_days_in_month(CAL_GREGORIAN, $dateTime->format('m'), $dateTime->format('Y'));
        $dateTime->modify(($invert ? '-' : '+') . $daysOfMonth . ' day');
    }
    return $dateTime;
}

$dateTime = new \DateTime('2004-12-31');

echo $dateTime->modify('-3 month')->format('Y-m-d'); // 2004-10-01

echo subMonths($dateTime, -3)->format('Y-m-d'); // 2004-09-30
2017-12-15 12:05:48
http://php5.kiev.ua/manual/ru/datetime.modify.html
@Anonimous 
There is no bug. Especially not any retarded one.

<? 
function plusOneMonthTests($dateString$expectation) {
   
$date = new DateTime($dateString);
    echo 
"[".$date->format('Y-m-d')."] +1 month = [".$date->modify('+1 month')->format('Y-m-d')."] $expectation \n";
}   
plusOneMonthTests('2001-01-01''as expected');
plusOneMonthTests('2001-01-27''as expected');
plusOneMonthTests('2001-01-28''as expected');
plusOneMonthTests('2001-01-29''what would you expect?');
plusOneMonthTests('2001-01-30''what would you expect?');
plusOneMonthTests('2001-01-31''what would you expect?');
?>
Result: 
[2001-01-01] +1 month = [2001-02-01] as expected 
[2001-01-27] +1 month = [2001-02-27] as expected 
[2001-01-28] +1 month = [2001-02-28] as expected 
[2001-01-29] +1 month = [2001-03-01] what would you expect? 29 of february??
[2001-01-30] +1 month = [2001-03-02] what would you expect? or 30 of february?
[2001-01-31] +1 month = [2001-03-03] what would you expect? 

As with any tool you need to know how to use it. 

I think most people are looking for "the same day of the next month" (or any other number or months). 

The calendar is twisted, don't blame the library.
2019-02-18 18:53:33
http://php5.kiev.ua/manual/ru/datetime.modify.html
date_default_timezone_set('Europe/Amsterdam');

$dt = new DateTime('27 October 2019 00:20:00');
print_r($dt);
$dt->modify('600 min');
print_r($dt);

$dt = new DateTime('27 October 2019 00:20:00');
$dt->add(date_interval_create_from_date_string('600 min'));
print_r($dt);

// produces
DateTime Object
(
    [date] => 2019-10-27 00:20:00.000000
    [timezone_type] => 3
    [timezone] => Europe/Amsterdam
)
DateTime Object
(
    [date] => 2019-10-27 10:20:00.000000
    [timezone_type] => 3
    [timezone] => Europe/Amsterdam
)
DateTime Object
(
    [date] => 2019-10-27 09:20:00.000000
    [timezone_type] => 3
    [timezone] => Europe/Amsterdam
)
2019-10-25 19:27:51
http://php5.kiev.ua/manual/ru/datetime.modify.html
Автор:
Made a different fixed version using the month not the day

<?php

function modifyMonth(DateTime $datestring $modificator): DateTime {
   
$destMonth $date->format('m') + $date->format('Y') * 12 + ($modificator);
   
$date->modify("$modificator months");
    while (
$date->format('m') + $date->format('Y') * 12 $destMonth)
       
$date->modify('-1 day');
    return 
$date;
}
?>

Testing :

<?php
$dates 
= [
    [
'2020/02/29''+1''2020/03/29'],
    [
'2020/02/29 12:34''-1''2020/01/29 12:34'],
    [
'2020/03/29 01:01''+1''2020/04/29 01:01'],
    [
'2020/03/29''-1''2020/02/29'],
    [
'2020/03/30''+1''2020/04/30'],
    [
'2020/03/30 23:58''-1''2020/02/29 23:58'],
    [
'2020/03/31''+1''2020/04/30'],
    [
'2020/03/31''-1''2020/02/29'],
    [
'2020/03/31''+2''2020/05/31'],
    [
'2020/03/31 00:01''-2''2020/01/31 00:01'],
    [
'2020/03/01''+1''2020/04/01'],
    [
'2020/03/01''-1''2020/02/01'],
    [
'2020/02/01''+1''2020/03/01'],
    [
'2020/02/01''-1''2020/01/01'],
    [
'2020/04/01''+1''2020/05/01'],
    [
'2020/04/01 22:22''-1''2020/03/01 22:22'],
    [
'2020/12/31''+2''2021/02/28'],
    [
'2020/01/31''-2''2019/11/30'],
];

foreach (
$dates as $date) {
   
$test = new DateTime($date[0]);
   
modifyMonth($test$date[1]);
    if (
$test != new DateTime($date[2]))
        echo 
$date[0] . " " $date[1] . " != " $test->format('c') . "\n";
}
?>

Testing prints no error
2020-03-31 15:48:44
http://php5.kiev.ua/manual/ru/datetime.modify.html
Beware, the modify function does not treat .5 as a half minute!

echo "start with:           $str\n";
$datetimeObj = new DateTime($str);
$datetimeObj->modify('1 minutes');
echo "add 1 min:            ".$datetimeObj->format('m/d/Y h:i:s A')."\n";
$datetimeObj = new DateTime($str);
$datetimeObj->modify('.5 minutes');
echo "add .5 min:           ".$datetimeObj->format('m/d/Y h:i:s A')."\n";
$datetimeObj->modify('.53453531 minutes');
echo "add .53453531 min:    ".$datetimeObj->format('m/d/Y h:i:s A')."\n";

start with:              05/25/2021 02:53:40 PM
add 1 min:              05/25/2021 02:54:40 PM
add .5 min:             05/25/2021 02:58:40 PM
add .53453531 min: 01/12/2123 03:09:40 AM

.5 minutes actually ends up adding 5 minutes, not a half minute, and .53453531 adds 53453531 minutes.

So, if you have a function that accepts a number for adding minutes to a datetime, you have to check for < 1 and > -1, and then possibly convert that to seconds and do a seconds modification.
2021-05-26 00:12:39
http://php5.kiev.ua/manual/ru/datetime.modify.html
Автор:
Keep in mind that method chaining is only available from PHP 5.3, so with older versions, this will not work:

<?php
$exp_date 
= new DateTime();
echo 
$exp_date->modify("-10 month")->format("Y-m-d");
?>

This will work:

<?php
$exp_date 
= new DateTime();
$exp_date->modify("-10 month");
echo 
$exp_date->format("Y-m-d");
?>
2022-03-28 06:49:46
http://php5.kiev.ua/manual/ru/datetime.modify.html

    Поддержать сайт на родительском проекте КГБ