Я бы сделал это с помощью простой логической логики:
SELECT *, (now() AT TIME ZONE a.timezone)::time AS local_time
FROM contact c INNER JOIN
account a
ON a.id = c.account_id
WHERE (EXTRACT(DOW FROM now() AT TIME ZONE a.timezone) IN (6, 0) AND
(now() AT TIME ZONE a.timezone)::time BETWEEN '15:30'::time AND '22:00'::time
) OR
(EXTRACT(DOW FROM now() AT TIME ZONE a.timezone) NOT IN (6, 0) AND
(now() AT TIME ZONE a.timezone)::time BETWEEN '17:30'::time AND '22:00'::time
);
Из-за повторения я мог бы склоняться сформулировать это следующим образом:
SELECT *, nowtz::time AS local_time
FROM (VALUES (now() AT TIME ZONE a.timezone)) v(nowtz) CROSS JOIN
contact c INNER JOIN
account a
ON a.id = c.account_id
WHERE (EXTRACT(DOW FROM nowtz) IN (6, 0) AND
(nowtz::time BETWEEN '15:30'::time AND '22:00'::time)
) OR
(EXTRACT(DOW FROM nowtz) NOT IN (6, 0) AND
(nowtz::time BETWEEN '17:30'::time AND '22:00'::time)
)
Логика WHERE
можетбыть упрощенным до:
WHERE (EXTRACT(DOW FROM nowtz) IN (6, 0) AND nowtz::time >= '15:30'::time OR
nowtz::time >= '17:30'::time
) AND
nowtz::time <= '22:00'::time