Pull to refresh

PHP: работа с промежутками времени

Reading time 3 min
Views 1.8K
Как-то раз по поставленной задаче столкнулся я с проблемой, решения которой я в интернете так и не нашел. Либо проблема специфическая и никто с ней не сталкивался, либо она примитивная, а я использовал не те процедуры поиска. Но как и для любого программера мне стало интересно решить ее самому и своим способом…

Проблема заключалась вот в чем: есть к примеру 10 задач выполняющихся паралельно, каждая задача разбита на подзадачи которые стартуют в определенное время и известна их продолжительность, нам надо добавить в одну из задач пару подзадач, но в начале нужно узнать есть ли в заданом интервале свободные отрезки времени нужной нам продолжительности и со скольки до скольки они длятся. Мы имеем $reservArray с данными которые содержат в себе для каждого элемента масива время старта и окончания события, так же мы имеем время старта и окончания ($timeArray) промежутка в котором нам необходимо проверить какие промежутки и какой продолжительности у нас останутся если в заданом промежутке произойдут все события из пердыдущего массива.

Как результат мне было нужно чтоб функция вернула масив с свободными промежутками если они больше чем та продолжительность которую я передаю функции как параметр $duration, так же была добавлена переменная прогрешности для времени старта и окончания события, которая мне в тот момент была необходима чтобы отсечь промежутки не представляющие для меня интереса (меньше 3 сек)



function getFreeTimeArray($timeArray, $reservArray, $duration, $nullDuration = 3) {
  $resultArray = null;
  $tmpArray[] = $timeArray;
  if (!empty($reservArray) && is_array($reservArray)) {
    foreach ($reservArray as $value) {
      if (!empty($tmpArray))
        foreach ($tmpArray as $tmp_key => $tmp_val) {
          /*
           * reserved line
           * a|============|b
           *
           * time line
           * x|------------|y
           *
           *
           * a = $value['start']
           * b = $value['end']
           *
           * x = $tmp_val['start']
           * y = $tmp_val['end']
           */
          /* if x>a && x>b
           *
           * a|====|b
           *
           * x|------|y
           *
           *
           * OR y
           *
           * a|====|b
           *
           * x|------|y
           *
           *
           * => reserved & time line not intersect
           */
          if (($tmp_val['start'] > $value['start'] && $tmp_val['start'] > $value['end']) 
              || ($tmp_val['end'] < $value['start'] && $tmp_val['end'] < $value['end'])) {
          } else {
//reserved & time line intersect
            /* if x<=a && y>=b
             *
             * a|====|b
             *
             * x|------------|y
             *
             */
            if ($tmp_val['start'] <= $value['start'] && $tmp_val['end'] >= $value['end']) {
//if (a-x) > nullDuration -> save data to array('start'=>x,'end'=>(a-1))
              if (($value['start'] - $tmp_val['start']) > $nullDuration)
                $tmpArray[] = array('start' => $tmp_val['start'], 'end' => $value['start'] - 1);
//if (y-b) > nullDuration -> save data to array('start'=>(b+1),'end'=>y)
              if (($tmp_val['end'] - $value['end']) > $nullDuration)
                $tmpArray[] = array('start' => ($value['end'] + 1), 'end' => $tmp_val['end']);
//delete this time interval
              unset($tmpArray[$tmp_key]);
            }
            /* if x>=a && y<=b
             *
             * a|==========|b
             *
             * x|------|y
             *
             */
            else if ($tmp_val['start'] >= $value['start'] && $tmp_val['end'] <= $value['end']) {
              unset($tmpArray[$tmp_key]);
            }
            /* if x>=a && x<=b
             *
             * a|=====|b
             *
             * x|------------|y
             *
             */ else if ($tmp_val['start'] >= $value['start'] && $tmp_val['start'] <= $value['end']) {
              if (($tmp_val['end'] - $value['end']) > $nullDuration)
                $tmpArray[] = array('start' => ($value['end'] + 1), 'end' => $tmp_val['end']);
              unset($tmpArray[$tmp_key]);
            }
            /* if y>=a && y<=b
             *
             * a|=====|b
             *
             * x|----------|y
             *
             */
            else if ($tmp_val['end'] >= $value['start'] && $tmp_val['end'] <= $value['end']) {
              if (($value['start'] - $tmp_val['start']) > $nullDuration)
                $tmpArray[] = array('start' => $tmp_val['start'], 'end' => ($value['start'] - 1));
              unset($tmpArray[$tmp_key]);
            }
          }
        }
    }
  }
// if result is not null
// check duration in result data and sort array
  if (!empty($tmpArray)) {
    $tmpArray2 = null;
    foreach ($tmpArray as $val) {
      if ($duration <= ($val['end'] - $val['start']))
        $tmpArray2[$val['start']] = $val;
    }
    ksort($tmpArray2);
    $tmpArray = $tmpArray2;
  }
  $resultArray = $tmpArray;
  return $resultArray;
}



в результате передачи данной функции всех параметров я получал на выходе масив промежутков времени свободных от событий и по продолжительности больше заданной в $duration

если будут вопросы — задавайте, но хотелось бы выслушать решение подобной проблемы другими способами. ;)
оригинал статьи в моем блоге на ЖЖ

P.S. если минусуете то хоть укажите что не понравилось, или у меня плохое настроение, давай и другим испорчу…
Человек решает проблему и предлагает ее решение другим, а кто-то втихую минусует и у него от этого настроение поднимается…

P.S.2 Вот тролли… хоть выскажите что не нравится, зачем просто так минусовать??? еще пару решений на Javascript и PHP есть, но даже и не знаю с такими тролями только мемуары тут писать можно, судя по оценке данного топика бесплатные решения тут не нравятся… по крайней мере высказываний за что минусы тут пару а минусов больше чем плюсов. есть ли смыл публиковаться дальше?

PPS благодаря MikhailEdoshin было найдено решение позволяющее заменить строки 46-52 на
if($tmp_val['start'] < $value['end'] && $value['start'] < $tmp_val['end'])
за что ему отдельное спасибо!
Tags:
Hubs:
-2
Comments 16
Comments Comments 16

Articles