This is a bit complicated. First you need the time of the next event for each entry. The following subquery adds over the next time if it is within the bounds:
select t.*, (select event_date from t t2 where t2.item_id = t.item_id and t2.event_date > t.event_date and <date comparison here> order by event_date limit 1 ) as nexted from t
The correlated subquery is used here. <date comparison here> is for any date matching. When there is no entry, the value will be NULL.
Now, with this information ( nexted ) there is a trick to get grouping. For any record, this is the first event after which nexted is NULL. This will be the last event in the series. Unfortunately, this requires two levels of nested correlated subqueries (or aggregation with aggregations). The result looks a bit cumbersome:
select item_id, GROUPING, MIN(event_date) as start_date, MAX(event_date) as end_date, COUNT(*) as num_dates from (select t.*, (select min(t2.event_date) from (select t1.*, (select event_date from t t2 where t2.item_id = t1.item_id and t2.event_date > t1.event_date and <date comparison here> order by event_date limit 1 ) as nexted from t1 ) t2 where t2.nexted is null ) as grouping from t ) s group by item_id, grouping;
source share