【问题标题】:Excel find next available date from list of day/time slotsExcel 从日期/时间段列表中查找下一个可用日期
【发布时间】:2019-06-23 05:51:06
【问题描述】:

在 Excel 中,假设我有一个每周可用的可用日期和时间列表(2 个单独的列):

DAY         TIME
Monday      5:00 PM
Tuesday     4:00 PM
Wednesday   11:00 AM
Thursday    4:00 PM
Friday      11:00 AM
Friday      12:00 PM

这个列表是可变的,可以随时更改,所以解决方案需要是一个公式,可以根据可用列表的变化重新计算。

然后我有一列可能的“开始”日期/时间:

START TIME
3/12/19 3:00 PM (Tuesday)
3/12/19 4:00 PM (Tuesday)
3/15/19 2:00 PM (Friday)

有没有一种方法可以将开始日期旁边的 3 个单独列中的下 3 个可用天数/时间计算为初始开始日期之后的实际日期?如果可用日期与开始日期是一周中的同一天,则需要检查时间是否早于可用时间。如果是,那么它可以在同一天晚些时候......如果开始时间在可用时间之后,那么它必须在一周之后。

计算的时间可以与前一行相同,因此公式不需要考虑任何类型的重复预订。 2 行中的相同日期/时间将产生相同的 3 个下一个可用日期/时间。

所以在上面的例子中,它会导致:

START TIME          Next Available Date 1    Next Available Date 2    Next Available Date 3
3/12/19 3:00 PM     3/12/19 4:00 PM          3/13/19 11:00 AM         3/14/19 4:00 PM          
3/12/19 4:01 PM     3/13/19 11:00 AM         3/14/19 4:00 PM          3/15/19 11:00 AM 
3/15/19 2:00 PM     3/18/19 5:00 PM          3/19/19 4:00 PM          3/20/19 11:00 AM 

我一直在尝试使用数组公式,但无法让它适用于所有情况。解决方案需要基于公式,并且不使用 VBA 或 UDF。

【问题讨论】:

  • 我认为你问错了问题。恕我直言,您需要一个基于可用日期列表从 NOW() 计算的列表,基本上是将您的基于工作日的列表转换为基于日期的列表,该列表不包括过去的任何内容并至少延长 7 天到未来。然后,您可以在此列表中找到 3 个未来日期,而无需将日期转换为工作日或排除过去的日期。显然,只有当您有合适的清单可供参考时,才能完成这项任务。
  • 我不认为 N​​ow() 参与其中,因为它必须从列出的开始日期确定下一个日期。这是未来与过去的基础。如果开始日期是 3 年前,它仍然应该计算之后的 3 个日期。 Now() 是否改变并不重要(即,我今天打开它还是明天打开它)。
  • 了解这一点很有用。关键是要避免规则,“如果可用日期与开始日期相同,则需要检查时间”。这将使公式的大小增加一倍或三倍,并且应该通过没有开始日期而是开始时间来排除,并且列表中不包含不合适的日期,这意味着,列表必须构建为仅包含合适的时间。

标签: excel excel-formula


【解决方案1】:

这可能会像铅气球一样下降,并且可能过度设计,但如果您正在寻找 VBA 解决方案,这应该适合您。

将以下代码添加到 VBA 编辑器中的新模块中...

Public Function CalculateNextAvailableDay(ByVal rngAvailableDays As Range, ByVal dtDate As Date, ByVal lngAvailableDayIndex As Long) As Date
    Dim strThisDay As String, tmThisTime As Variant, i As Long, intAvailableDay As Integer, lngRow As Long, dtNextDate As Date, arrNextAvailableDates() As Variant
    Dim lngArrayIndex As Long, intNextDateDay As Integer, lngMaxSecondsDiff As Long, lngSecondsDiff As Long, intDateOffset As Integer
    Dim lngIndexToRemove As Long, x As Long, bBeenThrough As Boolean

    Application.Volatile

    ' First, build up the range of next available DATES, not DAYS.
    For lngRow = 1 To rngAvailableDays.Rows.Count
        strThisDay = UCase(Trim(rngAvailableDays.Cells(lngRow, 1)))

        tmThisTime = TimeValue(rngAvailableDays.Cells(lngRow, 2).Text)

        Select Case strThisDay
            Case "SUNDAY"
                intAvailableDay = 1
            Case "MONDAY"
                intAvailableDay = 2
            Case "TUESDAY"
                intAvailableDay = 3
            Case "WEDNESDAY"
                intAvailableDay = 4
            Case "THURSDAY"
                intAvailableDay = 5
            Case "FRIDAY"
                intAvailableDay = 6
            Case "SATURDAY"
                intAvailableDay = 7
        End Select

        dtNextDate = DateValue(Split(CStr(dtDate))(0)) + tmThisTime
        intDateOffset = 0

        Do While 1 = 1
            dtNextDate = DateAdd("d", intDateOffset, dtNextDate)
            intNextDateDay = Weekday(dtNextDate)

            intDateOffset = 1

            If intNextDateDay = intAvailableDay And dtNextDate >= dtDate Then
                ' This date counts, add it to the list of available next dates.
                ReDim Preserve arrNextAvailableDates(lngArrayIndex)
                arrNextAvailableDates(lngArrayIndex) = dtNextDate

                lngArrayIndex = lngArrayIndex + 1

                Exit Do
            End If
        Loop
    Next

    ' Now find the next available date.
    For x = 1 To lngAvailableDayIndex
        lngMaxSecondsDiff = 0
        bBeenThrough = False

        ' We have all of the next available dates.
        For i = 0 To UBound(arrNextAvailableDates)
            If arrNextAvailableDates(i) <> "" Then
                lngSecondsDiff = Abs(DateDiff("s", arrNextAvailableDates(i), dtDate))

                If lngSecondsDiff < lngMaxSecondsDiff Or Not bBeenThrough Then
                    lngMaxSecondsDiff = lngSecondsDiff
                    lngIndexToRemove = i
                    bBeenThrough = True
                End If
            End If
        Next

        dtNextDate = arrNextAvailableDates(lngIndexToRemove)
        arrNextAvailableDates(lngIndexToRemove) = ""
    Next

    CalculateNextAvailableDay = dtNextDate
End Function

...要使用,请在第一个表格的顶部(不包括标题)上定义一个名为 rngAvailableDays 的命名范围。

使用您的矩阵,将“可用日期 1”等的标题更改为数字,例如...

  • “上市日期1”,改为“1”
  • “上市日期2”,改为“2”
  • “上市日期3”,改为“3”

然后,您可以将它们自定义格式为 ... "Available Date" 0 ... 这样它们就可以像以前一样显示,但它们必须只是数字。

完成后,将以下公式添加到“下一个可用日期”矩阵的第一个单元格中...

=CalculateNextAvailableDay(rngAvailableDays,$D2,E$1)

... 将“$D2”替换为第一个开始日期,将“E$1”替换为“Available Date 1”标题字段。

现在填写并交叉并交叉你的手指,它应该适合你。

确保将日期格式化为日期和时间!

我希望一切都清楚。

告诉我你的情况。

【讨论】:

  • 谢谢,但我应该更清楚一点,它需要是一个没有 VBA 或 UDF 的全公式解决方案。
猜你喜欢
  • 2015-04-26
  • 2021-04-22
  • 2021-03-11
  • 1970-01-01
  • 2017-10-14
  • 1970-01-01
  • 1970-01-01
  • 2018-03-14
  • 1970-01-01
相关资源
最近更新 更多