Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Advertencia
Hay un problema con el uso de esta función. El último lunes en algunos años naturales se puede devolver como la semana 53 cuando debe ser la semana 1. Para obtener más información y una solución alternativa, consulte Format o DatePart funciones pueden devolver un número de semana incorrecto para el último lunes del Año.
Síntomas
Cuando se usa la función Format o DatePart para determinar el número de semana de las fechas con la sintaxis siguiente:
Format(AnyDate, "ww", vbMonday, vbFirstFourDays)
DatePart("ww", AnyDate, vbMonday, vbFirstFourDays)
El último lunes en algunos años naturales se devuelve como la semana 53 cuando debe ser la semana 1.
Causa
Al determinar el número de semana de una fecha según el estándar ISO 8601, la llamada de función subyacente al archivo Oleaut32.dll devuelve erróneamente la semana 53 en lugar de la semana 1 para el último lunes en determinados años.
Resolución
Use una función definida por el usuario para devolver el número de semana en función de las reglas del estándar ISO 8601. En este artículo se incluye un ejemplo.
Más información
El estándar ISO 8601 se usa ampliamente en Europa e incluye:
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."
Se puede implementar aplicando estas reglas para las semanas del calendario:
- Un año se divide en 52 o 53 semanas naturales.
- Una semana natural tiene siete días. El lunes es el día 1 y el domingo es el día 7.
- La primera semana natural de un año es la que contiene al menos cuatro días.
- Si no se concluye un año en un domingo, los últimos 1-3 días pertenecen a la primera semana natural del año siguiente o a los primeros 1-3 días del próximo año pertenecen a la última semana natural del año actual.
- Solo un año a partir o finalizando el jueves tiene 53 semanas naturales.
En Visual Basic y Visual Basic para Aplicaciones, toda la funcionalidad de fecha, excepto la función DateSerial, procede de llamadas al archivo Oleaut32.dll. Dado que las funciones Format() y DatePart() pueden devolver el número de semana del calendario para una fecha determinada, ambos se ven afectados por este error. Para evitar este problema, debe usar el código alternativo que proporciona este artículo.
Pasos para reproducir el comportamiento
Abra el proyecto de Visual Basic en una aplicación de Office (Alt + F11).
En el menú Proyecto , agregue un nuevo módulo.
Pegue el código siguiente en el módulo:
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
Utiliza (Ctrl + G) para abrir la ventana Inmediata si aún no está abierta.
Escriba ?Test1 en la ventana Inmediata y presione Entrar, tenga en cuenta los siguientes resultados en la ventana Inmediata:
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
Con este formato, todas las semanas comienzan con el lunes, para que el 29 de diciembre de 2003 se considere el inicio de la semana 1 y no parte de la semana 53.
Escriba ? Test2 en la ventana Inmediato y presione Entrar para ver una lista de fechas en el intervalo especificado que experimenta este problema. La lista incluye la fecha, día de la semana (siempre lunes), el número de semana que Format devuelve (53) y el número de semana que debería devolver (1). Por ejemplo:
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 ...
Soluciones alternativas
Si usa las funciones Format o DatePart, debe comprobar el valor devuelto. Cuando sea el valor 53, ejecute otra comprobación y obligue una devolución de 1, si es necesario. En este ejemplo de código se muestra una manera de hacerlo:
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
Puede evitar el uso de estas funciones para determinar el número de semana escribiendo código que implemente las reglas ISO 8601 descritas anteriormente. En el ejemplo siguiente se muestra una función de reemplazo para devolver el número de semana.
Ejemplo paso a paso
Abra el proyecto de Visual Basic en una aplicación de Office (Alt + F11).
En el menú Proyecto , agregue un nuevo módulo.
Pegue el código siguiente en el módulo:
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
Usa (Ctrl + G) para abrir la ventana Inmediata si no está abierta ya.
Escriba ? Test3 en la ventana Inmediato y presione Entrar, tenga en cuenta los siguientes resultados en la ventana Inmediato:
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
El lunes se considera la semana 1 como debería ser.