The subject matter is night hours payment calculation.
- Employees are paid extra for hours actually worked from 10 P.M. to 6 A.M.
-- shift start time can vary
-- shift end time can vary
-- from shift start, employee works 4 hours then breaks for 30 minutes
then works 4 hours then breaks for 30 minutes
and so on until shift end.
-- "night hours" are hours within the 4-hour work periods that fall between 10 P.M. and 6 A.M.
The OP is trying to calculate total night hours (including breaks) minus breaks.
I suggest directly calculating the night hours within each 4-hour work period.
- Approach:
-- calculate work periods when actual work was done
-- calculate night work duration within each work period
--- if period start at night then night work start = period start else = next night work start
--- if period end at night then night work end = period end else = previous night work end
--- sum night work durations when night work end is later than night work start.
In my code, the first WITH clause generates 48 test cases, with shifts starting every 30 minutes and lasting 17 hours.
alter session set nls_date_format='mm-dd hh24:mi';
with shifts(shift_start, shift_end) as (
select trunc(sysdate) + level/48,
trunc(sysdate) + level/48 + 17/24
from dual
connect by level <= 48
)
, work_periods as (
select SHIFT_START, SHIFT_END,
WORK_START, extract(hour from cast(work_start as timestamp)) start_hour,
WORK_END, extract(hour from cast(work_end as timestamp)) end_hour
from shifts, lateral(
select shift_start + 4.5/24 * (level - 1) WORK_START,
least(shift_end, shift_start + 4.5/24 * (level - 1) + 4/24) WORK_END
from dual
connect by shift_start + 4.5/24 * (level - 1) < shift_end
)
)
select shift_start, shift_end,
round(24 * sum(night_end - night_start), 4) night_hours
from (
select shift_start, shift_end,
case when start_hour >= 22 or start_hour < 6 then work_start else trunc(work_start) + 22/24 end night_start,
case when end_hour >= 22 or end_hour < 6 then work_end else trunc(work_end) + 6/24 end night_end
from work_periods
) a
where night_end > night_start
group by shift_start, shift_end
order by 1,2
shift_start shift_end night_hours
08-13 00:30 08-13 17:30 5
08-13 01:00 08-13 18:00 4,5
08-13 01:30 08-13 18:30 4
08-13 02:00 08-13 19:00 4
08-13 02:30 08-13 19:30 3,5
08-13 03:00 08-13 20:00 3
08-13 03:30 08-13 20:30 2,5
08-13 04:00 08-13 21:00 2
08-13 04:30 08-13 21:30 1,5
08-13 05:00 08-13 22:00 1
08-13 05:30 08-13 22:30 1
08-13 06:00 08-13 23:00 1
08-13 06:30 08-13 23:30 1,5
08-13 07:00 08-14 00:00 2
08-13 07:30 08-14 00:30 2,5
08-13 08:00 08-14 01:00 3
08-13 08:30 08-14 01:30 3,5
08-13 09:00 08-14 02:00 3,5
08-13 09:30 08-14 02:30 4
08-13 10:00 08-14 03:00 4,5
08-13 10:30 08-14 03:30 5
08-13 11:00 08-14 04:00 5,5
08-13 11:30 08-14 04:30 6
08-13 12:00 08-14 05:00 6,5
08-13 12:30 08-14 05:30 7
08-13 13:00 08-14 06:00 7,5
08-13 13:30 08-14 06:30 7
08-13 14:00 08-14 07:00 7
08-13 14:30 08-14 07:30 7
08-13 15:00 08-14 08:00 7
08-13 15:30 08-14 08:30 7
08-13 16:00 08-14 09:00 7
08-13 16:30 08-14 09:30 7
08-13 17:00 08-14 10:00 7,5
08-13 17:30 08-14 10:30 7,5
08-13 18:00 08-14 11:00 7
08-13 18:30 08-14 11:30 7
08-13 19:00 08-14 12:00 7
08-13 19:30 08-14 12:30 7
08-13 20:00 08-14 13:00 7
08-13 20:30 08-14 13:30 7
08-13 21:00 08-14 14:00 7
08-13 21:30 08-14 14:30 7,5
08-13 22:00 08-14 15:00 7,5
08-13 22:30 08-14 15:30 7
08-13 23:00 08-14 16:00 6,5
08-13 23:30 08-14 16:30 6
08-14 00:00 08-14 17:00 5,5
Best regards,
Stew