如何计算“可用时间段”[重复]

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);

Eval

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;
}