This question already has an answer here:
I'm building a service booking system, and want to get a list of "available time periods" after some bookings are made.
So for example, a day has 24 hours so the available time is
{"begin":"0:00","end":"23:59"},
and there're a few bookings already: [{"begin":"9:30","end":"10:30"},{"begin":"12:30","end":"14:00"}]
and I want to get a list of time available: [{"begin":"0:0","end":"9:30"},{"begin":"10:30",to:"12:30"},{"begin":"14:00","to":"23:59"}]
Is there any tools available in PHP for doing so? Or is there a algorithm that can be used?
Update: The unavailable time may be overlapping, as I'm thinking about adding "rules"(everyday starts from 10, and every 3rd day of the month is off etc.) for example: [{"begin":0:00,"end":10:00},{"begin":"9:30","end":"10:30"},{"begin":"12:30","end":"14:00"}]
</div>
I don't think you need algo for this, try below code:
$slots = '[{"begin":"9:30","end":"10:30"},{"begin":"12:30","end":"14:00"}]';
$slots = json_decode($slots );
$check_time = "13:30";
$check_timestamp = strtotime($check_time);
$status = FALSE;
foreach($slots as $slot){
$start = strtotime($slot->begin);
$end = strtotime($slot->end);
if($check_timestamp >= $start && $check_timestamp <= $end )
$status = TRUE;
}
var_dump( $status);
Here's what I got, which nicely divide the time periods, taking into account overlapping occupied periods and occupied periods that's out of scope.
function getAvailable(){
//Container of the results
$result=[];
//container of unprocessed period
$toProcess=[
"from"=>(new DateTime("2013-8-31 0:0:0")),
"to"=>(new DateTime("2013-8-31 23:59:59"))
];
//already occupied periods, should be ordered by "from" time
$unavailable=[
[
"from"=>(new DateTime("2013-8-30 5:0:0")),
"to"=>(new DateTime("2013-8-30 7:0:0"))
],
[
"from"=>(new DateTime("2013-8-31 5:0:0")),
"to"=>(new DateTime("2013-8-31 7:0:0"))
],
[
"from"=>(new DateTime("2013-8-31 6:0:0")),
"to"=>(new DateTime("2013-8-31 13:0:0"))
],
[
"from"=>(new DateTime("2013-9-1 20:0:0")),
"to"=>(new DateTime("2013-9-1 21:0:0"))
]
];
foreach($unavailable as $one){
//divide unprocessed period with a booked period
$res=divideTime($toProcess,$one);
//Get an unbooked period
if($res[0])array_push($result,$res[0]);
//The rest is for further dividing
$toProcess=$res[1];
//If there's no more periods to divide
if(!$res[1]){
break;
}
}
//All the already occupied periods have been processed.
//The rest is unoccupied.
if($toProcess){
array_push($result,$toProcess);
}
//Display the result
exit(var_dump($result));
}
//Divide period $c0 by $c1
function divideTime($c0,$c1){
//result containers
$r0=[];
$r1=[];
if($c1["from"]<=$c0["from"]){
$r0=Null;
}else{
$r0["from"]=$c0["from"];
if($c1["from"]>=$c0["to"]){
$r0["to"]=$c0["to"];
}else{
$r0["to"]=$c1["from"];
}
}
if($c1["to"]>=$c0["to"]){
$r1=Null;
}else{
if($c1["to"]<=$c0["from"]){
$r1["from"]=$c0["from"];
}else{
$r1["from"]=$c1["to"];
}
$r1["to"]=$c0["to"];
}
return [$r0,$r1];
}
Here is a php solution:
$busy_slots = array(
array("begin"=>new DateTime("2013-01-01 09:30"),
"end"=>new DateTime("2013-01-01 10:30"))
,array("begin"=>new DateTime("2013-01-01 12:30"),
"end"=>new DateTime("2013-01-01 14:00"))
);
$free_slots = array(
array("begin"=>new DateTime("2013-01-01 00:00"),
"end"=>new DateTime("2013-01-02 00:00")));
foreach ($busy_slots as $slot) {
$free_slots=ocupe_slot($free_slots, $slot);
}
var_dump($free_slots);
function ocupe_slot($free_slots,$b_slot) {
$result=array();
foreach ($free_slots as $free_slot) {
if ($b_slot["begin"] <= $free_slot["begin"]) {
if ($b_slot["end"] < $free_slot["begin"]) {
array_push($result, $free_slot);
} else if ($b_slot["end"] < $free_slot["end"]) {
array_push($result,array("begin"=>$b_slot["end"], "end"=>$free_slot["end"]));
} else {
// the whole slot is busy
}
} else if ($b_slot["begin"] < $free_slot["end"]) {
if ($b_slot["end"] < $free_slot["end"]) {
array_push($result,array("begin"=>$free_slot["begin"], "end"=>$b_slot["begin"]));
array_push($result,array("begin"=>$b_slot["end"], "end"=>$free_slot["end"]));
} else {
array_push($result,array("begin"=>$free_slot["begin"], "end"=>$b_slot["begin"]));
}
} else {
array_push($result, $free_slot);
}
}
return $result;
}