 Split a block of time if appointments occur within (sort of solved)
<p>There are two types of time_block - free, appointment - each time_block has a start_time and end_time.<br/>
Say I have five appointment time_blocks and two free time_blocks.<br/></p>

<p>I need to create actual free time_blocks that fill with free time between the appointments, like so:<br/></p>

<pre><code>    $appointments = array(
    array(
        'start_time' =&gt; 730,
        'end_time' =&gt; 830),
    array(
        'start_time' =&gt; 830,
        'end_time' =&gt; 930),
    array(
        'start_time' =&gt; 945,
        'end_time' =&gt; 1000),
    array(
        'start_time' =&gt; 1045,
        'end_time' =&gt; 1100),
    array(
        'start_time' =&gt; 1130,
        'end_time' =&gt; 1145)
);

$free_time_blocks = array(
    array(
        'start_time' =&gt; 900,
        'end_time' =&gt; 1000),
    array(
        'start_time' =&gt; 1030,
        'end_time' =&gt; 1200)
);


// Result should be
$actual_free_time = array(
    array(
        'start_time' =&gt; 930,
        'end_time' =&gt; 945
    ),
    array(
        'start_time' =&gt; 1030,
        'end_time' =&gt; 1045
    ),
    array(
        'start_time' =&gt; 1100,
        'end_time' =&gt; 1130
    ),
    array(
        'start_time' =&gt; 1145,
        'end_time' =&gt; 1200
    ),
)
</code></pre>

<p>=== Sort of solution ===
This is ugly as sin, but it works with every situation I've put it through. I hate solving problems by trial and error, and if anyone has a more elegant solution then I'd love to hear it. I can't help feeling I'm making this much more complicated than it needs to be.</p>

<pre><code>&lt;?php
function getAppointmentsInRange($start_time, $end_time){
    $appointments = array(
        array(
            'start_time' =&gt; 730,
            'end_time' =&gt; 830),
        array(
            'start_time' =&gt; 830,
            'end_time' =&gt; 930),
        array(
            'start_time' =&gt; 945,
            'end_time' =&gt; 1000),
        array(
            'start_time' =&gt; 1000,
            'end_time' =&gt; 1035),
        array(
            'start_time' =&gt; 1035,
            'end_time' =&gt; 1100),
        array(
            'start_time' =&gt; 1105,
            'end_time' =&gt; 1125),
        array(
            'start_time' =&gt; 1130,
            'end_time' =&gt; 1230)
    );

    foreach($appointments as $appointment){
        if($appointment['start_time'] &lt; $end_time &amp;&amp; $appointment['end_time'] &gt; $start_time){
            $return[] = $appointment;
        }
    }
    return $return;
}

function setFreeTime($start_time, $end_time){
    echo "Free Time. Start: $start_time, End: $end_time &lt;br/&gt;";
}

$free_time_blocks = array(
    array(
        'start_time' =&gt; 900,
        'end_time' =&gt; 1000),
    array(
        'start_time' =&gt; 1030,
        'end_time' =&gt; 1200)
);



foreach($free_time_blocks as $free_time_block){

    // Get appointments with any part falling inside the range (eg. starting before but ending after the start)
    $appointments = getAppointmentsInRange($free_time_block['start_time'], $free_time_block['end_time']);

    $start_time = $free_time_block['start_time'];
    $end_time = $free_time_block['start_time'];

    $finished = false;

    $i = 0;
    foreach($appointments as $appointment){
        echo "trying...&lt;br/&gt;";

        $next = $i + 1;
        $prev = $i - 1;

        if($appointment['start_time'] &lt;= $free_time_block['start_time']){
            echo "case 1 &lt;br/&gt;";
            // If appointment starts before ftb then start ftb at end of appointment, and end at start of next appointment or end of ftb
            if($appointment['end_time'] &lt; $free_time_block['end_time']){
                $start_time = $appointment['end_time'];
            }else{
                $start_time = $end_time;
                break;
            }
            if(isset($appointments[$next])){
                $end_time = $appointments[$next]['start_time'];
            }else{
                $end_time = $free_time_block['end_time'];
            }
        }
        elseif($appointment['start_time'] &gt; $free_time_block['start_time']){
            echo 'case 2 &lt;br/&gt;';
            // If appointment starts during ftb then start ftb at last end time
            // Start time = previous end time

            if($appointment['end_time'] &lt; $free_time_block['end_time']){
                if(isset($appointments[$next])){
                    $end_time = $appointment['start_time'];
                }else{
                    $end_time = $free_time_block['end_time'];
                }
            }elseif($start_time &lt; $appointment['start_time']){
                if(isset($appointments[$prev])){
                    $start_time = $appointments[$prev]['end_time'];
                }
                $end_time = $appointment['start_time'];
            }else{
                break;
            }

        }
        elseif($appointment['start_time'] == $end_time){
            echo "case 3 &lt;br/&gt;";
            if($appointment['end_time'] &lt; $free_time_block['end_time']){
                $start_time = $appointment['start_time'];
            }else{
                break;
            }
            if(isset($appointments[$next])){
                $end_time = $appointments[$next]['start_time'];
            }else{
                $end_time = $free_time_block['end_time'];
            }
        }

        if($start_time != $end_time){
            setFreeTime($start_time, $end_time);
            $start_time = $end_time;
        }

        $i++;
    }
    echo "&lt;hr/&gt;";
}
</code></pre>
