Предложите следующую доступную дату для бронирования

У меня есть таблица под названием бронирования , в которой есть следующие столбцы и данные:

ID | Client | Start At          | End At
1    103      2020-12-17 14:15    2020-12-17 14:30
2    202      2020-12-17 14:35    2020-12-17 15:00
3    204      2020-12-17 16:00    2020-12-17 16:20
4    158      2020-12-17 17:00    2020-12-17 18:00
5    157      2020-12-19 10:00    2020-12-19 10:15
6    142      2020-12-21 10:00    2020-12-21 10:15

При создании бронирований действуют следующие правила:

  • Воскресенье недоступно
  • С понедельника по пятницу с 10:00 до 19:00
  • Доступность по субботам с 10:00 до 20:00.
  • Продолжительность бронирования является динамической (может составлять 5 минут, 30 минут, 1 час, 2 часа и т. Д.)

Пока мой код проверяет только, занята ли определенная дата. Допустим, я хочу проверить дату2020-12-17 14:20 к2020-12-17 14:30 доступен.

SELECT * 
FROM bookings 
WHERE 
(
    (start_at <= '2020-12-17 14:20' AND end_at >= '2020-12-17 14:20') OR 
    (start_at <= '2020-12-17 14:30' AND end_at >= '2020-12-17 14:30') OR 
    (start_at >= '2020-12-17 14:20' AND end_at <= '2020-12-17 14:30')
)

Это отлично работает и вернет, что дата недоступна (как вы можете видеть вID 1 ).

Что мне нужно:

  • Предлагать моим пользователям следующую доступную дату с учетом правил
  • Чтобы предложить ближайшую следующую дату после выбранной даты

Итак, давайте рассмотрим следующий пример:

  1. Пользователь выбирает дату2020-12-17 14:40 к2020-12-17 15:00 [ 20 мин ] [ Занят ] [ Советовать :2020-12-17 15:00 ]
  2. Пользователь выбирает дату2020-12-17 18:00 к2020-12-17 19:15 [ 1ч15 мин ] [ Занят ] [ Советовать :2020-12-18 10:00 ]
  3. Пользователь выбирает дату2020-12-21 10:10 к2020-12-21 10:20 [ 10 мин ] [ Занят ] [ Предложить :2020-12-21 10:15 ]
  4. Пользователь выбирает дату2020-12-21 12:00 к2020-12-21 12:20 [ 20 мин ] [ бесплатно ]

Могу ли я добиться этого с помощью простого SQL или мне нужно добавить в него некоторую логику PHP?

Источник
  • 0
    Я имею в виду, я думаю, что это возможно, возможно, также с SQL, но я не уверен в том, что его можно будет поддерживать
  • 0
    Кроме того, я нашел этот stackoverflow.com/questions/5124386/…, который может быть вам полезен
  • 0
    Как формировать эти предложения? Следующий доступный термин, который достаточно велик? Или, возможно, ближайший (учитывая условия до выбранного, а не сразу после)?
  • 0
    Между прочим, правило перекрытий следующее: событие A перекрывает событие B, если событие A начинается до окончания события B и заканчивается после начала события B.
  • 0
    @El_Vanja Ближайшее было бы лучше, и мне нужно только первое предложение
  • 0
    И я думаю, вам следует изменить вопрос, чтобы уточнить, что вы хотите получить наиболее близкий результат (независимо от того, до или после выбранных дат)
  • 0
    На самом деле @Strawberry, теперь, когда я думаю, он должен быть ближайшим после выбранной даты, иначе он всегда будет предлагать одну и ту же дату! Я исправлюсь.
Codelisting
за 0 против
Лучший ответ

Решено .

Алгоритм выбора предложенной даты - это, по сути, бесконечный цикл, пока мы не найдем свободное место в бронировании.

В моем случае есть несколько правил:

  • С понедельника по пятницу = бронирование с 10:00 до 19:00.
  • Суббота = бронирование с 10:00 до 20:00
  • Воскресенье = бронирование запрещено
  • Заказы могут иметь динамический диапазон (начало <-> конец)

Принимая во внимание эти правила:

$suggestedDate = '';
$startAt = '2020-12-18 10:00';
$endAt = '2020-12-18 10:45';

do 
{
    // The SQL code is in the original post 
    $isAvailable = SQL('...');
    
    if ($isAvailable)
        $suggestedDate = $startAt;
    else
    {
        $_startAt = new DateTime($startAt);
        $_endAt = new DateTime($endAt);
        $diff = $_endAt->diff($startAt);
        
        // Calculates the time difference in minutes (converts the hours in minutes as well, so 1h15 = 75min)
        $minutes = $diff->h * 60;
        $minutes += $diff->i;
        
        /**
         * Input:
         *  - Start At: 2020-12-18 10:00    End At: 2020-12-18 10:45    Minutes: 45
         * 
         * Output:
         *  - Start At: 2020-12-18 10:45    End At: 2020-12-18 11:30    Available? No
         *  - Start At: 2020-12-18 11:30    End At: 2020-12-18 12:15    Available? Yes!
         */
        $startAt = date('Y-m-d H:i', strtotime("+{$minutes} minutes", strtotime($startAt)));
        $endAt = date('Y-m-d H:i', strtotime("+{$minutes} minutes", strtotime($endAt)));
        $dayOfWeek = date('l', strtotime($startAt));
        $isMaxTime = false;
        
        // Grabs for the days of the week the max time
        if (in_array($dayOfWeek, ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']))
            $maxTime = date('Y-m-d 19:00', strtotime($startAt));
        else if ($dayOfWeek == 'Saturday')
            $maxTime = date('Y-m-d 20:00', strtotime($startAt));
            
        $_endAt = new \DateTime($endAt);
        $_maxTime = new \DateTime($maxTime);
        
        // Will check if the `endAt` is bigger than the maximum allowed time
        if ($_endAt > $_maxTime)
            $isMaxTime = true;
        
        /**
         * Here we just check if the day is Sunday or if the maximum time has been reached. In both situations
         * all we have to do is increment one day & start all over again, but starting at 10am!
         */
        if ($dayOfWeek == 'Sunday' || $isMaxTime)
        {
            $startAt = date('Y-m-d 10:00', strtotime("+1 day", strtotime($startAt)));
            $endAt = date('Y-m-d 10:00', strtotime("+1 day", strtotime($endAt)));
            $endAt = date('Y-m-d H:i', strtotime("+{$minutes} minutes", strtotime($endAt)));
        }       
    }   
} while (empty($suggestedDate));

echo $suggestedDate;
Codelisting
Популярные категории
На заметку программисту