Funktion der Anzahl der Schalttage in einem Zeitraum

Hintergrund

Wie Sie wissen, "ist Faulheit der Motor des Fortschritts." Bei meiner Arbeit hatte ich einmal ein Problem, als es notwendig war, eine Tabelle zur Berechnung der Zinsen für einen Darlehensvertrag zu erstellen, in der die tatsächliche Anzahl von Tagen in einem Jahr für die Basis hätte sein sollen. Die Unannehmlichkeit war, dass Sie die Schaltjahre nicht vergessen und die Tage, die zum Schaltjahr gehören, und die Tage der Nicht-Schaltjahre trennen mussten. Eine einfache Formel wurde geschrieben, aber später fand ich heraus, dass die Berechnung von Schaltjahren nicht so einfach ist.





Beschreibung des Problems

Ich wollte die Formel verbessern. Im Internet habe ich viele Programmtexte gefunden, in denen die Anzahl der Schaltjahre und Nicht-Schaltjahre und -tage in einem Zeitraum berechnet wurde. Leider war ich nicht zufrieden damit, dass die Geschwindigkeit dieser Funktionen von der Anzahl der Jahre im Zeitraum abhing. Und ich wollte, dass die Funktion genauso schnell funktioniert, egal wie viele Jahre in diesem Zeitraum. Aber während der Entwicklung musste ich den zulässigen Zeitraum der Funktion begrenzen.





Grund 1

Die meisten Länder leben nach dem Gregorianischen Kalender, dessen Regeln für Schaltjahre bereits 1582 von Papst Gregor XIII. Festgelegt wurden :





1. Ein Jahr, dessen Zahl durch 400 teilbar ist, ist ein Schaltjahr;





2. Der Rest der Jahre, deren Anzahl ein Vielfaches von 100 ist, sind Nicht-Schaltjahre (zum Beispiel die Jahre 1700, 1800, 1900, 2100, 2200, 2300).





3.       , 4, - .





2900, 3200, 4000, 01.01.2900.





2

Excel VBA (Visual Basic for Applications). , MS Office, .





Excel , 1900 1904. 1900. , 1 01 1900 , 2 – 2 .





VBA CDate(expression), Date . 1, Date 31 1899 . 60 CDate 28.02.1900, 29.02.1900 (, , 1900 ). , 01 1900 .





Excel, Microsoft , . 01 1900 .





, () , .





, 4, 4 () 1 . 1- 1 4, 2- 5 8 .





1 4 (, 2021 506- , 1)





3 :





Sprung ^ {total} _ {Tage} = B ^ {vom Startdatum} _ {Tage bis zum Ende des Quartetts} + B ^ {dazwischen.  Quartette} _ {Tage} + B ^ {vom Beginn des letzten Quartals} _ {bis zum Ende des Tages}

:





:





In ^ {vom Startdatum} _ {bis zum Ende des Quartetts} = Datum_ {Ende} - Datum_ {Start}

, , :





In ^ {vom Startdatum} _ {bis zum Ende des Quartetts} = Datum_ {Ende} - 31. Dezember (Jahr_ {Datum Ende} -1)

, , :





In ^ {vom Startdatum} _ {bis zum Ende des Quartetts} = 31. Dezember Jahr_ {Startdatum} - Datum_ {Start}

, , , 1- 366 ( 1 3, ).





VBA:





Private Function first_quartet_leap_year_days(ByVal d_begin As Date, ByVal d_end As Date) As Long

    Dim result As Long
    result = 0
    
    Dim year_diff As Long
    Dim quartet_index_diff As Long
    
    year_diff = year(d_end) - year(d_begin)
    quartet_index_diff = quartet_index(year(d_end)) - quartet_index(year(d_begin))
    
    If year_diff = 0 And is_year_leap(d_begin) Then
        result = DateDiff("d", d_begin, d_end)
        first_quartet_leap_year_days = result
        Exit Function
    End If
    
    If quartet_index_diff = 0 Then
    
        If is_year_leap(d_begin) Then
            result = DateDiff("d", d_begin, CDate(DateSerial(year(d_begin), 12, 31)))
            first_quartet_leap_year_days = result
            Exit Function
        
        End If
        
        If is_year_leap(d_end) Then
            result = DateDiff("d", CDate(DateSerial(year(d_end) - 1, 12, 31)), d_end)
            first_quartet_leap_year_days = result
            Exit Function
        End If
        
    Else
    
        If is_year_leap(d_begin) Then
            result = DateDiff("d", d_begin, CDate(DateSerial(year(d_begin), 12, 31)))
            first_quartet_leap_year_days = result
            Exit Function
        Else
        
            If Not is_quartet_noleap(quartet_index(year(d_begin))) Then
                result = 366
                first_quartet_leap_year_days = result
                Exit Function
            End If
            
        End If
        
    End If

    first_quartet_leap_year_days = result
    
End Function
      
      







>0, 3- " ".





, , :





In ^ {vom Anfang des Quartetts} _ {bis zum Enddatum} = Datum_ {Ende} - 31. Dezember (Jahr_ {Enddatum} -1)
Private Function last_quartet_leap_year_days(ByVal d_begin As Date, ByVal d_end As Date) As Long
    
    Dim result As Long
    result = 0
     
    Dim quartet_index_diff As Long
       
    quartet_index_diff = quartet_index(year(d_end)) - quartet_index(year(d_begin))
    
    If quartet_index_diff > 0 Then
    
        If is_year_leap(d_end) Then
            result = DateDiff("d", CDate(DateSerial(year(d_end) - 1, 12, 31)), d_end)
        End If
        
    End If
    
     
    last_quartet_leap_year_days = result
    
End Function
      
      







>1, 2- " ".





B ^ {dazwischen.  Quartette} _ {Tage} = 366 * K_ {Quartette} - K_ {volle 100 Jahre} + K_ {volle 400 Jahre}

– . 1999 – 19, 2001 – 20, 1.





400-.





Private Function middle_quartets_leap_year_days(ByVal d_begin As Date, ByVal d_end As Date) As Long
    
    Dim quartet_count As Long
    
    quartet_count = middle_quartets_count(d_begin, d_end)
    
    If quartet_count = 0 Then
    
        middle_quartets_leap_year_days = 0
        Exit Function
        
    End If
    
    Dim q_begin, q_end As Long
    
    q_begin = quartet_index(year(d_begin))
    q_end = quartet_index(year(d_end)) - 1
    
    Dim quot_25, quot_100 As Integer
    
    quot_25 = WorksheetFunction.Quotient(q_end, 25) - WorksheetFunction.Quotient(q_begin, 25)
    quot_100 = WorksheetFunction.Quotient(q_end, 100) - WorksheetFunction.Quotient(q_begin, 100)
    
    Dim result As Long
    
    result = (quartet_count - quot_25 + quot_100) * 366
    
    middle_quartets_leap_year_days = result
        
End Function
      
      







:





Public Function LEAP_DAYS(ByVal val_begin As Long, ByVal val_end As Long, Optional count_first_day = 0, Optional count_last_day = 1) As Long
    
    Dim d_begin, d_end As Date
    
    count_first_day = IIf(count_first_day <> 0, 1, 0)
    count_last_day = IIf(count_last_day <> 0, 1, 0)
    
    
    d_begin = CDate(val_begin)
    d_end = CDate(val_end)
    
    Dim check_error As Variant
    check_error = check_constrains(d_begin, d_end)
    
    If IsError(check_error) Then
        LEAP_DAYS = check_error
        Exit Function
    End If
    
    Dim result As Long
    result = 0
    
    If is_year_leap(d_begin) And count_first_day = 1 Then result = result + 1
    If is_year_leap(d_end) And count_last_day = 0 Then result = result - 1
    
    result = result + first_quartet_leap_year_days(d_begin, d_end) _
            + middle_quartets_leap_year_days(d_begin, d_end) _
            + last_quartet_leap_year_days(d_begin, d_end)
    
    LEAP_DAYS = result
    
End Function
      
      



count_first_day



count_last_day



1 0. Date . .





, , . 23-24 .





, .





, . , (2900 - 1900). , 2900 .





Unten finden Sie einen Link zum Github, in dem die vollständige Implementierung der Funktionen zur Berechnung von Schalt- und gemeinsamen Tagen in einem Zeitraum in VBA für die Arbeit in Excel beschrieben ist. Sie können diese Funktion einfach in Ihre Lieblingssprache portieren und in Ihren Projekten verwenden.





Github





Quellen und zusätzliche Links

  1. Ein Artikel aus der Zeitschrift "General Book" "Wir berechnen die Zinsen fĂĽr das Darlehen: der erste Tag, der letzte Tag"





  2. Excel geht fälschlicherweise davon aus, dass 1900 ein Schaltjahr ist.





  3. Wikipedia-Artikel "Gregorianischer Kalender"













All Articles