Notes
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Avertissement
Il existe un problème avec l’utilisation de cette fonction. Le lundi dernier dans certaines années civiles peut être retourné comme semaine 53 quand il devrait être la semaine 1. Pour plus d’informations et une solution de contournement, consultez fonctions Format ou DatePart peuvent retourner un numéro de semaine incorrect pour le lundi dernier dans l’année.
Symptômes
Lorsque vous utilisez la fonction Format ou DatePart pour déterminer le numéro de semaine des dates à l’aide de la syntaxe suivante :
Format(AnyDate, "ww", vbMonday, vbFirstFourDays)
DatePart("ww", AnyDate, vbMonday, vbFirstFourDays)
Le lundi dernier dans certaines années civiles est retourné comme semaine 53 quand il devrait être la semaine 1.
La cause
Lorsque vous déterminez le numéro de semaine d’une date selon la norme ISO 8601, l’appel de fonction sous-jacent au fichier Oleaut32.dll retourne incorrectement 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 pour retourner le numéro de semaine en fonction des règles de la norme ISO 8601. Un exemple est inclus dans cet article.
Plus d’informations
La norme ISO 8601 est largement utilisée en Europe et inclut :
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."
Elle peut être implémentée en appliquant ces règles pour les semaines de calendrier :
- Une année est divisée en 52 ou 53 semaines civiles.
- Une semaine civile a sept jours. Le lundi est le jour 1 et dimanche est le jour 7.
- La première semaine civile d’une année est celle contenant au moins quatre jours.
- Si une année n’est pas terminée le dimanche, ses 1 à 3 derniers jours appartiennent à la première semaine civile de l’année suivante ou les 1 à 3 premiers jours de l’année prochaine appartiennent à la dernière semaine civile de l’année actuelle.
- Seule une année commençant ou se terminant un jeudi a 53 semaines civiles.
Dans Visual Basic et Visual Basic pour Applications, toutes les fonctionnalités de date, à l’exception de la fonction DateSerial, proviennent d’appels au fichier Oleaut32.dll. Étant donné que les fonctions Format() et DatePart() peuvent retourner le numéro de semaine civile pour une date donnée, ces deux fonctions sont affectées par ce bogue. Pour éviter ce problème, vous devez utiliser le code de remplacement fourni par cet article.
Étapes de reproduction du comportement
Ouvrez le projet Visual Basic dans une application Office (Alt + F11).
Dans le menu Projet , ajoutez un nouveau module.
Collez le code suivant dans le module :
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
Utilisez (Ctrl + G) pour ouvrir la fenêtre Immédiate si elle n’est pas déjà ouverte.
Tapez ?Test1 dans la fenêtre d’immédiat et appuyez sur Entrée, remarquez les résultats suivants dans la fenêtre d’immédiat :
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
Avec ce format, toutes les semaines commencent par lundi, de sorte que le 29 décembre 2003 devrait être considéré comme le début de la semaine 1 et non une partie de la semaine 53.
Type ? Test2 dans la fenêtre Exécution et appuyez sur Entrée pour afficher la liste des dates dans la plage spécifiée qui rencontre ce problème. La liste inclut la date, le jour de la semaine (toujours lundi), le numéro de semaine retourné par format (53) et le numéro de semaine qu’il doit retourner (1.) Par 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 ...
Contournements
Si vous utilisez les fonctions Format ou DatePart, vous devez vérifier la valeur de retour. Lorsque c'est 53, effectuez une nouvelle vérification et forcez un retour de 1, si nécessaire. Cet exemple de code illustre une façon de procéder comme suit :
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 éviter d’utiliser ces fonctions pour déterminer le numéro de semaine en écrivant du code qui implémente les règles ISO 8601 décrites ci-dessus. L’exemple suivant illustre une fonction de remplacement destinée à renvoyer le numéro de la semaine.
Exemple pas à pas
Ouvrez le projet Visual Basic dans une application Office (Alt + F11).
Dans le menu Projet , ajoutez un nouveau module.
Collez le code suivant dans le module :
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
Utilisez (Ctrl + G) pour ouvrir la fenêtre Imédiate si elle n’est pas déjà ouverte.
Tapez ?Test3 dans la fenêtre Immédiat et appuyez sur Entrée, notez les résultats suivants dans la fenêtre Immédiat :
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
On considère que le lundi est la Semaine 1, comme c'est le cas normalement.