31

我想添加两个日期间隔来计算以小时和分钟为单位的总持续时间实际上我想执行 addittion 如下所示:

$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 中以总小时和分钟格式获取两个间隔的总和

4

4 回答 4

45

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存储它的值,然后从它扩展以进行您自己的计算。以下示例(Demo)很粗糙,它没有考虑倒置的东西,它没有(重新)设置$daysfalse并且我没有在创建时检查/测试周期说明符的 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 扩展,它实际上是可能的(至少在某种程度上)。

于 2012-07-19T08:32:53.627 回答
9

此函数允许您组合任意数量的 DateInterval

/**
 * 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);
}
于 2014-08-05T22:19:31.457 回答
1
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>";
于 2015-03-20T07:36:51.873 回答
0

我也有同样的情况。我通过创建一个新的来解决我的问题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
*/
于 2020-10-27T08:40:43.150 回答