A Better WORKDAY Function
This page describes a VBA function that can replace Excel's WORKDAY function.
Excel provides a function named WORKDAY that returns a date that is some given number of weekdays, optionally
excluding holidays, after a given date. In Excel 2003 and earlier, this function is part of the Analysis ToolPak add-in.
In Excel 2007 and later, it is, like all ATP functions, native to Excel.
Excel's WORKDAY function suffers from a significant shortcoming. It is hard-coded to exclude Saturdays and Sundays. You cannot
specify other or more days of the week to exclude from the calculation. This page describes a VBA function named Workday2 that
allows you to specify any days of week to exclude from the calculation.
The function declaration for Workday2 is:
Public Function Workday2(StartDate As Date, DaysRequired As Long, _
ExcludeDOW As EDaysOfWeek, Optional Holidays As Variant) As Variant
StartDate is the date from which the counting of days begins. DaysRequired is the
number of work days after StartDate whose is to be returned. ExcludeDOW is a value that
indicates which days of the week to exclude. This is explained below. Holidays is an array or range contains the
dates of holidays to exclude from the calculation.
The EDaysOfWeek is an Enum data type assigning values to each day of the week. It is defined as:
Enum EDaysOfWeek
Sunday = 1
Monday = 2
Tuesday = 4
Wednesday = 8
Thursday = 16
Friday = 32
Saturday = 64
End Enum
As you can see, each value assigned to a day of week is a power of 2. Each day of week turns on one bit of the Enum value. This allows you to
specify more than one day of week by simply adding the corresponding values together. For example, to exclude Tuesdays and Fridays, you would use
Tuesday + Friday. Since Tuesday is equal to 4, it has a binary representation of 00000100. In binary, Friday,
which equals
32, is 00100000. When these are added together, the result is 00100100. This shows that the bits
for Tuesday and Friday are turned on, and all the other day's bits are off. Note that the values used for the weekdays are not the same
as the constants used by Excel and by VBA (the relationship between the Enum's values and the VBA values is shown in the comments within the Enum).
If you specify that all days of week are to be excluded (ExcludeDOW >= 127), the function will return a
#VALUE error.
For example, to find the date that is 15 days past 5-January-2009, excluding Tuesdays and Fridays, you can use
=WORKDAY2(DATE(2009,1,5),15,4+32). The result is 26-January-2009. To exclude holidays, put the dates to exclude
in some range of cells, say K1:K10, and pass that range as the final parameter to Workday2:
=WORKDAY2(DATE(2009,1,5),15,4+32,K1:K10).
The complete code for the Workday2 function is shown below:
Enum EDaysOfWeek
Sunday = 1
Monday = 2
Tuesday = 4
Wednesday = 8
Thursday = 16
Friday = 32
Saturday = 64
End Enum
Function Workday2(StartDate As Date, DaysRequired As Long, _
ExcludeDOW As EDaysOfWeek, Optional Holidays As Variant) As Variant
Dim N As Long
Dim C As Long
Dim TestDate As Date
Dim HNdx As Long
Dim CurDOW As EDaysOfWeek
Dim IsHoliday As Boolean
Dim RunawayLoopControl As Long
Dim V As Variant
If DaysRequired < 0 Then
Workday2 = CVErr(xlErrValue)
Exit Function
ElseIf DaysRequired = 0 Then
Workday2 = StartDate
Exit Function
End If
If ExcludeDOW >= (Sunday + Monday + Tuesday + Wednesday + _
Thursday + Friday + Saturday) Then
Workday2 = CVErr(xlErrValue)
Exit Function
End If
RunawayLoopControl = DaysRequired * 10000
N = 0
C = 0
Do Until C = DaysRequired
N = N + 1
TestDate = StartDate + N
CurDOW = 2 ^ (Weekday(TestDate) - 1)
If (CurDOW And ExcludeDOW) = 0 Then
IsHoliday = False
If IsMissing(Holidays) = False Then
For Each V In Holidays
If V = TestDate Then
IsHoliday = True
Exit For
End If
Next V
End If
If IsHoliday = False Then
C = C + 1
End If
End If
If N > RunawayLoopControl Then
Workday2 = CVErr(xlErrValue)
Exit Function
End If
Loop
Workday2 = StartDate + N
End Function
The NETWORKDAYS function, which returns the number of weekdays between two dates, optionally excluding holidays, suffers from the
same shortcoming as WORKDAY; that is, Saturday and Sunday are hard coded into the function and cannot be changed. For a solution
to this problem that doesn't rely on WORKDAY or the Analysis ToolPak add-in, see the better NETWORKDSAYS page.
|
This page last updated: 18-August-2009. |