使用DatePart()的ISO8601周数不正确

时间:2015-07-22 10:46:17

标签: .net vb.net date iso week-number

我班上有以下Sub。我没有错误,但结果与ISO-8601标准不符

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

给定日期dt从m_CurrentWeekNoYear返回的值的一些示例

  • 20/07/2015 - > 30-2015正确
  • 09/03/2015 - > 11-2015正确
  • 29/12/2014 - > 53-2014错误应该是01-2015 ...使用02/01/2015 也给了53-2014
  • 05/01/2015 - > 01-2015错误应该是02-2015 ...使用09/01/2015也给了01-2015
  • 30/12/2013 - > 53-2013错误应该是01-2014 ...使用04/01/2014也给了53-2013
  • 06/01/2014 - > 02-2014正确

然后,当我到了一年,实际上有53周时,它可以工作。

  • 28/12/2009 - > 53-2009更正
  • 04/01/2010 - > 01-2010正确

我出错的任何想法?

2 个答案:

答案 0 :(得分:2)

使用DateAdd和DatePart在这种情况下是出了名的不好,但问题是.NET计算周数的方式存在(错误)不一致。

有关详情ISO 8601 Week of Year format in Microsoft .Net

,请参阅此页面

“特别是ISO 8601总是有7天的周。如果一年的第一个部分周不包含星期四,那么它被计为上一年的最后一周。同样,如果是最后一周前一年不包含星期四那么它的[原文如此]对待就像下一年的第一周.GetWeekOfYear()有第一个行为,但不是第二个“

这是我编写的一些代码,用于根据定义获取ISO 8601周数:

“根据ISO-8601标准的周数,从星期一开始的星期。一年的第一周是包含该年的第一个星期四(='第一个4天的一周')的星期。一年中的周数是52或53。“

echo $value['num_comma'];
echo $value['alinea'];
echo $value['corpo'];

它使用以下更通用的方法,使用ISO标准的细节来查找一年中的一周:

''' <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

此代码使用此扩展方法,即快速查找以查找一周的下一天:

'Need a calendar - Culture's 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

我用这个尝试了你的测试用例并获得了以下内容:

<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

答案 1 :(得分:1)

以下是DatePart函数中error的简单解决方法:

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