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

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

    Проблема заключалась вот в чем: есть к примеру 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'])
    за что ему отдельное спасибо!
    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 16

      0
      Спрячьте часть с кодом под кат. А то как-то некрасиво получается…
        0
        подскажите плиз как это мой первый топик с кодом ;)
          0
          В то место с которого вы хотите, чтобы текст был скрыт вставьте тег <habracut />
            0
            спсасибо, исправил
        0
        //all is ok ;)
        а зачем вам вообще сюда заходить, если там ничего не происходит???
          0
          планировалось под контроль состояния задачи, но на данном этапе не использую пока
          0
          ну и cs, длинное условие на 40+ символов и действие для него еще 40+ символов в одну строку…
          ну ладно, я работаю на 1920х1080, но на 1024 больше 80 влезает с трудом, да и так читается с трудом
            –1
            надеюсь так удобнее…
              0
              ну ведь правда повышается читаемость, когда на новой строке с отступом от условия? ;)
                0
                честно говоря часто такой стиль встречаю, но мне он неудобен почему-то ;)
            0
            Выше уже к столькому придрались что даже как-то неудобно… ))
            В общем если не трудно организуйте подсветку кода :)
              0
              буду благодарен за подсказку как это тут делается…
            • UFO just landed and posted this here
                0
                >>Условие, которое вы используете для определения, пересекаются ли отрезки вообще, можно упростить до start1 < end2 and start2 < end1. Если True, то пересекаются

                отличная поправка! тяжело было понять ее, но теперь это поможет мне во многих подобных случаях сократить количество условий

                к сожалению не имею достаточно кармы чтоб отблагодарить за решение.
                  0
                  связанные списки довольно интересное решение, но нигде не могу найти их реализацию в PHP, если у Вас есть такая информация, буду благодарен
                  • UFO just landed and posted this here

                Only users with full accounts can post comments. Log in, please.