This might be a simplified version of what your are after - it doesn't include days, but that should be fairly simple to add in:
An example table with some data:
CREATE TABLE `courses` (
`course_id` int(11) NOT NULL AUTO_INCREMENT,
`time_in` time DEFAULT NULL,
`time_out` time DEFAULT NULL,
PRIMARY KEY (`course_id`)
) ENGINE=InnoDB;
INSERT INTO courses VALUES
(1, '09:00', '10:00'),
(2, '09:30', '10:30'),
(3, '10:00', '11:00'),
(4, '10:30', '11:30'),
(5, '12:00', '13:00');
For every row (each timeslot), determine if there are any other rows that do not overlap. Note that this allows for end and start times that are the same:
SELECT
c1.course_id,
c1.time_in,
c1.time_out,
c2.course_id,
c2.time_in,
c2.time_out
FROM courses AS c1
JOIN (
SELECT course_id, time_in, time_out FROM courses
) AS c2
ON (c1.time_out > c2.time_in) XOR (c1.time_in < c2.time_out)
ORDER BY c1.course_id, c1.time_in;
+-----------+----------+----------+-----------+----------+----------+
| course_id | time_in | time_out | course_id | time_in | time_out |
+-----------+----------+----------+-----------+----------+----------+
| 1 | 09:00:00 | 10:00:00 | 3 | 10:00:00 | 11:00:00 |
| 1 | 09:00:00 | 10:00:00 | 4 | 10:30:00 | 11:30:00 |
| 1 | 09:00:00 | 10:00:00 | 5 | 12:00:00 | 13:00:00 |
| 2 | 09:30:00 | 10:30:00 | 4 | 10:30:00 | 11:30:00 |
| 2 | 09:30:00 | 10:30:00 | 5 | 12:00:00 | 13:00:00 |
| 3 | 10:00:00 | 11:00:00 | 1 | 09:00:00 | 10:00:00 |
| 3 | 10:00:00 | 11:00:00 | 5 | 12:00:00 | 13:00:00 |
| 4 | 10:30:00 | 11:30:00 | 5 | 12:00:00 | 13:00:00 |
| 4 | 10:30:00 | 11:30:00 | 2 | 09:30:00 | 10:30:00 |
| 4 | 10:30:00 | 11:30:00 | 1 | 09:00:00 | 10:00:00 |
| 5 | 12:00:00 | 13:00:00 | 1 | 09:00:00 | 10:00:00 |
| 5 | 12:00:00 | 13:00:00 | 2 | 09:30:00 | 10:30:00 |
| 5 | 12:00:00 | 13:00:00 | 3 | 10:00:00 | 11:00:00 |
| 5 | 12:00:00 | 13:00:00 | 4 | 10:30:00 | 11:30:00 |
+-----------+----------+----------+-----------+----------+----------+