Navrhoval bych vygenerovat všechny rozsahy pracovní doby mezi created_at
a aktuální_časové razítko a jejich sečtením. I když to není zdaleka optimální řešení z hlediska výkonu, myslím, že je to nejpřímější přístup. Používám časové razítko s rozsahem časového pásma rozsah tstz
s křižovatkou operátor (*)
.
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
Viz nastavení a příklad v db<>fiddle
Upozornění
I když byla implementace navržena tak, aby byla snadno srozumitelná a laditelná, může mít za následek špatný výkon – zejména při použití s velmi starými daty created_at. Pokud to tak může být ve vašem systému, může být lepší napsat funkci, která zkontroluje den v týdnu v created_at a current_date, zjistí počet dní mezi nimi a určí pracovní hodiny.