N S

Novick Software Management • Design • Programming • Training • Consulting

   

 

 

SQL Server T-SQL User-Defined Function of the Week

Calculating the Weekdays Between Two Dates

Volume 1 Number 3   December 6, 2002 (Bonus Issue)

Sign up for this newsletter at:
http://www.novicksoftware.com/UdfOfWeek/UDFofWeekSignup.htm

Visit http://www.NovickSoftware.com for additional material
about SQL Server, Visual Basic, ASP, XML, .Net and security.

Visit the T-SQL UDF of the Week Archives at:
http://www.NovickSoftware.com/UdfOfWeek/UDFofWeekArchive.htm

Check out the UDF Frequently Asked Questions at:
http://www.novicksoftware.com/UdfOfWeek/UDF_FAQ.htm

To ask a UDF related question or to contribute a UDF,
send e-mail to udf@NovickSoftware.com

When you want to know the number of days between two dates, the 
built-in function DATEDIFF does the trick.  But sometimes you 
need to know the number of weekdays between two dates.  That 
turns out to be somewhat harder.  None of the built-in functions
will do the job.

One way to compute weekdays between two dates is to use a table
with a row for every date and columns that designate it as a 
weekday and possibly as a holiday.  This solution works great
and it works particularly well when you have several different 
calendars.  However, for weekdays it isn't necessary.

This issues's UDF, udf_DT_WeekdaysBtwn, computes the week days 
between two dates.  Here's the script that creates it:

/------------- Copy From Below this line ----------------------\

CREATE    FUNCTION dbo.udf_DT_WeekdaysBtwn (

        @dtStart datetime -- Day we want to start counting from
      , @dtEnd   datetime -- Day we count until
      )
	RETURNS INT -- Number of Week days between two dates.

AS BEGIN

/*Computes the number of weekdays between two dates. Does not 
* account for holidays, They're counted if they're M-F.  It 
* counts only one of the end days. So if the dates are the same
* the result is zero.  Order does not matter. Will swap dates 
* if @dtEnd < @dtStart.
* 
* This function is sensitive to the setting of @@DATEFIRST. Any 
* value other than 7 (the default) will make the results 
* incorrect. A test for this will cause the function to re
*
* Related Functions: udf_DateBusinessdaysBetween
*
* Common Usage:
select dbo.udf_DT_WeekdaysBtwn ('2002-07-01', '2002-07-05')
*
* Test:
PRINT 'Test 1 7/1-7/5    ' + case when 
         4= dbo.udf_DT_WeekdaysBtwn ('2002-07-01', '2002-07-05')
             then 'Worked' else 'ERROR' END
PRINT 'Test 2 11/27-12/5 ' + case when
         6= dbo.udf_DT_WeekdaysBtwn ('2002-11-27', '2002-12-05')
             then 'Worked' else 'ERROR' END
* © Copyright 2002 Andrew Novick.  You may use this function
* in your databases, including databases that you sell. You may
* not publish this function, either in print or electronically.
****************************************************************/

    if @@DATEFIRST <> 7 return NULL -- 7 is the default.

    -- Days are broken into 3 parts for calculation.
        -- 1) The remaining weekdays in the week with the start date
        -- 2) The weekdays in the full weeks between the start and end
        -- 3) the weekdays in the week with the end date.
    -- The three are totaled for the result.

    DECLARE @nFullWeeks int -- complete weeks between
          , @nFullWeekDays int -- Days in Full Weeks
          , @nStartWeekDays int -- Days in the starting week
          , @nEndWeekDays int -- Days in the ending week
          , @dtSWap datetime -- for switching end and start dates

    -- First a test for End before Start, Swap Dates if needed
    if @dtEnd < @dtStart BEGIN
        -- swap
        SET @dtSWAP = @dtEnd
        SET @dtEnd = @dtStart
        Set @dtStart = @dtSwap
    END

    -- Number of days in the week of @dtStart
    SELECT @nStartWeekDays = 7 - datepart(dw, @dtStart)
                                - CASE WHEN 7= datepart(dw, @dtStart)
                                 THEN 0
                                 ELSE 1
                                 END

    -- Calculate the number of full weeks 
    select @nFullWeeks = datediff( week, @dtStart, @dtEnd) - 1 
                                               -- -1 for current week

    -- calculate the number of days in these full wks.
    select @nFullWeekDays = @nFullWeeks * 5

    -- Finally, the number of days in the week with the end date.
    SELECT @nEndWeekDays = datepart(dw, @dtEnd) - -- take off to 
                                             -- adjust for wkend
                                CASE WHEN datepart( dw, @dtEnd) = 7
                                     THEN 2
                                     ELSE 1
                                     END

    -- Sum everything together and return it
    RETURN @nFullWeekDays + @nStartWeekDays + @nEndWeekDays

END
GO

GRANT EXECUTE ON udf_DT_WeekdaysBtwn to PUBLIC
GO
\------------ Stop copying above this line --------------------/

Let's test it out:

/------------- Copy From Below this line ----------------------\
select  dbo.udf_DT_WeekdaysBtwn 
              ('2002-11-27', '2002-12-06') as [11/27-12/6 Fri]
      , dbo.udf_DT_WeekdaysBtwn 
              ('2002-11-27', '2002-12-07') as [11/27-12/7 Sat]
      , dbo.udf_DT_WeekdaysBtwn 
              ('2002-11-27', '2002-12-08') as [11/27-12/8 Sun]
      , dbo.udf_DT_WeekdaysBtwn 
              ('2002-11-27', '2002-12-09') as [11/27-12/9 Mon]
GO
\------------ Stop copying above this line --------------------/

(Results)

1/27-12/6 Fri 11/27-12/7 Sat 11/27-12/8 Sun 11/27-12/9 Mon 
-------------- -------------- -------------- -------------- 
             7              7              7              8 

As you can see, the first weekend, 11/30 and 12/1, isn't
counted.  Saturday and Sunday aren't counted, but Monday is.

+--------------------------------------------------------------+
Do you have a great UDF that you'd like to share?  Or maybe you
have a T-SQL problem that you think could be solved by a UDF
but you don't know how? Please send them to:

UDF@NovickSoftware.com 

and they might be published in this newsletter.  I try 
and respond to every request that I get.  

Thanks,  
Andrew Novick
+--------------------------------------------------------------+

This newsletter is published by Novick Software 
http://NovickSoftware.com
Copyright (c) 2002 Novick Software. All rights reserved.


RSS as HTML

Personal Blog

 
New Tips:

Loading SQL Profiler trace (.trc) files with fn_trace_gettrace

Upcoming
Presentations:

Big Data:
Working with Terabytes
in SQL Server

July 9 '08


Full Schedule