计算仅在营业时间内的日期之间的时间

时间:2013-06-02 14:58:56

标签: asp.net vb.net

我正在尝试计算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语句实现这一点,这似乎是一种无用的方法我想知道是否有人有任何指示让我朝着正确的方向前进。

非常感谢

3 个答案:

答案 0 :(得分: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

控制台应用的输出:

答案 1 :(得分:0)

基本上,您只计算开始和结束之间非营业时间的时间

因此,您所做的是为日期范围

创建非工作时间的“表格”

说它是1/1/2013 08:20到3/1/2013 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中执行此操作

答案 2 :(得分: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)