如何计算办公时间 (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
我有一个 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 |