Я пытался отобразить свободные временные интервалы.
Учитывая данные ниже, в основном нам нужно найти способ отображать не зарезервированные временные интервалы в рабочее время. Кажется, это очень легко сделать как человек, но программирование это … честно говоря, я просто схожу с ума: 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, но на самом деле он не работает … существует необходимость в некоторой рекурсивной функции.
Вот мое решение — я предполагаю, что первый час в интервале времени, например [’08: 00 ‘,’ 12:00 ‘], всегда меньше, чем второй час. Вместо того чтобы использовать ваш timestring_to_time
а также timestring_diff
Я пишу свои собственные процедуры для преобразования времени в число — timeToNum
а также numToTime
(Вы можете легко расширить их, чтобы включить секунды: num=3600*hour + 60*min + sec
, sec=num%60, h=floor(num/3600), min=floor((num-h*3600)/60)
):
<?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
от $old_opening_hours
вычтите одну занятую щель из нее. И повторите эту операцию для каждого слота (каждый раз получая новый массив противостоящих часов)
Чтобы сделать вычитание двух сплетений, я:
08*60+30 = 510
sub
функция) — в качестве примера [500 800] — [600 700] = [[500 600], [700 800]],Вы можете немного улучшить это решение, не конвертируя время-число на каждой итерации, а сделав это для каждой входной информации в начале и конвертировав число-время для каждой выходной информации в конце. И, вероятно, вы можете уменьшить количество условий в sub
функция — однако текущая версия очень понятна.
Других решений пока нет …