Aquí hay una solución solo de SQL. Usé DATETIME para las columnas. Almacenar la hora por separado es un error en mi opinión, ya que tendrás problemas cuando las horas pasen de la medianoche. Sin embargo, puede ajustar esto para manejar esa situación si es necesario. La solución también supone que las horas de inicio y finalización NO SON NULAS. Nuevamente, puede ajustar según sea necesario si ese no es el caso.
La esencia general de la solución es obtener todas las horas de inicio que no se superponen con ningún otro período, obtener todas las horas de finalización que no se superponen con ningún período y luego unirlas.
Los resultados coinciden con sus resultados esperados, excepto en un caso, en el que al verificar a mano parece que tiene un error en su salida esperada. El día 6 debe haber un intervalo que termine en 2009-06-06 10:18:45.000.
SELECT
ST.start_time,
ET.end_time
FROM
(
SELECT
T1.start_time
FROM
dbo.Test_Time_Spans T1
LEFT OUTER JOIN dbo.Test_Time_Spans T2 ON
T2.start_time < T1.start_time AND
T2.end_time >= T1.start_time
WHERE
T2.start_time IS NULL
) AS ST
INNER JOIN
(
SELECT
T3.end_time
FROM
dbo.Test_Time_Spans T3
LEFT OUTER JOIN dbo.Test_Time_Spans T4 ON
T4.end_time > T3.end_time AND
T4.start_time <= T3.end_time
WHERE
T4.start_time IS NULL
) AS ET ON
ET.end_time > ST.start_time
LEFT OUTER JOIN
(
SELECT
T5.end_time
FROM
dbo.Test_Time_Spans T5
LEFT OUTER JOIN dbo.Test_Time_Spans T6 ON
T6.end_time > T5.end_time AND
T6.start_time <= T5.end_time
WHERE
T6.start_time IS NULL
) AS ET2 ON
ET2.end_time > ST.start_time AND
ET2.end_time < ET.end_time
WHERE
ET2.end_time IS NULL