如何计算办公时间 (9-5) 和非办公时间的分钟数

How do I work out minutes that occurred during office hours (9-5) and out of office hours

我有一个 activity 开始的日期时间字段和一个 active_time 分钟的整数字段。

我想做的是在几分钟内(然后是几小时/60)算出 activity 在工作时间 (9-5) 和工作时间以外的时间花费了多少时间。

数据列
日期时间:'2022-02-28 16:54:00.000 +0000'.
Active_time 分钟:'20'

期望的输出:
Activity 工作时间:'6'
Activity 超时工作时间:'14'

有人可以帮忙吗?

非常感谢。

我想不出使用内置日期函数来解决这个问题的方法,所以这可能不是最漂亮的解决方案,但数学是存在的。这会将 start_timestamp/active_time 转换为相对于您的营业时间

的分钟数

我减去 540,基本上将时间 9:00AM 设置为“0 分钟”,使数字更易于处理。这使得 5:00PM “480 分钟”

那就只需要减去营业时间内外的时间了。

set startdatetime = '2022-03-23 7:31:00'::timestamp_ntz;
set active_minutes = 125;
set business_start = 0;
set business_end = 480;

select 
-540 + (hour($startdatetime) * 60 + minute($startdatetime)) as start_minute,
start_minute + $active_minutes as end_minute,
-- End time (within business hours) - Start time (within business hours). Can't be less than 0
greatest(0, least(end_minute, $business_end) - greatest(start_minute, $business_start)) as minutes_during_business,
-- End - Start. With any "business minutes" ignored. first for pre-work minutes, then for post-work minutes
least(end_minute, $business_start) - least(start_minute, $business_start)
+ greatest(end_minute, $business_end) - greatest(start_minute, $business_end) as minutes_outside_business,
minutes_during_business / 60 as hours_during_business,
minutes_outside_business / 60 as hours_outside_business;
;

如果您的活跃分钟数跨越到第二天的工作时间,则此方法效果不佳。这需要一些额外的处理。

您还可以添加秒数,如果您确实需要额外的粒度,则将所有硬编码数字转换为秒数。

SELECT start_time, minutes, time_pre_work, work_time, post_work_time
FROM (
    SELECT *
        ,timeadd('minute', minutes, start_time) as time_end
        ,date_trunc('day', start_time) as day
        ,timeadd('hour', 8, day) as workday_start
        ,timeadd('hour', 17, day) as workday_end
        ,timediff('minute', least(start_time, workday_start), workday_start) as time_pre_work
        ,timediff('minute', greatest(start_time, workday_start), least(workday_end, time_end)) as work_time
        ,timediff('minute', greatest(workday_end, workday_end), greatest(workday_end, time_end)) as post_work_time
    FROM VALUES
        ('2022-02-28 16:54:00.000'::timestamp, 20)
        t(start_time, minutes)
);

给出:

START_TIME MINUTES TIME_PRE_WORK WORK_TIME POST_WORK_TIME
2022-02-28 16:54:00.000 20 0 6 14

日内剪报:

并且 multi-days 的边界不正确,此数据:

 FROM VALUES
        ('2022-02-28 16:54:00.000'::timestamp, 20),
        ('2022-02-28 7:54:00.000'::timestamp, 20),
        ('2022-02-28 6:54:00.000'::timestamp, 1000)
        t(start_time, minutes)

给出:

START_TIME MINUTES TIME_PRE_WORK WORK_TIME POST_WORK_TIME
2022-02-28 16:54:00.000 20 0 6
2022-02-28 07:54:00.000 20 6 14
2022-02-28 06:54:00.000 1,000 66 540

每天剪裁的天数:

WITH input_data as (
    SELECT * FROM VALUES
        ('2022-02-28 16:54:00.000'::timestamp, 20),
        ('2022-02-28 7:54:00.000'::timestamp, 20),
        ('2022-02-28 6:54:00.000'::timestamp, 3000)
        t(start_time, minutes)
), range as(
    SELECT row_number() over(order by null)-1 as rn
    FROM TABLE(generator(ROWCOUNT => 100))
), day_condition as (
    SELECT *
        ,timeadd('minute', minutes, start_time) as time_end
        ,date_trunc('day', dateadd('day', r.rn, start_time)) as r_day_start
        ,dateadd('day', 1, r_day_start ) as r_day_end
        ,greatest(r_day_start, start_time) as clip_start
        ,least(r_day_end, time_end) as clip_end
    -- insert logic for "which day is it and what hours it has here"
        ,timeadd('hour', 8, r_day_start) as workday_start
        ,timeadd('hour', 17, r_day_start) as workday_end
    FROM input_data i
    JOIN range r ON r.rn <= datediff(day, start_time, timeadd('minute', minutes, start_time))
) 
SELECT 
    start_time
    ,minutes
    ,r_day_start
    --,clip_start
    --,clip_end
    
    ,timediff('minute', least(clip_start, workday_start), workday_start) as time_pre_work
    ,timediff('minute', greatest(clip_start, workday_start), least(workday_end, clip_end)) as work_time
    ,timediff('minute', greatest(workday_end, workday_end), greatest(workday_end, clip_end)) as post_work_time
FROM day_condition
ORDER BY 1,3;
START_TIME MINUTES R_DAY_START TIME_PRE_WORK WORK_TIME POST_WORK_TIME
2022-02-28 06:54:00.000 3,000 2022-02-28 00:00:00.000 66 540 420
2022-02-28 06:54:00.000 3,000 2022-03-01 00:00:00.000 480 540 420
2022-02-28 06:54:00.000 3,000 2022-03-02 00:00:00.000 480 54 0
2022-02-28 07:54:00.000 20 2022-02-28 00:00:00.000 6 14 0
2022-02-28 16:54:00.000 20 2022-02-28 00:00:00.000 0 6 14