0

When looking for a solution for my question I found the following sql (Calculate business hours between two dates).

However, I want the starting point to be 8:30 instead of 9 and the end point 17:30 instead of 17. Currently I am using an integer. Can anyone help me with this? Thanks in advance!

    Create Function GetWorkingMin(@StartDate DateTime, @EndDate DateTime, @Country Varchar(2)) Returns Int 
AS
Begin
Declare @WorkMin int = 0   -- Initialize counter
Declare @Reverse bit       -- Flag to hold if direction is reverse
Declare @StartHour int = 9   -- Start of business hours (can be supplied as an argument if needed)
Declare @EndHour int = 17    -- End of business hours (can be supplied as an argument if needed)
Declare @Holidays Table (HDate DateTime)   --  Table variable to hold holidayes

-- If dates are in reverse order, switch them and set flag
If @StartDate>@EndDate 
Begin
    Declare @TempDate DateTime=@StartDate
    Set @StartDate=@EndDate
    Set @EndDate=@TempDate
    Set @Reverse=1
End
Else Set @Reverse = 0

-- Get country holidays from table based on the country code (Feel free to remove this or modify as per your DB schema)
Insert Into @Holidays (HDate) Select HDate from HOLIDAY Where COUNTRYCODE=@Country and HDATE>=DateAdd(dd, DateDiff(dd,0,@StartDate), 0)

If DatePart(HH, @StartDate)<@StartHour Set @StartDate = DateAdd(hour, @StartHour, DateDiff(DAY, 0, @StartDate))  -- If Start time is less than start hour, set it to start hour
If DatePart(HH, @StartDate)>=@EndHour+1 Set @StartDate = DateAdd(hour, @StartHour+24, DateDiff(DAY, 0, @StartDate)) -- If Start time is after end hour, set it to start hour of next day
If DatePart(HH, @EndDate)>=@EndHour+1 Set @EndDate = DateAdd(hour, @EndHour, DateDiff(DAY, 0, @EndDate)) -- If End time is after end hour, set it to end hour
If DatePart(HH, @EndDate)<@StartHour Set @EndDate = DateAdd(hour, @EndHour-24, DateDiff(DAY, 0, @EndDate)) -- If End time is before start hour, set it to end hour of previous day

If @StartDate>@EndDate Return 0

-- If Start and End is on same day
If DateDiff(Day,@StartDate,@EndDate) <= 0
Begin
    If Datepart(dw,@StartDate)>1 And DATEPART(dw,@StartDate)<7  -- If day is between sunday and saturday
        If (Select Count(*) From @Holidays Where HDATE=DateAdd(dd, DateDiff(dd,0,@StartDate), 0)) = 0  -- If day is not a holiday
            If @EndDate<@StartDate Return 0 Else Set @WorkMin=DATEDIFF(MI, @StartDate, @EndDate) -- Calculate difference
        Else Return 0
    Else Return 0
End
Else Begin
    Declare @Partial int=1   -- Set partial day flag
    While DateDiff(Day,@StartDate,@EndDate) > 0   -- While start and end days are different
    Begin
        If Datepart(dw,@StartDate)>1 And DATEPART(dw,@StartDate)<7    --  If this is a weekday
        Begin
            If (Select Count(*) From @Holidays Where HDATE=DateAdd(dd, DateDiff(dd,0,@StartDate), 0)) = 0  -- If this is not a holiday
            Begin
                If @Partial=1  -- If this is the first iteration, calculate partial time
                Begin 
                    Set @WorkMin=@WorkMin + DATEDIFF(MI, @StartDate, DateAdd(hour, @EndHour, DateDiff(DAY, 0, @StartDate)))
                    Set @StartDate=DateAdd(hour, @StartHour+24, DateDiff(DAY, 0, @StartDate)) 
                    Set @Partial=0 
                End
                Else Begin      -- If this is a full day, add full minutes
                    Set @WorkMin=@WorkMin + (@EndHour-@StartHour)*60        
                    Set @StartDate = DATEADD(DD,1,@StartDate)
                End
            End
            Else Set (at)StartDate = DATEADD(HOUR, (at)StartHour, CAST(CAST(DATEADD(DD,1,(at)StartDate) AS DATE) AS DATETIME))  
        End
        Else Set (at)StartDate = DATEADD(HOUR, (at)StartHour, CAST(CAST(DATEADD(DD,1,(at)StartDate) AS DATE) AS DATETIME))
    End
    If Datepart(dw,@StartDate)>1 And DATEPART(dw,@StartDate)<7  -- If last day is a weekday
        If (Select Count(*) From @Holidays Where HDATE=DateAdd(dd, DateDiff(dd,0,@StartDate), 0)) = 0   -- And it is not a holiday
            If @Partial=0 Set @WorkMin=@WorkMin + DATEDIFF(MI, @StartDate, @EndDate) Else Set @WorkMin=@WorkMin + DATEDIFF(MI, DateAdd(hour, @StartHour, DateDiff(DAY, 0, @StartDate)), @EndDate)
End 
If @Reverse=1 Set @WorkMin=-@WorkMin
Return @WorkMin

End

  • Why you don't use TIME instead of INT for @StartHour? – Zeki Gumus Dec 10 '18 at 10:24
  • We tried to rewrite the entire sql with time instead of integer but the output didn't match anymore. The hard thing is to use minutes in all the calculations.. For example: If start time is less than start hour, set it to start hour. – M. Geurtzen Dec 10 '18 at 11:06
  • I have put sample answer for you. I believe you can improve your function with this way. – Zeki Gumus Dec 10 '18 at 11:48

1 Answers1

0

Use TIME for start time. Then create INT variable to put converted value to minute to use for conditions.

I have created sample for you.

DECLARE @StartDate  DATETIME='2018-12-10 10:00'
DECLARE @ExpectedStartTime  TIME='08:30'

DECLARE @ExpectedStartMin   INT=DATEPART(HOUR,@ExpectedStartTime)*60+DATEPART(MINUTE,@ExpectedStartTime)
DECLARE @ActualStartMin     INT=DATEPART(HOUR,@StartDate)*60+DATEPART(MINUTE,@StartDate)

--Check before change the StartDate
SELECT @ExpectedStartMin, @ActualStartMin, @StartDate


If @ExpectedStartMin<@ActualStartMin Set @StartDate = CAST(CAST(@StartDate AS DATE) AS DATETIME)+@ExpectedStartTime
-- same way to the other conditions.
--
--

--Check after change the StartDate  
SELECT @ExpectedStartMin, @ActualStartMin, @StartDate
Zeki Gumus
  • 1,484
  • 7
  • 14