为了账号安全,请及时绑定邮箱和手机立即绑定

PHP获取日期数组,从一个长日期范围中分割出来

PHP获取日期数组,从一个长日期范围中分割出来

PHP
翻阅古今 2022-06-17 16:04:47
参考我的原始帖子(PHP split data range to get only chunks free),我做了一些实现,以获得更好的结果,但在某些情况下仍然不正确。我的目标是拆分原始范围日期,以仅获得未被活动占用的空闲块。这是我在 php 中的实际脚本:function date_compare($a, $b){    $t1 = strtotime($a['start']);    $t2 = strtotime($b['start']);    return $t1 - $t2;} $fullrange = array(   // <----------------------------------- one month range to split   "start" => "2019-12-01 00:00:00",   "end" => "2019-12-31 23:59:59");$result[] = $fullrange;$array_activities = array( // <--------------------------- activities (busy ranges)  0 => array(      "start" => "2019-12-08 09:00:00",      "end" => "2019-12-08 10:00:00"  ),  1 => array(      "start" => "2019-12-07 09:00:00",      "end" => "2019-12-07 17:40:00"  ),  2 => array(      "start" => "2019-12-10 10:00:00",      "end" => "2019-12-15 17:00:00"  ),  3 => array(      "start" => "2019-12-11 08:00:00",      "end" => "2019-12-17 21:00:00"  ),  4 => array(      "start" => "2019-12-08 08:57:05",      "end" => "2019-12-08 19:00:00"  ),  5 => array(      "start" => "2019-12-04 10:00:00",      "end" => "2019-12-05 17:00:00"  ),    6 => array(      "start" => "2019-12-20 10:00:00",      "end" => "2019-12-31 23:59:59"  ),    7 => array(      "start" => "2019-12-16 10:00:00",      "end" => "2019-12-31 23:59:59"  ));// reorder array of activities by date start  usort($array_activities, 'date_compare');foreach ( $array_activities as $index_1 => $array_activity ) {foreach ($result as $index_2 => $r) {    if ( $r['start'] < $array_activity['start'] && $array_activity['start'] < $r['end'] ) {        $temp = new Datetime($array_activity['start']);        $temp->modify("-1 second");        $result[$index_2]['end'] = $temp->format("Y-m-d H:i:s");        if ( $r['start'] < $array_activity['end'] && $array_activity['end'] < $r['end'] ) {        $result[] = array("start" => $array_activity['start'], "end" => $r['end']);        }    }}
查看完整描述

2 回答

?
波斯汪

TA贡献1811条经验 获得超4个赞

以下功能应该做到这一点(如果我没有错过任何东西)。对于每个活动,它会遍历所有空闲范围,检查活动是否重叠并相应地调整/创建新范围。


请注意,理想情况下,您的“句点”条目应该是对象(具有start和end作为DateTime属性),以便为函数提供更强的签名/减少多余代码的数量。


function getFreeTimeRanges(array $fullRange, array $activities): array

{

  $freeRanges = [[

    'start' => new \DateTime($fullRange['start']), 

    'end' => new \DateTime($fullRange['end'])

  ]];


  foreach ($activities as $activity) {

    $activityStart = new \DateTime($activity['start']);

    $activityEnd = new \DateTime($activity['end']);


    foreach ($freeRanges as &$range) {

      $activityIsOverlapping = $activityStart < $range['end'] 

          && $activityEnd > $range['start'];


      if ($activityIsOverlapping) {

        $activityStartsLater = $activityStart > $range['start'];

        $activityEndsBefore = $activityEnd < $range['end'];


        if ($activityStartsLater) {

          if ($activityEndsBefore) {

            $freeRanges[] = [

              'start' => $activityEnd->modify('+1 second'), 

              'end' => $range['end']

            ];

          }

          $range['end'] = $activityStart->modify('-1 second');

        }

        elseif ($activityEndsBefore) {

          $range['start'] = $activityEnd->modify('+1 second');

        }

      }

    }

  }


  uasort($freeRanges, static function (array $range1, array $range2) {

    return $range1['start'] <=> $range2['start'];

  });


  return array_map(static function ($range) {

    return [

      'start' => $range['start']->format('Y-m-d H:i:s'), 

      'end' => $range['end']->format('Y-m-d H:i:s')

    ];

  }, $freeRanges);

}


$fullRange = ['start' => '2019-12-01 00:00:00', 'end' => '2019-12-31 23:59:59'];

$activities = [

  0 => ['start' => '2019-12-08 09:00:00', 'end' => '2019-12-08 10:00:00'],

  1 => ['start' => '2019-12-07 09:00:00', 'end' => '2019-12-07 17:40:00'],

  2 => ['start' => '2019-12-10 10:00:00', 'end' => '2019-12-15 17:00:00'],

  3 => ['start' => '2019-12-11 08:00:00', 'end' => '2019-12-17 21:00:00'],

  4 => ['start' => '2019-12-08 08:57:05', 'end' => '2019-12-08 19:00:00'],

  5 => ['start' => '2019-12-04 10:00:00', 'end' => '2019-12-05 17:00:00'],

  6 => ['start' => '2019-12-20 10:00:00', 'end' => '2019-12-31 23:59:59'],

  7 => ['start' => '2019-12-16 10:00:00', 'end' => '2019-12-31 23:59:59']

];


print_r(getFreeTimeRanges($fullRange, $activities));

演示:https ://3v4l.org/p8Kvl


查看完整回答
反对 回复 2022-06-17
?
明月笑刀无情

TA贡献1828条经验 获得超4个赞

这可能适用于所有情况:


foreach ( $array_activities as $index_1 => $array_activity ) {


    foreach ($result as $index_2 => $r) {


        if ( $r['start'] < $array_activity['start'] && $array_activity['start'] < $r['end'] ) {


            $temp = new Datetime($array_activity['start']);

            $temp->modify("-1 second");


            $result[$index_2]['end'] = $temp->format("Y-m-d H:i:s");


            if ( $r['start'] < $array_activity['end'] && $array_activity['end'] < $r['end'] ) {


            $result[] = array("start" => $array_activity['start'], "end" => $r['end']);


            }


        } else {


            if ( $array_activity['start'] <= $r['start'] && $array_activity['end'] >= $r['end'] ) {

                unset($result[$index_2]);   

            }


        }


    }



    foreach ($result as $index_2 => $r) {


        if ( $r['start'] < $array_activity['end'] && $array_activity['end'] < $r['end'] ) {


            $temp = new Datetime($array_activity['end']);

            $temp->modify("+1 second");


            $result[$index_2]['start'] = $temp->format("Y-m-d H:i:s");

            $result[$index_2]['end'] = $r['end'];



        }


    }




    echo '<pre>';

var_dump($result);

echo '</pre>';



}


查看完整回答
反对 回复 2022-06-17
  • 2 回答
  • 0 关注
  • 104 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信