首页 >数据库 >mysql教程 >如何计算 PostgreSQL 中日期之间的工作时间(考虑周末和特定工作时间)?

如何计算 PostgreSQL 中日期之间的工作时间(考虑周末和特定工作时间)?

Patricia Arquette
Patricia Arquette原创
2025-01-03 10:35:40367浏览

How Can I Calculate Working Hours Between Dates in PostgreSQL, Considering Weekends and Specific Working Hours?

计算 PostgreSQL 中日期之间的工作时间

简介

在各种场景中,确定两个时间戳之间的工作小时数在工资单和调度等领域被证明是至关重要的。在 PostgreSQL 中,此计算需要仔细考虑工作日和特定时间的参数。本文概述了一个全面的解决方案,考虑到以下标准:

  • 周末(周六和周日) 不计入工作时间。
  • 工作时间定义为周一至周五,上午 8 点至凌晨 3 点pm.
  • 小数小时将包含在计算中。

解决方案

方法1:四舍五入仅两个时间戳的结果

此方法适用于以 1 小时为单位,忽略小数小时。这是一种简单但不太精确的方法。

查询:

SELECT count(*) AS work_hours
FROM   generate_series (timestamp '2013-06-24 13:30'
                      , timestamp '2013-06-24 15:29' - interval '1h'
                      , interval '1h') h
WHERE  EXTRACT(ISODOW FROM h) < 6
AND    h::time >= '08:00'
AND    h::time &amp;lt;= '14:00';

示例输入:

2013-06-24 13:30, 2013-06-24 15:29

输出:

2

方法 2:时间戳表的舍入结果

这种方法扩展了之前的方法来处理时间戳表

查询:

SELECT t_id, count(*) AS work_hours
FROM  (
   SELECT t_id, generate_series (t_start, t_end - interval '1h', interval '1h') AS h
   FROM   t
   ) sub
WHERE  EXTRACT(ISODOW FROM h) < 6
AND    h::time >= '08:00'
AND    h::time <= '14:00'
GROUP  BY 1
ORDER  BY 1;

方法三:更精确的计算

对于更细粒度的计算,更小的时间单位可以是已考虑。

查询:

SELECT t_id, count(*) * interval '5 min' AS work_interval
FROM  (
   SELECT t_id, generate_series (t_start, t_end - interval '5 min', interval '5 min') AS h
   FROM   t
   ) sub
WHERE  EXTRACT(ISODOW FROM h) < 6
AND    h::time >= '08:00'
AND    h::time <= '14:55'
GROUP  BY 1
ORDER  BY 1;

示例输入:

| t_id | t_start                | t_end                  |
|------|-------------------------|-------------------------|
| 1    | 2009-12-03 14:00:00    | 2009-12-04 09:00:00    |
| 2    | 2009-12-03 15:00:00    | 2009-12-07 08:00:00    |
| 3    | 2013-06-24 07:00:00    | 2013-06-24 12:00:00    |
| 4    | 2013-06-24 12:00:00    | 2013-06-24 23:00:00    |
| 5    | 2013-06-23 13:00:00    | 2013-06-25 11:00:00    |
| 6    | 2013-06-23 14:01:00    | 2013-06-24 08:59:00    |

输出:

| t_id | work_interval |
|------|----------------|
| 1    | 1 hour         |
| 2    | 8 hours        |
| 3    | 0 hours        |
| 4    | 0 hours        |
| 5    | 6 hours        |
| 6    | 1 hour         |

方法 4:精确结果

此方法提供微秒精度的精确结果。它更复杂,但计算效率更高。

查询:

WITH var AS (SELECT '08:00'::time  AS v_start
                  , '15:00'::time  AS v_end)
SELECT t_id
     , COALESCE(h.h, '0')  -- add / subtract fractions
       - CASE WHEN EXTRACT(ISODOW FROM t_start) < 6
               AND t_start::time > v_start
               AND t_start::time < v_end
         THEN t_start - date_trunc('hour', t_start)
         ELSE '0'::interval END
       + CASE WHEN EXTRACT(ISODOW FROM t_end) < 6
               AND t_end::time > v_start
               AND t_end::time < v_end
         THEN t_end - date_trunc('hour', t_end)
         ELSE '0'::interval END                 AS work_interval
FROM   t CROSS JOIN var
LEFT   JOIN (  -- count full hours, similar to above solutions
   SELECT t_id, count(*)::int * interval '1h' AS h
   FROM  (
      SELECT t_id, v_start, v_end
           , generate_series (date_trunc('hour', t_start)
                            , date_trunc('hour', t_end) - interval '1h'
                            , interval '1h') AS h
      FROM   t, var
      ) sub
   WHERE  EXTRACT(ISODOW FROM h) < 6
   AND    h::time >= v_start
   AND    h::time <= v_end - interval '1h'
   GROUP  BY 1
   ) h USING (t_id)
ORDER  BY 1;

这个全面的解决方案解决了在 PostgreSQL 中准确高效地计算工作时间的需求。

以上是如何计算 PostgreSQL 中日期之间的工作时间(考虑周末和特定工作时间)?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn