Measure time duration between events, partitioned by hours
This is more sophisticated than I first understood. One way to handle it is with generate-series(), range types and associated functions and operators:

SELECT user_id, hour, sum(upper(min_on) - lower(min_on)) AS minutes_on
FROM  (
   SELECT user_id, hour, u.range * h.range AS min_on
   FROM  (
      SELECT hour, tsrange(hour, hour + interval '1h') AS range
      FROM   generate_series('2015-10-07 00:00'::timestamp  -- defines range of interest
                           , '2015-10-08 03:00'::timestamp  -- cut off the rest
                           , interval '1h') hour
      ) h
   JOIN  (
      SELECT user_id, event_type
           , tsrange(created_at
                   , lead(created_at) OVER (PARTITION BY user_id ORDER BY created_at)
                    ) AS range
      FROM   user_online_offline_events
      -- add WHERE conditions to limit selection
      -- careful with cutting off leading "on" / trailing "off" events
      ) u ON u.event_type = 1 AND u.range &amp;&amp; h.range
   ) sub
GROUP  BY  user_id, hour
ORDER  BY  user_id, hour;


SQL Fiddle with extended data.

Major points


Define the outer time frame in generate_series() once. The function generates one row per hour.
Minutes per hours of the day in multiple days are summed up - if the outer time frame spans multiple days.
Hours without any online time are not in the result. If you need that use LEFT JOIN instead of JOIN
Using the overlap operator &amp;&amp; for ranges to identify matching hours and the intersection operator * to calculate actual overlaps.
Resulting times are given as interval. Since multiple days might be summed, the result can be more than one hour and a simple EXTRACT() would not capture that. You can extract minutes  as integer number this way:

EXTRACT('epoch' FROM sum(upper(min_on) - lower(min_on))) / 60 AS minutes_on

Basic timestamp ranges are computed naively with the window function lead(). This assumes that every log-on is followed by a log-off, which typically misses special cases:


Multiple log-on / log-off events for the same user in a row
No matching log-on / log-off


You need to define exactly which corner cases can exist and how you want to handle them. There is a solution either way.