【问题标题】:How we can add two date intervals in PHP我们如何在 PHP 中添加两个日期间隔
【发布时间】:2012-07-19 08:21:10
【问题描述】:

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

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

【问题讨论】:

    标签: php datetime addition dateinterval


    【解决方案1】:

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

    完整示例/(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";
    

    您可能还想考虑查看DateInterval 如何存储其值,然后从它扩展以进行您自己的计算。下面的例子(Demo)很粗略,它没有考虑the inverted thingy,它确实考虑了not (re)set $days to false,我还没有检查/测试the period specifier on creation的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 扩展,它实际上是可能的(至少在某种程度上)。

    【讨论】:

    • 更多实验:codepad.viper-7.com/Lh2DtL (gist)
    • 您好,如果您的解决方案总时间大于 60 秒、60 分钟、24 小时等,该怎么办? :)
    • @Talus:看到要点,并不是说它是完美的,但它显示了你如何处理它。
    • 是的,我指的是您发布的最后一个 sn-p(DateInterval 的扩展名)。但是第一个 sn-p(当您添加/减去间隔然后计算差异时)是我所做的,并且效果很好:)
    • 我现在使用它并创建了一个请求 PHP 核心向 DateInterval 类添加一个新方法:github.com/php/php-src/pull/390
    【解决方案2】:

    此函数允许您组合任意数量的 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);
    }
    

    【讨论】:

    • 这对我不起作用,$endTime 我认为是因为DateTimeImmutable。当我将 new DateTimeImmutable 更改为 new DateTime() 时工作了
    • @Gyfis Strange,它对我来说很好用。请记住,Immutables 将在更改时返回一个新实例。
    【解决方案3】:
    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>";
    

    【讨论】:

      【解决方案4】:

      我也有同样的情况。我通过创建一个新的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
      */
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-01-01
        • 2013-10-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多