【问题标题】:Calculating YEARFRAC in Excel for dates spanning leap year在 Excel 中计算跨越闰年的日期的 YEARFRAC
【发布时间】:2020-10-13 14:18:39
【问题描述】:

如果使用 Excel 的 YEARFRAC(date1,date2,1) 函数,则 Excel 将根据第二个参数使用基础。如果 date1 和 date2 在同一年,则无关紧要,但如果 date1 是闰年(例如 2020 年)而 date2 是非闰年(例如 2021 年),则很重要

我认为更准确的计算会考虑到date1 的基础可能与date2 的基础不同。

例如YEARFRAC(15/12/2020,15/01/2021,1) 返回0.08493151 但真正的计算是(31/12/2020-15/12/2020)/366 + (15/01/2020-31/12/2020)/365 = 0.084811737

我在 VBA 中实现了以下内容。有没有人有任何从根本上更好的方法(在 Excel 或 VBA 中)? (我不是在寻找对我匆忙的 VBA 代码的微小改进)

使用yearFracVBA("AA1","AA2")调用它

Function yearFracVBA(aDate1, aDate2)
    result = 0
    y1 = Application.Evaluate("=YEAR(" & aDate1 & ")")
     y2 = Application.Evaluate("=YEAR(" & aDate2 & ")")
     
    For Y = y1 To y2
       fraction = 0
       If Y = y1 And Y = y2 Then fraction = Application.Evaluate("=YEARFRAC(" & aDate1 & "," & aDate2 & ",1)")
       If Y = y1 And Y < y2 Then fraction = Application.Evaluate("=YEARFRAC(" & aDate1 & ",DATE(YEAR(" & aDate1 & "),12,31),1)")
       If Y > y1 And Y < y2 Then fraction = 1
       If Y > y1 And Y = y2 Then fraction = Application.Evaluate("=YEARFRAC(DATE(YEAR(" & aDate2 & ")-1,12,31)," & aDate2 & ",1)")
       result = result + fraction
    Next Y
    yearFracVBA = result
End Function

【问题讨论】:

    标签: excel vba leap-year


    【解决方案1】:

    以下代码不需要 Excel。它适用于任何 VBA 应用程序:

    Option Explicit
    
    Public Function YearFracActual(ByVal aDate1 As Date, ByVal aDate2 As Date) As Double
        Dim lowerDate As Date
        Dim upperDate As Date
        Dim year1 As Integer
        Dim year2 As Integer
        
        'Get dates in order
        If aDate1 > aDate2 Then
            lowerDate = aDate2
            upperDate = aDate1
        Else
            lowerDate = aDate1
            upperDate = aDate2
        End If
        
        'Round down (floor) - exclude any time (hours, minutes, seconds)
        lowerDate = VBA.Int(lowerDate)
        upperDate = VBA.Int(upperDate)
        
        'Get years
        year1 = Year(lowerDate)
        year2 = Year(upperDate)
        
        If year1 = year2 Then
            YearFracActual = (upperDate - lowerDate) / GetDaysInYear(year1)
        Else
            Dim lowerFrac As Double
            Dim upperFrac As Double
            Dim midFrac As Double
        
            lowerFrac = (DateSerial(year1, 12, 31) - lowerDate) / GetDaysInYear(year1)
            midFrac = year2 - year1 - 1
            upperFrac = (upperDate - DateSerial(year2 - 1, 12, 31)) / GetDaysInYear(year2)
            
            YearFracActual = lowerFrac + midFrac + upperFrac
        End If
    End Function
    
    Private Function GetDaysInYear(ByVal year_ As Integer) As Integer
        If IsLeapYear(year_) Then
            GetDaysInYear = 366
        Else
            GetDaysInYear = 365
        End If
    End Function
    
    Private Function IsLeapYear(ByVal year_ As Integer) As Boolean
        If year_ Mod 400 = 0 Then
            IsLeapYear = True
        ElseIf year_ Mod 100 = 0 Then
            IsLeapYear = False
        Else
            IsLeapYear = (year_ Mod 4 = 0)
        End If
    End Function
    

    【讨论】:

      【解决方案2】:

      如果你不想使用 VBA,那么在 Excel 中你可以使用这个公式:

      =ABS(YEARFRAC(A1,EOMONTH(A1,12-MONTH(A1)),1)+YEAR(B1)-YEAR(A1)-1+YEARFRAC(B1,EOMONTH(B1,-MONTH(B1)),1))

      其中 A1 和 B1 是包含 2 个日期的单元格

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-05-06
        相关资源
        最近更新 更多