PHP将两个DateInterval对象添加到一起

PHP将两个DateInterval对象添加到一起,php,datetime,dateinterval,Php,Datetime,Dateinterval,我正在用PHP处理一些时间记录实验中的数字。如何将两个DateInterval对象添加到一起 其中一个日期间隔是这样的(两个DateTime对象之间的差异): 另一个日期间隔仅定义为: $abc = new \DateInterval( 'PT1H' ); // DateInterval with duration of 1 hour 我读过几篇文章,其中一篇应该将我的DateInterval转换为DateTime对象,然后使用$dateTimeObject->add(…)-函数。但我觉得这很

我正在用PHP处理一些时间记录实验中的数字。如何将两个DateInterval对象添加到一起

其中一个日期间隔是这样的(两个DateTime对象之间的差异):

另一个日期间隔仅定义为:

$abc = new \DateInterval( 'PT1H' ); // DateInterval with duration of 1 hour
我读过几篇文章,其中一篇应该将我的DateInterval转换为DateTime对象,然后使用
$dateTimeObject->add(…)
-函数。但我觉得这很傻。这是一个持续时间,-那么我为什么要把它转换成它不是的东西,以便正确地处理它

我在下面写了一个函数来解决这个问题,但它看起来很笨拙。它可以写得更好吗?或者有更好的方法来总结两个DateInterval对象吗

function sumDateIntervals($dateinterval_one, $dateinterval_two)
{
  $d1_years = $dateinterval_one->y;
  $d1_months = $dateinterval_one->m;
  $d1_days = $dateinterval_one->d;
  $d1_hours = $dateinterval_one->h;
  $d1_minutes = $dateinterval_one->i;
  $d1_seconds = $dateinterval_one->s;
  $d1_float = $dateinterval_one->f;

  $d2_years = $dateinterval_two->y;
  $d2_months = $dateinterval_two->m;
  $d2_days = $dateinterval_two->d;
  $d2_hours = $dateinterval_two->h;
  $d2_minutes = $dateinterval_two->i;
  $d2_seconds = $dateinterval_two->s;
  $d2_float = $dateinterval_two->f;

  $return_dateinterval = new DateInterval( 
                     'P' . ( string ) ( $d1_years + $d2_years ) . 'Y' 
                     . ( string ) ( $d1_months + $d2_months ) . 'M' 
                     . ( string ) ( $d1_days + $d2_days ) . 'DT' 
                     . ( string )  ($d1_hours + $d2_hours ) . 'H' 
                     . ( string ) ( $d1_minutes + $d2_minutes ) . 'M' 
                     . ( string ) ($d1_seconds + $d2_seconds ) . 'S' );

  return $return_dateinterval;
}

另一种方法可能是使用magic
\uuuu set\u state()
方法创建新的日期间隔,从两个现有间隔中的等效属性之和构建所需的属性值数组

演示此方法的快速而难看的代码块(未经测试):

$properties = ['y' => PHP_INT_MAX,'m' => 12,'d' => 30,'h' => 24,'i' => 60,'s' => 60];


$dti1 = new DateInterval('P1Y7M16DT15H30M15S');
$dti2 = new DateInterval('P2Y8M26DT14H40M55S');

$state = array_fill_keys(array_keys($properties), null);

$carry = 0;
foreach(array_reverse($properties) as $property => $limit) {
    $state[$property] = $dti1->{$property} + $dti2->{$property} + $carry;
    $carry = 0;
    if ($state[$property] > $limit) {
        do {
            $state[$property] -= $limit;
            ++$carry;
        } while ($state[$property] > $limit);
        $state[$property] = $state[$property] % $limit;
    }
}

$newInterval = DateInterval::__set_state($state);

var_dump($newInterval);

处理
day
属性需要进行一些清理,并且要允许在PHP7.1中添加
f
属性,您的解决方案看起来是实现此功能的最佳方式

不需要显式地将总和转换为字符串(PHP还是这样做的)。如果要使其更具可读性,可以使用以下命令为参数生成字符串和更短的名称:

function sumDateIntervals(DateInterval $a, DateInterval $b)
{
    return new DateInterval(sprintf('P%dY%dM%dDT%dH%dM%dS',
        $a->y + $b->y,
        $a->m + $b->m,
        $a->d + $b->d,
        $a->h + $b->h,
        $a->i + $b->i,
        $a->s + $b->s
    ));
}

隐马尔可夫模型。。。这似乎相当先进。有几件事我不太明白。与我建议的方法相比,这种方法有什么好处?不一定有好处,只是不同的方法。。。。尽管
limit
逻辑试图将各个属性值保持在适当的范围内,因此您不会得到(例如)
PT47H
,但是
P1DT23H
最近在PHP8时就出现了问题。这里面并没有溢出,所以它会使ISO日期间隔变得荒谬和难以推理。尝试
var_dump(sumdateinterval(新的日期间隔('P0DT30S')、新的日期间隔('P0DT30S'))
,我希望返回的是
P0Y0M0DT0H1M0S
,相反,返回的是
P0Y0M0DT0H0M60S
,这可能是等效的,但想象一下,在任何情况下,时间分量S或M都>30,H都>12。还要考虑几天、几个月、几年。我想这是一个很难解决的问题。
function sumDateIntervals(DateInterval $a, DateInterval $b)
{
    return new DateInterval(sprintf('P%dY%dM%dDT%dH%dM%dS',
        $a->y + $b->y,
        $a->m + $b->m,
        $a->d + $b->d,
        $a->h + $b->h,
        $a->i + $b->i,
        $a->s + $b->s
    ));
}