Date 计数X从输入日期算起的工作日数
我有一个Microsoft Access数据库,要求用户输入一个Date 计数X从输入日期算起的工作日数,date,ms-access,vba,Date,Ms Access,Vba,我有一个Microsoft Access数据库,要求用户输入一个打开日期:值。一旦输入,这将触发另一个字段中的计算,截止日期(25 WD):。这通过后一个字段中的以下功能工作: =DateAdd("d",25,[Date opened]) 但是,我想做的是,从打开日期:中输入的日期算起,计算25个工作日。我有一个表holidays,其中包含截至2020年的英国假期列表 可以说,我如何合并为两个,以生成一个有效的截止日期(25 WD):值,该值不计算假日中列出的任何日期 例如,如果输入的日期是2
打开日期:
值。一旦输入,这将触发另一个字段中的计算,截止日期(25 WD):
。这通过后一个字段中的以下功能工作:
=DateAdd("d",25,[Date opened])
但是,我想做的是,从打开日期:
中输入的日期算起,计算25个工作日。我有一个表holidays
,其中包含截至2020年的英国假期列表
可以说,我如何合并为两个,以生成一个有效的截止日期(25 WD):
值,该值不计算假日中列出的任何日期
例如,如果输入的日期是2015年1月1日,则该函数将从2015年1月1日算起25个工作日,这意味着它将排除该期间内的所有周末和任何银行假日,并且字段截止日期(25 WD)
中的结果日期值也将是一个工作日(即,不是周末或银行假日)你可能需要一个UDF来度过这段时间。比如
Function addWorkDays(addNumber As Long, Date2 As Date) As Date
'********************
'Code Courtesy of
' Paul Eugin
'********************
Dim finalDate As Date
Dim i As Long, tmpDate As Date
tmpDate = Date2
i = 1
Do While i <= addNumber
If Weekday(tmpDate) <> 1 And Weekday(tmpDate) <> 7 And _
DCount("*", "tbl_BankHolidays", "bankDate = " & Format(tmpDate, "\#mm\/dd\/yyyy\#")) = 0 Then i = i + 1
tmpDate = DateAdd("d", 1, tmpDate)
Loop
Do While Weekday(tmpDate) = 1 Or Weekday(tmpDate) = 7 Or _
DCount("*", "tbl_BankHolidays", "bankDate = " & Format(tmpDate, "\#mm\/dd\/yyyy\#")) <> 0
tmpDate = DateAdd("d", 1, tmpDate)
Loop
addWorkDays = tmpDate
End Function
希望这有帮助
编辑:我添加了另一个循环,以查看结束日期是否在银行假日或周末,如果是,则将再添加一天,直到到达工作日。您可以使用此功能:
Public Function DateAddWorkdays( _
ByVal lngNumber As Long, _
ByVal datDate As Date, _
Optional ByVal booWorkOnHolidays As Boolean) _
As Date
' Adds lngNumber of workdays to datDate.
' 2014-10-03. Cactus Data ApS, CPH
' Calendar days per week.
Const clngWeekdayCount As Long = 7
' Workdays per week.
Const clngWeekWorkdays As Long = 5
' Average count of holidays per week maximum.
Const clngWeekHolidays As Long = 1
' Maximum valid date value.
Const cdatDateRangeMax As Date = #12/31/9999#
' Minimum valid date value.
Const cdatDateRangeMin As Date = #1/1/100#
Dim aHolidays() As Date
Dim lngDays As Long
Dim lngDiff As Long
Dim lngDiffMax As Long
Dim lngSign As Long
Dim datDate1 As Date
Dim datDate2 As Date
Dim datLimit As Date
Dim lngHoliday As Long
lngSign = Sgn(lngNumber)
datDate2 = datDate
If lngSign <> 0 Then
If booWorkOnHolidays = True Then
' Holidays are workdays.
Else
' Retrieve array with holidays between datDate and datDate + lngDiffMax.
' Calculate the maximum calendar days per workweek.
lngDiffMax = lngNumber * clngWeekdayCount / (clngWeekWorkdays - clngWeekHolidays)
' Add one week to cover cases where a week contains multiple holidays.
lngDiffMax = lngDiffMax + Sgn(lngDiffMax) * clngWeekdayCount
datDate1 = DateAdd("d", lngDiffMax, datDate)
aHolidays = GetHolidays(datDate, datDate1)
End If
Do Until lngDays = lngNumber
If lngSign = 1 Then
datLimit = cdatDateRangeMax
Else
datLimit = cdatDateRangeMin
End If
If DateDiff("d", DateAdd("d", lngDiff, datDate), datLimit) = 0 Then
' Limit of date range has been reached.
Exit Do
End If
lngDiff = lngDiff + lngSign
datDate2 = DateAdd("d", lngDiff, datDate)
Select Case Weekday(datDate2)
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 datDate and datDate1.
ElseIf DateDiff("d", datDate2, aHolidays(lngHoliday)) = 0 Then
' This datDate2 hits a holiday.
' Subtract one day before adding one after the loop.
lngDays = lngDays - lngSign
Exit For
End If
Next
On Error GoTo 0
lngDays = lngDays + lngSign
End Select
Loop
End If
DateAddWorkdays = datDate2
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
公共功能DateAddWorkdays(_
ByVal LGNNUMBER尽可能长_
ByVal datDate作为日期_
可选的ByVal booworkinholidays(作为布尔值)_
截止日期
'将工作日数添加到datDate。
'2014-10-03.仙人掌数据ApS,CPH
'每周日历天数。
Const clngWeekdayCount作为Long=7
“每周工作日。
常数clngWeekWorkdays的长度=5
'每周最多的平均假日数。
Const clngWeekHolidays长度=1
'最大有效日期值。
Const cdatDateRangeMax As Date=#1999年12月31日#
'最小有效日期值。
常数cdatDateRangeMin作为日期=#1/1/100#
Dim aHolidays()作为日期
暗淡的长发
模糊lngDiff与长
Dim lngDiffMax尽可能长
暗号只要长
Dim datDate1作为日期
Dim datDate2作为日期
日期限制为日期
朦胧的白天和漫长的白天一样
lngSign=Sgn(lngNumber)
datDate2=datDate
如果lngSign为0,则
如果booworknholidays=True,则
“假期就是工作日。
其他的
'检索datDate和datDate+lngDiffMax之间有假日的数组。
'计算每个工作周的最大日历天数。
lngDiffMax=lngNumber*CLNGWEEKKDAYCOUNT/(clngWeekWorkdays-clngWeekHolidays)
'添加一周以涵盖一周包含多个假期的情况。
lngDiffMax=lngDiffMax+Sgn(lngDiffMax)*clngWeekdayCount
datDate1=DateAdd(“d”,lngDiffMax,datDate)
aHolidays=GetHolidays(datDate,datDate1)
如果结束
直到lngDays=lngNumber
如果lngSign=1,则
datLimit=cdatDateRangeMax
其他的
datLimit=CDATDATERAGEMIN
如果结束
如果DateDiff(“d”,DateAdd(“d”,lngDiff,datDate),datLimit)=0,则
'已达到日期范围的限制。
退出Do
如果结束
lngDiff=lngDiff+lngSign
datDate2=DateAdd(“d”,lngDiff,datDate)
选择案例工作日(datDate2)
案件:星期六、星期日
“跳过周末。
其他情况
“检查是否可以跳过假期。
'在未分配数组上使用LBound和UBound时忽略错误。
出错时继续下一步
对于lngHoliday=LBound(aHolidays)到UBound(aHolidays)
如果错误编号>0,则
“datDate和datDate1之间没有假日。
ElseIf DateDiff(“d”,datDate2,aHolidays(lngHoliday))=0
“这是一个假日。
'在循环后加一之前减去一天。
lngDays=lngDays-lngSign
退出
如果结束
下一个
错误转到0
lngDays=lngDays+lngSign
结束选择
环
如果结束
DateAddWorkdays=datDate2
端函数
公众假期(_
ByVal DatDate 1作为日期_
ByVal DatDate 2作为日期_
可选的ByVal booDesc(作为布尔值)_
截止日期()
'查找datDate1和datDate2之间的假日计数。
'假日以日期数组的形式返回。
'DAO对象被声明为静态,以加快使用相同日期参数的重复调用。
'2014-10-03.仙人掌数据ApS,CPH
“放假日的桌子。
常量cstrTable为String=“tblHoliday”
'表中包含假日日期的字段。
Const cstrField As String=“HolidayDate”
'数组的常量。
Const clngDimRecordCount的长度=2
Const clngDimFieldOne的长度=0
作为DAO.Database的静态数据库
静态rst作为DAO.Recordset
静态DatDate1最后为日期
静态datDate2Last As Date
Dim adatDays()作为日期
暗淡的前卫
作为字符串的Dim strSQL
作为字符串的Dim strDate1
作为字符串的Dim strDate2
作为字符串的Dim strOrder
暗淡的长发
如果DateDiff(“d”,datDate1,datDate1Last)0或DateDiff(“d”,datDate2,datDate2Last)0,则
'自上次调用以来,datDate1或datDate2已更改。
strDate1=格式(datDate1,\\\ yyyy\/mm\/dd\\)
strDate2=格式(datDate2,\\\ yyyy\/mm\/dd\\)
strOrder=格式(booDesc,“\A\s\c;\D\e\s\c”)
strSQL=“选择”&cstrField&“来自”&cstrTable&”
Public Function DateAddWorkdays( _
ByVal lngNumber As Long, _
ByVal datDate As Date, _
Optional ByVal booWorkOnHolidays As Boolean) _
As Date
' Adds lngNumber of workdays to datDate.
' 2014-10-03. Cactus Data ApS, CPH
' Calendar days per week.
Const clngWeekdayCount As Long = 7
' Workdays per week.
Const clngWeekWorkdays As Long = 5
' Average count of holidays per week maximum.
Const clngWeekHolidays As Long = 1
' Maximum valid date value.
Const cdatDateRangeMax As Date = #12/31/9999#
' Minimum valid date value.
Const cdatDateRangeMin As Date = #1/1/100#
Dim aHolidays() As Date
Dim lngDays As Long
Dim lngDiff As Long
Dim lngDiffMax As Long
Dim lngSign As Long
Dim datDate1 As Date
Dim datDate2 As Date
Dim datLimit As Date
Dim lngHoliday As Long
lngSign = Sgn(lngNumber)
datDate2 = datDate
If lngSign <> 0 Then
If booWorkOnHolidays = True Then
' Holidays are workdays.
Else
' Retrieve array with holidays between datDate and datDate + lngDiffMax.
' Calculate the maximum calendar days per workweek.
lngDiffMax = lngNumber * clngWeekdayCount / (clngWeekWorkdays - clngWeekHolidays)
' Add one week to cover cases where a week contains multiple holidays.
lngDiffMax = lngDiffMax + Sgn(lngDiffMax) * clngWeekdayCount
datDate1 = DateAdd("d", lngDiffMax, datDate)
aHolidays = GetHolidays(datDate, datDate1)
End If
Do Until lngDays = lngNumber
If lngSign = 1 Then
datLimit = cdatDateRangeMax
Else
datLimit = cdatDateRangeMin
End If
If DateDiff("d", DateAdd("d", lngDiff, datDate), datLimit) = 0 Then
' Limit of date range has been reached.
Exit Do
End If
lngDiff = lngDiff + lngSign
datDate2 = DateAdd("d", lngDiff, datDate)
Select Case Weekday(datDate2)
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 datDate and datDate1.
ElseIf DateDiff("d", datDate2, aHolidays(lngHoliday)) = 0 Then
' This datDate2 hits a holiday.
' Subtract one day before adding one after the loop.
lngDays = lngDays - lngSign
Exit For
End If
Next
On Error GoTo 0
lngDays = lngDays + lngSign
End Select
Loop
End If
DateAddWorkdays = datDate2
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