開始週と終了週(ISO週として定義されているため、月曜日だけでなく開始する場合もあります)として指定された期間に関する情報があります。
ISOの定義に関しては、1か月にwikipで4週間または5週間の説明が含まれる場合があります。いくつかの期間が完全に数か月に含まれているかどうか、および次のコマンドを実行した後を確認したいと思います。
Excel VBAでこれを行うにはどうすればよいですか?上記のチェックを達成するのに役立つ特別な機能はありますか?
開始週と終了週(ISO週として定義されているため、月曜日だけでなく開始する場合もあります)として指定された期間に関する情報があります。
ISOの定義に関しては、1か月にwikipで4週間または5週間の説明が含まれる場合があります。いくつかの期間が完全に数か月に含まれているかどうか、および次のコマンドを実行した後を確認したいと思います。
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を返します。
少し調整することで、週の始まりが丸1週間よりも心配な場合に備えて、最初の週と先週の両方の開始日を報告することができます。
使用したテストケース:
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