VB.NET中如何按8小时工作日计算日期间时长并排除周末?
计算VB.NET中两个日期的实际工作时长(排除周末,按8小时/天计算)
嗨,我懂你遇到的麻烦了——直接用DateDiff算出来的时长会把周末、非工作时间都算进去,确实会高估实际投入的工作时长。咱们可以把计算拆解成几个精准的部分来解决,下面是具体思路和代码实现:
核心思路
要算出准确的工作时长,咱们得拆成三块来计算:
- 起始日期当天的剩余工作时长:如果当天是工作日,计算从起始时间到当日工作结束点的时长
- 结束日期当天的已工作时长:如果当天是工作日,计算从当日工作开始点到结束时间的时长
- 中间完整工作日的总时长:统计两个日期之间的完整工作日数量(排除周末),再乘以每天8小时的标准时长
同时还要处理一些边界情况:比如两个日期在同一天、其中某一天是周末,或者起始时间晚于当日工作结束时间(这种情况当天就没有有效工作时长)。
完整代码实现
下面是封装好的VB.NET函数,你可以直接用,也能根据自己的实际工作时间调整workStart和workEnd的默认值:
Function CalculateWorkHours(startDate As DateTime, endDate As DateTime) As Double ' 定义每日工作时间段(可根据实际情况修改) Dim workStart As TimeSpan = New TimeSpan(9, 0, 0) ' 9:00 AM Dim workEnd As TimeSpan = New TimeSpan(17, 0, 0) ' 5:00 PM Dim dailyWorkHours As Double = workEnd.Subtract(workStart).TotalHours ' 默认8小时 ' 如果起始日期晚于结束日期,直接返回0 If startDate > endDate Then Return 0 Dim totalHours As Double = 0 ' 处理起始日期当天的工作时长 If IsWorkDay(startDate) Then Dim startOfWorkDay As DateTime = New DateTime(startDate.Year, startDate.Month, startDate.Day) + workStart Dim endOfWorkDay As DateTime = New DateTime(startDate.Year, startDate.Month, startDate.Day) + workEnd Select Case True Case startDate >= endOfWorkDay ' 起始时间在工作结束后,当天无有效时长 Case startDate <= startOfWorkDay totalHours += dailyWorkHours Case Else totalHours += endOfWorkDay.Subtract(startDate).TotalHours End Select End If ' 处理结束日期当天的工作时长 If IsWorkDay(endDate) Then Dim startOfWorkDay As DateTime = New DateTime(endDate.Year, endDate.Month, endDate.Day) + workStart Dim endOfWorkDay As DateTime = New DateTime(endDate.Year, endDate.Month, endDate.Day) + workEnd Select Case True Case endDate <= startOfWorkDay ' 结束时间在工作开始前,当天无有效时长 Case endDate >= endOfWorkDay totalHours += dailyWorkHours Case Else totalHours += endDate.Subtract(startOfWorkDay).TotalHours End Select End If ' 处理起始和结束日期为同一天的情况(避免重复计算) If startDate.Date = endDate.Date Then If IsWorkDay(startDate) Then Dim actualStart As DateTime = If(startDate < startOfWorkDay, startOfWorkDay, startDate) Dim actualEnd As DateTime = If(endDate > endOfWorkDay, endOfWorkDay, endDate) totalHours = If(actualStart < actualEnd, actualEnd.Subtract(actualStart).TotalHours, 0) Else totalHours = 0 End If Else ' 计算中间的完整工作日数量并累加时长 Dim startNextDay As DateTime = startDate.Date.AddDays(1) Dim endPrevDay As DateTime = endDate.Date.AddDays(-1) If startNextDay <= endPrevDay Then Dim workDaysCount As Integer = CountWorkDays(startNextDay, endPrevDay) totalHours += workDaysCount * dailyWorkHours End If End If Return totalHours End Function ' 辅助函数:判断日期是否为工作日(排除周六、周日) Function IsWorkDay(dateToCheck As DateTime) As Boolean Return dateToCheck.DayOfWeek <> DayOfWeek.Saturday AndAlso dateToCheck.DayOfWeek <> DayOfWeek.Sunday End Function ' 辅助函数:计算两个日期之间的完整工作日数量 Function CountWorkDays(startDate As DateTime, endDate As DateTime) As Integer If startDate > endDate Then Return 0 Dim totalDays As Integer = (endDate - startDate).Days + 1 ' 计算总天数中的周末数量 Dim weekends As Integer = (totalDays + CInt(startDate.DayOfWeek)) \ 7 * 2 ' 调整首尾的周末天数(避免多算) If startDate.DayOfWeek = DayOfWeek.Sunday Then weekends -= 1 If endDate.DayOfWeek = DayOfWeek.Saturday Then weekends -= 1 Return totalDays - weekends End Function
测试你的示例
用你给出的案例验证:
- 起始日期:
1/23/2020 9:00:00 AM(周四,工作日) - 结束日期:
1/27/2020 1:30:00 PM(周一,工作日)
计算过程:
- 1/23当天:从9:00到17:00,共8小时
- 中间完整工作日:1/24(周五),1天×8小时=8小时
- 1/25、1/26为周末,直接排除
- 1/27当天:从9:00到13:30,共4.5小时
总时长:8 + 8 + 4.5 = 20.5小时
调用函数验证的代码:
Dim date1 As DateTime = DateTime.Parse("1/23/2020 9:00:00 AM") Dim date2 As DateTime = DateTime.Parse("1/27/2020 1:30:00 PM") Dim hours As Double = CalculateWorkHours(date1, date2) ' 最终hours的值为20.5
额外说明
- 如果你的工作时段不是9:00-17:00,只需要修改函数里的
workStart和workEnd参数即可 - 这个函数暂时没处理节假日,如果需要排除节假日,可以在
IsWorkDay函数里添加逻辑(比如维护一个节假日列表,检查当前日期是否在列表内)
内容的提问来源于stack exchange,提问作者C. Clements
相关产品推荐
相关产品推荐

