Just minutes by hour

I have two fields in the data table - "startTime" and "endTime". These two fields represent the length of time spent by the user on a specific task. These are varchar fields. So, let's say we have startTime from "21:05:00" and endTime "22:09:00". I need a code to summarize the total number of minutes spent per hour 21 and 22 hundred hours separately (i.e. 9 minutes). So, not just a small minute, but the breakdown of the clock.

What could be the best way to do this?

So far I have created a table that will return all possible hours within 24 hours. Here's a sample:

Hour    startTime                endTime
0       2015-01-01 00:00:00.000  2015-01-01 01:00:00.000
1       2015-01-01 01:00:00.000  2015-01-01 02:00:00.000
2       2015-01-01 02:00:00.000  2015-01-01 03:00:00.000

And I converted the startTime field from varchar to dateteime and called it sessionHour:

Convert(datetime, startTime) As sessionHour

In addition, I was able to get the startTime hour by doing:

DateAdd(Minute, 60 * (DateDiff(Minute, 0, startTime) / 60), 0)  As hourOf

, , .

+4
3

. . CROSS APPLY. SQLFiddle .

DECLARE @Durations TABLE (ID int IDENTITY(1,1), StartTime datetime, EndTime datetime);

INSERT INTO @Durations VALUES
('2015-01-01 21:05:00', '2015-01-01 22:09:00'),
('2015-01-01 01:05:00', '2015-01-01 01:20:00'),
('2015-01-01 11:05:00', '2015-01-01 13:09:00'),
('2015-01-01 15:05:00', '2015-01-01 17:50:00'),
('2015-01-01 16:30:00', '2015-01-01 17:20:00');

datetime , varchar datetime.

. , . 24. ​​ .

DECLARE @Numbers TABLE (Number int);
INSERT INTO @Numbers VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
-- Number of rows in this table should be more than the longest duration in hours

datetime. -, .

DECLARE @VarStart datetime;
SET @VarStart = '2000-01-01';

-

SELECT *
FROM
    @Durations AS D
    CROSS APPLY
    (
        SELECT N.Number
        FROM @Numbers AS N
        WHERE N.Number <= DATEDIFF(hour, StartTime, EndTime)
    ) AS CA_Number
ORDER BY ID;

ID   StartTime              EndTime                Number
1    2015-01-01 21:05:00    2015-01-01 22:09:00    0
1    2015-01-01 21:05:00    2015-01-01 22:09:00    1
2    2015-01-01 01:05:00    2015-01-01 01:20:00    0
3    2015-01-01 11:05:00    2015-01-01 13:09:00    0
3    2015-01-01 11:05:00    2015-01-01 13:09:00    1
3    2015-01-01 11:05:00    2015-01-01 13:09:00    2
4    2015-01-01 15:05:00    2015-01-01 17:50:00    0
4    2015-01-01 15:05:00    2015-01-01 17:50:00    1
4    2015-01-01 15:05:00    2015-01-01 17:50:00    2
5    2015-01-01 16:30:00    2015-01-01 17:20:00    0
5    2015-01-01 16:30:00    2015-01-01 17:20:00    1

, . - .

SELECT *
    ,DATEDIFF(minute, MaxStart, MinEnd) AS MinutesPerHour
FROM
    @Durations AS D
    CROSS APPLY
    (
        SELECT N.Number
        FROM @Numbers AS N
        WHERE N.Number <= DATEDIFF(hour, StartTime, EndTime)
    ) AS CA_Number
    CROSS APPLY
    (
        SELECT
            DATEADD(hour, CA_Number.Number, StartTime) AS HourStart
            ,DATEADD(hour, CA_Number.Number+1, StartTime) AS HourEnd
    ) AS CA_HourEnd
    CROSS APPLY
    (
        -- Truncate to 1 hour.
        SELECT
            DATEADD(hour, DATEDIFF(hour, @VarStart, HourStart), @VarStart) AS HourStartFinal
            ,DATEADD(hour, DATEDIFF(hour, @VarStart, HourEnd), @VarStart) AS HourEndFinal
    ) AS CA_HourEndFinal
    -- Intersect intervals [StartTime, EndTime] with [HourStartFinal, HourEndFinal]
    CROSS APPLY
    (
        SELECT
            CASE WHEN StartTime > HourStartFinal THEN StartTime ELSE HourStartFinal END AS MaxStart
            ,CASE WHEN EndTime < HourEndFinal THEN EndTime ELSE HourEndFinal END AS MinEnd
    ) AS CA_Intersect
ORDER BY ID;

CA_HourEnd CA_HourEndFinal Number. . :

ID   StartTime              EndTime                Number    HourStart              HourEnd                HourStartFinal         HourEndFinal           MaxStart               MinEnd                 MinutesPerHour
1    2015-01-01 21:05:00    2015-01-01 22:09:00    0         2015-01-01 21:05:00    2015-01-01 22:05:00    2015-01-01 21:00:00    2015-01-01 22:00:00    2015-01-01 21:05:00    2015-01-01 22:00:00    55
1    2015-01-01 21:05:00    2015-01-01 22:09:00    1         2015-01-01 22:05:00    2015-01-01 23:05:00    2015-01-01 22:00:00    2015-01-01 23:00:00    2015-01-01 22:00:00    2015-01-01 22:09:00    9
2    2015-01-01 01:05:00    2015-01-01 01:20:00    0         2015-01-01 01:05:00    2015-01-01 02:05:00    2015-01-01 01:00:00    2015-01-01 02:00:00    2015-01-01 01:05:00    2015-01-01 01:20:00    15
3    2015-01-01 11:05:00    2015-01-01 13:09:00    0         2015-01-01 11:05:00    2015-01-01 12:05:00    2015-01-01 11:00:00    2015-01-01 12:00:00    2015-01-01 11:05:00    2015-01-01 12:00:00    55
3    2015-01-01 11:05:00    2015-01-01 13:09:00    1         2015-01-01 12:05:00    2015-01-01 13:05:00    2015-01-01 12:00:00    2015-01-01 13:00:00    2015-01-01 12:00:00    2015-01-01 13:00:00    60
3    2015-01-01 11:05:00    2015-01-01 13:09:00    2         2015-01-01 13:05:00    2015-01-01 14:05:00    2015-01-01 13:00:00    2015-01-01 14:00:00    2015-01-01 13:00:00    2015-01-01 13:09:00    9
4    2015-01-01 15:05:00    2015-01-01 17:50:00    0         2015-01-01 15:05:00    2015-01-01 16:05:00    2015-01-01 15:00:00    2015-01-01 16:00:00    2015-01-01 15:05:00    2015-01-01 16:00:00    55
4    2015-01-01 15:05:00    2015-01-01 17:50:00    1         2015-01-01 16:05:00    2015-01-01 17:05:00    2015-01-01 16:00:00    2015-01-01 17:00:00    2015-01-01 16:00:00    2015-01-01 17:00:00    60
4    2015-01-01 15:05:00    2015-01-01 17:50:00    2         2015-01-01 17:05:00    2015-01-01 18:05:00    2015-01-01 17:00:00    2015-01-01 18:00:00    2015-01-01 17:00:00    2015-01-01 17:50:00    50
5    2015-01-01 16:30:00    2015-01-01 17:20:00    0         2015-01-01 16:30:00    2015-01-01 17:30:00    2015-01-01 16:00:00    2015-01-01 17:00:00    2015-01-01 16:30:00    2015-01-01 17:00:00    30
5    2015-01-01 16:30:00    2015-01-01 17:20:00    1         2015-01-01 17:30:00    2015-01-01 18:30:00    2015-01-01 17:00:00    2015-01-01 18:00:00    2015-01-01 17:00:00    2015-01-01 17:20:00    20

, :

SELECT
    HourStartFinal
    ,SUM(DATEDIFF(minute, MaxStart, MinEnd)) AS SumMinutesPerHour
FROM
    @Durations AS D
    CROSS APPLY
    (
        SELECT N.Number
        FROM @Numbers AS N
        WHERE N.Number <= DATEDIFF(hour, StartTime, EndTime)
    ) AS CA_Number
    CROSS APPLY
    (
        SELECT
            DATEADD(hour, CA_Number.Number, StartTime) AS HourStart
            ,DATEADD(hour, CA_Number.Number+1, StartTime) AS HourEnd
    ) AS CA_HourEnd
    CROSS APPLY
    (
        -- Truncate to 1 hour.
        SELECT
            DATEADD(hour, DATEDIFF(hour, @VarStart, HourStart), @VarStart) AS HourStartFinal
            ,DATEADD(hour, DATEDIFF(hour, @VarStart, HourEnd), @VarStart) AS HourEndFinal
    ) AS CA_HourEndFinal
    -- Intersect intervals [StartTime, EndTime] with [HourStartFinal, HourEndFinal]
    CROSS APPLY
    (
        SELECT
            CASE WHEN StartTime > HourStartFinal THEN StartTime ELSE HourStartFinal END AS MaxStart
            ,CASE WHEN EndTime < HourEndFinal THEN EndTime ELSE HourEndFinal END AS MinEnd
    ) AS CA_Intersect
GROUP BY HourStartFinal
ORDER BY HourStartFinal;

HourStartFinal             SumMinutesPerHour
2015-01-01 01:00:00.000    15
2015-01-01 11:00:00.000    55
2015-01-01 12:00:00.000    60
2015-01-01 13:00:00.000    9
2015-01-01 15:00:00.000    55
2015-01-01 16:00:00.000    90
2015-01-01 17:00:00.000    70
2015-01-01 21:00:00.000    55
2015-01-01 22:00:00.000    9

SQLFiddle

+2

, CROSS APPLY.

, , starttime endtime, , minutediff , 60.

, - .

DECLARE @UserTask TABLE (ID int IDENTITY(1,1),UserID INT,TaskID INT, StartTime datetime, EndTime datetime);

INSERT INTO @UserTask VALUES
(1,1,'2015-01-01 21:05:00', '2015-01-01 22:09:00'),
(1,1,'2015-01-01 01:05:00', '2015-01-01 01:20:00'),
(1,1,'2015-01-01 11:05:00', '2015-01-01 13:09:00'),
(1,1,'2015-01-01 15:05:00', '2015-01-01 17:50:00'),
(1,1,'2015-01-01 16:30:00', '2015-01-01 17:20:00'),
(2,2,'2015-01-01 21:05:00', '2015-01-01 22:09:00');

;WITH CTENum AS 
(
SELECT 1 rn UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
), CTEHours as 
(
SELECT TOP 24 ROW_NUMBER()OVER(ORDER BY c1.rn) - 1 rn FROM CTENum c1 CROSS JOIN CTENum c2
)
SELECT ID,UserID,TaskID,StartTime,EndTime,rn as DayHour,
CASE WHEN r_asc = 1 AND r_desc = 1 THEN DATEDIFF(minute,StartTime,EndTime) 
WHEN r_asc = 1 THEN 60 - DATEPART(minute,StartTime)
WHEN r_desc = 1 THEN DATEPART(minute,EndTime)
ELSE 60 END MinuteTime
FROM @UserTask
CROSS APPLY(
SELECT *,ROW_NUMBER()OVER(ORDER BY rn ASC) r_asc,ROW_NUMBER()OVER(ORDER BY rn DESC) r_desc
FROM CTEHours C
WHERE C.rn BETWEEN DATEDIFF(hour,CONVERT(VARCHAR(10),StartTime,112),StartTime) AND DATEDIFF(hour,CONVERT(VARCHAR(10),StartTime,112),EndTime)
) N
ORDER BY ID,DayHour
+1

You might want to look into the function datepart(), this will help you to manipulate your dates more efficiently. For instance:

select @endOfHour = dateadd(hour,
    1,
    datetimefromparts(
        datepart(year, @startTime),
        datepart(month, @startTime),
        datepart(day, @startTime),
        datepart(hour, @startTime),
        0,
        0,
        0));


select h.theHour, @startTime, @endOfHour, datediff(minute, @startTime, @endOfHour)
from ListOfHours as h
where datepart(hour, @startTime) = h.Hour;
0
source

All Articles