VBA – 检查一些时间段是否完全包含在一个月内

我有一些关于开始和结束周的时间段的信息(定义为ISO周,所以他们不仅可以在星期一开始)。

关于ISO定义,一个月可能包含wikip的 4或5个星期的描述 。 我想检查一些时间段是否完全包含在几个月内,并在执行下一个命令之后。

我如何在Excel VBA中执行此操作? 有什么特别的function可以帮我实现上述的检查吗?

这有帮助吗?

Function ContainedInMonth(OriginalStartDate As String, _ OriginalEndDate As String) As Boolean Dim MonthSet As Variant Dim AryCounter As Integer, ISOOffset As Integer Dim StartYear As Integer, EndYear As Integer Dim StartWeek As Integer, EndWeek As Integer Dim StartDay As Integer, EndDay As Integer Dim FormattedStartDate As Date, FormattedEndDate As Date ' This section may (will) vary, depending on your data. ' I'm assuming "YYYY-WW" is passed... ' Also, error/formatting checking for these values is needed ' and wil differ depending on that format. StartYear = Val(Left(OriginalStartDate, 4)) StartWeek = Val(Right(OriginalStartDate, 2)) EndYear = Val(Left(OriginalEndDate, 4)) EndWeek = Val(Right(OriginalEndDate, 2)) If StartYear <> EndYear Or StartWeek > EndWeek Then ContainedInMonth = False ElseIf StartWeek = EndWeek Then ContainedInMonth = True Else ' Using the calculation from wikipedia. Honestly, I'm not sure that ' I understand this bit, but it seemed to work for my test cases. ISOOffset = Weekday(CDate("1/4/" & StartYear), vbMonday) + 3 StartDay = (StartWeek * 7) - ISOOffset ' Adding 0 for start of week EndDay = (EndWeek * 7) + 6 - ISOOffset ' Adding 6 for end of week ' Set the starting day for each month, depending on leap year. If StartYear Mod 4 = 0 Then MonthSet = Array(0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335) Else MonthSet = Array(0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334) End If FormattedStartDate = 0:FormattedEndDate = 0 For AryCounter = 11 To 0 Step -1 If StartDay > MonthSet(AryCounter) And FormattedStartDate = 0 Then ' Using MM/DD/YYYY format - this may be different for you FormattedStartDate = CDate(AryCounter + 1 & _ "/" & StartDay - MonthSet(AryCounter) & "/" & StartYear) End If If EndDay > MonthSet(AryCounter) And FormattedEndDate = 0 Then FormattedEndDate = CDate(AryCounter + 1 & _ "/" & EndDay - MonthSet(AryCounter) & "/" & EndYear) End If Next AryCounter ContainedInMonth = IIf(Month(FormattedStartDate) = Month(FormattedEndDate), True, False) End If End Function 

这是基于我自己的一些假设testing代码(作为工作表函数或通过VBA)。 (需要你的数据testing肯定…)如果你有一个特定的格式的例子,我会改变这个代码来匹配。

这假设你将正确的variables传递给函数中的正确位置。 没有适当的检查开始/结束date顺序,但至less不应该有任何错误。

此外,可能有更有效的方法来做到这一点,而不是循环这些数组,但这是有效的。

这只是计算给定开始周的第一天和给定结束周的最后一天的date。 如果这两个date都在同一个月份,那么函数返回true。

稍微调整一下,如果你担心本周的开始时间超过整周,那么我们可以报告第一周和最后一周的开始date。

使用的testing用例:

 Start End Result 2012-01 2012-05 FALSE 2012-01 2012-04 TRUE 2012-05 2012-07 FALSE 2012-25 2012-26 TRUE 2012-52 2012-01 FALSE 2012-28 2012-25 FALSE 

编辑:

按照您提供的示例,这是一个更新的函数。 这将像VBA函数一样工作,返回您正在查找的格式化date/月份的数组(变体)。 要将其转换为工作表函数,只需稍作调整即可返回string(已在函数中创build – 请参阅注释)。

我假设你的例子是错误的(参见我的testing用例),但是如果我错了,可以修改它。

 Function ContainsWhatMonths(OriginalStartDate As String, _ OriginalEndDate As String) As Variant Dim MonthSet As Variant Dim AryCounter As Integer, ISOOffset As Integer Dim StartYear As Integer, EndYear As Integer Dim StartWeek As Integer, EndWeek As Integer Dim StartDay As Integer, EndDay As Integer Dim StartWeekStartDate As Date, StartWeekEndDate As Date Dim EndWeekStartDate As Date, EndWeekEndDate As Date Dim FormattedStartDate As Date, FormattedEndDate As Date Dim TotalMonths As Integer, OutputMonths As String StartYear = Val(Right(OriginalStartDate, 4)) StartWeek = Val(Left(OriginalStartDate, 2)) EndYear = Val(Right(OriginalEndDate, 4)) EndWeek = Val(Left(OriginalEndDate, 2)) If StartYear <= EndYear Then ' Using the calculation from wikipedia. Honestly, I'm not sure that ' I understand this bit, but it seemed to work for my test cases. ISOOffset = Weekday(CDate("1/4/" & StartYear), vbMonday) + 3 StartDay = (StartWeek * 7) - ISOOffset ' Adding 0 for start of week EndDay = (EndWeek * 7) + 6 - ISOOffset ' Adding 6 for end of week ' Set the starting day for each month, depending on leap year. If StartYear Mod 4 = 0 Then MonthSet = Array(0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335) Else MonthSet = Array(0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334) End If For AryCounter = 11 To 0 Step -1 If StartDay > MonthSet(AryCounter) Then ' Using MM/DD/YYYY format - this may be different for you StartWeekStartDate = CDate(AryCounter + 1 & _ "/" & StartDay - MonthSet(AryCounter) & "/" & StartYear) StartWeekEndDate = StartWeekStartDate + 6 If Month(StartWeekStartDate) <> Month(StartWeekEndDate) Then FormattedStartDate = DateSerial(StartYear, Month(StartWeekEndDate), 1) Else FormattedStartDate = DateSerial(StartYear, Month(StartWeekEndDate) + 1, 1) End If Exit For End If Next AryCounter If EndYear Mod 4 = 0 Then MonthSet = Array(0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335) Else MonthSet = Array(0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334) End If For AryCounter = 11 To 0 Step -1 If EndDay > MonthSet(AryCounter) Then EndWeekStartDate = CDate(AryCounter + 1 & _ "/" & EndDay - MonthSet(AryCounter) & "/" & EndYear) EndWeekEndDate = EndWeekStartDate + 6 If Month(EndWeekStartDate) <> Month(EndWeekEndDate) Then FormattedEndDate = CDate(Month(EndWeekEndDate) & "/1/" & EndYear) - 1 Else FormattedEndDate = CDate(Month(EndWeekEndDate) & "/1/" & EndYear) End If Exit For End If Next AryCounter ' Switch the commenting on these two lines to return the string ContainsWhatMonths = Array() 'ContainsWhatMonths = vbNullString TotalMonths = (Year(FormattedEndDate) - Year(FormattedStartDate)) * 12 + _ Month(FormattedEndDate) - Month(FormattedStartDate) If TotalMonths >= 0 Then For AryCounter = 0 To TotalMonths OutputMonths = OutputMonths & "," & _ Format(DateAdd("m", AryCounter, FormattedStartDate), "MM/YYYY") Next OutputMonths = Right(OutputMonths, Len(OutputMonths) - 1) ' Switch the commenting on these two lines to return the string ContainsWhatMonths = Split(OutputMonths, ",") 'ContainsWhatMonths = OutputMonths End If End If End Function 

testing用例:

 "18-2010", "20-2010" 'Null "17-2010", "20-2010" 'Null "17-2010", "21-2010" '05/2010 "18-2010", "25-2010" '06/2010 "17-2010", "25-2010" '05/2010,06/2010 "19-2010", "26-2010" '06/2010