Make a dimension called Dim_Hours and do a cross join with the table that contains begin and end timestamps.
use the above explanation to write your SQL
WITH TEMP AS
(SELECT [ID] ,
[On_DateTime] ,
[Off_DateTime] ,
[On_Duration_Minutes] ,
dh.Hour_Number
FROM [dbo].[tableWithData] f
CROSS JOIN dim_Hour dh
WHERE 1=1 )--when -ve and hour part matches start of hour
SELECT t.*,
[On_DateTime],
dateadd(HOUR, datediff(HOUR, 0, dateadd(mi, 60, [On_DateTime])), 0),
DATEDIFF(SECOND, [On_DateTime], dateadd(HOUR, datediff(HOUR, 0, dateadd(mi, 60, [On_DateTime])), 0))/60.0 on_Duration_minutes_Derived
FROM TEMP t
WHERE 1=1
AND datepart(HH, [On_DateTime]) - datepart(HH, [Off_DateTime]) <= -1
AND t.Hour_Number =datepart(HH, [On_DateTime])
UNION --when -ve and hour part matches end of hour
SELECT t.*,
dateadd(HOUR, datediff(HOUR, 0, [Off_DateTime]), 0),
[Off_DateTime],
DATEDIFF(SECOND, dateadd(HOUR, datediff(HOUR, 0, [Off_DateTime]), 0), [Off_DateTime])/60.0 on_Duration_minutes_Derived
FROM TEMP t
WHERE 1=1
AND datepart(HH, [On_DateTime]) - datepart(HH, [Off_DateTime]) <= -1
AND t.Hour_Number =datepart(HH, [Off_DateTime])
UNION --when -ve and hour part between start and end of hour excludint boundries
SELECT t.*,
dateadd(HOUR, datediff(HOUR, 0, [Off_DateTime]), 0),
[Off_DateTime],
60.00 on_Duration_minutes_Derived
FROM TEMP t
WHERE 1=1
AND datepart(HH, [On_DateTime]) - datepart(HH, [Off_DateTime]) <= -1
AND t.Hour_Number >datepart(HH, [On_DateTime])
AND t.Hour_Number< datepart(HH, [Off_DateTime])
UNION --when 0 and hour part matches with start/end
SELECT t.*,
dateadd(HOUR, datediff(HOUR, 0, [Off_DateTime]), 0),
[Off_DateTime],
CASE
WHEN on_Duration_minutes<0 THEN 0
ELSE on_Duration_minutes
END on_Duration_minutes_Derived
FROM TEMP t
WHERE 1=1
AND datepart(HH, [On_DateTime]) - datepart(HH, [Off_DateTime]) = 0
AND t.Hour_Number=datepart(HH, [On_DateTime])
UNION --when +ve and hour part matches start of hour
SELECT t.*,
[On_DateTime],
dateadd(HOUR, datediff(HOUR, 0, dateadd(mi, 60, [On_DateTime])), 0),
DATEDIFF(SECOND, [On_DateTime], dateadd(HOUR, datediff(HOUR, 0, dateadd(mi, 60, [On_DateTime])), 0))/60.0 on_Duration_minutes_Derived
FROM TEMP t
WHERE 1=1
AND datepart(HH, [On_DateTime]) - datepart(HH, [Off_DateTime]) >= 1
AND t.Hour_Number =datepart(HH, [On_DateTime])
UNION --when +ve and hour part matches end of hour
SELECT t.*,
dateadd(HOUR, datediff(HOUR, 0, [Off_DateTime]), 0),
[Off_DateTime],
DATEDIFF(SECOND, dateadd(HOUR, datediff(HOUR, 0, [Off_DateTime]), 0), [Off_DateTime])/60.0 on_Duration_minutes_Derived
FROM TEMP t
WHERE 1=1
AND datepart(HH, [On_DateTime]) - datepart(HH, [Off_DateTime]) >= 1
AND t.Hour_Number =datepart(HH, [Off_DateTime])
UNION --when +ve and hour part between start of hour and end of hour
SELECT t.*,
dateadd(HOUR, datediff(HOUR, 0, [Off_DateTime]), 0),
[Off_DateTime],
60.00 on_Duration_minutes_Derived
FROM TEMP t
WHERE 1=1
AND datepart(HH, [On_DateTime]) - datepart(HH, [Off_DateTime]) >= 1
AND t.Hour_Number!=datepart(HH, [On_DateTime])
AND t.Hour_Number!=datepart(HH, [Off_DateTime])
AND (t.Hour_Number <datepart(HH, [Off_DateTime])
OR t.Hour_Number > datepart(HH, [On_DateTime]))
ORDER BY 2,
3,
4