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.
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.
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
Démarrez un projet EXE standard dans Visual Basic. Form1 est créé par défaut.
Ajoutez deux CommandButtons à Form1.
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
Maintenez enfoncée la touche CTRL et appuyez sur la touche G pour ouvrir la fenêtre Exécution.
Exécutez le projet, cliquez sur Command1 et notez les résultats suivants dans la fenêtre Exécution :
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.
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 :
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
Démarrez un projet EXE standard dans Visual Basic. Form1 est créé par défaut.
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
Ajoutez un CommandButton à Form1.
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
Maintenez enfoncée la touche CTRL et appuyez sur la touche G pour ouvrir la fenêtre Exécution.
Exécutez le projet et cliquez sur Command1 pour afficher les résultats suivants dans la fenêtre Exécution :
Numéro d'article: 200299 - Dernière mise à jour: lundi 19 septembre 2005 - Version: 3.0
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.
Quel niveau d'effort avez-vous dû personnellement fournir pour utiliser cet article ?
Très faible
Faible
Moyen
Elevé
Très élevé
Dites-nous pourquoi et ce que nous pouvons faire pour améliorer ces informations.
Merci ! Vos commentaires sont très utiles pour l'amélioration de notre contenu d'aide et de support. Si vous avez besoin d'aide complémentaire, veuillez consulter la page d'accueil d'aide et support.