Речь идет не о "пропастях и островах". Этот метод работает с группами с последовательными значениями констант некоторого поля, но вам нужно работать с границами таких групп. Итак:
create table state_log(timestamp timestamp, object_id int, state boolean, level int);
insert into state_log values
('2018-01-01 00:00:01', 123, 'f', 100),
('2018-01-02 00:00:02', 123, 't', 100),
('2018-01-02 00:00:03', 123, 'f', 100),
('2018-01-03 00:00:04', 123, 'f', 100),
('2018-01-03 00:00:05', 123, 'f', 100),
('2018-01-06 00:00:06', 123, 't', 90),
('2018-01-07 00:00:07', 123, 't', 90),
('2018-01-08 00:00:08', 123, 'f', 90);
select
timestamp::date as start,
coalesce(lead(timestamp) over (order by timestamp), now()::timestamp)::date as end,
object_id, state, level
from (
select
*,
coalesce(lag(state) over (order by timestamp) <> state, true) as is_new_group
from state_log) as t
where
object_id = 123 and timestamp >= date '2018-01-01' and
is_new_group
order by timestamp;
Результат (я удаляю часть времени, чтобы сделать ее более похожей на результат, указанный в вопросе):
┌────────────┬────────────┬───────────┬───────┬───────┐
│ start │ end │ object_id │ state │ level │
├────────────┼────────────┼───────────┼───────┼───────┤
│ 2018-01-01 │ 2018-01-02 │ 123 │ f │ 100 │
│ 2018-01-02 │ 2018-01-02 │ 123 │ t │ 100 │
│ 2018-01-02 │ 2018-01-06 │ 123 │ f │ 100 │
│ 2018-01-06 │ 2018-01-08 │ 123 │ t │ 90 │
│ 2018-01-08 │ 2018-08-30 │ 123 │ f │ 90 │
└────────────┴────────────┴───────────┴───────┴───────┘