Home >Database >Mysql Tutorial >How to Calculate Working Hours Between Two Dates in PostgreSQL, Excluding Weekends?

How to Calculate Working Hours Between Two Dates in PostgreSQL, Excluding Weekends?

Mary-Kate Olsen
Mary-Kate OlsenOriginal
2024-12-31 20:14:14889browse

How to Calculate Working Hours Between Two Dates in PostgreSQL, Excluding Weekends?

Calculate Working Hours Between 2 Dates in PostgreSQL

Problem Statement

Design an algorithm to compute working hours between two timestamps, considering that weekends are not working days and weekdays are counted from 8 am to 3 pm.

Solution

Step 1: Identify Working Hours per Day

Define working hours as weekdays from 8 am to 3 pm:

WITH WorkingHours AS (
  SELECT '08:00'::time AS start_time, '15:00'::time AS end_time
)

Step 2: Calculate Intervals for Each Day

Create a series of intervals for each day within the given date range:

SELECT t_id,
       generate_series(date_trunc('day', t_start), date_trunc('day', t_end), '1 day') AS day
FROM   t

Step 3: Compute Working Hours for Each Interval

Interpolate working hours for each day and compute fractional hours using the range type tsrange:

SELECT t_id,
       SUM(CASE
         WHEN EXTRACT(ISODOW FROM day) < 6 THEN
           COALESCE(
             f_worktime(day::timestamp + WorkingHours.start_time, day::timestamp + WorkingHours.end_time),
             '0'
           )
         ELSE
           '0'
       END) AS work_time
FROM   WorkingHours
CROSS JOIN (
  SELECT t_id, day
  FROM   temp
) AS temp
GROUP  BY 1

Step 4: Function to Calculate Fractional Hours

Define a function f_worktime to calculate fractional hours:

CREATE FUNCTION f_worktime(_start timestamp, _end timestamp)
RETURNS interval
LANGUAGE sql AS
$func$
SELECT COALESCE(upper(tsrange(_start::timestamp, _end::timestamp)) - lower(tsrange(_start::timestamp, _end::timestamp)), '0')::interval;
$func$
IMMUTABLE;

Example

WITH t AS (
  SELECT 0 AS t_id, '2023-05-01 09:00'::timestamp AS t_start, '2023-05-01 11:30'::timestamp AS t_end
UNION ALL
  SELECT 1, '2023-05-02 10:00'::timestamp, '2023-05-02 18:00'::timestamp
UNION ALL
  SELECT 2, '2023-05-03 09:15'::timestamp, '2023-05-04 10:45'::timestamp
)
SELECT t.t_id, extract(hour from work_time) AS working_hours
FROM   t
CROSS JOIN (
  SELECT t_id, SUM(CASE WHEN EXTRACT(ISODOW FROM day) < 6 THEN f_worktime(day::timestamp + WorkingHours.start_time, day::timestamp + WorkingHours.end_time) ELSE '0' END) AS work_time
  FROM   WorkingHours
  CROSS JOIN (
    SELECT t_id, day
    FROM   (
      SELECT t_id,
             generate_series(date_trunc('day', t_start), date_trunc('day', t_end), '1 day') AS day
      FROM   t
    ) AS temp
  ) AS temp
  GROUP  BY 1
) AS temp;

Output:

| t_id | working_hours |
|------|---------------|
|    0 |             3 |
|    1 |             8 |
|    2 |             3 |

The above is the detailed content of How to Calculate Working Hours Between Two Dates in PostgreSQL, Excluding Weekends?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn