Calculate Working Days Minus Holidays in VBA

I was looking for a function that calculates working days, minus holidays, for a small project I've been working on. I decided to write one myself, but below I've also demonstrated an alternate way that uses the ATP (Analysis ToolPak) functions for VBA.

Function WorkDays(StartDate As Variant, EndDate As Variant) As Long
' adapted from:
' http://www.exceltip.com/st/Calculate_the_count_of_workdays_between_two_dates_using_VBA_in_Microsoft_Excel/523.html
' and http://support.microsoft.com/kb/97757
'
' returns the count of days between StartDate - EndDate minus Saturdays and Sundays
' also checks for holidays (added by Jimmy Pena 6/17/2008)

Dim lCounter As Long
Dim DaysCount As Long
Dim HolidaysList()
Dim ArrMember
Dim bWasFound As Boolean

bWasFound = False

StartDate = DateValue(StartDate)
EndDate = DateValue(EndDate)

' define holiday list as an array which we will check against
' each day; if match is found, do not increase workday count
'
' edit/add/delete as needed
' these are US Federal Holidays
HolidaysList = Array("1/1/2007", "1/15/2007", "2/19/2007", "5/28/2007", "7/4/2007", "9/3/2007", "10/8/2007", "11/12/2007", _
"11/22/2007", "12/25/2007", "1/1/2008", "1/21/2008", "2/18/2008", "5/26/2008", "7/4/2008", "9/1/2008", "10/13/2008", _
"11/11/2008", "11/27/2008", "12/25/2008")

For lCounter = StartDate To EndDate
    If Weekday(lCounter, vbMonday) < 6 Then
        For Each ArrMember In HolidaysList
            If Format(ArrMember, "mm/dd/yyyy") = Format(lCounter, "mm/dd/yyyy") Then
                bWasFound = True
                Exit For
            Else
                bWasFound = False
            End If
        Next ArrMember

        If bWasFound = False Then
            DaysCount = DaysCount + 1
        End If
    End If
Next lCounter
WorkDays = DaysCount
End Function

Here we create an array of holidays, then loop through the dates passed as arguments to the function to see if they are not weekend days. The inner loop checks to see if the date matches one of the holidays in the array variable. If both conditions are met (i.e. a weekday and not a holiday) we add to the count (DaysCount variable).

The Boolean variable is used as a flag inside the loop — if the date matches a holiday date, the flag is raised and the loop immediately exits. We check the flag after the loop is complete and add to the count if it was left False.

To use:

MsgBox WorkDays("1/1/2008", "1/31/2008")

Or since the function returns a Long value, assign the result to a variable

Dim lCountOfDays As Long
lCountOfDays = WorkDays("1/1/2008", "1/31/2008")

Here's another way, using the ATP library for VBA. To set a reference, open the VBE and go to Tools > References and set a reference to "atpvbaen.xls".

ATP VBA Functions Library

You may also need to go back to Excel and go to Tools > Add-Ins and select "Analysis ToolPak – VBA".

ATP VBA In Excel

Now you can use the NETWORKDAYS function directly in VBA like this:

Dim HolidaysList()

HolidaysList = Array("1/1/2007", "1/15/2007", "2/19/2007", "5/28/2007", "7/4/2007", "9/3/2007", "10/8/2007", "11/12/2007", _
"11/22/2007", "12/25/2007", "1/1/2008", "1/21/2008", "2/18/2008", "5/26/2008", "7/4/2008", "9/1/2008", "10/13/2008", _
"11/11/2008", "11/27/2008", "12/25/2008")

MsgBox networkdays("1/1/2008", "1/31/2008", HolidaysList)

Which should give you the same answer, and in my tests, at approximately the same speed.

Personally I like my way better, but that's only because I worked on it and I hate throwing away old code. Plus it uses built-in functions in case you don't want to add additional object libraries to your VBE. As you can see above, I already have a lot, so anything already built-in to VBA I can use is something I will prefer.

Enjoy,
JP

Related Articles:

About JP

I'm just an average guy who writes VBA code for a living. This is my personal blog. Excel and Outlook are my thing, with a sprinkle of Access and Word here and there. Follow this space to learn more about VBA. Keep Reading »

Share This Article:

Share and bookmark this articledelicious buttonfacebook buttonlinkedin buttonstumbleupon buttontwitter button

comment bubble 13 Comments:

  1. M White writes:

    Hi – down here in the southern hemisphere we run with different date formats ie day/month/year and I can not get this macro to calculate correctly.
    I am trying to calculate the number of hours between when a quote was requested and when it was submitted – using 24 hours per day x total days – weekends – holidays.

    I have been playing with both Workdays function and TimeDiff function VBA code but to no avail as yet. I have tried holiday dates in different formats in Sub.

    eg Input data:
    Date/time quote requested 5/02/2008 8:00 (i.e. in one field with format d/mm/yyyy h:mm)
    Date/Time quote submitted 30/04/2008 17:00

    NZ HolidaysList = Array("1/01/2007", "6/02/2007", "6/04/2007", "9/04/2007", "25/04/2007", "4/06/2007", "22/10/2007", "25/12/2007", "26/12/2007")

    = 85.38 days – 24 days weekends – 4days holidays = 57.38 days, x24 = 1377 hours

    Networkdays = 58 days, x 24 = 1392hours

    With
    Const ComeIn As Date = "0:00"
    Const Leave As Date = "23:59"
    TimeDiff = 1448 hours which has added more hours not subtracted for holidays or failed to find any holidays (which is what I thought it would do if could not match holidays with dates)?

    I have also played with modified code from "Visual Basic Language Developer's Handbook" by Ken Getz and Mike Gilbert and once again can not get calculating correctly. I do not want to use american date formats for my quote data as it has NZ users.
    Please can you help.

    • Ethan writes:

      How do I modify it for a 6 day workweek? Sundays we are closed. Nice stuff. Thanks

      • JP writes:

        I assume you mean Monday through Saturday? The Weekday function currently excludes Saturday and Sunday. Just make it exclude Sunday only.

        Change the 6 to a 7 in this line:

        If Weekday(lCounter, vbMonday) < 7 Then

  2. JP writes:

    I'll check it out and let you know. It would probably help if you send me the full code you are using. Just use the contact form and paste in the code:

    http://www.jpsoftwaretech.com/Contact.html

    –JP

  3. JP writes:

    I just noticed that your work date range is in 2008, but the holidays list is in 2007. If that is the case, the NETWORKDAYS function won't subtract the holidays from the total workdays.

    If you can fix that, it should work. Let me know!

    –JP

  4. Dave writes:

    Curious… can anyone think of a method to go the opposite way? I have the code above in my macro (which works GREAT! Thank you!), but we often have contract modifications come in that don't provide formal end dates and instead simply give a set amount of hours. I'd like to be able to enter in the start date and amount of hours allotted and have it tell me when the contract modification would end (business days only, 8 hours a day, no holidays).

    As an very simple example: Say I have a contract that starts on 1/12/09 and is for 80 hours. I'd like to put "1/12/09" in A1, 80 in A2, and have A3 calculate "1/26/09" (factors in weekends and MLK holiday).

    Is that even possible?

    • JP writes:

      I see what you mean. Currently I only have code samples that calculate the number of working hours or days between two dates, but not one that returns the date X hours after a given start date. Let me see what I can come up with, but in the meantime you might want to google "Excel calculate working hours" and browse some of the links on the first few pages.

  5. Dave writes:

    I did the same googling actually, hoping I could hack it out myself before posting for advice. That said, I don't play in the Microsoft world much at all and wasn't sure how flexible Excel was with situations like that. I'm more on the unix/linux side… (still googling though)

  6. JP writes:

    Dave,
    I finally created the code you're looking for, look for a new blog entry shortly.

  7. S Bhatnagar writes:

    Hi M White
    I am working on a project in which i have used ur above macro. I am using above macro to track containers which are coming from NA to Eur I need to count no. of working days excuding the date of arrival for eg. if material comes at port on 13/02/2009(friday) and leave port on 19/02/2009(thursday) then no of working days should be 4 not 5(1st problem) another thing If material has reached the port and not gone out of port then =workdays(today()-startdate)(2nd problem).
    can you please help me in editing that macro…
    1. No. of working days for the long duration i.e. more than two weeks are not coming correct.
    2. If end date is not there then it should automaticaly take Todays date as a end date.

    Reagrds
    Shikher,

    • JP writes:

      What you can do is write a function to check if a particular day is a business day (i.e. not a weekend or holiday). I've written most of the code already, see this post:

      http://www.jpsoftwaretech.com/blog/2009/02/calculate-working-days-from-start-date/

      What you can do is call the original function to return the working day, subtract one from the result, and call the function you just wrote to see if that day is a working day.

      For the first problem you listed (No. of working days for the long duration i.e. more than two weeks are not coming correct.) can you provide an example?

      For the second problem you listed (If end date is not there then it should automaticaly take Todays date as a end date.) you have to make the second parameter optional, and then at the start of the macro, check if the end user passed in a value for that parameter. If not, then make it equal to todays date.

      Function WorkDays(StartDate As Variant, Optional EndDate As Variant) As Long
      Dim lCounter As Long
      Dim DaysCount As Long
      Dim HolidaysList()
      Dim ArrMember
      Dim bWasFound As Boolean
      
      bWasFound = False
      
      StartDate = DateValue(StartDate)
      If EndDate = "" Then
        EndDate = Format(Now, "dd/mm/yyyy")
      Else
        EndDate = DateValue(EndDate)
      End If
  8. JohnD writes:

    Just wanted to say thanks for the code to do this without the Analysis ToolPak. It's saved me a lot of work. :)

Mentions:

  1. Cristi @ UndeInGalati » Blog Archive » Microsoft Excel – Workday says:

    [...] cel putin doua posibilitati de a face calculul de care aveam nevoie, detalii despre ele gasiti aici si aici dar nu am sa insist pe ele din simplul motiv ca nu le-am folosit). Daca nu gasiti in help [...]

Comments on this article are closed. Why?

Site last updated: February 12, 2012