营业时间内的时差
Time difference within business hours
我想找出 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
到 [=] 的 8+1 小时组成的 9 小时15=]
对于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 |
+----------------------------------+---------------------+----------+
我建议生成 created_at
和 current_timestamp 之间的所有营业时间范围并将它们相加。虽然它在性能方面远非最佳解决方案,但我认为这是最直接的方法。
我使用时区范围为 tstzrange with intersection 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 的星期几,找到它们之间的天数并确定工作时间。
我想找出 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
到 [=] 的 8+1 小时组成的 9 小时15=]
对于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 |
+----------------------------------+---------------------+----------+
我建议生成 created_at
和 current_timestamp 之间的所有营业时间范围并将它们相加。虽然它在性能方面远非最佳解决方案,但我认为这是最直接的方法。
我使用时区范围为 tstzrange with intersection 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 的星期几,找到它们之间的天数并确定工作时间。