Как мы можем добавить два интервала даты в PHP

я хочу добавить два интервала дат, чтобы рассчитать общую продолжительность в часах и минутах, на самом деле я хочу выполнить добавление, как показано ниже:

$a = new DateTime('14:25');
$b = new DateTime('17:30');
$interval1 = $a->diff($b);
echo "interval 1 : " . $interval1->format("%H:%I");
echo "<br />";

$c = new DateTime('08:00');
$d = new DateTime('13:00');
$interval2 = $c->diff($d);
echo "interval 2 : " . $interval2->format("%H:%I");
echo "<br />";

echo "Total interval : " . $interval1 + $interval2;

Любая идея, как выполнить этот тип добавления интервала, чтобы получить сумму двух интервалов в общем формате часов и минут в PHP


person Sheikh Rahat Ali    schedule 19.07.2012    source источник


Ответы (3)


В PHP нет перегрузки операторов*, поэтому + с объектами заставляет PHP сначала попытаться преобразовать их в строку, но DateInterval этого не поддерживает:

interval 1: 03:05
interval 2: 05:00
Total interval : 08:05

Вместо этого вам нужно создать новый объект DateTime, затем использовать функцию add, чтобы добавить интервалы и, наконец, отобразить разницу с контрольной точкой:

$e = new DateTime('00:00');
$f = clone $e;
$e->add($interval1);
$e->add($interval2);
echo "Total interval : ", $f->diff($e)->format("%H:%I"), "\n";

Полный пример/(Демо):

$a = new DateTime('14:25');
$b = new DateTime('17:30');
$interval1 = $a->diff($b);
echo "interval 1: ", $interval1->format("%H:%I"), "\n";

$c = new DateTime('08:00');
$d = new DateTime('13:00');
$interval2 = $c->diff($d);
echo "interval 2: ", $interval2->format("%H:%I"), "\n";

$e = new DateTime('00:00');
$f = clone $e;
$e->add($interval1);
$e->add($interval2);
echo "Total interval : ", $f->diff($e)->format("%H:%I"), "\n";

Вы также можете подумать о том, как DateInterval хранит свои значения, а затем расширить их, чтобы выполнить собственные вычисления. Следующий пример (Демо) является грубым, он не учитывает перевернутая штука, она не (повторно) установить $days на false, и я не проверял/не тестировал спецификацию ISO описатель периода при создании, но я думаю, что этого достаточно, чтобы показать идею:

class MyDateInterval extends DateInterval
{
    /**
     * @return MyDateInterval
     */
    public static function fromDateInterval(DateInterval $from)
    {
        return new MyDateInterval($from->format('P%yY%dDT%hH%iM%sS'));
    }
                                  
    public function add(DateInterval $interval)
    {
        foreach (str_split('ymdhis') as $prop)
        {
            $this->$prop += $interval->$prop;
        }
    }
}

$a = new DateTime('14:25');
$b = new DateTime('17:30');
$interval1 = $a->diff($b);
echo "interval 1: ", $interval1->format("%H:%I"), "\n";

$c = new DateTime('08:00');
$d = new DateTime('13:00');
$interval2 = $c->diff($d);
echo "interval 2: ", $interval2->format("%H:%I"), "\n";
                                  
$e = MyDateInterval::fromDateInterval($interval1);
$e->add($interval2);
echo "Total interval: ", $e->format("%H:%I"), "\n";

* Если вы пишете расширение PHP, это действительно возможно (по крайней мере, отчасти).

person hakre    schedule 19.07.2012
comment
Еще несколько экспериментов: codepad.viper-7.com/Lh2DtL (суть) - person hakre; 19.07.2012
comment
Привет, что, если с вашим решением общее количество больше 60 секунд, 60 минут, 24 часов и т. д.? :) - person Talus; 25.01.2013
comment
@Talus: Поймите суть, не то, чтобы она была идеальной, но она показывает, как вы можете с этим справиться. - person hakre; 26.01.2013
comment
Да, я имел в виду последний фрагмент (расширение DateInterval), который вы опубликовали. Но первый фрагмент (когда вы добавляете/вычитаете интервалы, а затем вычисляете разницу) был тем, что я сделал, и это работает довольно хорошо :) - person Talus; 09.02.2013
comment
Мой ответ не совсем правильный, например, с некоторыми классами DateTime вы действительно можете использовать оператор +. - person hakre; 09.02.2013
comment
Я использовал это сейчас и создал запрос для ядра PHP, чтобы добавить новый метод в класс DateInterval: github.com/php/php-src/pull/390 - person SimonSimCity; 28.07.2013
comment
Вау, это очень мило, Саймон! Спасибо за все ваши усилия. - person hakre; 28.07.2013
comment
Я в основном сделал то, что вы показали во втором блоке кода. Но закачал в метод add объект типа \DateInterval('P135DT15H14M'). Поскольку интервалы, с которыми я работаю, не зависят от даты, это отлично сработало для решения моей проблемы получения общего количества часов между двумя из этих стилей интервалов дат (это совокупные часы). Спасибо! - person Patrick; 11.10.2017
comment
Разве формат return new DateInterval()... не должен быть P%yY%mM%dDT%hH%iM%sS? В предоставленном формате отсутствуют месяцы... - person thedom; 11.02.2018

Эта функция позволяет вам комбинировать любое количество DateIntervals

/**
 * Combine a number of DateIntervals into 1 
 * @param DateInterval $...
 * @return DateInterval
 */
function addDateIntervals()
{
    $reference = new DateTimeImmutable;
    $endTime = clone $reference;

    foreach (func_get_args() as $dateInterval) {
        $endTime = $endTime->add($dateInterval);
    }

    return $reference->diff($endTime);
}
person dave1010    schedule 05.08.2014
comment
Это не сработало для меня, $endTime я думаю, из-за DateTimeImmutable. Работало, когда я поменял new DateTimeImmutable на new DateTime() - person Gyfis; 11.05.2015
comment
@Gyfis Странно, у меня это работает отлично. Помните, что Immutables вернет новый экземпляр при изменении. - person David Yell; 16.01.2017

У меня была такая же ситуация. Я решаю это для своего случая, создавая новый объект stdClass, этот объект эмулирует объект DateInterval, однако это не настоящий объект DateInterval. Затем я перебираю каждый реальный DateInterval, выполняя операцию составного присваивания (например, +=) для нужного свойства. Смотри ниже:

$dateTimeA = new DateTime('-10 day');
$dateTimeB = new DateTime('-8 day');
$dateTimeC = new DateTime('-6 day');
$dateTimeD = new DateTime('-4 day');

$intervalA = date_diff($dateTimeA, $dateTimeB);
$intervalB = date_diff($dateTimeC, $dateTimeD);

$intervalC = new StdClass; // $intervalC is an emulation of DateInterval 
$intervalC->days = 0;

foreach([$intervalA, $intervalB] as $interval) {
    $intervalC->days += (int)$interval->format('%d');
}


var_dump($intervalC);
/*
object(stdClass)[7]
  public 'days' => int 4
*/
person Julian    schedule 27.10.2020