我有一些关于某些时间段的信息作为开始和结束周(定义为ISO周,因此它们不仅可以在星期一开始)。VBA - 检查一些时间段是否完全包含在某个月
关于ISO定义,一个月可能包含4或5周description on wikip。 我想检查一些时间段是否完全包含在几个月内,并在它执行下一个命令之后。
如何在Excel VBA中执行此操作?有什么特殊功能可以帮助我实现上述检查?
我有一些关于某些时间段的信息作为开始和结束周(定义为ISO周,因此它们不仅可以在星期一开始)。VBA - 检查一些时间段是否完全包含在某个月
关于ISO定义,一个月可能包含4或5周description on wikip。 我想检查一些时间段是否完全包含在几个月内,并在它执行下一个命令之后。
如何在Excel VBA中执行此操作?有什么特殊功能可以帮助我实现上述检查?
这有帮助吗?
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
这是测试的代码基于我自己的一些假设(其中工程作为工作表函数或通过VBA)。 (需要你的数据测试肯定...)如果你有一个特定的格式示例,我会改变这个代码来匹配。
这假定您将正确的变量传递给函数中的正确位置。没有适当的开始/结束日期顺序检查,尽管至少不应该有任何错误。
此外,可能会有更有效的方法来做到这一点,而不是循环这些数组,但这是有效的。
这是干什么的,简单地说,就是计算给定开始周的第一天和给定结束周的最后一天的日期。如果这两个日期都在同一个月,那么该函数返回true。
只需稍作调整,我们可以报告第一周和上周的开始日期,以防您担心本周的开始时间超过整周。使用
测试用例:
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函数一样工作,返回您正在查找的格式化日期/月份的数组(变体)。要将其转换为工作表函数,只需稍作调整即可返回字符串(已在函数中创建 - 请参阅注释)。
我在假设您的例子错了(请参阅我的测试用例),但是如果这是我的错误,那么可以将其修改为可用。
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
测试用例:
"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
好的代码,但是当我开始阅读时...我意识到这不是我想要实现的...对不起,这是我的错 - 我错误地描述了这个问题。 – matandked 2012-04-19 10:58:28
好的代码,但是当我开始阅读时...我意识到这不是我想要实现的......对不起,这是我的错 - 我错误地描述了这个问题。我们来考虑几个月2010/2010和06/2010 05/2010月开始于18-2010周,结束于21-2010 月06/2012开始于22-2010周,结束于25-2010。 让我举一些例子 Start_wk \t End_wk \t \t结果(月) 18-2010 \t \t 20-2010 \t \t NULL 17-2010 \t \t 20-2010 \t \t NULL 17-2010 \t \t 21- 2010 \t 05/2010 18-2010 \t \t 25-2010 \t \t 05/2010,06/2010 19-2010 \t \t 26-2010 \t \t 06/2010 – matandked 2012-04-19 11:28:09
我已经更新了上面的代码。请在这里使用评论进行交流,因为为自己的问题添加新答案的做法不正确。它不仅从该网站的Q + A格式转移,但我不会看到您以这种方式发布的任何更新。评论我的回答将确保我收到通知。 – Gaffi 2012-05-21 19:48:47
能否请您提供您的数据的样本? – Gaffi 2012-04-18 13:32:39