Je suggérerais de générer toutes les plages d'heures d'ouverture entre created_at
et current_timestamp et en les additionnant. Bien qu'il soit loin d'être une solution optimale en termes de performances, je pense que c'est l'approche la plus simple. J'utilise l'horodatage avec la plage de fuseau horaire /docs/current/rangetypes.html#RANGETYPES-BUILTIN">tstzrange
avec intersection opérateur (*)
.
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
Voir la configuration et l'exemple dans db<>fiddle
Mise en garde
Bien que l'implémentation ait été conçue pour être facile à comprendre et à déboguer, elle peut entraîner des performances médiocres, en particulier si elle est utilisée avec de très anciennes dates created_at. Si tel est le cas dans votre système, vous feriez peut-être mieux d'écrire une fonction qui vérifie le jour de la semaine de created_at et current_date, trouve le nombre de jours entre eux et détermine les heures de travail.