Invalid ISO8601 week number using DatePart ()

I have the following Sub inside my class. I have no errors, but the results do not meet the ISO-8601 standards.

Private Sub calculateAllProperties(ByVal dt As Date) Select Case dt.DayOfWeek Case DayOfWeek.Monday m_CurrentWeekStartDate = dt Case DayOfWeek.Tuesday m_CurrentWeekStartDate = DateAdd(DateInterval.Day, -1, dt) Case DayOfWeek.Wednesday m_CurrentWeekStartDate = DateAdd(DateInterval.Day, -2, dt) Case DayOfWeek.Thursday m_CurrentWeekStartDate = DateAdd(DateInterval.Day, -3, dt) Case DayOfWeek.Friday m_CurrentWeekStartDate = DateAdd(DateInterval.Day, -4, dt) Case DayOfWeek.Saturday m_CurrentWeekStartDate = DateAdd(DateInterval.Day, -5, dt) Case DayOfWeek.Sunday m_CurrentWeekStartDate = DateAdd(DateInterval.Day, -6, dt) End Select 'Now we have our start point of m_CurrentWeekStartDate we can calculate all other properties. m_CurrentWeekStartYear = DatePart(DateInterval.Year, m_CurrentWeekStartDate) m_CurrentWeekNo = DatePart(DateInterval.WeekOfYear, m_CurrentWeekStartDate, Microsoft.VisualBasic.FirstDayOfWeek.Monday, FirstWeekOfYear.FirstFourDays) m_CurrentWeekNoYear = CurrentWeekNo.ToString("D2") & "-" & CurrentWeekStartYear.ToString m_CurrentYearWeekNo = CurrentWeekStartYear.ToString & "-" & CurrentWeekNo.ToString("D2") m_PreviousWeekStartDate = DateAdd(DateInterval.Day, -7, m_CurrentWeekStartDate) m_PreviousWeekStartYear = DatePart(DateInterval.Year, m_PreviousWeekStartDate) m_PreviousWeekNo = DatePart(DateInterval.WeekOfYear, m_PreviousWeekStartDate, Microsoft.VisualBasic.FirstDayOfWeek.Monday, FirstWeekOfYear.FirstFourDays) m_PreviousWeekNoYear = PreviousWeekNo.ToString("D2") & "-" & PreviousWeekStartYear.ToString m_PreviousYearWeekNo = PreviousWeekStartYear.ToString & "-" & PreviousWeekNo.ToString("D2") End Sub 

Some examples of values ​​returned from m_CurrentWeekNoYear for a given dt date

  • 07/20/2015 β†’ 30-2015 correct
  • 03/09/2015 β†’ 11-2015 correct
  • 12/29/2014 β†’ 53-2014 the wrong should be 01-2015 ... from 02/01/2015 also gave 53-2014
  • 01/05/2015 β†’ 01-2015 should be incorrectly 02-2015 ... using 01/01/2015 is also given 01-2015
  • 12/30/2013 β†’ 53-2013 wrong should be 01-2014 ... using 04/01/2014 also gave 53-2013
  • 01/06/2014 β†’ 02-2014 correct

Then, when I reached a year that actually has 53 weeks, it works.

  • 12/28/2009 β†’ 53-2009 correct
  • 01/04/2010 β†’ 01-2010 correct

Any ideas I was mistaken in?

+5
source share
2 answers

Using DateAdd and DatePart is notoriously bad for this kind of thing, but the problem is that there is a (error) inconsistency in how .NET calculates the week number.

See this page for more information. ISO 8601 Week of Year format at Microsoft.Net

β€œIn particular, ISO 8601 always has 7-day weeks. If the first incomplete week of the year does not contain Thursday, then it is considered the last week of the previous year. Similarly, if the last week of the previous year does not contain Thursday, and then it [sic] is treated as the first next week of the next year. GetWeekOfYear () has the first behavior, but not the second "

This is the code I wrote to get the ISO 8601 week number based on the definition:

"The week number is in accordance with ISO-8601, weeks starting on Monday. The first week of the year is the week that contains this year on the first Thursday (=" First 4-day week "). The year is 52 or 53."

 ''' <summary> ''' Finds the ISO 8601 Week Number based on a given date ''' </summary> ''' <param name="dateValue"></param> ''' <returns></returns> ''' <remarks>ISO 8601 Specifies Monday as the First Day of the week and week one defined as the First Four Day Week</remarks> Public Shared Function GetIso8601WeekOfYear(ByVal dateValue As DateTime) As Integer Return GetWeekOfYear(dateValue, DayOfWeek.Sunday, CalendarWeekRule.FirstFourDayWeek) End Function 

It uses the following more general methods to find the week of the year using the specifics of the ISO standard:

 'Need a calendar - Culture irrelevent since we specify start day of week Private Shared cal As Calendar = CultureInfo.InvariantCulture.Calendar ''' <summary> ''' Returns the week number of the year based on the Last Day of the Week and the Week One Rule ''' </summary> ''' <param name="dateValue">The date to find the week number for</param> ''' <param name="lastDayOfWeek">The last day of the week</param> ''' <param name="rule">The Definition of Week One</param> ''' <returns>An integer specifying the week number in the year</returns> ''' <remarks></remarks> Public Shared Function GetWeekOfYear(ByVal dateValue As DateTime, ByVal lastDayOfWeek As DayOfWeek, ByVal rule As CalendarWeekRule) As Integer 'There is a bug in the .NET framework where some dates at the end of the year return the incorrect week number so to find the correct value we need to cheat. 'Find the DayOfWeek that represents the first day based on the last day Dim firstDayOfWeek As DayOfWeek = lastDayOfWeek.Increment 'Find the date of the last day of the week, this ensures that we get the correct week number value dateValue = GetWeekendingDate(dateValue, lastDayOfWeek) 'Return the value of the week for the last day of the week Return cal.GetWeekOfYear(dateValue, rule, firstDayOfWeek) End Function ''' <summary> ''' Finds the week ending date for a specified date value ''' </summary> ''' <param name="dateValue">The date to find the week ending date for</param> ''' <param name="lastDayOfWeek">The last day of the week</param> ''' <returns>A date value that is the last day of the week that contains the specified dateValue</returns> ''' <remarks></remarks> Public Shared Function GetWeekendingDate(ByVal dateValue As DateTime, ByVal lastDayOfWeek As DayOfWeek) As DateTime 'Find out how many days difference from the date we are testing to the end of the week Dim dayOffset As Integer = lastDayOfWeek - cal.GetDayOfWeek(dateValue) If dayOffset < 0 Then dayOffset += 7 'Add days to the test date so that it is the last day of the week Return dateValue.AddDays(dayOffset) End Function 

This code uses this extension method, which is a quick search to find the next day of the week:

 <Extension()> Public Function Increment(ByVal aDay As DayOfWeek) As DayOfWeek Select Case aDay Case DayOfWeek.Sunday : Return DayOfWeek.Monday Case DayOfWeek.Monday : Return DayOfWeek.Tuesday Case DayOfWeek.Tuesday : Return DayOfWeek.Wednesday Case DayOfWeek.Wednesday : Return DayOfWeek.Thursday Case DayOfWeek.Thursday : Return DayOfWeek.Friday Case DayOfWeek.Friday : Return DayOfWeek.Saturday Case DayOfWeek.Saturday : Return DayOfWeek.Sunday Case Else : Return Nothing End Select End Function 

I tried my test cases and got the following:

 Debug.WriteLine(GetIso8601WeekOfYear(Date.Parse("20/07/2015"))) '30 Debug.WriteLine(GetIso8601WeekOfYear(Date.Parse("09/03/2015"))) '11 Debug.WriteLine(GetIso8601WeekOfYear(Date.Parse("29/12/2014"))) '1 Debug.WriteLine(GetIso8601WeekOfYear(Date.Parse("05/01/2015"))) '2 Debug.WriteLine(GetIso8601WeekOfYear(Date.Parse("30/12/2013"))) '1 Debug.WriteLine(GetIso8601WeekOfYear(Date.Parse("06/01/2014"))) '2 
+2
source

Here is a simple way to work around error in the DatePart function:

 Week = DatePart("ww", myDate, vbMonday, vbFirstFourDays) If Week = 53 And DatePart("ww", DateAdd("d", 7, myDate), vbMonday, vbFirstFourDays) = 2 Then Week = 1 End If 
+1
source

All Articles