Sugiro gerar todos os intervalos de horário comercial entre
created_at
e current_timestamp e somando-os. Embora esteja longe de ser a solução ideal em termos de desempenho, acho que é a abordagem mais direta. Uso timestamp com intervalo de fuso horário tstzrange
com interseção 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
Veja a configuração e o exemplo em db<>fiddle
Palavra de cautela
Embora a implementação tenha sido feita para ser fácil de entender e depurar, ela pode resultar em desempenho ruim - especialmente se usada com datas created_at muito antigas. Se esse for o caso em seu sistema, talvez seja melhor escrever uma função que verifique o dia da semana do created_at e current_date, encontre o número de dias entre eles e determine as horas de trabalho.