【问题标题】:Time difference within business hours营业时间内的时差
【发布时间】:2021-07-15 13:08:27
【问题描述】:

我想找出NOW() 和时间戳列之间的时间差。 在计算时差时,只需要计算从上午 9 点到下午 5 点的营业时间和工作日。

例如对于第一条记录2021-04-21 07:56:36,如果现在是2021-04-21 10:00:00,则必须从上午9点开始计算时差,此时结果为1小时,如下所示:

(NOW() - created_at) - ('2021-04-21 09:00'::timestamp - created_at) AS timediff

对于2021-04-19 21:55:46 的第二条记录,结果将是从2021-04-20 09:00 到2021-04-20 17:00 和2021-04-21 09:00 到2021-04-21 10:00:00 的8+1 小时组成的9 小时

对于2021-04-17 14:22:05 的第三条记录,它将是 17 小时,由 8+8+1 小时组成。

样本数据:

+----------------------------------+---------------------+
|                id                |     created_at      |
+----------------------------------+---------------------+
| 9d38ea6e7077400db310cfc47b31d482 | 2021-04-21 07:56:36 |
| 9d38ea6e7077400db310cfc47b31d481 | 2021-04-19 21:55:46 |
| 9d38ea6e7077400db310cfc47b31d480 | 2021-04-17 14:22:05 |
| 9d38ea6e7077400db310cfc47b31d479 | 2021-04-18 22:43:44 |
+----------------------------------+---------------------+

期望的结果:

+----------------------------------+---------------------+----------+
|                id                |     created_at      | timediff |
+----------------------------------+---------------------+----------+
| 9d38ea6e7077400db310cfc47b31d482 | 2021-04-21 07:56:36 | 01:00:00 |
| 9d38ea6e7077400db310cfc47b31d481 | 2021-04-19 21:55:46 | 09:00:00 |
| 9d38ea6e7077400db310cfc47b31d480 | 2021-04-17 14:22:05 | 17:00:00 |
| 9d38ea6e7077400db310cfc47b31d479 | 2021-04-18 22:43:44 | 17:00:00 |
+----------------------------------+---------------------+----------+

【问题讨论】:

    标签: postgresql datetime timestamp date-arithmetic


    【解决方案1】:

    我建议生成 created_at 和 current_timestamp 之间的所有营业时间范围并将它们相加。虽然它在性能方面远非最佳解决方案,但我认为这是最直接的方法。 我使用时区范围 tstzrange 与交点 operator (*) 的时间戳。

    SELECT id,
      created_at,
      SUM(upper(business_range) - lower(business_range) ) business_hours
    FROM (
      SELECT id, 
        created_at,
        tstzrange(date_in_range + '09:00'::time with time zone, date_in_range + '17:00'::time with time zone) 
          * tstzrange(created_at, current_timestamp) as business_range
      FROM (
        SELECT id,
          created_at,
          created_at::date + generate_series(0, current_timestamp::date - created_at::date) as date_in_range 
        FROM times
      ) dates_in_range
      WHERE date_part('dow', date_in_range) in (1,2,3,4,5)
    ) business_hour_ranges
    GROUP BY
      id,
      created_at
    

    查看db<>fiddle中的设置和示例

    注意事项

    虽然实现易于理解和调试,但它可能会导致性能不佳 - 特别是在使用非常旧的 created_at 日期时。如果您的系统可能是这种情况,您最好编写函数来检查 created_at 和 current_date 的星期几,找出它们之间的天数并确定工作时间。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-08-04
      • 1970-01-01
      • 2018-01-21
      • 2015-04-11
      • 2011-02-12
      • 2014-05-31
      • 1970-01-01
      • 2013-02-02
      相关资源
      最近更新 更多