Looking for definitive ISO week calculator in Visual Basic (in Visual Studio Express 2010)

╄→尐↘猪︶ㄣ 提交于 2019-12-12 19:29:56

问题


I'm looking for a definitive, standard (i.e. certified as being correct or tested reasonably thoroughly) for calculating the ISO week from a date, in Visual Basic (i.e. to run in a Visual Studio Express 2010 Visual Basic project)

(Unsuccessful) Research so far:

  • I found some routines that were Visual Basic for Applications oriented; reliant on Excel environment, some things not present in Visual Studio Express 2010 Visual Basic:

    • http://www.xtremevbtalk.com/showthread.php?t=180642
    • http://www.ozgrid.com/forum/showthread.php?t=41999
    • http://www.ozgrid.com/forum/showthread.php?t=50982
    • http://www.vbaexpress.com/kb/getarticle.php?kb_id=744


  • DatePart Visual Basic library function may be useful: http://msdn.microsoft.com/en-us/library/20ee97hz(v=vs.80).aspx - BUT apparently there is a bug: "BUG: Format or DatePart Functions Can Return Wrong Week Number for Last Monday in Year": http://support.microsoft.com/kb/200299 (has this been solved? It's rather old, 2004 so perhaps?)

  • Other routines: http://forums.devx.com/showthread.php?t=130782 But doesn't state how it is based on the ISO standard

  • Also, a search on Stack Overflow gave me results that weren't quite what I was looking for: https://stackoverflow.com/search?q=iso+week


回答1:


Thanks @assylias - an answer in that question is pretty close, if not exactly what I'm looking for: https://stackoverflow.com/a/1226248/227926

Note to use this solution I should add that you need to import the Calendar abstract class defintion:

Imports System.Globalization

AND then instantiate an Instance of Calendar, I chose Gregorian Calendar as it is the defacto standard, but there are other (cultural) options:

Dim myCalendar As Calendar = New GregorianCalendar

Then, to quote the solution ( https://stackoverflow.com/a/1226248/227926 ):

You can use the Calendar.GetWeekOfYear method to get the week number of a date, with the CalendarWeekRule.FirstFourDayWeek value to specify how the weeks are determined, and DayOfWeek.Monday to specify the first weekday. That follows the ISO specification.

Example:

int week = myCalendar.GetWeekOfYear(DateTime.Today,
CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);

I will not mark my question as a duplicate, because their question title "Calculate the start and end date of a week given the week number and year in C# (based on the ISO specification)" is distinctly different from mine and they mention C# (not Visual Basic although they do want Visual Basic as well).

Keeping my question present should help others in their search for the same.

Thanks!




回答2:


I don't know about VS Express, but I just wrote this (in full VS) based on the wikipedia article:

Public Function GetIsoYearAndWeek(day As Date) As Integer()
    Dim g As New System.Globalization.GregorianCalendar()

    Dim year = g.GetYear(day)
    Dim dow = g.GetDayOfWeek(day)

    'Per MSDN, dow is 0 for sunday, per ISO, this should be 7
    If (dow = 0) Then dow = 7

    'usually, this calculation gives the week number
    'http://en.wikipedia.org/wiki/ISO_week_date#Calculation
    Dim week = Math.Floor((g.GetDayOfYear(day) - dow + 10) / 7)

    'If the week is 0 or 53, we should do some checks
    If (week = 0) Then
        'if we get week=0, the week is actually in last year
        year -= 1

        'A week has 53 weeks only if it starts on a thursday 
        'or is a leap year starting on a wednesday
        Dim jan1st = New Date(year, 1, 1, g)
        If (jan1st.DayOfWeek = DayOfWeek.Thursday _
                OrElse jan1st.DayOfWeek = DayOfWeek.Wednesday _
                        AndAlso g.IsLeapYear(year)) Then
            week = 53
        Else
            week = 52
        End If
    ElseIf (week = 53) Then
        'determine if this week's thursday is in this year, if 
        'it's not, this week is also in the next year
        Dim thursday = day.AddDays(4 - dow)
        If (g.GetYear(thursday) > year) Then
            Return {year + 1, 1}
        End If
    End If

    Return {year, week}
End Function



回答3:


[EDIT] I just noticed the last response to this thread was also made by myself, talk about reinventing the wheel. However, I do think the following class is a nice wrapper for the method explained above, so I modified it to incorporate the calculation method I used there.

I'm not sure about VSExpress, but in full VB, I'd just extend GregorianCalendar to add functionality to get the week year and simplify access to the correct week number:

Public Class IsoWeekCalendar
Inherits Globalization.GregorianCalendar

'Get the ISO week number
Public Overloads Function GetWeekOfYear(d As DateTime) As Integer
    Dim Week As Integer
    'year is passed byref
    GetYearAndWeek(d, Week:=Week)
    Return Week
End Function

'Get the year that belongs with the week
Public Function GetWeekYear(d As DateTime) As Integer
    Dim Year As Integer
    'year is passed byref
    GetYearAndWeek(d, Year:=Year)
    Return Year
End Function

'Get both the week and year by ref
Public Sub GetYearAndWeek(d As DateTime, Optional ByRef Year As Integer = 0, Optional ByRef Week As Integer = 0)
    Dim yearweek = GetYearAndWeek(d)
    Year = yearweek.Item1
    Week = yearweek.Item2
End Sub

'Get both the week and year
Public Function GetYearAndWeek(d As DateTime) As Tuple(Of Integer, Integer)
    Dim year = Me.GetYear(d)
    Dim dow = Me.GetDayOfWeek(d)

    'Per MSDN, dow is 0 for sunday, per ISO, this should be 7
    If (dow = 0) Then dow = 7

    'usually, this calculation gives the week number
    'http://en.wikipedia.org/wiki/ISO_week_date#Calculation
    Dim week As Integer = Math.Floor((Me.GetDayOfYear(d) - dow + 10) / 7)

    'If the week is 0 or 53, we should do some checks
    If (week = 0) Then
        'if we get week=0, the week is actually in last year
        year -= 1

        'A week has 53 weeks only if it starts on a thursday 
        'or is a leap year starting on a wednesday
        Dim jan1st = New Date(year, 1, 1, Me)
        If (jan1st.DayOfWeek = DayOfWeek.Thursday _
                OrElse jan1st.DayOfWeek = DayOfWeek.Wednesday _
                        AndAlso Me.IsLeapYear(year)) Then
            week = 53
        Else
            week = 52
        End If
    ElseIf (week = 53) Then
        'determine if this week's thursday is in this year, if 
        'it's not, this week is also in the next year
        Dim thursday = d.AddDays(4 - dow)
        If (Me.GetYear(thursday) > year) Then
            year += 1
            week = 1
        End If
    End If

    Return Tuple.Create(year, week)
End Function

'Get the date from the year, week and DoW, again, using calculation from
'http://en.wikipedia.org/wiki/ISO_week_date#Calculation
Public Function GetDate(year As Integer, week As Integer, Optional day As DayOfWeek = DayOfWeek.Monday) As DateTime
    Dim ordinal = (week * 7) + IsoDayOfWeek(day) - (GetIsoDayOfWeek(New Date(year, 1, 4, Me)) + 3)
    Return New Date(year, 1, 1, Me).AddDays(ordinal - 1)
End Function

'Get the previous date with the supplied DoW
Public Function GetPrev(d As DateTime, day As DayOfWeek) As DateTime
    If (d.DayOfWeek <> day) Then
        Return GetPrev(d.AddDays(-1), day)
    End If
    Return d
End Function

'Get the next date with the supplied DoW
Public Function GetNext(d As DateTime, day As DayOfWeek) As DateTime
    If (d.DayOfWeek <> day) Then
        Return GetPrev(d.AddDays(1), day)
    End If
    Return d
End Function

'Get the ISO day of week
Public Function GetIsoDayOfWeek(time As Date) As Integer
    Return IsoDayOfWeek(MyBase.GetDayOfWeek(time))
End Function

'Translate .NET DoW to ISO DoW
Public Function IsoDayOfWeek(d As DayOfWeek) As Integer
    If (d = DayOfWeek.Sunday) Then Return 7
    Return d
End Function

End Class



来源:https://stackoverflow.com/questions/9741424/looking-for-definitive-iso-week-calculator-in-visual-basic-in-visual-studio-exp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!