Mysql:如何计算两个时间戳之间的营业时间而忽略周末

时间:2012-11-17 00:01:40

标签: mysql sql date

我的表有示例数据,我需要计算两列中两个时间戳之间的业务时间。营业时间:上午9:00至下午5:00,周六和周日疏忽,我不考虑公共假期。有人可以提供一些如何实现这一目标的指导方针吗?我想要第3栏中所述的所需输出,日期格式为:yyyy-mm-dd

    Created date             Updated date         Business hrs
    2012-03-05 9:00am   2012-03-05 3:00pm             6
    2012-03-05 10:00am  2012-03-06 10:00am            9
    2012-03-09 4:00pm   2012-03-19 10:00am            2

4 个答案:

答案 0 :(得分:17)

问题是不应该考虑公众假期,所以这个答案就是这样 - 计算考虑周末的营业时间,但忽略可能的公众假期。

如果您需要考虑公共假期,您需要有一个单独的表格,列出公共假期的日期,这些日期可能因年度和州与州或国家而异。主要公式可能保持不变,但您需要从公共假期的结果小时数中减去给定的日期范围。

让我们创建一个包含一些涵盖各种情况的样本数据的表:

CREATE TABLE T (CreatedDate datetime, UpdatedDate datetime);

INSERT INTO T VALUES
('2012-03-05 09:00:00', '2012-03-05 15:00:00'), -- simple part of the same day
('2012-03-05 10:00:00', '2012-03-06 10:00:00'), -- full day across the midnight
('2012-03-05 11:00:00', '2012-03-06 10:00:00'), -- less than a day across the midnight
('2012-03-05 10:00:00', '2012-03-06 15:00:00'), -- more than a day across the midnight
('2012-03-09 16:00:00', '2012-03-12 10:00:00'), -- over the weekend, less than 7 days
('2012-03-06 16:00:00', '2012-03-15 10:00:00'), -- over the weekend, more than 7 days
('2012-03-09 16:00:00', '2012-03-19 10:00:00'); -- over two weekends

在MS SQL Server中,我使用以下公式:

SELECT
    CreatedDate,
    UpdatedDate,
    DATEDIFF(minute, CreatedDate, UpdatedDate)/60.0 -
    DATEDIFF(day,    CreatedDate, UpdatedDate)*16 -
    DATEDIFF(week,   CreatedDate, UpdatedDate)*16 AS BusinessHours
FROM T

产生以下结果:

+-------------------------+-------------------------+---------------+
|       CreatedDate       |       UpdatedDate       | BusinessHours |
+-------------------------+-------------------------+---------------+
| 2012-03-05 09:00:00     | 2012-03-05 15:00:00     | 6             |
| 2012-03-05 10:00:00     | 2012-03-06 10:00:00     | 8             |
| 2012-03-05 11:00:00     | 2012-03-06 10:00:00     | 7             |
| 2012-03-05 10:00:00     | 2012-03-06 15:00:00     | 13            |
| 2012-03-09 16:00:00     | 2012-03-12 10:00:00     | 2             |
| 2012-03-06 16:00:00     | 2012-03-15 10:00:00     | 50            |
| 2012-03-09 16:00:00     | 2012-03-19 10:00:00     | 42            |
+-------------------------+-------------------------+---------------+

它有效,因为在SQL Server DATEDIFF中返回指定的 startdate enddate datepart 边界的计数>

每天有8个工作小时。我计算两个日期之间的总小时数,然后减去中午的数量乘以每天16个非营业时间,然后减去周末的数量乘以16(周六+周日的8 + 8个工作小时)。

它还假设给定的开始和结束日期/时间是在营业时间内。

在MySQL中,最接近的等价物是TIMESTAMPDIFF,但它的工作方式不同。它有效地计算以秒为单位的差异,并将所选单位中的秒数除以(丢弃小数部分)。

因此,要获得我们需要的结果,我们可以计算某个锚定日期时间与TIMESTAMPDIFFCreatedDate之间的UpdatedDate,而不是计算CreatedDate和{{之间的差异1}}直接。

我选择了UpdatedDate,这是星期一。您可以选择任何其他星期一(或星期日,如果您的星期日从星期日开始)午夜为锚定日期。

MySQL查询变为(参见SQL Fiddle):

2000-01-03 00:00:00

答案 1 :(得分:3)

创建一个名为BusinessHours的表,其中一个名为Hour的列包含日期时间。 Make Hour是主键。编写一个流程来填充一年中的每个工作小时(2012-01-02 00:90:00, 2012-01-02 00:10:00等)。这应该不难,因为规则很简单。这听起来像是很多数据,但在宏观方案中却并非如此(一年只有8760小时 - 即使你的日期时间分别为8个字节,这也是一个惊人的60kB)。确保安排作业以保持其填充。

然后:

Select
  y.CreatedDate,
  y.UpdatedDate,
  Count(*) as BusinessHours
From
  YourTable y
    Inner Join
  BusinessHours h
    On h.Hour >= y.CreatedDate And h.Hour < y.UpdatedDate
Group By
  y.CreatedDate,
  y.UpdatedDate

如果您考虑过公共假期,这也为您提供了一种相当简单的方法 - 只需从BusinessHours表中取出行。

答案 2 :(得分:0)

SELECT (FLOOR(DATEDIFF (UpdatedDate, CreatedDate) / 7) * 5 + MOD (DATEDIFF (UpdatedDate, CreatedDate), 7)) * 8 +
       TIMEDIFF (TIME (UpdatedDate), TIME(CreatedDate))
FROM YourTable

以上内容并不完整,因为它只是“估算”周末......但它应该让你开始......另一种选择是使用有效营业时间表(详见this answer from Laurence)。

有关参考,请参阅MySQL documentation

答案 3 :(得分:0)

使用datediff计算开始和结束时间之间的差异,然后减去(date_add,负时数)非工作时间:24周末天,16天工作日预计结束和开始日需要额外的计算。 是否一天是周末,可以使用dayofweek方法指定。