Being a bit bored, I whipped up a semi-functional script, but I wasn't bored enough to actually test its functionality, so do note that:
1. it does not handle everything as it should. Things like two courses starting on the same time aren't handled.
2. Several overlapping courses in a row is most likely not handled either. I havn't checked if this works, and whenever I don't test stuff like this, it usually doesn't work.
3. Border cases may very well be screwed up.
4. you'll need to refactor the code to make it easily readable.
Also if someone has a smarter way of dealing with this issue while using a table, I'd be interested in hearing about it, since this may be unnecessarily complex. But I'm dead tired and this was the only thing that came to me.
$times =
array(
array(
'start' => mktime(10, 0, 0, 12, 28, 2009),
'end' => mktime(11, 0, 0, 12, 28, 2009),
'name' => 'First'
),
array(
'start' => mktime(12, 0, 0, 12, 28, 2009),
'end' => mktime(14, 0, 0, 12, 28, 2009),
'name' => 'Second'
),
array(
'start' => mktime(13, 0, 0, 12, 28, 2009),
'end' => mktime(13, 30, 0, 12, 28, 2009),
'name' => 'Third'
)
,
array(
'start' => mktime(17, 0, 0, 12, 28, 2009),
'end' => mktime(19, 0, 0, 12, 28, 2009),
'name' => 'Fourth'
),
array(
'start' => mktime(18, 30, 0, 12, 28, 2009),
'end' => mktime(19, 30, 0, 12, 28, 2009),
'name' => 'Fifth'
)
,
array(
'start' => mktime(8, 30, 0, 12, 29, 2009),
'end' => mktime(20, 0, 0, 12, 29, 2009),
'name' => 'Tuesday'
)
);
$prevTime = mktime(8, 0, 0, 12, 28, 2009);
$prevDay = 1;
$days = array();
$imax = count($times);
$interval = 30;
$tdata = array();
$colors = array('#CFF', '#FCF', '#FFC', '#CCF', '#CFC', '#FCC', '#AFF', '#FAF', '#FFA', '#AAF', '#AFA', '#FAA', 'none' => '#FFF');
$coursesToday = 0;
$dayIs = date('d');
$monthIs = date('m');
$yearIs = date('Y');
$startHour = 8;
$endHour = 20;
$firstTime = mktime($startHour, 0, 0);
$lastTime = mktime($endHour, 0, 0);
$daysScheduled = 0;
$diff = ($lastTime - $firstTime) / (60 * $interval);
for ($i = 0; $i < $diff; ++$i) {
$tdata[0][] = '<td>'.date('G:i', mktime(8, 30 * $i, 0)).'</td>';
}
for ($i = 0; $i < $imax; ++$i) {
if ($prevDay != ($thisDay = date('N', $times[$i]['start']))) {
# possibly add empty entry for yesterday here.
$prevDay = $thisDay;
$daysScheduled++;
$firstTime = mktime($startHour, 0, 0, $monthIs, $dayIs + $daysScheduled, $yearIs);
$lastTime = mktime($endHour, 0, 0, $monthIs, $dayIs + $daysScheduled, $yearIs);
$coursesToday = 0;
$prevTime = $firstTime;
}
# no courses before this interval. pad with empty cells
if (($dif = $times[$i]['start'] - $prevTime) > 0) {
$rowspan = $dif / (60 * $interval);
$tdata[$prevDay][] = '<td rowspan="'.$rowspan.'" style="background-color: '.$colors['none'].';"
> </td>';
for($j = 1; $j < $rowspan; ++$j)
$tdata[$prevDay][] = '';
$prevTime = $times[$i]['end'];
}
# nothing following this course. no overlaps possible
if ($i + 1 == $imax) {
$rowspan = ($times[$i]['end'] - $times[$i]['start']) / (60 * $interval);
$tdata[$prevDay][] = '<td rowspan="'.$rowspan.'"
style="background-color: '.(isset($times[$i]['color']) ? $times[$i]['color'] : $colors[$coursesToday++]).';'.
(isset($times[$i]['overlap']) ? ' border: 1pt solid red;' : '') .'"
>'. $times[$i]['name'] .
' ('. date('G:i', $times[$i]['start']) . ' - ' . date('G:i', $times[$i]['end']) .
') </td>';
for($j = 1; $j < $rowspan; ++$j)
$tdata[$prevDay][] = '';
}
# There is one more course following this one: overlap possible
$overlapPossible = true;
while($i + 1 < $imax && $overlapPossible) {
# no overlap
if ($times[$i]['end'] <= $times[$i + 1]['start']) {
$overlapPossible = false;
$rowspan = ($times[$i]['end'] - $times[$i]['start']) / (60 * $interval);
$tdata[$prevDay][] = '<td rowspan="'.$rowspan.'"
style="background-color: '.(isset($times[$i]['color']) ? $times[$i]['color'] : $colors[$coursesToday++]).';'.
(isset($times[$i]['overlap']) ? ' border: 1pt solid red;' : '') .'"
>'. $times[$i]['name'] .
' ('. date('G:i', $times[$i]['start']) . ' - ' . date('G:i', $times[$i]['end']) .
') </td>';
for($j = 1; $j < $rowspan; ++$j)
$tdata[$prevDay][] = '';
}
else {
# This time interval for this course completely contains the next course
if ($times[$i]['end'] > $times[$i + 1]['end']) {
# insert a new array element
$times = array_merge( array_slice($times, 0, $i + 2),
array(
array(
'start' => $times[$i + 1]['end'],
'end' => $times[$i]['end'],
'name' => $times[$i]['name'],
'color' => $colors[$coursesToday]
)
),
array_slice($times, $i + 2)
);
# adjust $imax for new length of array
++$imax;
$times[$i + 1]['overlap'] = true;
$times[$i]['origEnd'] = $times[$i]['end'];
$times[$i]['end'] = $times[$i + 1]['start'];
$rowspan = ($times[$i]['end'] - $times[$i]['start']) / (60 * $interval);
$tdata[$prevDay][] =
'<td rowspan="'.$rowspan.'"
style="background-color: '.(isset($times[$i]['color']) ? $times[$i]['color'] : $colors[$coursesToday++]).
(isset($times[$i]['overlap']) ? ' border: 1pt solid red;' : '') .'"
>'.$times[$i]['name'] .
' ('. date('G:i', $times[$i]['start']) . ' - ' . date('G:i', $times[$i]['origEnd']) .
') </td>';
for($j = 1; $j < $rowspan; ++$j)
$tdata[$prevDay][] = '';
++$i;
}
# Time interval for this course ends in the middle of the next course
else if ($times[$i]['end'] > $times[$i + 1]['start']) {
$times[$i]['origEnd'] = $times[$i]['end'];
$times[$i]['end'] = $times[$i + 1]['start'];
$times[$i + 1]['overlap'] = true;
$rowspan = ($times[$i]['end'] - $times[$i]['start']) / (60 * $interval);
$tdata[$prevDay][] =
'<td rowspan="'.$rowspan.'"
style="background-color: '.$colors[$coursesToday++].';'.
(isset($times[$i]['overlap']) ? ' border: 1pt solid red;' : '') .'"
>'.$times[$i]['name'] .
' ('. date('G:i', $times[$i]['start']) . ' - ' . date('G:i', $times[$i]['origEnd']) .
') </td>';
for($j = 1; $j < $rowspan; ++$j)
$tdata[$prevDay][] = '';
$overlapPossible = false;
}
}
}
$prevTime = $times[$i]['end'];
}
echo '<pre>';
print_r($tdata);
echo '</pre>';
echo '<table>';
$timeMax = count($tdata[0]);
for ($timeEntry = 0; $timeEntry < $timeMax; ++$timeEntry) {
echo '
<tr>
';
foreach($tdata as $day) {
echo isset($day[$timeEntry]) ?
$day[$timeEntry]
:
'<td style="background-color: '.$colors['none'].';"
> </td>';
}
echo '
</tr>
';
}
echo '
</tr>
</table>';