Logo

SQL Server BUSDAYS Function

Updated 2023-10-06 23:25:11.657000

Description

Calculate the number of business days from a start date (inclusive) to an end date (exclusive).

Syntax

SELECT [westclintech].[wct].[BUSDAYS] (
  <@StartDate, datetime,>
 ,<@EndDate, datetime,>
 ,<@Holidays, nvarchar(max),>)

Arguments

@StartDate

the start date for the calculation. @StartDate is an expression of type datetime or of a type that can be implicitly converted to datetime.

@EndDate

the end date for the calculation. @EndDate is an expression of type datetime or of a type that can be implicitly converted to datetime.

@Holidays

a comma separated string containing the holiday (non-business) dates to be used in the calculation of the number of business days. You can use the aggregate function NBD NBD to create an appropriately formatted string.

Return Type

int

Remarks

@StartDate cannot be NULL.

@EndDate cannot be NULL.

Saturday and Sunday are always treated as non-business days.

Examples

In this example we will put the holiday string into a variable, using the NBD function and calculate the number of business days and the actual number of days between different date combinations.

/*Populate the variable*/
DECLARE @h as varchar(max);
SET @h =
(
    SELECT wct.NBD(d)
    FROM
    (
        SELECT '2010-01-01'
        UNION ALL
        SELECT '2010-01-18'
        UNION ALL
        SELECT '2010-02-15'
        UNION ALL
        SELECT '2010-05-31'
        UNION ALL
        SELECT '2010-07-05'
        UNION ALL
        SELECT '2010-09-06'
        UNION ALL
        SELECT '2010-10-11'
        UNION ALL
        SELECT '2010-11-25'
        UNION ALL
        SELECT '2010-12-24'
        UNION ALL
        SELECT '2010-12-31'
        UNION ALL
        SELECT '2011-01-17'
        UNION ALL
        SELECT '2011-02-21'
        UNION ALL
        SELECT '2011-05-30'
        UNION ALL
        SELECT '2011-07-04'
        UNION ALL
        SELECT '2011-09-05'
        UNION ALL
        SELECT '2011-10-10'
        UNION ALL
        SELECT '2011-10-11'
        UNION ALL
        SELECT '2011-11-24'
        UNION ALL
        SELECT '2011-12-26'
        UNION ALL
        SELECT '2012-01-02'
        UNION ALL
        SELECT '2012-01-16'
        UNION ALL
        SELECT '2012-02-20'
        UNION ALL
        SELECT '2012-05-28'
        UNION ALL
        SELECT '2012-07-04'
        UNION ALL
        SELECT '2012-09-03'
        UNION ALL
        SELECT '2012-10-08'
        UNION ALL
        SELECT '2012-11-12'
        UNION ALL
        SELECT '2012-11-22'
        UNION ALL
        SELECT '2012-12-25'
        UNION ALL
        SELECT '2013-01-01'
        UNION ALL
        SELECT '2013-01-21'
        UNION ALL
        SELECT '2013-02-18'
        UNION ALL
        SELECT '2013-05-27'
        UNION ALL
        SELECT '2013-07-04'
        UNION ALL
        SELECT '2013-09-02'
        UNION ALL
        SELECT '2013-10-14'
        UNION ALL
        SELECT '2013-11-11'
        UNION ALL
        SELECT '2013-11-28'
        UNION ALL
        SELECT '2013-12-25'
        UNION ALL
        SELECT '2014-01-01'
        UNION ALL
        SELECT '2014-01-20'
        UNION ALL
        SELECT '2014-02-17'
        UNION ALL
        SELECT '2014-05-26'
        UNION ALL
        SELECT '2014-07-04'
        UNION ALL
        SELECT '2014-09-01'
        UNION ALL
        SELECT '2014-10-13'
        UNION ALL
        SELECT '2014-11-11'
        UNION ALL
        SELECT '2014-11-27'
        UNION ALL
        SELECT '2014-12-25'
        UNION ALL
        SELECT '2015-01-01'
        UNION ALL
        SELECT '2015-01-19'
        UNION ALL
        SELECT '2015-02-16'
        UNION ALL
        SELECT '2015-05-25'
        UNION ALL
        SELECT '2015-07-03'
        UNION ALL
        SELECT '2015-09-07'
        UNION ALL
        SELECT '2015-10-12'
        UNION ALL
        SELECT '2015-11-11'
        UNION ALL
        SELECT '2015-11-26'
        UNION ALL
        SELECT '2015-12-25'
    ) n(d)
);

Calculate business days using the previously declared variable.

SELECT *,
       wct.BUSDAYS([Start Date], [End Date], @h) as [Business Days],
       DATEDIFF(d, [Start Date], [End Date]) as Actual
FROM
(
    SELECT '2015-08-01',
           '2014-11-19'
    UNION ALL
    SELECT '2014-11-01',
           '2015-04-12'
    UNION ALL
    SELECT '2010-03-16',
           '2015-12-12'
    UNION ALL
    SELECT '2009-10-21',
           '2011-11-24'
    UNION ALL
    SELECT '2014-07-22',
           '2015-10-13'
    UNION ALL
    SELECT '2013-02-03',
           '2012-02-27'
    UNION ALL
    SELECT '2013-04-26',
           '2015-01-23'
    UNION ALL
    SELECT '2013-01-07',
           '2011-06-07'
    UNION ALL
    SELECT '2015-08-04',
           '2010-09-23'
    UNION ALL
    SELECT '2013-12-16',
           '2015-08-25'
    UNION ALL
    SELECT '2015-01-02',
           '2013-08-07'
    UNION ALL
    SELECT '2009-12-02',
           '2011-10-07'
    UNION ALL
    SELECT '2014-06-14',
           '2015-10-23'
    UNION ALL
    SELECT '2010-01-15',
           '2015-03-13'
    UNION ALL
    SELECT '2015-01-19',
           '2010-06-07'
    UNION ALL
    SELECT '2014-09-20',
           '2012-12-31'
    UNION ALL
    SELECT '2009-11-08',
           '2014-09-01'
    UNION ALL
    SELECT '2011-07-28',
           '2015-09-24'
    UNION ALL
    SELECT '2010-11-07',
           '2011-06-08'
    UNION ALL
    SELECT '2013-01-08',
           '2014-11-26'
    UNION ALL
    SELECT '2012-07-12',
           '2015-02-04'
    UNION ALL
    SELECT '2012-07-03',
           '2012-08-30'
) m([Start Date], [End Date]);

This produces the following result.

Start DateEnd DateBusiness DaysActual
2015-08-012014-11-19-176-255
2014-11-012015-04-12109162
2010-03-162015-12-1214442097
2009-10-212011-11-24529764
2014-07-222015-10-13308448
2013-02-032012-02-27-236-342
2013-04-262015-01-23436637
2013-01-072011-06-07-397-580
2015-08-042010-09-23-1220-1776
2013-12-162015-08-25425617
2015-01-022013-08-07-351-513
2009-12-022011-10-07467674
2014-06-142015-10-23341496
2010-01-152015-03-1312941883
2015-01-192010-06-07-1159-1687
2014-09-202012-12-31-434-628
2009-11-082014-09-0112111758
2011-07-282015-09-2410441519
2010-11-072011-06-08146213
2013-01-082014-11-26474687
2012-07-122015-02-04642937
2012-07-032012-08-304158

Let's assume that we keep holidays on a table indexed by country code in our database. We could run the following SQL using CROSS APPLY to supply holiday information to the function.

SELECT [Start Date]
,[End Date]
,wct.BUSDAYS([Start Date],[End Date],h) as [Business Days]
,DATEDIFF(d,[Start Date],[End Date]) as Actual
FROM (
      SELECT '2015-08-01','2014-11-19' UNION ALL
      SELECT '2014-11-01','2015-04-12' UNION ALL
      SELECT '2010-03-16','2015-12-12' UNION ALL
      SELECT '2009-10-21','2011-11-24' UNION ALL
      SELECT '2014-07-22','2015-10-13' UNION ALL
      SELECT '2013-02-03','2012-02-27' UNION ALL
      SELECT '2013-04-26','2015-01-23' UNION ALL
      SELECT '2013-01-07','2011-06-07' UNION ALL
      SELECT '2015-08-04','2010-09-23' UNION ALL
      SELECT '2013-12-16','2015-08-25' UNION ALL
      SELECT '2015-01-02','2013-08-07' UNION ALL
      SELECT '2009-12-02','2011-10-07' UNION ALL
      SELECT '2014-06-14','2015-10-23' UNION ALL
      SELECT '2010-01-15','2015-03-13' UNION ALL
      SELECT '2015-01-19','2010-06-07' UNION ALL
      SELECT '2014-09-20','2012-12-31' UNION ALL
      SELECT '2009-11-08','2014-09-01' UNION ALL
      SELECT '2011-07-28','2015-09-24' UNION ALL
      SELECT '2010-11-07','2011-06-08' UNION ALL
      SELECT '2013-01-08','2014-11-26' UNION ALL
      SELECT '2012-07-12','2015-02-04' UNION ALL
      SELECT '2012-07-03','2012-08-30'
      ) m([Start Date],[End Date])
CROSS APPLY (
      SELECT wct.NBD(Holiday) FROM HOLIDAYS
      WHERE Country = 'US'
      ) k(h)

This produces the following result.

Start DateEnd DateBusiness DaysActual
2015-08-012014-11-19-175-255
2014-11-012015-04-12108162
2010-03-162015-12-1214432097
2009-10-212011-11-24528764
2014-07-222015-10-13308448
2013-02-032012-02-27-235-342
2013-04-262015-01-23436637
2013-01-072011-06-07-397-580
2015-08-042010-09-23-1220-1776
2013-12-162015-08-25425617
2015-01-022013-08-07-351-513
2009-12-022011-10-07467674
2014-06-142015-10-23341496
2010-01-152015-03-1312941883
2015-01-192010-06-07-1158-1687
2014-09-202012-12-31-433-628
2009-11-082014-09-0112101758
2011-07-282015-09-2410441519
2010-11-072011-06-08146213
2013-01-082014-11-26474687
2012-07-122015-02-04642937
2012-07-032012-08-304158

Let's look at what happens if the start date is a Saturday.

DECLARE @sd as datetime;
DECLARE @h as varchar(max);
SET @sd = '2012-05-26';
SET @h =
(
    SELECT wct.NBD(holiday)FROM HOLIDAYS WHERE COUNTRY = 'US'
);
SELECT RIGHT(Convert(varchar, @sd, 106), 11) as [Start Date],
       RIGHT(Convert(varchar, seriesvalue, 106), 11) as [End Date],
       wct.BUSDAYS(@sd, seriesvalue, @h) as [Business Days],
       DATEDIFF(d, @sd, seriesvalue) as [Actual Days]
FROM wctMath.wct.SeriesDate(@sd, '2012-06-06', NULL, NULL, NULL);

This produces the following result.

Start DateEnd DateBusiness DaysActual Days
26 May 201226 May 201200
26 May 201227 May 201201
26 May 201228 May 201202
26 May 201229 May 201203
26 May 201230 May 201214
26 May 201231 May 201225
26 May 201201 Jun 201236
26 May 201202 Jun 201237
26 May 201203 Jun 201238
26 May 201204 Jun 201249
26 May 201205 Jun 2012510
26 May 201206 Jun 2012611

Notice that is not until 30-May-2012 that one business day has elapsed. There are 4 actual days from 26-May-2012 to 30-May-2012. 26-May-2012 is a Saturday, 27-May-2012 is a Sunday, and 28-May-2012 is holiday. Of the 4 days, 3 are non-business days, so the result is 1 business day.

Let's look at what happens if the end date is a Sunday.

DECLARE @ed as datetime;
DECLARE @h as varchar(max);
SET @ed = '2012-06-03';
SET @h =
(
    SELECT wct.NBD(holiday)FROM HOLIDAYS WHERE COUNTRY = 'US'
);
SELECT RIGHT(Convert(varchar, seriesvalue, 106), 11) as [Start Date],
       RIGHT(Convert(varchar, @ed, 106), 11) as [End Date],
       wct.BUSDAYS(seriesvalue, @ed, @h) as [Business Days],
       DATEDIFF(d, seriesvalue, @ed) as [Actual Days]
FROM wctMath.wct.SeriesDate('2012-05-23', @ed, NULL, NULL, NULL);

This produces the following result.

Start DateEnd DateBusiness DaysActual Days
23 May 201203 Jun 2012611
24 May 201203 Jun 2012510
25 May 201203 Jun 201249
26 May 201203 Jun 201238
27 May 201203 Jun 201237
28 May 201203 Jun 201236
29 May 201203 Jun 201235
30 May 201203 Jun 201224
31 May 201203 Jun 201213
01 Jun 201203 Jun 201202
02 Jun 201203 Jun 201201
03 Jun 201203 Jun 201200

Notice that there 11 actual days between 23-May-2012 and 03-Jun-2012, but there are only 6 business days. There are two Saturdays (26-May-2012 and 02-Jun-2012), two Sundays (27-May-2012 and 03-Jun-2012) and one holiday (28-May-2012).

See Also

BUSINESSDATE - Calculate a Business Date from an offset

BUSINESSDATEWE - Calculate a Business Date from an offset and specified weekend days

FIRSTWEEKDAY - Calculate the last occurrence of a weekday in a given month

LASTWEEKDAY - Calculate the first occurrence of a weekday in a given month

NETWORKDAYS - Calculate the number of working days between two dates (inclusive)

NBD - Create holiday string

YEARFRAC - Calculate the difference between two dates as a fraction of a year