Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Varning
Det finns ett problem med användningen av den här funktionen. Den sista måndagen under vissa kalenderår kan returneras som vecka 53 när det ska vara vecka 1. För mer information och en lösning, se Format eller DatePart-funktionerna kan returnera fel veckonummer för årets sista måndag.
Symptome
När du använder antingen funktionen Format eller DatePart för att fastställa veckonumret för datum med hjälp av följande syntax:
Format(AnyDate, "ww", vbMonday, vbFirstFourDays)
DatePart("ww", AnyDate, vbMonday, vbFirstFourDays)
Den sista måndagen under vissa kalenderår returneras som vecka 53 när det ska vara vecka 1.
Orsak
När du fastställer veckonumret för ett datum enligt STANDARDEN ISO 8601 returnerar den underliggande funktionsanropet till Oleaut32.dll-filen av misstag vecka 53 i stället för vecka 1 för den senaste måndagen under vissa år.
Lösning / Beslut
Använd en användardefinierad funktion för att returnera veckonumret baserat på reglerna för STANDARDEN ISO 8601. Ett exempel ingår i den här artikeln.
Mer information
ISO 8601-standarden används i stor utsträckning i Europa och omfattar:
ISO 8601 "Data elements and interchange formats - Information interchange - Representation of dates and times"
ISO 8601 : 1988 (E) paragraph 3.17:
"week, calendar: A seven day period within a calendar year, starting on a Monday and identified by its ordinal number within the year; the first calendar week of the year is the one that includes the first Thursday of that year. In the Gregorian calendar, this is equivalent to the week which includes 4 January."
Det kan implementeras genom att tillämpa dessa regler för kalenderveckor:
- Ett år är indelat i antingen 52 eller 53 kalenderveckor.
- En kalendervecka har sju dagar. Måndag är dag 1 och söndag är dag 7.
- Den första kalenderveckan på ett år är den som innehåller minst fyra dagar.
- Om ett år inte avslutas på en söndag tillhör antingen dess 1-3 sista dagar nästa års första kalendervecka eller de första 1-3 dagarna nästa år tillhör det nuvarande årets sista kalendervecka.
- Endast ett år som börjar eller avslutas på en torsdag har 53 kalenderveckor.
I Visual Basic och Visual Basic för program kommer alla datumfunktioner, förutom funktionen DateSerial, från anrop till filen Oleaut32.dll. Eftersom både funktionerna Format() och DatePart() kan returnera kalenderveckanumret för ett visst datum påverkas båda av den här buggen. För att undvika det här problemet måste du använda den alternativa kod som den här artikeln innehåller.
Steg för att återskapa beteende
Öppna Visual Basic-projektet i ett Office-program (Alt + F11).
Lägg till en ny modul på Projekt-menyn .
Klistra in följande kod i modulen:
Option Explicit Public Function Test1() ' This code tests a "problem" date and the days around it Dim DateValue As Date Dim i As Integer Debug.Print " Format function:" DateValue = #12/27/2003# For i = 1 To 4 ' examine the last 4 days of the year DateValue = DateAdd("d", 1, DateValue) Debug.Print "Date: " & DateValue & " Day: " & _ Format(DateValue, "ddd") & " Week: " & _ Format(DateValue, "ww", vbMonday, vbFirstFourDays) Next i End Function Public Function Test2() ' This code lists all "Problem" dates within a specified range Dim MyDate As Date Dim Years As Long Dim days As Long Dim woy1 As Long Dim woy2 As Long Dim ToPrint As String For Years = 1850 To 2050 For days = 0 To 3 MyDate = DateSerial(Years, 12, 28 + days) woy1 = Format(MyDate, "ww", vbMonday, vbFirstFourDays) woy2 = Format(MyDate, "ww", vbMonday, vbFirstFourDays) If woy2 > 52 Then If Format(MyDate + 7, "ww", vbMonday, vbFirstFourDays) = 2 Then _ woy2 = 1 End If If woy1 <> woy2 Then ToPrint = MyDate & String(13 - Len(CStr(MyDate)), " ") ToPrint = ToPrint & Format(MyDate, "dddd") & _ String(10 - Len(Format(MyDate, "dddd")), " ") ToPrint = ToPrint & woy1 & String(5 - Len(CStr(woy1)), " ") ToPrint = ToPrint & woy2 Debug.Print ToPrint End If Next days Next Years End Function
Använd (Ctrl + G) för att öppna det omedelbara fönstret om det inte redan är öppet.
Typ ? Test1 i fönstret Omedelbart och tryck på Retur. Observera följande resultat i fönstret Omedelbart:
Format function: Date: 12/28/03 Day: Sun Week: 52 Date: 12/29/03 Day: Mon Week: 53 Date: 12/30/03 Day: Tue Week: 1 Date: 12/31/03 Day: Wed Week: 1
Med det här formatet börjar alla veckor med måndag, så att 29 december 2003 bör betraktas som början av vecka 1 och inte en del av vecka 53.
Typ ? Test2 i fönstret Omedelbart och tryck på Retur för att se en lista med datum i det angivna intervall som upplever det här problemet. Listan innehåller datum, Veckodag (alltid måndag), Veckonummer som returneras av Format (53) och veckonumret som ska returneras (1.) Till exempel:
12/29/1851 Monday 53 1 12/31/1855 Monday 53 1 12/30/1867 Monday 53 1 12/29/1879 Monday 53 1 12/31/1883 Monday 53 1 12/30/1895 Monday 53 1 ...
Lösningar
Om du använder funktionerna Format eller DatePart måste du kontrollera returvärdet. När den är 53 kör du en annan kontroll och tvingar fram en retur på 1 om det behövs. Det här kodexemplet visar ett sätt att göra detta:
Function WOY (MyDate As Date) As Integer ' Week Of Year
WOY = Format(MyDate, "ww", vbMonday, vbFirstFourDays)
If WOY > 52 Then
If Format(MyDate + 7, "ww", vbMonday, vbFirstFourDays) = 2 Then WOY = 1
End If
End Function
Du kan undvika att använda dessa funktioner för att fastställa veckonummer genom att skriva kod som implementerar ISO 8601-reglerna som beskrivs ovan. I följande exempel visas en ersättningsfunktion för att returnera veckonumret.
Steg för steg-exempel
Öppna Visual Basic-projektet i ett Office-program (Alt + F11).
Lägg till en ny modul på Projekt-menyn .
Klistra in följande kod i modulen:
Option Explicit Function WeekNumber(InDate As Date) As Integer Dim DayNo As Integer Dim StartDays As Integer Dim StopDays As Integer Dim StartDay As Integer Dim StopDay As Integer Dim VNumber As Integer Dim ThurFlag As Boolean DayNo = Days(InDate) StartDay = Weekday(DateSerial(Year(InDate), 1, 1)) - 1 StopDay = Weekday(DateSerial(Year(InDate), 12, 31)) - 1 ' Number of days belonging to first calendar week StartDays = 7 - (StartDay - 1) ' Number of days belonging to last calendar week StopDays = 7 - (StopDay - 1) ' Test to see if the year will have 53 weeks or not If StartDay = 4 Or StopDay = 4 Then ThurFlag = True Else ThurFlag = False VNumber = (DayNo - StartDays - 4) / 7 ' If first week has 4 or more days, it will be calendar week 1 ' If first week has less than 4 days, it will belong to last year's ' last calendar week If StartDays >= 4 Then WeekNumber = Fix(VNumber) + 2 Else WeekNumber = Fix(VNumber) + 1 End If ' Handle years whose last days will belong to coming year's first ' calendar week If WeekNumber > 52 And ThurFlag = False Then WeekNumber = 1 ' Handle years whose first days will belong to the last year's ' last calendar week If WeekNumber = 0 Then WeekNumber = WeekNumber(DateSerial(Year(InDate) - 1, 12, 31)) End If End Function Function Days(DayNo As Date) As Integer Days = DayNo - DateSerial(Year(DayNo), 1, 0) End Function Public Function Test3() Dim DateValue As Date, i As Integer Debug.Print " WeekNumber function:" DateValue = #12/27/2003# For i = 1 To 4 ' examine the last 4 days of the year DateValue = DateAdd("d", 1, DateValue) Debug.Print "Date: " & DateValue & " Day: " & _ Format(DateValue, "ddd") & " Week: " & WeekNumber(DateValue) Next i End Function
Använd (Ctrl + G) för att öppna det omedelbara fönstret om det inte redan är öppet.
Typ ?Test3 i fönstret Omedelbart och tryck på Retur. Observera följande resultat i fönstret Omedelbart:
WeekNumber function: Date: 12/28/03 Day: Sun Week: 52 Date: 12/29/03 Day: Mon Week: 1 Date: 12/30/03 Day: Tue Week: 1 Date: 12/31/03 Day: Wed Week: 1
Måndagen anses vara vecka 1 som den ska vara.