Sugeriría generar todos los rangos de horas de trabajo entre created_at
y current_timestamp y sumarlos. Si bien está lejos de ser una solución óptima en términos de rendimiento, creo que es el enfoque más directo. Uso la marca de tiempo con el rango de zona horaria rango tstz
con intersección operador (*)
.
SELECT id,
created_at,
SUM(upper(business_range) - lower(business_range) ) business_hours
FROM (
SELECT id,
created_at,
tstzrange(date_in_range + '09:00'::time with time zone, date_in_range + '17:00'::time with time zone)
* tstzrange(created_at, current_timestamp) as business_range
FROM (
SELECT id,
created_at,
created_at::date + generate_series(0, current_timestamp::date - created_at::date) as date_in_range
FROM times
) dates_in_range
WHERE date_part('dow', date_in_range) in (1,2,3,4,5)
) business_hour_ranges
GROUP BY
id,
created_at
Consulte la configuración y el ejemplo en db<>fiddle
Palabra de precaución
Si bien la implementación se hizo para que fuera fácil de entender y depurar, puede resultar en un rendimiento deficiente, especialmente si se usa con fechas created_at muy antiguas. Si ese es el caso en su sistema, es mejor que escriba una función que verifique el día de la semana de created_at y current_date, encuentre la cantidad de días entre ellos y determine las horas de trabajo.