Postgresql 营业时间内的时差

Postgresql 营业时间内的时差,postgresql,datetime,timestamp,date-arithmetic,Postgresql,Datetime,Timestamp,Date Arithmetic,我想找出NOW()和时间戳列之间的时间差。
 计算时差时,只需计算从上午9点到下午5点以及工作日的营业时间。
 e、 g.对于第一条记录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:

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


e、 g.对于第一条记录
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

第三条记录为
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 |
+----------------------------------+---------------------+----------+

我建议生成在创建的
和当前时间戳之间的所有工作时间范围,并将它们相加。虽然就性能而言,这远不是最佳解决方案,但我认为这是最直接的方法。
我使用带有时区范围和交叉点的时间戳

请参见中的设置和示例

警告 虽然实现很容易理解和调试,但它可能会导致性能低下,尤其是在与非常旧的创建的_一起使用时。如果您的系统中可能存在这种情况,您最好编写一个函数,检查创建的_的星期几和当前的_日期,查找它们之间的天数并确定工作时间

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