Проблема с номерами недель между датами на Новый год - PullRequest
1 голос
/ 08 июля 2019

Задача

Следующий [mcve] выведет массив массивов номеров недель между двумя датами. Это работает, когда обе даты находятся в одном и том же году, однако некоторые годы имеют 52 недели и начинаются в последние дни прошлого года. А у других есть 53 недели.

Примером 52 недель является календарь 2020 :

Jan 2020 Calendar

Где первая неделя начинается 30 декабря.

А примером 53 недель является календарь 2016 :

Jan 2016 Calendar

Это начинается только 4 января.

код

Следующий код комментируется и выводит массив массивов с номерами недель.

Sub w_test()
    Dim Arr() As Variant, ArrDateW() As Variant
    'Initial Date
    DateI = DateSerial(2015, 5, 5)
    'Final Date
    DateF = DateSerial(2017, 9, 20)
    'Difference in weeks between DateI and DateF
    weekDif = DateDiff("ww", DateI, DateF) + k - 1

    i = Weekday(DateI)
    d = DateI

    'If not Sunday, go back to last week, to start the loop
    If i <> 1 Then
        d = DateAdd("d", -(i - 1), d)
    End If

    ReDim ArrDateW(weekDif)
    ReDim Arr(2)
    'Loop on all weeks between two dates to populate array of arrays
    For i = 0 To weekDif
        'Date
        Arr(0) = d
        'Trying to solve problem with New Year
        If Application.WorksheetFunction.WeekNum(d) = 53 Then
            flag = True
        End If
        If flag = False Then
            Arr(1) = Application.WorksheetFunction.WeekNum(d)
        Else
            Arr(1) = Application.WorksheetFunction.WeekNum(DateSerial(Year(d) + 1, 1, 1))
            flag = False
        End If

        'Year
        Arr(2) = Year(d)
        'Populate array of arrays
        ArrDateW(i) = Arr
        'Next Week Number
        d = DateAdd("ww", 1, d)
    Next i

    'To stop with Ctrl+F8
    Debug.Print d
End Sub

Вопрос

У

2015 было 53 недели, однако программа выдает следующее:

Output Local Variable

А в период с 2016 по 2017 выводится беспорядок:

Output Local Variable

Как исправить программу для правильного вывода номеров недели?

1 Ответ

1 голос
/ 08 июля 2019

Я пошел по-другому, полагаясь на встроенные функции VBA для правильного вычисления номеров недель.Прочитайте о номерах недель ISO: этот ответ и узнайте, как я использую функцию DataPart - хотя вы можете заменить свою собственную версию функции Рон де Брейн * номером недели ISO , еслиВы чувствуете, что это оправдано.

Несколько быстрых замечаний:

  1. Всегда используйте Option Explicit
  2. Попробуйте использовать более описательную переменнуюимена.Вы знаете, о чем говорите сейчас.Через несколько месяцев вам будет трудно вспомнить, что означают d и Arr (даже если сейчас это кажется очевидным).Это просто хорошая привычка и делает код самодокументируемым.
  3. Мой пример ниже разбивает логику на отдельную функцию с необязательным параметром (просто для удовольствия), который позволит вызывающей стороне изменять начало недели.на другой день.

Кодовый модуль:

Option Explicit

Sub w_test()
    Dim initialDate As Date
    Dim finaldate As Date
    initialDate = #5/5/2015#
    finaldate = #9/29/2017#

    Dim weeks As Variant
    weeks = WeekNumbers(initialDate, finaldate)

    Debug.Print "There are " & UBound(weeks, 1) & " weeks between " & _
                Format(initialDate, "dd-mmm-yyyy") & " and " & _
                Format(finaldate, "dd-mmm-yyyy")
End Sub

Private Function WeekNumbers(ByVal initialDate As Date, _
                             ByVal finaldate As Date, _
                             Optional ByVal weekStart As VbDayOfWeek = vbSunday) As Variant
    Dim numberOfWeeks As Long
    numberOfWeeks = DateDiff("ww", initialDate, finaldate, weekStart, vbFirstFullWeek)

    Dim startOfWeek As Date
    If Weekday(initialDate) <> vbSunday Then
        Dim adjustBy As Long
        If Weekday(initialDate) > weekStart Then
            adjustBy = Weekday(initialDate) - weekStart
        Else
            adjustBy = (Weekday(initialDate) + 7) - weekStart
        End If
        startOfWeek = DateAdd("d", -adjustBy, initialDate)
    End If

    Dim allTheWeeks As Variant
    ReDim allTheWeeks(1 To numberOfWeeks)

    Dim weekInfo As Variant
    ReDim weekInfo(1 To 3)

    Dim i As Long
    For i = 1 To numberOfWeeks
        weekInfo(1) = startOfWeek
        weekInfo(2) = DatePart("ww", startOfWeek, weekStart, vbFirstFourDays)
        weekInfo(3) = Year(startOfWeek)
        allTheWeeks(i) = weekInfo
        startOfWeek = DateAdd("ww", 1, startOfWeek)
    Next i

    WeekNumbers = allTheWeeks
End Function
...