Получить время между 9 утра и 5 вечера между двумя датами

#mysql #sql

#mysql #sql

Вопрос:

У меня есть две таблицы с приведенной ниже структурой.

Таблица задач

введите описание изображения здесь

Таблица времени выполнения задач

введите описание изображения здесь

Я хочу получить время между start_date_time и end_date_time в днях, часах и минутах. Время между 9 утра и 5 вечера является рабочим временем и должно учитываться только для расчета. Например, если start_date_time есть 2019-03-25 09:00:00 и end_date_time is 2019-03-26 17:00:00 , то расчетное время составит 2 дня. Если end_date_time равно 2019-03-26 12:00:00 , то расчетное время составит 1 день 3 часа. Одна и та же задача может содержать несколько записей о времени, и общее время должно быть рассчитано. Я пытался с помощью приведенного ниже запроса получить время, но это дает общее количество часов. Мне нужны только часы между 9 утра и 5 вечера. Скрипка с БД

 SELECT t.task_name, sum(time_to_sec(timediff(end_date_time, start_date_time )) / 3600) FROM `task_time` tt left join task t on tt.task_id=t.task_id
group by tt.task_id
  

Ответ №1:

Самый простой способ справиться с этим — вычислить дни и часы отдельно, а затем просто посчитать день как 8 часов. Что-то вроде этого:

 SELECT t.task_name, 
       SUM(TIMESTAMPDIFF(DAY, DATE(start_date_time), DATE(end_date_time)) * 8  
           TIMESTAMPDIFF(MINUTE, TIME(start_date_time), TIME(end_date_time)) / 60) AS task_time
FROM task t
JOIN task_time tt ON tt.task_id = t.task_id
GROUP BY t.task_name
  

Вывод (для моих демонстрационных данных)

 task_name   task_time
task1       16
task2       11
task3       4
  

Демо на dbfiddle

Обновить

Этот запрос позволит определять время начала и окончания вне пределов 9 утра-5 вечера, считая только часы между 9 утра и 5 вечера в качестве рабочих часов. Это работает, вводя время начала и окончания в диапазон 9 утра-5 вечера с помощью GREATEST и LEAST :

 SELECT t.task_name, 
       SUM(TIMESTAMPDIFF(DAY, start_date, end_date) * 8  
           TIMESTAMPDIFF(MINUTE, TIME(start_time), TIME(end_time)) / 60) AS task_time
FROM task t
JOIN (SELECT task_id,
             DATE(start_date_time) AS start_date,
             DATE(end_date_time) AS end_date,
             GREATEST('09:00', LEAST('17:00', TIME(start_date_time))) AS start_time,
             GREATEST('09:00', LEAST('17:00', TIME(end_date_time))) AS end_time
      FROM task_time) tt ON tt.task_id = t.task_id
GROUP BY t.task_name
  

Обновленная демонстрация

Обновление 2

Этот запрос возвращает время в виде дней, часов и минут, а не просто часов.

 SELECT t.task_name,
       days   FLOOR(minutes / 480) AS days,
       CASE WHEN minutes < 0 THEN 8   FLOOR(minutes % 480 / 60)
            ELSE FLOOR(minutes % 480 / 60)
            END AS hours,
       CASE WHEN minutes < 0 THEN (60   (minutes % 60)) % 60
            ELSE minutes % 60
            END AS minutes
FROM (SELECT t.task_name, 
             SUM(TIMESTAMPDIFF(DAY, start_date, end_date)) AS days,
             SUM(TIMESTAMPDIFF(MINUTE, TIME(start_time), TIME(end_time))) AS minutes
      FROM task t
      JOIN (SELECT task_id,
                   DATE(start_date_time) AS start_date,
                   DATE(end_date_time) AS end_date,
                   GREATEST('09:00', LEAST('17:00', TIME(start_date_time))) AS start_time,
                   GREATEST('09:00', LEAST('17:00', TIME(end_date_time))) AS end_time
            FROM task_time) tt ON tt.task_id = t.task_id
      GROUP BY t.task_name) t
  

Обновленная демонстрация

Комментарии:

1. Важно то, что мы должны учитывать только время между 9 утра и 5 вечера.

2. @user1690835 пока время начала и окончания находится между 9 утра и 5 вечера, это будет сделано. Возможно ли, что их может и не быть?

3. Этого может и не быть. Я добавил скрипту DB в вопросе.

4. Если пользователь работает сверхурочно, это не будет учитываться. Если ему потребуется 9 утра-8 вечера для выполнения задачи, будет учитываться только 9 утра-5 вечера. Я знаю, что это сложный запрос, вот почему я попросил о помощи.

5. @user1690835 не беспокойтесь, просто хотел убедиться. Смотрите мою правку.