计算两个时段之间的预订持续时间

时间:2019-04-14 23:58:45

标签: mysql

在预订系统中,我想计算从8am到4pm的两个日期(2019年1月1日至2019年1月2日)之间预订资源的小时总数。

如果预订持续不超过一天,我设法计算出预订资源的总小时数。如果预订持续超过一天,就会出现问题。

通过以下预订,我希望结果是9.5小时。

startDatetime           endDatetime
2019-01-01 14:30:00     2019-01-02 18:30:00

这是我尝试过的代码:

SELECT resourceID, 
       SEC_TO_TIME(sum(LEAST(TIME_TO_SEC(TIME(endDatetime)), TIME_TO_SEC('16:00')) - GREATEST(TIME_TO_SEC(TIME(startDatetime)), TIME_TO_SEC('08:00')))) AS totalTimeBooked 
FROM booking 
WHERE startDatetime BETWEEN '2019-01-01 00:00:00' AND '2019-01-02 23:59:59'
  AND (TIME(startDatetime) BETWEEN '08:00' AND '16:00' 
    OR TIME(endDatetime) BETWEEN '08:00' AND '16:00')
group by resourceID

1 个答案:

答案 0 :(得分:0)

您可以使用以下解决方案为每个booked_time获取resourceID

SELECT
  resourceID,
  SEC_TO_TIME(
    SUM(
      CASE WHEN DATEDIFF(DATE(endDatetime), DATE(startDatetime)) = 0 THEN
        GREATEST(TIME_TO_SEC(TIMEDIFF(LEAST('16:00:00', TIME(endDatetime)), LEAST(GREATEST('08:00:00', TIME(startDatetime)), '16:00:00'))), 0)
      ELSE
        TIME_TO_SEC(TIMEDIFF('16:00:00', LEAST(GREATEST('08:00:00', TIME(startDatetime)), '16:00:00')))
        + TIME_TO_SEC(TIMEDIFF(GREATEST('08:00:00', LEAST('16:00:00', TIME(endDatetime))), '08:00:00'))
        + ((DATEDIFF(DATE(endDatetime), DATE(startDatetime)) - 1) * TIME_TO_SEC(TIMEDIFF('16:00:00', '08:00:00')))
      END
    )
  ) AS booked_time
FROM table_name
GROUP BY resourceID

您可以使用以下查询来获取每一行的结果(可用于测试上述查询):

SELECT
  resourceID, startDatetime, endDatetime,
  SEC_TO_TIME(
    CASE WHEN DATEDIFF(DATE(endDatetime), DATE(startDatetime)) = 0 THEN
      GREATEST(TIME_TO_SEC(TIMEDIFF(LEAST('16:00:00', TIME(endDatetime)), LEAST(GREATEST('08:00:00', TIME(startDatetime)), '16:00:00'))), 0)
    ELSE
      TIME_TO_SEC(TIMEDIFF('16:00:00', LEAST(GREATEST('08:00:00', TIME(startDatetime)), '16:00:00')))
      + TIME_TO_SEC(TIMEDIFF(GREATEST('08:00:00', LEAST('16:00:00', TIME(endDatetime))), '08:00:00'))
      + ((DATEDIFF(DATE(endDatetime), DATE(startDatetime)) - 1) * TIME_TO_SEC(TIMEDIFF('16:00:00', '08:00:00')))
    END
  ) AS booked_time
FROM table_name
ORDER BY resourceID, startDatetime, endDatetime

demo on dbfiddle.com


注意:您必须小心使用SEC_TO_TIME功能。在大量数据或大日期范围内,您可以达到TIME数据类型的最大值:

  

MySQL检索并以“ TIME”格式(或“ HH:MM:SS”格式表示小时值)显示HHH:MM:SS值。 TIME值的范围可以从“ -838:59:59”到“ 838:59:59”。小时部分可能是如此之大,因为TIME类型不仅可以用来表示一天中的某个时间(必须少于24小时),而且可以用来表示经过的时间或两个事件之间的时间间隔(可能大于24小时,甚至是负数)。
  来源: https://dev.mysql.com/doc/refman/8.0/en/time.html


您还询问了如何获得入住率。您可以通过上面的查询使用以下解决方案:

SELECT
  resourceID,
  booked_time,
  CONCAT((TIME_TO_SEC(booked_time) / TIME_TO_SEC(TIMEDIFF('16:00:00', '08:00:00')) * 100), '%') AS 'occupancy_rate'
FROM (
  SELECT
    resourceID,
    SEC_TO_TIME(
      SUM(
        CASE WHEN DATEDIFF(DATE(endDatetime), DATE(startDatetime)) = 0 THEN
          GREATEST(TIME_TO_SEC(TIMEDIFF(LEAST('16:00:00', TIME(endDatetime)), LEAST(GREATEST('08:00:00', TIME(startDatetime)), '16:00:00'))), 0)
        ELSE
          TIME_TO_SEC(TIMEDIFF('16:00:00', LEAST(GREATEST('08:00:00', TIME(startDatetime)), '16:00:00')))
          + TIME_TO_SEC(TIMEDIFF(GREATEST('08:00:00', LEAST('16:00:00', TIME(endDatetime))), '08:00:00'))
          + ((DATEDIFF(DATE(endDatetime), DATE(startDatetime)) - 1) * TIME_TO_SEC(TIMEDIFF('16:00:00', '08:00:00')))
        END
      )
    ) AS booked_time
  FROM table_name
  GROUP BY resourceID
) t_occupancy_rate

demo on dbfiddle.uk