Count work days between two dates

前端 未结 24 2686
失恋的感觉
失恋的感觉 2020-11-22 01:05

How can I calculate the number of work days between two dates in SQL Server?

Monday to Friday and it must be T-SQL.

相关标签:
24条回答
  • 2020-11-22 01:50

    If you need to add work days to a given date, you can create a function that depends on a calendar table, described below:

    CREATE TABLE Calendar
    (
      dt SMALLDATETIME PRIMARY KEY, 
      IsWorkDay BIT
    );
    
    --fill the rows with normal days, weekends and holidays.
    
    
    create function AddWorkingDays (@initialDate smalldatetime, @numberOfDays int)
        returns smalldatetime as 
    
        begin
            declare @result smalldatetime
            set @result = 
            (
                select t.dt from
                (
                    select dt, ROW_NUMBER() over (order by dt) as daysAhead from calendar 
                    where dt > @initialDate
                    and IsWorkDay = 1
                    ) t
                where t.daysAhead = @numberOfDays
            )
    
            return @result
        end
    
    0 讨论(0)
  • 2020-11-22 01:50

    Create function like:

    CREATE FUNCTION dbo.fn_WorkDays(@StartDate DATETIME, @EndDate DATETIME= NULL )
    RETURNS INT 
    AS
    BEGIN
           DECLARE @Days int
           SET @Days = 0
    
           IF @EndDate = NULL
                  SET @EndDate = EOMONTH(@StartDate) --last date of the month
    
           WHILE DATEDIFF(dd,@StartDate,@EndDate) >= 0
           BEGIN
                  IF DATENAME(dw, @StartDate) <> 'Saturday' 
                         and DATENAME(dw, @StartDate) <> 'Sunday' 
                         and Not ((Day(@StartDate) = 1 And Month(@StartDate) = 1)) --New Year's Day.
                         and Not ((Day(@StartDate) = 4 And Month(@StartDate) = 7)) --Independence Day.
                  BEGIN
                         SET @Days = @Days + 1
                  END
    
                  SET @StartDate = DATEADD(dd,1,@StartDate)
           END
    
           RETURN  @Days
    END
    

    You can call the function like:

    select dbo.fn_WorkDays('1/1/2016', '9/25/2016')
    

    Or like:

    select dbo.fn_WorkDays(StartDate, EndDate) 
    from table1
    
    0 讨论(0)
  • 2020-11-22 01:50

    I found the below TSQL a fairly elegant solution (I don't have permissions to run functions). I found the DATEDIFF ignores DATEFIRST and I wanted my first day of the week to be a Monday. I also wanted the first working day to be set a zero and if it falls on a weekend Monday will be a zero. This may help someone who has a slightly different requirement :)

    It does not handle bank holidays

    SET DATEFIRST 1
    SELECT
    ,(DATEDIFF(DD,  [StartDate], [EndDate]))        
    -(DATEDIFF(wk,  [StartDate], [EndDate]))        
    -(DATEDIFF(wk, DATEADD(dd,-@@DATEFIRST,[StartDate]), DATEADD(dd,-@@DATEFIRST,[EndDate]))) AS [WorkingDays] 
    FROM /*Your Table*/ 
    
    0 讨论(0)
  • 2020-11-22 01:51

    Another approach to calculating working days is to use a WHILE loop which basically iterates through a date range and increment it by 1 whenever days are found to be within Monday – Friday. The complete script for calculating working days using the WHILE loop is shown below:

    CREATE FUNCTION [dbo].[fn_GetTotalWorkingDaysUsingLoop]
    (@DateFrom DATE,
    @DateTo   DATE
    )
    RETURNS INT
    AS
         BEGIN
             DECLARE @TotWorkingDays INT= 0;
             WHILE @DateFrom <= @DateTo
                 BEGIN
                     IF DATENAME(WEEKDAY, @DateFrom) IN('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday')
                         BEGIN
                             SET @TotWorkingDays = @TotWorkingDays + 1;
                     END;
                     SET @DateFrom = DATEADD(DAY, 1, @DateFrom);
                 END;
             RETURN @TotWorkingDays;
         END;
    GO
    

    Although the WHILE loop option is cleaner and uses less lines of code, it has the potential of being a performance bottleneck in your environment particularly when your date range spans across several years.

    You can see more methods on how to calculate work days and hours in this article: https://www.sqlshack.com/how-to-calculate-work-days-and-hours-in-sql-server/

    0 讨论(0)
  • 2020-11-22 01:51

    Using a date table:

        DECLARE 
            @StartDate date = '2014-01-01',
            @EndDate date = '2014-01-31'; 
        SELECT 
            COUNT(*) As NumberOfWeekDays
        FROM dbo.Calendar
        WHERE CalendarDate BETWEEN @StartDate AND @EndDate
          AND IsWorkDay = 1;
    

    If you don't have that, you can use a numbers table:

        DECLARE 
        @StartDate datetime = '2014-01-01',
        @EndDate datetime = '2014-01-31'; 
        SELECT 
        SUM(CASE WHEN DATEPART(dw, DATEADD(dd, Number-1, @StartDate)) BETWEEN 2 AND 6 THEN 1 ELSE 0 END) As NumberOfWeekDays
        FROM dbo.Numbers
        WHERE Number <= DATEDIFF(dd, @StartDate, @EndDate) + 1 -- Number table starts at 1, we want a 0 base
    

    They should both be fast and it takes out the ambiguity/complexity. The first option is the best but if you don't have a calendar table you can allways create a numbers table with a CTE.

    0 讨论(0)
  • 2020-11-22 01:51

    That's working for me, in my country on Saturday and Sunday are non-working days.

    For me is important the time of @StartDate and @EndDate.

    CREATE FUNCTION [dbo].[fnGetCountWorkingBusinessDays]
    (
        @StartDate as DATETIME,
        @EndDate as DATETIME
    )
    RETURNS INT
    AS
    BEGIN
        DECLARE @res int
    
    SET @StartDate = CASE 
        WHEN DATENAME(dw, @StartDate) = 'Saturday' THEN DATEADD(dd, 2, DATEDIFF(dd, 0, @StartDate))
        WHEN DATENAME(dw, @StartDate) = 'Sunday' THEN DATEADD(dd, 1, DATEDIFF(dd, 0, @StartDate))
        ELSE @StartDate END
    
    SET @EndDate = CASE 
        WHEN DATENAME(dw, @EndDate) = 'Saturday' THEN DATEADD(dd, 0, DATEDIFF(dd, 0, @EndDate))
        WHEN DATENAME(dw, @EndDate) = 'Sunday' THEN DATEADD(dd, -1, DATEDIFF(dd, 0, @EndDate))
        ELSE @EndDate END
    
    
    SET @res =
        (DATEDIFF(hour, @StartDate, @EndDate) / 24)
      - (DATEDIFF(wk, @StartDate, @EndDate) * 2)
    
    SET @res = CASE WHEN @res < 0 THEN 0 ELSE @res END
    
        RETURN @res
    END
    
    GO
    
    0 讨论(0)
提交回复
热议问题