0

我正在尝试计算 vb.net 中两个日期/时间之间的时间量,以便在 aspx 网页上使用。我已经在这里和其他来源搜索了很多年,但我并没有走得太远。我找到的所有示例都与 PHP 或 SQL 相关。

基本上我有以下......

Dim StartDateTime As DateTime = #5/27/2013 6:00:00 AM#

Dim FinishDateTime As DateTime = #5/28/2013 10:30:00 AM#

Dim Minutes As Long = DateDiff(DateInterval.Minute, StartDateTime, FinishDateTime, Microsoft.VisualBasic.FirstDayOfWeek.Monday)

计算开始和结束之间的分钟数。问题是我只希望它计算我们设定的营业时间 (9-5) 的时间,因此在示例中它应该返回 9.5 小时或 570 分钟,如果时间超过周末,最终不会计算任何时间。

开始时间可以是任何时间(因此可以在营业时间之前或之后),而结束时间通常是营业时间,我们不得不假设它也可以是任何时间。

我也许可以使用大量的 IF 语句来实现这一点,这似乎是一种低效的方法我想知道是否有人有任何指示让我朝着正确的方向前进。

非常感谢

4

3 回答 3

1

我已经创建了一个函数来获取 2 个日期(含)之间的工作日列表,减去假期和周末,如下所示:

Function GetWorkingDates(startDate As Date, endDate As Date, holidayDates As Date()) As List(Of Date)
    If endDate < startDate Then
        Throw New ArgumentOutOfRangeException("endDate", "Value must be equal or larger than 'startDate' parameter.")
    End If

    Dim listDate As List(Of Date) = Enumerable.Range(0, 1 + CInt((endDate - startDate).TotalDays)).Select(Function(n) startDate.AddDays(n)).ToList

    ' if defined, remove holidays from listDate
    If holidayDates IsNot Nothing Then listDate.RemoveAll(Function(d) holidayDates.Contains(d))

    ' remove weekends as defined below
    Dim weekends As DayOfWeek() = {DayOfWeek.Saturday, DayOfWeek.Sunday}
    listDate.RemoveAll(Function(d) weekends.Contains(d.DayOfWeek))

    Return listDate
End Function

为了获得总小时数,我刚刚创建了一个新函数来从上面现有函数的结果中获取总时间跨度:

Function GetTotalWorkingTimeSpan(startDateTime As Date, endDateTime As Date, startWorkTime As TimeSpan, endWorkTime As TimeSpan, holidayDates As Date()) As TimeSpan
    If endDateTime < startDateTime Then
        Throw New ArgumentOutOfRangeException("endDate", "Value must be equal or larger than 'startDate' parameter.")
    End If

    If endWorkTime < startWorkTime Then
        Throw New ArgumentOutOfRangeException("endWorkTime", "Value must be equal or larger than 'startWorkTime' parameter.")
    End If

    ' get list of working days minus weekends and holidays
    Dim lstWorkDays As List(Of Date) = GetWorkingDates(startDateTime.Date, endDateTime.Date, holidayDates)

    ' get total minutes by bultiplying total working days and total minutes per day
    Dim totalMinutes As Double = lstWorkDays.Count * (endWorkTime - startWorkTime).TotalMinutes

    ' deduct the first day's hour if occured later than the startWorkTime, only if startDateTime is a working day
    If lstWorkDays.Contains(startDateTime.Date) Then
        Dim minutesOffset As Double = (startDateTime.TimeOfDay - startWorkTime).TotalMinutes
        If minutesOffset > 0 Then totalMinutes -= minutesOffset
    End If

    ' deduct the last day's hour if occured ealier than the endWorkTime, only if endDateTime is a working day
    If lstWorkDays.Contains(endDateTime.Date) Then
        Dim minutesOffset As Double = (endWorkTime - endDateTime.TimeOfDay).TotalMinutes
        If minutesOffset > 0 Then totalMinutes -= minutesOffset
    End If

    Return TimeSpan.FromMinutes(totalMinutes)
End Function

使用您的数据,我创建了一个测试控制台:

Sub Main()
    Dim sdt As Date = #5/27/2013 6:00:00 AM#
    Dim edt As Date = #5/28/2013 10:30:00 AM#
    Dim hols() As Date = {} ' add holiday dates here

    Dim lst As List(Of Date) = GetWorkingDates(sdt, edt, Nothing) ' or simply Nothing to not check for holidays
    Console.WriteLine("Num of working days = " & lst.Count)
    Console.WriteLine()

    Console.WriteLine("List of working dates:")
    lst.ForEach(Sub(d) Console.WriteLine("* " & d.ToLongDateString))
    Console.WriteLine()

    Dim totalWorkingTimeSpan As TimeSpan = GetTotalWorkingTimeSpan(sdt, edt, New TimeSpan(9, 0, 0), New TimeSpan(17, 0, 0), hols)
    Console.WriteLine("Total working hours = " & totalWorkingTimeSpan.TotalMinutes & " minutes, or " & totalWorkingTimeSpan.TotalHours & " hours")

    PromptExit()
End Sub

控制台应用程序的输出:

于 2013-06-03T11:00:02.770 回答
0

基本上,您只需计算开始和结束之间非工作时间的时间量

所以你要做的是为日期范围创建一个非工作时间的“表格”

假设是 2013 年 1 月 1 日 08:20 到 2013 年 3 月 1 日 17:30

1/1/2013 00:00:00 to 1/1/2013 08:59:59
1/1/2013 17:00:00 to 1/1/2013 23:59:59
2/1/2013 00:00:00 to 1/2/2013 08:59:59
2/1/2013 17:00:00 to 1/2/2013 23:59:59
3/1/2013 00:00:00 to 3/1/2013 08:59:59
3/1/2013 17:00:00 to 3/1/2013 23:59:59

然后你替换第一个开始时间和最后一个结束时间得到

1/1/2013 08:20:00 to 1/1/2013 08:59:59
1/1/2013 17:00:00 to 1/1/2013 23:59:59
2/1/2013 00:00:00 to 1/2/2013 08:59:59
2/1/2013 17:00:00 to 1/2/2013 23:59:59
3/1/2013 00:00:00 to 3/1/2013 08:59:59
3/1/2013 17:00:00 to 3/1/2013 17:30:00

上述时间之和为非营业时间。所以你只需从结尾减去它 - 开始。

有很多不同的方法来做到这一点。在此处搜索,您将找到如何使用 CTE 在 SQL 中执行此操作

于 2013-06-02T15:28:59.700 回答
0

这可以通过代码来实现。将开始和结束时间“标准化”为工作时间需要进行一些计算,确定周末需要进行一些额外的计算,但这是一个相对简单的练习:

    ' Define the start and end hour of the work day
    Const START_HOUR As Integer = 9
    Const FINISH_HOUR As Integer = 17

    Dim StartDateTime As DateTime = #5/27/2013 6:00:00 AM#

    Dim FinishDateTime As DateTime = #5/28/2013 10:30:00 AM#

    If StartDateTime.Hour < START_HOUR Then
        ' If the current hour is less than the start hour, go to the start of the current day
        StartDateTime = New DateTime(StartDateTime.Year, StartDateTime.Month, StartDateTime.Day, START_HOUR, 0, 0)

    ElseIf StartDateTime.Hour > FINISH_HOUR Then
        ' If the current hour is greater than the end hour, go to the start of the next day
        StartDateTime = New DateTime(StartDateTime.Year, StartDateTime.Month, StartDateTime.Day + 1, START_HOUR, 0, 0)

    End If

    If FinishDateTime.Hour < START_HOUR Then
        ' If the current hour is less than the start hour, go back to the end of the previous day
        FinishDateTime = New DateTime(FinishDateTime.Year, FinishDateTime.Month, FinishDateTime.Day - 1, FINISH_HOUR, 0, 0)

    ElseIf FinishDateTime.Hour > FINISH_HOUR Then
        ' If the current hour is greater than the end hour, go to the end hour of the current day
        FinishDateTime = New DateTime(FinishDateTime.Year, FinishDateTime.Month, FinishDateTime.Day, FINISH_HOUR, 0, 0)

    End If

    ' Determine the total number of actual days the date range crosses
    Dim Days = Math.Ceiling(FinishDateTime.Subtract(StartDateTime).TotalDays)

    Dim Weekends As Double

    ' Determine the number of weekends (might need work)
    If FinishDateTime.DayOfWeek > StartDateTime.DayOfWeek Then
        ' I'm sure this needs work
        Weekends = Math.Floor(Days / 7) + 1
    Else
        Weekends = Math.Floor(Days / 7)
    End If

    ' Determine the number of minutes between the start of the work day and the actual start time
    Dim StartMinutesOffset = ((StartDateTime.Hour * 60) + StartDateTime.Minute) - (START_HOUR * 60)
    ' Determine number of minutes between the finish time and the end of the work day
    Dim FinishMinutesOffset = (FINISH_HOUR * 60) - ((FinishDateTime.Hour * 60) + FinishDateTime.Minute)

    ' The number of minutes is the number of days less 2 * the number of weekends less the start time offset less the finish time offset
    Dim TotalMinutes = (Days - (Weekends * 2)) * ((FINISH_HOUR - START_HOUR) * 60) - StartMinutesOffset - FinishMinutesOffset

    Debug.WriteLine(TotalMinutes)
于 2013-06-02T20:19:06.657 回答