WITH
MYTAB (A, B) AS
(
VALUES ('2021-08-03 13:22:29'::TIMESTAMP, '2021-08-09 15:51:59'::TIMESTAMP)
)
, MYTAB2 (A, B) AS
(
SELECT
CASE WHEN DAYOFWEEK(A) IN (1, 7) THEN DATE (A) + 1 DAY ELSE A END
, CASE WHEN DAYOFWEEK(B) IN (1, 7) THEN B - (MIDNIGHT_SECONDS (B) + 1) SECOND ELSE B END
FROM MYTAB
)
, R (TS) AS
(
SELECT V.TS
FROM MYTAB2 T, TABLE (VALUES T.A, T.B) V (TS)
WHERE T.A <= T.B
UNION ALL
SELECT DATE (R.TS) + 1 DAY
FROM R, MYTAB2 T
WHERE DATE (R.TS) + 1 DAY < DATE (T.B)
)
SELECT
COALESCE
(
-- Seconds between start and end
(DAYS (MAX (TS)) - DAYS (MIN (TS))) * 86400
+ MIDNIGHT_SECONDS (MAX (TS)) - MIDNIGHT_SECONDS (MIN (TS))
-- SUM of seconds for weekend days is subtracted
- SUM (CASE WHEN DAYOFWEEK (TS) IN (1, 7) THEN 86400 ELSE 0 END)
, 0
) / 3600 AS HRS
FROM R
The idea is to construct the following table with Recursive Common Table expression first:
2021-08-03 13:22:29 --> 2021-08-04 00:00:00 (if start is a weekend)
2021-08-04 00:00:00 --> 2021-08-05 00:00:00 (if start is a weekend)
...
2021-08-08 00:00:00 --> 2021-08-07 00:00:00 (if end is a weekend)
2021-08-09 15:51:59 --> 2021-08-08 23:59:59 (if end is a weekend)
That is: one timestamp for each day between the start and the end timestamps. These start and end timestamps are adjusted:
- If start is a weekend - change it to the start of the next day
- If end is a weekend - change it to the end of the previous day
The final calculation is simple: we subtract sum of seconds for all weekends in the list from the difference in seconds between start and end.