使用模块计算两个日期之间的工作日

时间:2015-08-24 13:15:00

标签: ms-access access-vba

我不是很熟练编写代码,但我写了这个模块来计算两个日期之间的工作日,我希望你的意见很好。它不包括假期,但我不需要它,所以没关系。

Public Function WD(SD As Date, ED As Date) As Double 'SD - start date, ED - end date
Dim A As Double
Dim B As Double
Dim IntASaturday As Double
Dim IntASunday As Double
Dim IntBSaturday As Double
Dim IntBSunday As Double
Dim C As Double
Dim D As Double

A = CDbl(SD)                            'Converting start date into a serial number of a date
B = CDbl(ED)                            'Converting end date into a serial number of a date


'Next is based on a fact that first date (1.1.1900.), serial number "1" is a Sunday,
'so serial number "7" is a Saturday

IntASaturday = Int(A / 7)               'Indentifying a number of saturdays in SD
IntASunday = Int((A - 1) / 7)           'Indentifying a number of sundays in SD
IntBSaturday = Int(B / 7)               'Indentifying a number of saturdays in ED
IntBSunday = Int((B - 1) / 7)           'Indentifying a number of sundays in ED

C = A - IntASaturday - IntASunday       'Removing Saturdays and Sundays from SD
D = B - IntBSaturday - IntBSunday       'Removing Saturdays and Sundays from ED

WD = D - C                              'Total work days

'It works like this -> if it is from Monday through Friday, it is 4 work days, not 5.
'But if it is from Friday to Friday, it is 5 work days. So End date is not taken into account
'What do you think?
End Function

1 个答案:

答案 0 :(得分:0)

您应始终将日期视为日期,而不是字符串或数字。请注意不要让变量混淆名称。

这是一种方法:

Public Function DateDiffWorkdays( _
    ByVal datDate1 As Date, _
    ByVal datDate2 As Date, _
    Optional ByVal booWorkOnHolidays As Boolean) _
    As Long

'   Calculates the count of workdays between datDate1 and datDate2.
'   2014-10-03. Cactus Data ApS, CPH

    Dim aHolidays() As Date

    Dim lngDiff     As Long
    Dim lngSign     As Long
    Dim lngHoliday  As Long

    lngSign = Sgn(DateDiff("d", datDate1, datDate2))
    If lngSign <> 0 Then
        If booWorkOnHolidays = True Then
            ' Holidays are workdays.
        Else
            ' Retrieve array with holidays between datDate1 and datDate2.
            aHolidays = GetHolidays(datDate1, datDate2)
        End If

        Do Until DateDiff("d", datDate1, datDate2) = 0
            Select Case Weekday(datDate1)
                Case vbSaturday, vbSunday
                    ' Skip weekend.
                Case Else
                    ' Check for holidays to skip.
                    ' Ignore error when using LBound and UBound on an unassigned array.
                    On Error Resume Next
                    For lngHoliday = LBound(aHolidays) To UBound(aHolidays)
                        If Err.Number > 0 Then
                            ' No holidays between datDate1 and datDate2.
                        ElseIf DateDiff("d", datDate1, aHolidays(lngHoliday)) = 0 Then
                            ' This datDate1 hits a holiday.
                            ' Subtract one day before adding one after the loop.
                            lngDiff = lngDiff - lngSign
                            Exit For
                        End If
                    Next
                    On Error GoTo 0
                    lngDiff = lngDiff + lngSign
            End Select
            datDate1 = DateAdd("d", lngSign, datDate1)
        Loop
    End If

    DateDiffWorkdays = lngDiff

End Function

节假日,如果有一天你需要它:

Public Function GetHolidays( _
    ByVal datDate1 As Date, _
    ByVal datDate2 As Date, _
    Optional ByVal booDesc As Boolean) _
    As Date()

'   Finds the count of holidays between datDate1 and datDate2.
'   The holidays are returned as an array of dates.
'   DAO objects are declared static to speed up repeated calls with identical date parameters.
'   2014-10-03. Cactus Data ApS, CPH

    ' The table that holds the holidays.
    Const cstrTable             As String = "tblHoliday"
    ' The field of the table that holds the dates of the holidays.
    Const cstrField             As String = "HolidayDate"
    ' Constants for the arrays.
    Const clngDimRecordCount    As Long = 2
    Const clngDimFieldOne       As Long = 0

    Static dbs              As DAO.Database
    Static rst              As DAO.Recordset

    Static datDate1Last     As Date
    Static datDate2Last     As Date

    Dim adatDays()  As Date
    Dim avarDays    As Variant

    Dim strSQL      As String
    Dim strDate1    As String
    Dim strDate2    As String
    Dim strOrder    As String
    Dim lngDays     As Long

    If DateDiff("d", datDate1, datDate1Last) <> 0 Or DateDiff("d", datDate2, datDate2Last) <> 0 Then
        ' datDate1 or datDate2 has changed since the last call.
        strDate1 = Format(datDate1, "\#yyyy\/mm\/dd\#")
        strDate2 = Format(datDate2, "\#yyyy\/mm\/dd\#")
        strOrder = Format(booDesc, "\A\s\c;\D\e\s\c")

        strSQL = "Select " & cstrField & " From " & cstrTable & " " & _
            "Where " & cstrField & " Between " & strDate1 & " And " & strDate2 & " " & _
            "Order By 1 " & strOrder

        Set dbs = CurrentDb
        Set rst = dbs.OpenRecordset(strSQL, dbOpenSnapshot)

        ' Save the current set of date parameters.
        datDate1Last = datDate1
        datDate2Last = datDate2
    End If

    lngDays = rst.RecordCount
    If lngDays = 0 Then
        ' Leave adatDays() as an unassigned array.
    Else
        ReDim adatDays(lngDays - 1)
        ' As repeated calls may happen, do a movefirst.
        rst.MoveFirst
        avarDays = rst.GetRows(lngDays)
        ' rst is now positioned at the last record.
        For lngDays = LBound(avarDays, clngDimRecordCount) To UBound(avarDays, clngDimRecordCount)
            adatDays(lngDays) = avarDays(clngDimFieldOne, lngDays)
        Next
    End If

    ' DAO objects are static.
    ' Set rst = Nothing
    ' Set dbs = Nothing

    GetHolidays = adatDays()

End Function