This following functions will take the input for the
working start time of the day
working end time of the day
start time
end time
-- helper function CREATE OR REPLACE FUNCTION get_working_time_in_a_day(sdt TIMESTAMP, edt TIMESTAMP, swt TIME, ewt TIME) RETURNS INT AS $$ DECLARE sd TIMESTAMP; ed TIMESTAMP; swdt TIMESTAMP; ewdt TIMESTAMP; seconds INT; BEGIN swdt = sdt::DATE || ' ' || swt; -- work start datetime for a day ewdt = sdt::DATE || ' ' || ewt; -- work end datetime for a day IF (sdt < swdt AND edt <= swdt) -- case 1 and 2 THEN seconds = 0; END IF; IF (sdt < swdt AND edt > swdt AND edt <= ewdt) -- case 3 and 4 THEN seconds = EXTRACT(EPOCH FROM (edt - swdt)); END IF; IF (sdt < swdt AND edt > swdt AND edt > ewdt) -- case 5 THEN seconds = EXTRACT(EPOCH FROM (ewdt - swdt)); END IF; IF (sdt = swdt AND edt > swdt AND edt <= ewdt) -- case 6 and 7 THEN seconds = EXTRACT(EPOCH FROM (edt - sdt)); END IF; IF (sdt = swdt AND edt > ewdt) -- case 8 THEN seconds = EXTRACT(EPOCH FROM (ewdt - sdt)); END IF; IF (sdt > swdt AND edt <= ewdt) -- case 9 and 10 THEN seconds = EXTRACT(EPOCH FROM (edt - sdt)); END IF; IF (sdt > swdt AND sdt < ewdt AND edt > ewdt) -- case 11 THEN seconds = EXTRACT(EPOCH FROM (ewdt - sdt)); END IF; IF (sdt >= ewdt AND edt > ewdt) -- case 12 and 13 THEN seconds = 0; END IF; RETURN seconds; END; $$ LANGUAGE plpgsql; -- Get work time difference CREATE OR REPLACE FUNCTION get_working_time(sdt TIMESTAMP, edt TIMESTAMP, swt TIME, ewt TIME) RETURNS INT AS $$ DECLARE seconds INT = 0; strst VARCHAR(9) = ' 00:00:00'; stret VARCHAR(9) = ' 23:59:59'; tend TIMESTAMP; tempEdt TIMESTAMP; x int; BEGIN <<test>> WHILE sdt <= edt LOOP tend = sdt::DATE || stret; -- get the false end datetime for start time IF edt >= tend THEN tempEdt = tend; ELSE tempEdt = edt; END IF; -- skip saturday and sunday x = EXTRACT(DOW FROM sdt); if (x > 0 AND x < 6) THEN seconds = seconds + get_working_time_in_a_day(sdt, tempEdt, swt, ewt); ELSE -- RAISE NOTICE 'MISSED A DAY'; END IF; sdt = (sdt + (INTERVAL '1 DAY'))::DATE || strst; END LOOP test; --RAISE NOTICE 'diff in minutes = %', (seconds / 60); RETURN seconds; END; $$ LANGUAGE plpgsql; -- Table Definition DROP TABLE IF EXISTS test_working_time; CREATE TABLE test_working_time( pk SERIAL PRIMARY KEY, start_datetime TIMESTAMP, end_datetime TIMESTAMP, start_work_time TIME, end_work_time TIME ); -- Test data insertion INSERT INTO test_working_time VALUES (1, '2015-11-03 01:00:00', '2015-11-03 07:00:00', '08:00:00', '22:00:00'), (2, '2015-11-03 01:00:00', '2015-11-04 07:00:00', '08:00:00', '22:00:00'), (3, '2015-11-03 01:00:00', '2015-11-05 07:00:00', '08:00:00', '22:00:00'), (4, '2015-11-03 01:00:00', '2015-11-06 07:00:00', '08:00:00', '22:00:00'), (5, '2015-11-03 01:00:00', '2015-11-07 07:00:00', '08:00:00', '22:00:00'), (6, '2015-11-03 01:00:00', '2015-11-03 08:00:00', '08:00:00', '22:00:00'), (7, '2015-11-03 01:00:00', '2015-11-04 08:00:00', '08:00:00', '22:00:00'), (8, '2015-11-03 01:00:00', '2015-11-05 08:00:00', '08:00:00', '22:00:00'), (9, '2015-11-03 01:00:00', '2015-11-06 08:00:00', '08:00:00', '22:00:00'), (10, '2015-11-03 01:00:00', '2015-11-07 08:00:00', '08:00:00', '22:00:00'), (11, '2015-11-03 01:00:00', '2015-11-03 11:00:00', '08:00:00', '22:00:00'), (12, '2015-11-03 01:00:00', '2015-11-04 11:00:00', '08:00:00', '22:00:00'), (13, '2015-11-03 01:00:00', '2015-11-05 11:00:00', '08:00:00', '22:00:00'), (14, '2015-11-03 01:00:00', '2015-11-06 11:00:00', '08:00:00', '22:00:00'), (15, '2015-11-03 01:00:00', '2015-11-07 11:00:00', '08:00:00', '22:00:00'), (16, '2015-11-03 01:00:00', '2015-11-03 22:00:00', '08:00:00', '22:00:00'), (17, '2015-11-03 01:00:00', '2015-11-04 22:00:00', '08:00:00', '22:00:00'), (18, '2015-11-03 01:00:00', '2015-11-05 22:00:00', '08:00:00', '22:00:00'), (19, '2015-11-03 01:00:00', '2015-11-06 22:00:00', '08:00:00', '22:00:00'), (20, '2015-11-03 01:00:00', '2015-11-07 22:00:00', '08:00:00', '22:00:00'), (21, '2015-11-03 01:00:00', '2015-11-03 23:00:00', '08:00:00', '22:00:00'), (22, '2015-11-03 01:00:00', '2015-11-04 23:00:00', '08:00:00', '22:00:00'), (23, '2015-11-03 01:00:00', '2015-11-05 23:00:00', '08:00:00', '22:00:00'), (24, '2015-11-03 01:00:00', '2015-11-06 23:00:00', '08:00:00', '22:00:00'), (25, '2015-11-03 01:00:00', '2015-11-07 23:00:00', '08:00:00', '22:00:00'), (26, '2015-11-03 08:00:00', '2015-11-03 11:00:00', '08:00:00', '22:00:00'), (27, '2015-11-03 08:00:00', '2015-11-04 11:00:00', '08:00:00', '22:00:00'), (28, '2015-11-03 08:00:00', '2015-11-05 11:00:00', '08:00:00', '22:00:00'), (29, '2015-11-03 08:00:00', '2015-11-06 11:00:00', '08:00:00', '22:00:00'), (30, '2015-11-03 08:00:00', '2015-11-07 11:00:00', '08:00:00', '22:00:00'), (31, '2015-11-03 08:00:00', '2015-11-03 22:00:00', '08:00:00', '22:00:00'), (32, '2015-11-03 08:00:00', '2015-11-04 22:00:00', '08:00:00', '22:00:00'), (33, '2015-11-03 08:00:00', '2015-11-05 22:00:00', '08:00:00', '22:00:00'), (34, '2015-11-03 08:00:00', '2015-11-06 22:00:00', '08:00:00', '22:00:00'), (35, '2015-11-03 08:00:00', '2015-11-07 22:00:00', '08:00:00', '22:00:00'), (36, '2015-11-03 08:00:00', '2015-11-03 23:00:00', '08:00:00', '22:00:00'), (37, '2015-11-03 08:00:00', '2015-11-04 23:00:00', '08:00:00', '22:00:00'), (38, '2015-11-03 08:00:00', '2015-11-05 23:00:00', '08:00:00', '22:00:00'), (39, '2015-11-03 08:00:00', '2015-11-06 23:00:00', '08:00:00', '22:00:00'), (40, '2015-11-03 08:00:00', '2015-11-07 23:00:00', '08:00:00', '22:00:00'), (41, '2015-11-03 12:00:00', '2015-11-03 18:00:00', '08:00:00', '22:00:00'), (42, '2015-11-03 12:00:00', '2015-11-04 18:00:00', '08:00:00', '22:00:00'), (43, '2015-11-03 12:00:00', '2015-11-05 18:00:00', '08:00:00', '22:00:00'), (44, '2015-11-03 12:00:00', '2015-11-06 18:00:00', '08:00:00', '22:00:00'), (45, '2015-11-03 12:00:00', '2015-11-07 18:00:00', '08:00:00', '22:00:00'), (46, '2015-11-03 12:00:00', '2015-11-03 22:00:00', '08:00:00', '22:00:00'), (47, '2015-11-03 12:00:00', '2015-11-04 22:00:00', '08:00:00', '22:00:00'), (48, '2015-11-03 12:00:00', '2015-11-05 22:00:00', '08:00:00', '22:00:00'), (49, '2015-11-03 12:00:00', '2015-11-06 22:00:00', '08:00:00', '22:00:00'), (50, '2015-11-03 12:00:00', '2015-11-07 22:00:00', '08:00:00', '22:00:00'), (51, '2015-11-03 12:00:00', '2015-11-03 23:00:00', '08:00:00', '22:00:00'), (52, '2015-11-03 12:00:00', '2015-11-04 23:00:00', '08:00:00', '22:00:00'), (53, '2015-11-03 12:00:00', '2015-11-05 23:00:00', '08:00:00', '22:00:00'), (54, '2015-11-03 12:00:00', '2015-11-06 23:00:00', '08:00:00', '22:00:00'), (55, '2015-11-03 12:00:00', '2015-11-07 23:00:00', '08:00:00', '22:00:00'), (56, '2015-11-03 22:00:00', '2015-11-03 23:00:00', '08:00:00', '22:00:00'), (57, '2015-11-03 22:00:00', '2015-11-04 23:00:00', '08:00:00', '22:00:00'), (58, '2015-11-03 22:00:00', '2015-11-05 23:00:00', '08:00:00', '22:00:00'), (59, '2015-11-03 22:00:00', '2015-11-06 23:00:00', '08:00:00', '22:00:00'), (60, '2015-11-03 22:00:00', '2015-11-07 23:00:00', '08:00:00', '22:00:00'), (61, '2015-11-03 22:30:00', '2015-11-03 23:30:00', '08:00:00', '22:00:00'), (62, '2015-11-03 22:30:00', '2015-11-04 23:30:00', '08:00:00', '22:00:00'), (63, '2015-11-03 22:30:00', '2015-11-05 23:30:00', '08:00:00', '22:00:00'), (64, '2015-11-03 22:30:00', '2015-11-06 23:30:00', '08:00:00', '22:00:00'), (65, '2015-11-03 22:30:00', '2015-11-07 23:30:00', '08:00:00', '22:00:00'); -- select query to get work time difference SELECT start_datetime, end_datetime, start_work_time, end_work_time, get_working_time(start_datetime, end_datetime, start_work_time, end_work_time) AS diff_in_minutes FROM test_working_time;
This will give the difference of only the work hours in seconds between the start and end datetime