Search code examples
vbscriptasp-classic

How can I calculate how many working days are to a determined date?


I need to make something like a working days counter, but I don't know how:

Let's say someone makes a request today 04-25-2019 and it needs to be approved on 15 working days, that would be around 05-16-2019, how can this be done? I have no idea yet, and I should include the holidays of my country.

Which would be:

01-01-2019
19-04-2019
20-04-2019
01-05-2019
21-05-2019
29-06-2019
16-07-2019
15-08-2019
18-09-2019
19-09-2019
20-09-2019
12-10-2019
31-10-2019
01-11-2019
08-12-2019
25-12-2019

I tried this:

<%
DateFrom = "10/1/2012"
DateTo = "10/31/2012"
Weekends = 0
ActualDays = 0

' Step 1: Get the actual days
ActualDays = DateDiff("d", DateFrom, DateTo)

' Step 2: Find the weekends
For x = 0 To ActualDays - 1
    xDate = DateAdd("d", x, DateFrom)
    If Weekday(xDate, 1) = 1 Or Weekday(xDate, 1) = 7 Then
        Weekends = Weekends + 1
    End If
Next

WorkingDays = ActualDays - Weekends

response.Write "ActualDays: "&ActualDays  &" Weekends: "& Weekends &" WorkingDays: "& WorkingDays
%>

but it didn't work out as I desired.


Solution

  • You're on the right tracks, you just need to check for national holidays aswell (if it's not a weekend) and subtract weekends and national holidays from the actual days count to get the number of working days. Try this:

    ' You need to keep a record of national holidays and keep it updated. Probably best to do this
    ' outside of your function. You can't use a constant to store an array, you could just dim a 
    ' regular variable, but IMO a better alternative would be to use "Application" and set it in  
    ' your global.asa file under "Sub Application_OnStart"... or just use a database.
    
    Application("NationalHolidays") = array("01-01-2019","19-04-2019","20-04-2019","01-05-2019","21-05-2019","29-06-2019","16-07-2019","15-08-2019","18-09-2019","19-09-2019","20-09-2019","12-10-2019","31-10-2019","01-11-2019","08-12-2019","25-12-2019")
    
    
    function calcDays(fromDate,toDate)
    
        Dim ActualDays, Weekends, NationalHolidays, WorkingDays, nhIndex, x, y
    
        fromDate = cDate(fromDate)
        toDate = cDate(toDate)
    
        ActualDays = DateDiff("d",fromDate,toDate)      
        Weekends = 0    
        NationalHolidays = 0
        WorkingDays = 0
        nhIndex = 0
    
        ' Loop from start day to end day
    
        for x = 0 to ActualDays + 1
    
            ' Count the weekends
    
            if WeekDay(DateAdd("d",x,fromDate)) = 1 OR WeekDay(DateAdd("d",x,fromDate)) = 7 then
                Weekends = Weekends + 1
            else
    
                ' Check for national holidays if it's not a weekend
    
                if NOT nhIndex > uBound(Application("NationalHolidays")) then
                    for y = nhIndex to uBound(Application("NationalHolidays"))
                        ' This if/else logic assumes Application("NationalHolidays") is in ascending order.
                        if DateAdd("d",x,fromDate) = cDate(Application("NationalHolidays")(y)) then
                            NationalHolidays = NationalHolidays + 1
                            ' Keep track of the last national holiday found and start from that 
                            ' position + 1 on the next check.
                            nhIndex = y + 1
                            exit for
                        elseif cDate(Application("NationalHolidays")(y)) < DateAdd("d",x,fromDate) then
                            ' Keep count of national holidays that have already passed and skip them
                            ' on the next check.
                            nhIndex = y + 1
                        elseif cDate(Application("NationalHolidays")(y)) > DateAdd("d",x,fromDate) then
                            ' The national holiday dates have exceeded the current date, there's no
                            ' point in continuing checking.
                            exit for
                        end if
                    next
                end if
    
            end if
    
        next
    
        ' Working days is the number of days between "fromDate" and "toDate" minus weekends and national holidays
    
        WorkingDays = (ActualDays-Weekends-NationalHolidays)
    
        calcDays = "<p>Actual Days: " & ActualDays & "</p>" &_
        "<p>National Holidays: " & NationalHolidays & "</p>" &_
        "<p>Weekends: " & Weekends & "</p>" &_
        "<p>Working Days: " & WorkingDays & "</p>"
    
    end function
    
    response.write calcDays("29-04-2019","13-05-2019")
    

    April 29th 2019 to May 13th 2019

    Output:

    Actual Days: 14
    National Holidays: 1
    Weekends: 4
    Working Days: 9


    EDIT: To calculate Date X + Y Working Days = Date Z (as asked in your question), you can use this function:

    function AddWorkingDays(startDate,workingDays)
    
        startDate = cDate(startDate)
    
        Dim DayCount, workingDayCount, nhIndex, isNationalHoliday, x
    
        DayCount = 0
        workingDayCount = 0
        nhIndex = 0
    
        do until workingDayCount = workingDays
    
            ' Make sure it's not a weekend
    
            if NOT(WeekDay(DateAdd("d",DayCount,startDate)) = 1 OR WeekDay(DateAdd("d",DayCount,startDate)) = 7) then
    
                isNationalHoliday = false ' default
    
                ' Make sure it's not a national holiday
    
                if NOT nhIndex > uBound(Application("NationalHolidays")) then
                    for x = nhIndex to uBound(Application("NationalHolidays"))
                        ' This if/else logic assumes Application("NationalHolidays") is in ascending order.
                        if DateAdd("d",DayCount,startDate) = cDate(Application("NationalHolidays")(x)) then
                            isNationalHoliday = true
                            ' Keep track of the last national holiday found and start from that 
                            ' position + 1 on the next check.
                            nhIndex = x + 1
                            exit for
                        elseif cDate(Application("NationalHolidays")(x)) < DateAdd("d",DayCount,startDate) then
                            ' Keep count of national holidays that have already passed and skip them
                            ' on the next check.
                            nhIndex = x + 1
                        elseif cDate(Application("NationalHolidays")(x)) > DateAdd("d",DayCount,startDate) then
                            ' The national holiday dates have exceeded the current date, there's no
                            ' point in continuing checking.
                            exit for
                        end if
                    next
                end if
    
                if NOT isNationalHoliday then workingDayCount = workingDayCount + 1 ' It's a working day!
    
            end if
    
            ' Keep count of the total number of days needed to make up the working day target
    
            DayCount = DayCount + 1
    
        loop
    
        AddWorkingDays = DateAdd("d",DayCount,startDate)
    
    end function
    
    ' As in your question, calculate 15 working days from April 25th 2019
    response.write AddWorkingDays("25-04-2019",15)
    

    April 25th 2019 + 15 Working Days

    Output:

    May 17th 2019