Muotoilu- tai DatePart-funktiot voivat palauttaa väärän viikon numeron vuoden viimeiselle maanantaille

Huomautus

Office 365 ProPlus nimetään uudelleen Microsoft 365 Apps for enterprise -sovellukseksi. Lisätietoja tästä muutoksesta on tässä blogikirjoituksessa.

Varoitus

Tämän funktion käytössä on ongelma. Joidenkin kalenterivuosien viimeinen maanantai voidaan palauttaa viikon 53, jolloin sen pitäisi olla viikko 1. Lisätietoja ja vaihtoehtoinen menetelmä on kohdassa Muotoilu- tai DatePart-funktiot voivat palauttaa väärän viikon numeron vuoden viimeiselle maanantaille.

Oireet

Kun käytät joko Format- tai DatePart-funktiota päivämäärien viikkonumeron määrittämiseen seuraavan syntaksin avulla:

  • Format(AnyDate, "ww", vbMonday, vbFirstFourDays)
  • DatePart("ww", AnyDate, vbMonday, vbFirstFourDays)

joidenkin kalenterivuosien viimeinen maanantai palautetaan viikoksi 53, jolloin sen pitäisi olla viikko 1.

Syy

Kun päivämäärä viikkonumero määritetään ISO 8601 -standardin mukaisesti, Oleaut32.dll-tiedostoon kutsu palauttaa virheellisesti viikon 53 eikä viikon 1, joka on tiettyinä vuosina viimeisen maanantain viikon 1 sijaan.

Ratkaisu

Käyttäjän määrittämän funktion avulla voit palauttaa viikkonumeron ISO 8601 -standardin sääntöjen perusteella. Tässä artikkelissa on esimerkki.

Lisätietoja

ISO 8601 -standardia käytetään laajalti Euroopassa, ja se sisältää seuraavat:

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."

Tämän voi ottaa käyttöön käyttämällä näitä sääntöjä kalenteriviikoille:

  • Vuosi jaetaan joko 52 tai 53 kalenteriviikoon.
  • Kalenteriviikossa on 7 päivää. Maanantai on päivä 1, sunnuntai on päivä 7.
  • Vuoden ensimmäinen kalenteriviikko on se, joka sisältää vähintään neljä päivää.
  • Jos vuosi ei ole päättynyt sunnuntaina, sen 1–3 viimeistä päivää kuuluvat seuraavan vuoden ensimmäiseen kalenteriviikkoon tai ensi vuoden ensimmäiseen 1–3 päivään, kuuluvat nykyisen vuoden viime kalenteriviikoon.
  • Vain vuosi, joka alkaa tai päättää torstaista, sisältää 53 kalenteriviikkoa.

Visual Basic Visual Basic for Applications päivämäärätoiminto DateSerial-funktiota lukuun ottamatta tulee puheluista Oleaut32.dll tiedostoon. Koska sekä Format()- että DatePart()-funktiot voivat palauttaa kalenteriviikon numeron annettuna päivänä, tämä virhe vaikuttaa molempiin. Voit välttää tämän ongelman käyttämällä tässä artikkelissa tarkoitettua vaihtoehtoista koodia.

Toiston toimintavaiheet

  1. Avaa Visual Basic projekti Office sovelluksessa (Alt + F11).

  2. Lisää Project-valikosta uusi moduuli.

  3. Liitä seuraava koodi moduuliin:

    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
    
  4. Jos pikaikkuna ei ole jo avoinna, avaa se näppäinyhdistelmällä (Ctrl + G).

  5. Kirjoita ? Paina Enter-näppäintä ja paina sitten Heti-ikkunassa Testi1-painiketta. Huomaa seuraavat tulokset Välittömässä kentässä:

    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
    

    Tässä muodossa kaikki viikot alkavat maanantaista, joten 29.12.2003 pitäisi olla viikon 1 alku eikä osa viikkoa 53.

  6. Kirjoita ? Testaa2 Välitön-ikkunassa ja paina Enter-näppäintä, jos haluat nähdä luettelon määritetyn alueen päivämääristä, joissa tämä ongelma ilmenee. Luettelossa on päivämäärä, viikonpäivä (aina maanantai), Muotoilun palauttama viikko #-arvo (53) ja viikon numero (1).) Esimerkki:

    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
    ...
    

Vaihtoehtoinen menetelmä

Jos käytät Format- tai DatePart-funktioita, sinun on tarkistattava palautusarvo. Kun se on 53, suorita toinen tarkistus ja pakota tarvittaessa 1:n palautus. Tässä koodimallissa esitellään yksi tapa tehdä tämä:

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

Voit välttää näiden funktioiden käytön viikkonumeron määrittämiseen kirjoittamalla koodin, joka ottaa käyttöön edellä kuvatut ISO 8601 -säännöt. Seuraavassa esimerkissä esitellään korvaava funktio, joka palauttaa viikkonumeron.

Vaiheittainen esimerkki

  1. Avaa Visual Basic projekti Office sovelluksessa (Alt + F11).

  2. Lisää Project-valikosta uusi moduuli.

  3. Liitä seuraava koodi moduuliin:

    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
    
  4. Jos pikaikkuna ei ole jo avoinna, avaa se näppäinyhdistelmällä (Ctrl + G).

  5. Kirjoita ? Paina Enter-näppäintä ja kirjoita seuraavat tulokset heti näkyviin Testi3-ruutuun ja paina Enter-näppäintä:

    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
    

    Huomaa, että maanantai on viikon 1 päivä, kuten pitäisikin.