Aggregate rows for each group of rows
You can use status to set groups, and then get min and max time of each group.
If there is a serial id (PK), and it can be used to set an order, maybe you can get a better performance.
Due each intermediate status=0 belongs to two groups, I've added a new column with the time of the next row to get max(time).
with ev as
(
  select
      time, status,
      lead(time) over (order by time) as next_time,
      sum(case when status = 0 then 1 else 0 end) over (order by id) as grp
  from
      event
)
select 
    min(time) as min_time,
    max(next_time) as max_time,
    array_agg(row(time, status)) filter (where status &lt;&gt; 0) as events
from 
    ev
group by
    grp
order by
    grp;



min_time | max_time | events                                        
:------- | :------- | :---------------------------------------------
12:00:00 | 16:00:00 | {&quot;(13:00:00,8)&quot;,&quot;(14:00:00,4)&quot;,&quot;(15:00:00,2)&quot;}
16:00:00 | 20:00:00 | {&quot;(17:00:00,9)&quot;,&quot;(18:00:00,5)&quot;,&quot;(19:00:00,8)&quot;}
20:00:00 | 23:00:00 | {&quot;(21:00:00,1)&quot;,&quot;(22:00:00,3)&quot;}               
23:00:00 | null     | null                                          


db&lt;&gt;fiddle here