As funções Format ou DatePart podem retornar o número da semana errada para a última segunda-feira no ano
Aviso
Há um problema com o uso dessa função. A última segunda-feira em alguns anos calendários pode ser retornada como semana 53, quando deve ser a semana 1. Para obter mais informações e uma solução alternativa, consulte Formato ou funções DatePart podem retornar o número da semana errada para a última segunda-feira no ano.
Sintomas
Quando você usa a função Format ou DatePart para determinar o número da semana para datas usando a seguinte sintaxe:
Format(AnyDate, "ww", vbMonday, vbFirstFourDays)
DatePart("ww", AnyDate, vbMonday, vbFirstFourDays)
a última segunda-feira em alguns anos calendário é retornada como a semana 53, quando deve ser a semana 1.
Motivo
Ao determinar o número de semana de uma data de acordo com o padrão ISO 8601, a chamada de função subjacente para o arquivo Oleaut32.dll retorna erroneamente a semana 53 em vez da semana 1 para a última segunda-feira em determinados anos.
Resolução
Use uma função definida pelo usuário para retornar o número da Semana com base nas regras para o padrão ISO 8601. Um exemplo está incluído neste artigo.
Informações adicionais
O padrão ISO 8601 é usado extensivamente na Europa e inclui o seguinte:
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."
Isso pode ser implementado aplicando estas regras para semanas de calendário:
- Um ano é dividido em 52 ou 53 semanas calendário.
- Uma semana calendário tem 7 dias. Segunda-feira é dia 1, domingo é dia 7.
- A primeira semana calendário de um ano é aquela que contém pelo menos 4 dias.
- Se um ano não for concluído em um domingo, seus 1-3 últimos dias pertencem à primeira semana civil do próximo ano ou os primeiros 1-3 dias do próximo ano pertencem à última semana calendário do ano atual.
- Apenas um ano começando ou concluindo em uma quinta-feira tem 53 semanas calendário.
No Visual Basic e Visual Basic for Applications, todas as funcionalidades de data, exceto a função DateSerial, são provenientes de chamadas para o arquivo Oleaut32.dll. Como as funções Format() e DatePart() podem retornar o número da semana de calendário para uma determinada data, ambas são afetadas por esse bug. Para evitar esse problema, você deve usar o código alternativo que este artigo fornece.
Etapas para reproduzir o comportamento
Abra o projeto do Visual Basic em um aplicativo do Office (Alt + F11).
No menu Projeto , adicione um novo módulo.
Cole o seguinte código no 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
Use (Ctrl + G) para abrir a Janela Imediata se ainda não estiver aberta.
Digite ? Teste1 na janela Imediato e clique em Enter, observe os seguintes resultados na janela Imediata:
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
Com esse formato, todas as semanas começam com segunda-feira, de modo que 29/12/2003 deve ser considerado o início da Semana 1 e não parte da Semana 53.
Digite ? Teste2 na janela Imediato e clique em Enter para ver uma lista de datas no intervalo especificado que experimentam esse problema. A lista inclui a data, dia da semana (sempre segunda-feira), a Semana # retornada por Formato (53) e o número da Semana que deve retornar (1.) Por exemplo:
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 ...
Soluções alternativas
Se você usar as funções Formatar ou DatePart, precisará marcar o valor retornado. Quando tiver 53 anos, execute outra marcar e force um retorno de 1, se necessário. Este exemplo de código demonstra uma maneira de fazer isso:
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
Você pode evitar usar essas funções para determinar o número da semana escrevendo código que implementa as regras ISO 8601 descritas acima. O exemplo a seguir demonstra uma função de substituição para retornar o número da Semana.
Exemplo passo a passo
Abra o projeto do Visual Basic em um aplicativo do Office (Alt + F11).
No menu Projeto , adicione um novo módulo.
Cole o seguinte código no 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
Use (Ctrl + G) para abrir a Janela Imediata se ainda não estiver aberta.
Digite ? Teste3 na janela Imediato e clique em Enter, observe os seguintes resultados na janela Imediata:
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
Observe que segunda-feira é considerada a Semana 1 como deveria ser.
Comentários
https://aka.ms/ContentUserFeedback.
Em breve: Ao longo de 2024, eliminaremos os problemas do GitHub como o mecanismo de comentários para conteúdo e o substituiremos por um novo sistema de comentários. Para obter mais informações, consulteEnviar e exibir comentários de