Reputation: 2928
I have this example data set
ShiftDate Description StartTime EndTime IsWorkShift
2014-01-01 Day Shift 2013-12-31 21:00:00.000 2014-01-01 09:00:00.000 1
2014-01-01 Night Shift 2014-01-01 09:00:00.000 2014-01-01 21:00:00.000 0
2014-01-02 Day Shift 2014-01-01 21:00:00.000 2014-01-02 09:00:00.000 1
2014-01-02 Night Shift 2014-01-02 09:00:00.000 2014-01-02 21:00:00.000 0
2014-01-03 Day Shift 2014-01-02 21:00:00.000 2014-01-03 09:00:00.000 1
2014-01-03 Night Shift 2014-01-03 09:00:00.000 2014-01-03 21:00:00.000 0
2014-01-04 Day Shift 2014-01-03 21:00:00.000 2014-01-04 09:00:00.000 1
2014-01-04 Night Shift 2014-01-04 09:00:00.000 2014-01-04 21:00:00.000 0
2014-01-05 Day Shift 2014-01-04 21:00:00.000 2014-01-05 09:00:00.000 1
2014-01-05 Night Shift 2014-01-05 09:00:00.000 2014-01-05 21:00:00.000 0
I need to work out the EndTime given a StartTime and a Duration
For example If I supply a StartTime of "2014-01-01 21:00:00.000" and Duration of 24 hours
I would need "2014-01-03 09:00:00.000" returned as the EndTime
2014-01-02 Day Shift 12 Working Hours
2014-01-02 Night Shift 0 Working Hours
2014-01-03 Day Shift 12 Working Hours
I have got this working with a cursor but when I need to use it for say 50 calculations, it gets quite slow.
ALTER FUNCTION [Maintenance].[CalendarDuration]
(
@ServerID INT,
@UTCStartTime DATETIME,
@WorkingDuration INT
)
RETURNS int
AS
BEGIN
DECLARE @UTCEndTime as Datetime;
DECLARE @ShiftStartTime as datetime, @ShiftEndTime as datetime;
DECLARE @ShiftDuration as int;
DECLARE ShiftCursor CURSOR FAST_FORWARD
FOR SELECT t1.StartTime, t1.EndTime
FROM config.WorkingDayShiftPatterns t1
WHERE
t1.ServerID = @ServerID
AND t1.EndTime > @UTCStartTime
AND t1.IsWorkShift = 1
ORDER BY t1.StartTime;
OPEN ShiftCursor;
FETCH NEXT FROM ShiftCursor
INTO @ShiftStartTime, @ShiftEndTime;
WHILE @@FETCH_STATUS = 0
BEGIN
IF @ShiftStartTime < @UTCStartTime
SET @ShiftStartTime = @UTCStartTime;
SET @ShiftDuration = DATEDIFF(minute, @ShiftStartTime, @ShiftEndTime);
IF @ShiftDuration >= @WorkingDuration
BEGIN
SET @UTCEndTime = DATEADD(minute, @WorkingDuration, @ShiftStartTime);
BREAK;
END
ELSE
SET @WorkingDuration = @WorkingDuration - @ShiftDuration;
FETCH NEXT FROM ShiftCursor
INTO @ShiftStartTime, @ShiftEndTime;
END
CLOSE ShiftCursor;
DEALLOCATE ShiftCursor;
RETURN DATEDIFF(minute, @UTCStartTime, @UTCEndTime);
END
Upvotes: 0
Views: 484
Reputation: 181007
A common table expression can find the number of hours left at each shift's end, so that you easily can pick out the shift where the last hour is worked;
DECLARE @UTCStartTime DATETIME = '2014-01-01 21:00:00.000';
DECLARE @WorkingDuration INT = 24;
WITH WorkingShifts AS (
SELECT CASE WHEN @UTCStartTime<StartTime
THEN StartTime ELSE @UTCStartTime END StartTime, EndTime,
@WorkingDuration -
SUM(DATEDIFF(HH, CASE WHEN @UTCStartTime<StartTime
THEN StartTime ELSE @UTCStartTime
END, EndTime))
OVER (ORDER BY StartTime) left_after_shift
FROM WorkingDayShiftPatterns
WHERE IsWorkShift=1 AND EndTime >= @UTCStartTime
)
SELECT TOP 1 DATEADD(HH, left_after_shift, EndTime) done_at
FROM WorkingShifts
WHERE left_after_shift <= 0
ORDER BY StartTime;
SQLfiddle is a bit tired, so this is tested on SQL Server 2014. Don't have any older version to test on but it should work at least on 2012.
Upvotes: 2
Reputation: 71
would this work:
select min(EndTime)
from shifts
where EndTime >= DateAdd(hour, @Duration, @StartTime)
Upvotes: 0