Fonction du nombre de jours bissextiles dans une période

Contexte

Comme vous le savez, «la paresse est le moteur du progrĂšs». Dans mon travail, j'ai dĂ©jĂ  Ă©tĂ© confrontĂ© Ă  un problĂšme lorsqu'il Ă©tait nĂ©cessaire de dresser un tableau de calcul des intĂ©rĂȘts sur un accord de prĂȘt, oĂč le nombre rĂ©el de jours dans une annĂ©e aurait dĂ» ĂȘtre pour la base. L'inconvĂ©nient Ă©tait que vous ne deviez pas oublier les annĂ©es bissextiles et sĂ©parer les jours qui appartiennent Ă  l'annĂ©e bissextile et les jours des annĂ©es non bissextiles. Une formule simple a Ă©tĂ© Ă©crite, mais j'ai dĂ©couvert plus tard que le calcul des annĂ©es bissextiles n'est pas si simple.





description du problĂšme

Je voulais amĂ©liorer la formule. Sur Internet, j'ai trouvĂ© beaucoup de textes de programmes oĂč le nombre d'annĂ©es et de jours bissextiles ou non bissextiles dans une pĂ©riode Ă©tait calculĂ©. Mais, malheureusement, je n'Ă©tais pas satisfait du fait que la vitesse de ces fonctions dĂ©pendait du nombre d'annĂ©es dans la pĂ©riode. Et je voulais que la fonction fonctionne aussi rapidement, peu importe le nombre d'annĂ©es dans la pĂ©riode. Mais lors du dĂ©veloppement, j'ai dĂ» limiter la pĂ©riode autorisĂ©e de la fonction.





Raison 1

La plupart des pays vivent selon le calendrier grégorien, les rÚgles des années bissextiles pour lesquelles ont été déterminées en 1582 par le pape Grégoire XIII :





1. Une année dont le nombre est divisible par 400 est une année bissextile;





2. Les autres années, dont le nombre est un multiple de 100, sont des années non bissextiles (par exemple, les années 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 :





Saut ^ {total} _ {jours} = B ^ {de la date de début} _ {jours jusqu'à la fin du quatuor} + B ^ {entre les deux.  quatuors} _ {jours} + B ^ {du début du dernier trimestre} _ {jusqu'au jour de la fin}

:





:





Dans ^ {de la date de début} _ {à la fin du quatuor} = Date_ {end} - Date_ {début}

, , :





Dans ^ {de la date de début} _ {jusqu'à la fin du quatuor} = Date_ {end} - 31 décembre (Year_ {date end} -1)

, , :





Dans ^ {de la date de début} _ {à la fin du quatuor} = 31 décembre Année_ {date de début} - Date_ {début}

, , , 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- " ".





, , :





Dans ^ {du début du quatuor} _ {jusqu'à la date de fin} = Date_ {end} - 31 décembre (Année_ {date de fin} -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 ^ {entre les deux.  quatuors} _ {jours} = 366 * K_ {quatuors} - K_ {100 ans complets} + K_ {400 ans complets}

– . 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 .





Vous trouverez ci-dessous un lien vers le github, oĂč la mise en Ɠuvre complĂšte des fonctions de calcul des jours bissextiles et des jours communs dans une pĂ©riode dans VBA est prĂ©sentĂ©e, conçue pour fonctionner dans Excel. Vous pouvez facilement porter cette fonction dans votre langue prĂ©fĂ©rĂ©e et l'utiliser dans vos projets.





Github





Sources et liens supplémentaires

  1. Un article du magazine "General Book" "Nous calculons les intĂ©rĂȘts du prĂȘt: le premier jour, le dernier jour"





  2. Excel suppose à tort que 1900 est une année bissextile.





  3. Article Wikipedia "Calendrier grégorien"













All Articles