MSSQL Start and End Time Grouped by 10 Minute, for Elapsed Time

I need to take a start and end time that is already summarized in one row, and break it out into 10 minute window with the total time between.

Example of summary row.

    StartDowntime   |    EndDowntime    | ElapsedSecs
    =================================================
    1/17/2022 8:00  |    1/17/2022 9:05 |   3900

Desired output.

    Datetime        |    ElapsedSeconds  
    ===================================
    1/17/2022 8:00  |    600
    1/17/2022 8:10  |    600
    1/17/2022 8:20  |    600
    1/17/2022 8:30  |    600
    1/17/2022 8:40  |    600
    1/17/2022 8:50  |    600
    1/17/2022 9:00  |    300
    1/17/2022 9:10  |    0
    1/17/2022 9:20  |    0

What I've tried.

     ;with cte as 
        (select MIN(StartDowntime) as MinDate
              , MAX(StartDowntime) as MaxDate
              , convert(varchar(14),StartDowntime, 120) as StartDate
              , DATEPART(minute, StartDowntime) /15 as GroupID
              , avg(ElapsedSecs) as AvgAmount
         from tblOKDryerDowntime
          where StartDowntime >= '1/1/2022 7:00' and EndDowntime <= '1/17/2022 8:00'
         group by convert(varchar(14),StartDowntime, 120)
             , DATEPART(minute, StartDowntime) /15
             , Dryer,DowntimeCode)
             
    select dateadd(minute, 15*GroupID, CONVERT(datetime,StartDate+'00'))
             as [Start Date]
           , AvgAmount as [Average Amount]
      from cte
      order by [Start Date] desc

This gives me elapsed by start on the closest 15th minute.
But doesn't stop every 15 minutes.


Solution 1:

Discover the magic of a recursive CTE.

;WITH RCTE AS (
    SELECT 
      StartDowntime AS DownDatetime
    , 600 AS ElapsedSeconds
    , ElapsedSecs AS RemainingSeconds
    , EndDowntime
    , 1 AS Lvl
    FROM tblOKDryerDowntime
    
    UNION ALL
    
    SELECT
      DATEADD(second, ElapsedSeconds, DownDatetime)
    , iif(RemainingSeconds > ElapsedSeconds, 600, RemainingSeconds) 
    , iif(RemainingSeconds > ElapsedSeconds, RemainingSeconds - ElapsedSeconds, 0) 
    , EndDowntime
    , Lvl + 1
    FROM RCTE
    WHERE DownDatetime < EndDowntime
      AND RemainingSeconds > 0
)
SELECT DownDatetime, ElapsedSeconds
FROM RCTE
ORDER BY DownDatetime;
DownDatetime            | ElapsedSeconds
:---------------------- | -------------:
2022-01-17 08:00:00.000 |            600
2022-01-17 08:10:00.000 |            600
2022-01-17 08:20:00.000 |            600
2022-01-17 08:30:00.000 |            600
2022-01-17 08:40:00.000 |            600
2022-01-17 08:50:00.000 |            600
2022-01-17 09:00:00.000 |            600
2022-01-17 09:10:00.000 |            300

Demo on db<>fiddle here