DetailPage-MSS-KB

Base de connaissances

Numéro d'article: 200299 - Dernière mise à jour: lundi 19 septembre 2005 - Version: 3.0

Ancien nº de publication de cet article : F200299

Sommaire

Symptômes

Lorsque vous utilisez la fonction Format ou DatePart pour déterminer le numéro de semaine d'une date avec la syntaxe suivante :
Format(AnyDate, "ww", vbMonday, vbFirstFourDays)

DatePart("ww", AnyDate, vbMonday, vbFirstFourDays)
				
certaines années, la semaine 53 est renvoyée pour le dernier lundi alors que ce devrait être la semaine 1.

Cause

Lors de la détermination du numéro de semaine d'une date selon la norme ISO 8601, l'appel de la fonction sous-jacente au fichier Oleaut32.dll renvoie par erreur la semaine 53 au lieu de la semaine 1 pour le dernier lundi de certaines années.

Résolution

Utilisez une fonction définie par l'utilisateur qui renverra le numéro de la semaine conformément aux règles définies dans la norme ISO 8601. Un exemple est fourni dans cet article.

Statut

Microsoft a confirmé l'existence de ce problème dans le fichier Oleaut32.dll.

Plus d'informations

La norme ISO 8601, largement utilisée en Europe, stipule, entre autres :
  ISO 8601 Éléments de données et formats d'échange - Échange d'information   - Représentation de la date et de l'heure
  ISO 8601 : 1988 (E) paragraphe 3.17 :
  « semaine, calendrier : période de sept jours d'une année de calendrier, commençant
  un lundi et identifiée par son numéro ordinal dans l'année ;
  la première semaine de calendrier d'année est celle qui inclut le
  premier jeudi de cette année. Dans le calendrier grégorien, ceci équivaut
  à la semaine qui inclut le 4 janvier. »
				
Cette norme peut être mise en oeuvre en appliquant les règles suivantes aux semaines de calendrier :
  • Une année est divisée en 52 ou 53 semaines.
  • Une semaine se compose de 7 jours, lundi étant le jour 1 et dimanche le jour 7.
  • La première semaine d'une année est celle qui comporte au moins 4 jours.
  • Si une année ne se termine pas un dimanche, soit ses derniers jours 1 à 3 appartiennent à la semaine 1 de l'année suivante, soit les premiers jours 1 à 3 de l'année suivante appartiennent à la dernière semaine de l'année en cours.
  • Seule une année qui commence ou qui se termine un jeudi possède 53 semaines.
Dans Visual Basic et Visual Basic pour Applications, toutes les fonctions de date, à l'exception de la fonction DateSerial, s'appuient sur des appels au fichier Oleaut32.dll. Étant donné que les fonctions Format() et DatePart() peuvent renvoyer le numéro de la semaine d'une date donnée, elles sont toutes deux concernées par ce bogue. Pour éviter ce problème, vous devez employer le code alternatif fourni dans cet article.

Procédures pour reproduire le problème

  1. Démarrez un projet EXE standard dans Visual Basic. Form1 est créé par défaut.
  2. Ajoutez deux CommandButtons à Form1.
  3. Copiez le code suivant dans la fenêtre de code de Form1 :
    Option Explicit
    
    Private Sub Command1_Click()
    ' 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 Sub
    
    Private Sub Command2_Click()
    ' 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 Sub
    					
  4. Maintenez enfoncée la touche CTRL et appuyez sur la touche G pour ouvrir la fenêtre Exécution.
  5. Exécutez le projet, cliquez sur Command1 et notez les résultats suivants dans la fenêtre Exécution :
       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
    						
    Vous remarquerez qu'avec ce format, comme toutes les semaines commencent un lundi, la date du 12/29/2003 sera considérée comme le début de la semaine 1, et non comme faisant partie de la semaine 53.
  6. Cliquez sur Command2 pour afficher la liste des dates dans la période spécifiée qui présentent ce problème. La liste inclut la date, le jour de la semaine (toujours Lundi), le numéro de la semaine renvoyé par Format (53) et le numéro de la semaine qui devrait être renvoyé (1.) Exemple :
    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
    ...
    					

Contournement

Si vous utilisez la fonction Format ou DatePart, vous devez vérifier la valeur renvoyée et, si c'est la valeur 53, revérifier et forcer le retour de 1, le cas échéant. Cet exemple de code explique la procédure :
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
				
Vous pouvez remplacer ces fonctions déterminant le numéro d'une semaine par un code mettant en oeuvre les règles de la norme ISO 8601 décrites plus haut. Dans l'exemple qui suit, une autre fonction est utilisée pour renvoyer le numéro de la semaine.

Exemple étape par étape

  1. Démarrez un projet EXE standard dans Visual Basic. Form1 est créé par défaut.
  2. Dans le menu Projet, ajoutez un nouveau module et collez-y le code suivant :
    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
    					
  3. Ajoutez un CommandButton à Form1.
  4. Copiez le code suivant dans la fenêtre de code de Form1 :
    Private Sub Command1_Click()
       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 Sub
    					
  5. Maintenez enfoncée la touche CTRL et appuyez sur la touche G pour ouvrir la fenêtre Exécution.
  6. Exécutez le projet et cliquez sur Command1 pour afficher les résultats suivants dans la fenêtre Exécution :
       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
    					
    Vous remarquerez que Lundi (Monday) est considéré comme faisant partie de la semaine 1, comme il se doit.

Les informations contenues dans cet article s'appliquent au(x) produit(s) suivant(s):
  • Microsoft Visual Basic 6.0 Édition initiation
  • Microsoft Visual Basic 6.0 Édition professionnelle
  • Microsoft Visual Basic 6.0 Édition Entreprise
  • Microsoft Visual Basic Control Creation Edition
  • Microsoft Visual Basic 5.0 Édition initiation
  • Microsoft Visual Basic 5.0 Édition professionnelle
  • Microsoft Visual Basic 5.0 Édition Entreprise
  • Microsoft Visual Basic 4.0 Édition Standard
  • Microsoft Visual Basic 4.0 Édition professionnelle
  • Microsoft Visual Basic 4.0 32-Bit Enterprise Edition
  • Microsoft Visual Basic for Applications 5.0
  • Microsoft Visual Basic pour Applications 6.0
Mots-clés : 
kbbug kbdatetime kbpending KB200299
L'INFORMATION CONTENUE DANS CE DOCUMENT EST FOURNIE PAR MICROSOFT SANS GARANTIE D'AUCUNE SORTE, EXPLICITE OU IMPLICITE. L'UTILISATEUR ASSUME LE RISQUE DE L'UTILISATION DU CONTENU DE CE DOCUMENT. CE DOCUMENT NE PEUT ETRE REVENDU OU CEDE EN ECHANGE D'UN QUELCONQUE PROFIT.
Partager
Options de support supplémentaire
Forums du support Microsoft Community
Nous contacter directement
Trouver un partenaire Microsoft Certified Partner
Microsoft Store