确切的 Excel Days360 算法是什么?

acf*_*cis 5 c# algorithm excel vba

我正在将一些计算从 Excel 移植到使用 Days360 函数(默认/美国方法)的 C#。使用维基百科页面作为指南,我想出了这个代码:

    public static int Days360(DateTime a, DateTime b)
    {
        var dayA = a.Day;
        var dayB = b.Day;

        if (IsLastDayOfFebruary(a) && IsLastDayOfFebruary(b))
            dayB = 30;

        if (dayA == 31 || IsLastDayOfFebruary(a))
            dayA = 30;

        if (dayA == 30 && dayB == 31)
            dayB = 30;

        return ((b.Year - a.Year) * 12 + b.Month - a.Month) * 30 + dayB - dayA;
    }

    private static bool IsLastDayOfFebruary(DateTime date)
    {
        if (date.Month != 2)
            return false;

        int lastDay = DateTime.DaysInMonth(date.Year, 2);
        return date.Day == lastDay;
    }
Run Code Online (Sandbox Code Playgroud)

我用(小)范围的输入对其进行了测试,结果大多与 Excel 的本机函数一致,除非我对 a 和 b 都使用 2015-02-28。我的代码返回 0 和 Excel -2。

我的结果似乎更合理,但在这一点上,我更愿意计算与 Excel 完全相同的结果。可能还有其他意见他们不同意,所以我不想只针对那个日期做一个特例。

有谁知道 Excel 使用的确切算法?

编辑:我发布的原始代码中有一个与问题无关的明显错误。我已经修复了那个问题,但是在发布问题时我从错误的文件中复制了它。

ale*_*ver 0

该算法还包括可选参数method

int startMonthDays = 0; 
int endMonthDays = 0; 
double diff = 0;
if(method.Equals("TRUE"))
{

    if(dtStartDate.getDay() < 30)
    {
        startMonthDays = (30 - dtStartDate.getDay());
    }
    else
    {
        startMonthDays = 0; 
    }

    if(dtEndDate.getDay() < 30)
    {
        endMonthDays = dtEndDate.getDay();
    }
    else
    {
        endMonthDays = 30;  
    }

    diff =  (dtEndDate.getYear() - dtStartDate.getYear())*360 +
                    (dtEndDate.getMonth() - dtStartDate.getMonth() - 1)*30 +
                    startMonthDays + endMonthDays;
}
else
    {
        if(DateCalendar.daysInMonth(dtStartDate.getYear(), dtStartDate.getMonth()) == dtStartDate.getDay())
        {
            startMonthDays = 0; 
        }
        else
        {
            startMonthDays = (30 - dtStartDate.getDay());
        }

        if(DateCalendar.daysInMonth(dtEndDate.getYear(), dtEndDate.getMonth()) == dtEndDate.getDay())
        {
            if(dtStartDate.getDay() < DateCalendar.daysInMonth(dtStartDate.getYear(), dtStartDate.getMonth()) - 1)
            {
                if(DateCalendar.daysInMonth(dtEndDate.getYear(), dtEndDate.getMonth()) > 30)
                {
                    endMonthDays = DateCalendar.daysInMonth(dtEndDate.getYear(), dtEndDate.getMonth());
                }
                else
                {
                    endMonthDays = dtEndDate.getDay();
                }
            }
            else
            {
                if(DateCalendar.daysInMonth(dtEndDate.getYear(), dtEndDate.getMonth()) > 30)
                {
                    endMonthDays = DateCalendar.daysInMonth(dtEndDate.getYear(), dtEndDate.getMonth()) - 1;
                }
                else
                {
                    endMonthDays = dtEndDate.getDay();
                }
            }
        }
        else
        {
            endMonthDays = dtEndDate.getDay();

        }

        diff =  (dtEndDate.getYear() - dtStartDate.getYear())*360 +
                    (dtEndDate.getMonth() - dtStartDate.getMonth() - 1)*30 +
                    startMonthDays + endMonthDays;
    }
Run Code Online (Sandbox Code Playgroud)

public static int daysInMonth (int year, int month) 
{      
    if (DateTime.IsLeapYear(year) && month == 2) 
    {
        return 29;   
    }   
    else
    {
        return table[month - 1];  
    }
}
Run Code Online (Sandbox Code Playgroud)

private static readonly int[] table = new int[]{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
Run Code Online (Sandbox Code Playgroud)