Бих предложил да генерирате всички диапазони от работно време между created_at
и current_timestamp и сумирането им. Въпреки че е далеч от оптималното решение по отношение на производителността, мисля, че това е най-правият подход. Използвам клеймо за време с обхват на часовата зона tstzrange
с пресичане оператор (*)
.
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
Вижте настройката и примера в db<>fiddle
Внимание
Въпреки че внедряването е направено така, че да бъде лесно за разбиране и отстраняване на грешки, това може да доведе до лоша производителност - особено ако се използва с много стари дати created_at. Ако това може да е така във вашата система, може би е по-добре да напишете функция, която проверява деня от седмицата на created_at и current_date, намира броя на дните между тях и определя работното време.