Looks a bit messy, but I belive it'll work for your situation:
with cte_tally
as (select row_number() over(order by (select null))-1 as n
from (values(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) as cte_tally1(n) /* 12 hours */
/*****
* uncomment one line at the time, if above hour range is too small
cross apply (values(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) as cte_tally2(n) /* 144 hours = 6 days */
cross apply (values(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) as cte_tally3(n) /* 1728 hours = 72 days ~= 2½ months */
*
*****/
)
select a.[description]
,cast(dateadd(hour,b.n,a.[start date]) as date) as [date]
,datepart(hour,dateadd(hour,b.n,a.[start date])) as hour
,datediff(second
,case
when b.n=0
then a.[start date]
else dateadd(hour,datediff(hour,0,a.[start date])+b.n,0)
end
,case
when dateadd(hour,b.n+1,a.[start date])>=a.[end date]
then a.[end date]
else dateadd(hour,datediff(hour,0,a.[start date])+b.n+1,0)
end
)
as [duration(secs)]
,datediff(second
,case
when b.n=0
then a.[start date]
else dateadd(hour,datediff(hour,0,a.[start date])+b.n,0)
end
,case
when dateadd(hour,b.n+1,a.[start date])>=a.[end date]
then a.[end date]
else dateadd(hour,datediff(hour,0,a.[start date])+b.n+1,0)
end
)
/60.0
as [duration(min)]
from #yourtable as a
inner join cte_tally as b
on b.n<=datediff(hour,a.[start date],a.[end date])
order by a.[description]
,a.[start date]
,b.n
;