I really dislike using procedural loops in SQL Server which is why I'm offering this alternative solution.
You can get the results you want by using a recursive CTE.
I created some test data with
CREATE TABLE TestLocation
(Id INT IDENTITY(1,1),[Time] NVARCHAR(50),Location NVARCHAR(50))
INSERT INTO TestLocation VALUES
('08:00','Test Location'),
('08:15','Test Location'),
('08:30','Test Location1'),
('08:45','Test Location1'),
('09:00','Test Location2')
It's similar to the data you presented in your question but I wanted to change the location values when testing my query.
This single query then gives you the results you wanted
;with CTE AS
(
SELECT cast([Time] AS Time) AS [Time], 1 as RLevel, Id, Location
FROM TestLocation
UNION ALL
SELECT CAST(dateadd(Minute, 5, [Time]) AS Time), RLevel + 1, Id, Location
FROM CTE
WHERE RLevel < 3
)
select Id, [Time], Location
from CTE
WHERE [Time] <= (SELECT MAX([Time]) FROM TestLocation)
order by [Time]
For every record in your original data this rCTE is creating more rows, the first adds 5 minutes onto the time and because this is recursive, the next row adds 5 minutes onto the new row.
Note this only works if the original data is in 15 minute intervals without any breaks.
The easiest way to list all of the times between 08:00 to 09:00 (inclusive) in 5 minute intervals is
;with CTE AS
(
SELECT CAST('08:00' AS Time) AS datum
UNION ALL
SELECT dateadd(Minute, 5, datum)
FROM CTE
WHERE dateadd(Minute, 5, datum) < dateadd(Minute, 65, CAST('08:00' AS Time))
)
select * from CTE