从PHP中的时间范围删除时隙

时间:2018-11-16 23:29:48

标签: php loops date datetime

我试图显示空闲时隙。

基于下面的数据,基本上我们需要找到一种在开放时间内显示未预订时段的方法。作为一个人似乎很容易做,但是对它进行编程...老实说我只是疯了:D

// open hours   --------++++--++++-----  [[08:00,12:00], [14:00,18:00]]  
// booked slots ---------++----+-------  [[09:00,11:00], [15:00,16:00]]   
// expected     --------+--+--+-++-----  [[08,09], [11,12], [14,15], [16,18]]  

为清楚起见,我省略了几分钟,它将在实际程序中显示。

我准备了一个小提琴,以:https://ideone.com/Z9pPi3

<?php     
$opening_hours   = [['08:00','12:00'], ['14:00','18:00']];
$occupied_slots  = [['09:30','14:00'], ['15:10','16:35']];
$expected_result = [['08:00','09:30'], ['11:00','12:00'], ['14:00','15:10'], ['16:35','18:00']];
$valid_timeslots = [];

# - - - - - - - - helper functions

function timestring_to_time($hh_mm) {
    return (int) strtotime("1970-01-01 $hh_mm");
}

function timestring_diff($hh_mm_start, $hh_mm_end) {
    return abs(timestring_to_time($hh_mm_end) - timestring_to_time($hh_mm_start));
}

# find empty timeslots during opening hours given occupied slots
# H E R E   G O E S   T H E   M A G I C

var_dump($valid_timeslots);

我试图用if / else方法解决,但实际上不起作用...需要某种递归函数。

1 个答案:

答案 0 :(得分:1)

这是我的解决方案-我假设时间间隔的第一个小时,例如['08:00','12:00']总是小于第二个小时。我编写自己的过程而不是使用您的timestring_to_timetimestring_diff来将时间转换为数字-timeToNumnumToTime(您可以轻松地将它们扩展为包括秒:{{1 }},num=3600*hour + 60*min + sec):

sec=num%60, h=floor(num/3600), min=floor((num-h*3600)/60)

工作示例HERE

算法

通过从<?php $opening_hours = [['08:00','12:00'], ['14:00','18:00']]; $occupied_slots = [['09:30','11:00'], ['15:10','16:35']]; $expected_result = [['08:00','09:30'], ['11:00','12:00'], ['14:00','15:10'], ['16:35','18:00']]; $valid_timeslots = []; #find empty timeslots during opening hours given occupied slots function timeToNum($time) { preg_match('/(\d\d):(\d\d)/', $time, $matches); return 60*$matches[1] + $matches[2]; } function numToTime($num) { $m = $num%60; $h = intval($num/60) ; return ($h>9? $h:"0".$h).":".($m>9? $m:"0".$m); } // substraction interval $b=[b0,b1] from interval $a=[a0,a1] function sub($a,$b) { // case A: $b inside $a if($a[0]<=$b[0] and $a[1]>=$b[1]) return [ [$a[0],$b[0]], [$b[1],$a[1]] ]; // case B: $b is outside $a if($b[1]<=$a[0] or $b[0]>=$a[1]) return [ [$a[0],$a[1]] ]; // case C: $a inside $b if($b[0]<=$a[0] and $b[1]>=$a[1]) return [[0,0]]; // "empty interval" // case D: left end of $b is outside $a if($b[0]<=$a[0] and $b[1]<=$a[1]) return [[$b[1],$a[1]]]; // case E: right end of $b is outside $a if($b[1]>=$a[1] and $b[0]>=$a[0]) return [[$a[0],$b[0]]]; } // flat array and change numbers to time and remove empty (zero length) interwals e.g. [100,100] // [[ [167,345] ], [ [433,644], [789,900] ]] to [ ["07:00","07:30"], ["08:00","08:30"], ["09:00","09:30"] ] // (number values are not correct in this example) function flatAndClean($interwals) { $result = []; foreach($interwals as $inter) { foreach($inter as $i) { if($i[0]!=$i[1]) { //$result[] = $i; $result[] = [numToTime($i[0]), numToTime($i[1])]; } } } return $result; } // calculate new_opening_hours = old_opening_hours - occupied_slot function cutOpeningHours($op_h, $occ_slot) { foreach($op_h as $oh) { $ohn = [timeToNum($oh[0]), timeToNum($oh[1])]; $osn = [timeToNum($occ_slot[0]), timeToNum($occ_slot[1])]; $subsn[] = sub($ohn, $osn); } return $subsn; } $oph = $opening_hours; foreach($occupied_slots as $os) { $oph = flatAndClean(cutOpeningHours($oph, $os )); } $valid_timeslots = $oph; var_dump(json_encode(["result"=>$valid_timeslots])); 中减去一个占用的时隙来计算$new_opening_hours。并对每个广告位重复该操作(每次获取新的Oppening Hours数组)

要减去两个互惠对象I:

  1. 将“ 08:30”之类的时间转换为数字$old_opening_hours
  2. 减去两个可能有5种情况的互惠[a0,a1]-[b0,b1]的问题(看08*60+30 = 510函数)-例如[500,800]-[600,700] = [[500,600] ,[700,800]],
  3. 对于每个开放时间,减去给定的占用时隙,然后得出整洁的结果以计算新的开放时间

您可以通过在每次迭代时不转换时间数,但在开始时对每个输入数据进行转换,而在结束时对每个输出数据进行转换,对方法进行一些改进。也许您可以减少sub函数中的条件数量-但是当前版本非常清楚。