Почему недельная дата для 30 декабря 2014 года дает 1 вместо 53
Я пытаюсь получить неделю. от даты следующим образом:
DatePart("WW", "30/12/2014", vbMonday, vbFirstFourDays)
Однако, если он дает результат как 1, не должен ли он дать результат как 53? Какую роль в этом играют vbMonday и vbFirstFourDays?
2 ответа
DatePart("ww", <Date>, vbMonday, vbFirstFourDays)
действительно рассчитывает номер недели ISO 8601 правильно в большинстве случаев.
https://en.wikipedia.org/wiki/ISO_week_date:
Определение ISO 8601 для недели 01 - это неделя с первым четвергом григорианского года.
Следующие определения, основанные на свойствах этой недели, взаимно эквивалентны, поскольку неделя ISO начинается с понедельника:
* Это первая неделя с большинством (4 или более) дней в январе.
* так далее.
2015-01-01 был четверг, поэтому это первая неделя 2015 года.
Таким образом, 2014-12-29 - 2014-12-31 также относятся к первой неделе 2015 года.
Это потому, что функция DatePart не рассчитывается в соответствии со стандартом ISO-8601.
Вам понадобится такая функция, как эта, чтобы получить правильный номер недели и соответствующий год:
Public Function ISO_WeekYearNumber( _
ByVal datDate As Date, _
Optional ByRef intYear As Integer, _
Optional ByRef bytWeek As Byte) _
As String
' Calculates and returns year and week number for date datDate according to the ISO 8601:1988 standard.
' Optionally returns numeric year and week.
' 1998-2007, Gustav Brock, Cactus Data ApS, CPH.
' May be freely used and distributed.
Const cbytFirstWeekOfAnyYear As Byte = 1
Const cbytLastWeekOfLeapYear As Byte = 53
Const cbytMonthJanuary As Byte = 1
Const cbytMonthDecember As Byte = 12
Const cstrSeparatorYearWeek As String = "W"
Dim bytMonth As Byte
Dim bytISOThursday As Byte
Dim datLastDayOfYear As Date
intYear = Year(datDate)
bytMonth = Month(datDate)
bytWeek = DatePart("ww", datDate, vbMonday, vbFirstFourDays)
If bytWeek = cbytLastWeekOfLeapYear Then
bytISOThursday = Weekday(vbThursday, vbMonday)
datLastDayOfYear = DateSerial(intYear, cbytMonthDecember, 31)
If Weekday(datLastDayOfYear, vbMonday) >= bytISOThursday Then
' OK, week count of 53 is caused by leap year.
Else
' Correct for Access97/2000+ bug.
bytWeek = cbytFirstWeekOfAnyYear
End If
End If
' Adjust year where week number belongs to next or previous year.
If bytMonth = cbytMonthJanuary Then
If bytWeek >= cbytLastWeekOfLeapYear - 1 Then
' This is an early date of January belonging to the last week of the previous year.
intYear = intYear - 1
End If
ElseIf bytMonth = cbytMonthDecember Then
If bytWeek = cbytFirstWeekOfAnyYear Then
' This is a late date of December belonging to the first week of the next year.
intYear = intYear + 1
End If
End If
ISO_WeekYearNumber = CStr(intYear) & cstrSeparatorYearWeek & Format(bytWeek, "00")
End Function
Чтобы проверить номер недели:
Public Function ISO_WeekNumber( _
ByVal datDate As Date) _
As Byte
' Calculates and returns week number for date datDate according to the ISO 8601:1988 standard.
' 1998-2000, Gustav Brock, Cactus Data ApS, CPH.
' May be freely used and distributed.
Const cbytFirstWeekOfAnyYear As Byte = 1
Const cbytLastWeekOfLeapYear As Byte = 53
Dim bytWeek As Byte
Dim bytISOThursday As Byte
Dim datLastDayOfYear As Date
bytWeek = DatePart("ww", datDate, vbMonday, vbFirstFourDays)
If bytWeek = cbytLastWeekOfLeapYear Then
bytISOThursday = Weekday(vbThursday, vbMonday)
datLastDayOfYear = DateSerial(Year(datDate), 12, 31)
If Weekday(datLastDayOfYear, vbMonday) >= bytISOThursday Then
' OK, week count of 53 is caused by leap year.
Else
' Correct for Access97/2000 bug.
bytWeek = cbytFirstWeekOfAnyYear
End If
End If
ISO_WeekNumber = bytWeek
End Function