How we can add two date intervals in PHP

时光总嘲笑我的痴心妄想 提交于 2019-11-26 11:24:56

PHP has no operator overloading* so + with objects makes PHP trying it to convert them to string first, but DateInterval does not support that:

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

Instead you need to create a new DateTime object, then use the add function to add the intervals and finally display the difference to the reference point:

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

Full Exmaple/(Demo):

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

You might also want to consider looking how DateInterval stores its' values and then extend from it to do the calculation your own. The following example (Demo) is rough, it does not take into account the inverted thingy, it does not (re)set $days to false and I have not checked/tested the ISO specification of the period specifier on creation but I think it is enough to show the idea:

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

* If you write a PHP extension, it actually is possible (at least sort-of).

This function allows you to combine any number of 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);
}
function compare_dateInterval($interval1, $operator ,$interval2){
    $interval1_str = $interval1->format("%Y%M%D%H%I%S");
    $interval2_str = $interval2->format("%Y%M%D%H%I%S");
    switch($operator){
        case "<":
            return $interval1 < $interval2;
        case ">":
            return $interval1 > $interval2;
        case "==" :
            return $interval1 == $interval2;
        default:
            return NULL;
    }
}
function add_dateInterval($interval1, $interval2){
    //variables
    $new_value= [];
    $carry_val = array(
                    's'=>['value'=>60,'carry_to'=>'i'],
                    'i'=>['value'=>60,'carry_to'=>'h'],
                    'h'=>['value'=>24,'carry_to'=>'d'],
                    'm'=>['value'=>12,'carry_to'=>'y']
                );

    //operator selection
    $operator = ($interval1->invert == $interval2->invert) ? '+' : '-';

    //Set Invert
    if($operator == '-'){
        $new_value['invert'] = compare_dateInterval($interval1,">",$interval2)?$interval1->invert:$interval2->invert;
    }else{
        $new_value['invert'] = $interval1->invert;
    }

    //Evaluate
    foreach( str_split("ymdhis") as $property){
        $expression = 'return '.$interval1->$property.' '.$operator.' '.$interval2->$property.';';
        $new_value[$property] = eval($expression);
        $new_value[$property] = ($new_value[$property] > 0) ? $new_value[$property] : -$new_value[$property];
        }

    //carry up
    foreach($carry_val as $property => $option){
        if($new_value[$property] >= $option['value']){
            //Modulus
            $new_value[$property] = $new_value[$property] % $option['value'];
            //carry over
            $new_value[$option['carry_to']]++;
        }
    }

    $nv = $new_value;
    $result = new DateInterval("P$nv[y]Y$nv[m]M$nv[d]DT$nv[h]H$nv[i]M$nv[s]S");
    $result->invert = $new_value['invert'];
    return $result;
}

$a = new DateTime('00:0');
$b = new DateTime('17:30');
$interval1 = $a->diff($b);
echo "interval 1: ", $interval1->format("%H:%I"), "<br>";

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

$addition = add_dateInterval($interval1,$interval2);
echo "<pre>";
echo var_dump($addition);
echo "</pre>";
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!