Le dernier lundi de certaines années civiles est retourné en tant que semaine 53, alors qu’il 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 fonction sous-jacent au fichier Oleaut32.dll retourne 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 pour renvoyer le numéro de semaine en fonction des règles de la norme ISO 8601.
Un exemple est inclus dans cet article.
Informations supplémentaires
La norme ISO 8601 est largement utilisée en Europe et inclut les éléments suivants :
asciidoc
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."
Cela peut être implémenté 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 le dimanche est le jour 7.
La première semaine civile d’une année est celle qui contient au moins quatre jours.
Si une année n’est pas terminée un 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 suivante appartiennent à la dernière semaine civile de l’année actuelle.
Seule une année commençant ou se terminant le jeudi compte 53 semaines calendaires.
Dans Visual Basic et Visual Basic pour Applications, toutes les fonctionnalités de date, à l’exception de la fonction DateSerial, proviennent des appels au fichier Oleaut32.dll. Étant donné que les fonctions Format() et DatePart() peuvent renvoyer le numéro de semaine calendaire pour une date donnée, ces deux fonctions sont affectées par ce bogue. Pour éviter ce problème, vous devez utiliser l’autre code fourni par cet article.
Étapes pour reproduire le 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 :
VB
OptionExplicitPublicFunction Test1()
' This code tests a "problem" date and the days around itDim DateValue AsDateDim i AsInteger
Debug.Print " Format function:"
DateValue = #12/27/2003#For i = 1To4' 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
EndFunctionPublicFunction Test2()
' This code lists all "Problem" dates within a specified rangeDim MyDate AsDateDim Years AsLongDim days AsLongDim woy1 AsLongDim woy2 AsLongDim ToPrint AsStringFor Years = 1850To2050For days = 0To3
MyDate = DateSerial(Years, 12, 28 + days)
woy1 = Format(MyDate, "ww", vbMonday, vbFirstFourDays)
woy2 = Format(MyDate, "ww", vbMonday, vbFirstFourDays)
If woy2 > 52ThenIf Format(MyDate + 7, "ww", vbMonday, vbFirstFourDays) = 2Then _
woy2 = 1EndIfIf 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
EndIfNext days
Next Years
EndFunction
Utilisez (Ctrl + G) pour ouvrir la fenêtre Exécution si elle n’est pas déjà ouverte.
Tapez ? Test1 dans la fenêtre Exécution et appuyez sur Entrée, notez les résultats suivants dans la fenêtre Exécution :
Avec ce format, toutes les semaines commencent par lundi, de sorte que le 29 décembre 2003 doit être considéré comme le début de la semaine 1 et non comme faisant partie de la semaine 53.
Tapez ? 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 rencontrent 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 :
Si vous utilisez les fonctions Format ou DatePart, vous devez vérifier la valeur de retour. Quand il est 53, exécutez une autre vérification et forcez un retour de 1, si nécessaire. Cet exemple de code illustre une façon de procéder :
VB
Function WOY (MyDate AsDate) AsInteger' Week Of Year
WOY = Format(MyDate, "ww", vbMonday, vbFirstFourDays)
If WOY > 52ThenIf Format(MyDate + 7, "ww", vbMonday, vbFirstFourDays) = 2Then WOY = 1EndIfEndFunction
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 pour retourner le numéro de 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 :
VB
OptionExplicitFunction WeekNumber(InDate AsDate) AsIntegerDim DayNo AsIntegerDim StartDays AsIntegerDim StopDays AsIntegerDim StartDay AsIntegerDim StopDay AsIntegerDim VNumber AsIntegerDim ThurFlag AsBoolean
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 notIf StartDay = 4Or StopDay = 4Then ThurFlag = TrueElse 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 weekIf StartDays >= 4Then
WeekNumber = Fix(VNumber) + 2Else
WeekNumber = Fix(VNumber) + 1EndIf' Handle years whose last days will belong to coming year's first' calendar weekIf WeekNumber > 52And ThurFlag = FalseThen WeekNumber = 1' Handle years whose first days will belong to the last year's ' last calendar weekIf WeekNumber = 0Then
WeekNumber = WeekNumber(DateSerial(Year(InDate) - 1, 12, 31))
EndIfEndFunctionFunction Days(DayNo AsDate) AsInteger
Days = DayNo - DateSerial(Year(DayNo), 1, 0)
EndFunctionPublicFunction Test3()
Dim DateValue AsDate, i AsInteger
Debug.Print " WeekNumber function:"
DateValue = #12/27/2003#For i = 1To4' 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
EndFunction
Utilisez (Ctrl + G) pour ouvrir la fenêtre Exécution si elle n’est pas déjà ouverte.
Tapez ? Test3 dans la fenêtre Exécution et appuyez sur Entrée, notez les résultats suivants dans la fenêtre Exécution :
Souhaitez-vous en savoir plus sur les fonctions de programmation intégrées de Business Central ? Ce module aborde les différentes fonctions disponibles que vous pouvez utiliser lors du développement pour Business Central.