Я делал, но скорее всего делал не совсем правильно:
Есть таблица со "постоянным" расписанием, типа Иван Иванович в субботу работает с 9 до 18.
(id, workerId, weekday, fromTime, tillTime)
Есть вторая таблица, в ней храним изменения в стандартном расписании, типа в понедельник выйти не сможет, зато в воскресение поработает сверхурочно.
(id, workerId, type ENUM ('vacant', 'closed'), date, fromTime, tillTime)
Есть таблица записей, она же таблица занятых таймслотов:
(id, workerId, day, time, timeslotDescription)
При записи на определенное время в ней создается запись.
Расписание, когда можно записаться строиться таким образом:
- смотрим по первой таблице когда рабочее время,
- смотрим по второй таблице нет ли изменений на это время в этот день,
- смотрим по 3й таблице когда не занято время для записи, выводим свободные таймслоты для записи.