codice:
$dati[0]['id']=1;
$dati[0]['inizio']='2021-01-12 08:00:00';
$dati[0]['fine']='2021-01-12 08:30:00';


$dati[1]['id']=1;
$dati[1]['inizio']='2021-01-12 11:00:00';
$dati[1]['fine']='2021-01-12 11:10:00';


$dati[2]['id']=1;
$dati[2]['inizio']='2021-01-12 08:30:00';
$dati[2]['fine']='2021-01-12 08:40:00';


$dati[3]['id']=1;
$dati[3]['inizio']='2021-01-12 10:00:00';
$dati[3]['fine']='2021-01-12 11:00:00';
Metti la prima data di inizio e la prima data di fine in due variabili.
$i = inizio_1;
$f = fine_1;
Passi alla seconda data di inizio e la confronti con la prima data di fine.
Se è identica, questa seconda data di inizio diventa la "prima" e prosegui con il terzo gruppo.
if inizio_2 == $f -> $f = fine_2;
Se è diversa, è un altro "intervallo" e ricominci il ciclo "scartando" il primo e il secondo gruppo (dati[0] e dati[1]) o comunque scartando fin dove sei arrivato, così da iniziare da questa accoppiata che "non c'entra nulla con quanto iniziato".
Teoricamente dovrebbe funzionare, tutto sta nel come scriverlo :-D
Il problema può sorgere nel caso in cui, ad esempio, tu abbia qualcosa di questo genere
codice:
$dati[0]['id']=1;
$dati[0]['inizio']='2021-01-12 08:00:00';
$dati[0]['fine']='2021-01-12 08:30:00';


$dati[1]['id']=1;
$dati[1]['inizio']='2021-01-12 08:40:00';
$dati[1]['fine']='2021-01-12 09:10:00';


$dati[2]['id']=1;
$dati[2]['inizio']='2021-01-12 08:30:00';
$dati[2]['fine']='2021-01-12 08:40:00';


$dati[3]['id']=1;
$dati[3]['inizio']='2021-01-12 10:00:00';
$dati[3]['fine']='2021-01-12 11:00:00';
In questo caso dati[1] è consecutivo a dati[2] ma verrebbe scartato dall'approccio di cui sopra. Il rimedio potrebbe essere un sorting degli array in base alla data inizio, ovvero usando il array_multisort (la doc di Php ha un esempio molto simile al tuo caso) oppure con array_walk (doc di php ancora una volta in aiuto)