从重叠时间计算小时数

时间:2014-09-17 10:42:45

标签: php

我有各种各样的时间范围,如

10:00 12:00,
21:00 24:00,
11:30 12:00,
08:00 17:00

这些是用户的日程安排。我想从这些范围计算总小时数,但我不想计算重复的时间。如果我计算任何一小时,那么我不想再计算一次。我该怎么办呢。

我正在计算小时数。但我怎么能逃避重复的时间。我已经算过了。

$shifts = "10:00 12:00 | 21:00 24:00| 11:30 12:00|08:00 17:00";
$shifts = explode('|', $shifts);

$sum = 0;

$starts = array();
$ends = array();

foreach($shifts as $shift) {
    $times = explode(' ', trim($shift));
    $start = explode(':', $times[0]);
    $end = explode(':', $times[1]);

    $startime   = $start[0]*60 + $start[1];
    $endtime    = $end[0]*60 + $end[1];
    $flag = false;
    foreach ($starts as $key=>$start) {       
        if($startime < $start && $endtime > $ends[$key]) {
            $diff_old = ($start > $ends[$key]) ? $start - $ends[$key] : $ends[$key] - $start;
            $sum = $sum - $diff_old/60;
        }
        else if($startime > $start && $endtime <= $ends[$key]) {
            $flag = true;
            continue;
        }
    }   
    if($flag)
        continue;
    $starts[] = $startime;
    $ends[] = $endtime;  
    $diff = $startime > $endtime ? $startime - $endtime : $endtime - $startime;   
    $sum = $sum + $diff/60;
}

echo $sum;

我是通过上面的代码尝试这个,但它显示错误的答案。因为我不想计算已计算的小时数。这次显示的答案是12,但正确答案是10。

1 个答案:

答案 0 :(得分:2)

让我们考虑以下几点。如果我们有两个时间间隔[8, 10][9, 12],那么时间间隔的并集长度等于[8, 12]的长度。

如果我们有两个不相交的间隔([8, 9][10, 11]),我们不需要进行间隔合并来计算长度。相反,我们可以只取间隔长度的总和。

因此,尝试将间隔集减少到一组不相交的间隔是合乎逻辑的。然后问题变得微不足道。

//Check if [a0, a1] and [b0, b1] are disjoint
function isDisjoint($a, $b) {
   if(in_array($a[0], $b) || in_array($a[1], $b)) {
      return false;
   }
   return ($a[0] < $b[0]) ? ($a[1] < $b[0]) : ($a[0] > $b[1]);
}

//Make sure $a and $b are not disjoint before calling.
function mergeIntervals($a, $b) {
   return array(min($a[0], $b[0]), max($a[1], $b[1]));
}

//Generate a set of disjoint intervals
function genetrateDisjointSet($set) {
   $output = array();
   while(!empty($set)) {
      $interval = array_pop($set);
      $intervalDisjoint = false;

      while(!$intervalDisjoint) {
        $intervalDisjoint = true;
        foreach($set as $key => $value) {
           if(!isDisjoint($interval, $value)) {
              $interval = mergeIntervals($interval, $value);
              unset($set[$key]);
              $intervalDisjoint = false;
           }
        }
     }

     array_push($output, $interval);
  }

  return $output;
}

//Calculate the length of the set of intervals
function calcLength($set) {
   $set = genetrateDisjointSet($set);
   $length = 0;

   foreach($set as $value) {
      $length += $value[1] - $value[0];
   }

   return $length;
}

我们尝试使用您的示例

//You have to convert the time to minutes after 00:00.
$set = array(
   array(600, 720),
   array(1260, 1440),
   array(690, 720),
   array(480, 1020)
);
echo calcLength($set); //720 min = 12 h * 60

注意 08:0017:00 + 21:0024:009 + 3 = 12

修改将时间更改为00:00而非数小时后的分钟数。感谢Dharman的想法。