Ищем окончательный калькулятор недели ISO в Visual Basic (в Visual Studio Express 2010)

Я ищу окончательный стандарт (т.е. сертифицированный как правильный или достаточно тщательно протестированный) для расчета недели ISO с даты в Visual Basic (т.е. для запуска в проекте Visual Studio Express 2010 Visual Basic)

(Неудачное) исследование на данный момент:



person therobyouknow    schedule 16.03.2012    source источник
comment
Вы видели это: stackoverflow.com/questions/1226201/   -  person assylias    schedule 16.03.2012
comment
+1 Спасибо, @assylias, очень быстрый взгляд предполагает, что это может дать некоторые подсказки. Мне понадобится больше времени позже, чтобы посмотреть глубже.   -  person therobyouknow    schedule 16.03.2012


Ответы (3)


Спасибо @assylias - ответ на этот вопрос довольно близок, если не совсем то, что я ищу: https://stackoverflow.com/a/1226248/227926

Обратите внимание, что для использования этого решения я должен добавить, что вам нужно импортировать определение абстрактного класса календаря:

Imports System.Globalization

И затем создайте экземпляр календаря, я выбрал григорианский календарь, поскольку он является стандартом де-факто, но есть и другие (культурные) варианты:

Dim myCalendar As Calendar = New GregorianCalendar

Затем, чтобы процитировать решение ( https://stackoverflow.com/a/1226248/227926):

Вы можете использовать метод Calendar.GetWeekOfYear, чтобы получить номер недели даты, со значением CalendarWeekRule.FirstFourDayWeek, чтобы указать, как определяются недели, и DayOfWeek.Monday, чтобы указать первый день недели. Это соответствует спецификации ISO.

Пример:

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

Я не буду отмечать свой вопрос как дубликат, потому что заголовок их вопроса «Рассчитать дату начала и окончания недели с учетом номера недели и года в С# (на основе спецификации ISO)» заметно отличается от моего, и они упоминают С# ( не Visual Basic, хотя они тоже хотят Visual Basic).

Сохранение моего вопроса должно помочь другим в их поиске того же самого.

Спасибо!

person therobyouknow    schedule 17.03.2012
comment
Ответ выше дает неправильное значение. Возьмем дату 31.12.2008. Это НЕДЕЛЯ ISO номер 1, приведенный выше код дает ответ 53. На практике это решение соответствует моим потребностям, поэтому это просто предупреждение для других. В Викапедии есть хорошее описание действительных 53-недельных лет. (en.wikipedia.org/wiki/ISO_week_date) - person ; 22.05.2012
comment
+1 @Paul Ireland стоит отметить. Разве не существует календаря ISO? - person therobyouknow; 23.05.2012

Я не знаю о VS Express, но я только что написал это (в полном VS) на основе статьи в Википедии:

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
person Marten Jacobs    schedule 08.04.2014

[РЕДАКТИРОВАТЬ] Я только что заметил, что последний ответ на эту тему также был сделан мной, говоря о том, чтобы заново изобрести колесо. Тем не менее, я думаю, что следующий класс является хорошей оболочкой для метода, описанного выше, поэтому я модифицировал его, чтобы включить в него метод вычисления, который я использовал.

Я не уверен насчет VSExpress, но в полном VB я бы просто расширил GregorianCalendar, чтобы добавить функциональность для получения года недели и упростить доступ к правильному номеру недели:

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

Конец класса

person Marten Jacobs    schedule 13.11.2014