什么是Excel Days360算法?

时间:2015-05-11 12:46:45

标签: c# excel algorithm excel-vba vba

我正在将一些计算从Excel移植到使用Days360函数的C#(默认/ US方法)。以Wikipedia page为指导,我想出了这段代码:

    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;
    }

我使用(小)输入测试它,结果大多与Excel的本机功能一致,除非我使用2015-02-28进行a和b。我的代码返回0和Excel -2。

我的结果似乎更合理,但此时,我更愿意计算与Excel完全相同的结果。可能还有其他输入,他们不同意,所以我不想只针对那个日期做出特殊情况。

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

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

4 个答案:

答案 0 :(得分:2)

根据this Wikipedia article,Microsoft Excel Days360功能相当于30/360 BMA / PSA。因此,为了获得MS Excel的精确结果,我们需要实现BMA / PSA方法。我已经实现了这个方法。

private double Days360(DateTime StartDate, DateTime EndDate)
{
    int StartDay = StartDate.Day;
    int StartMonth = StartDate.Month;
    int StartYear = StartDate.Year;
    int EndDay = EndDate.Day;
    int EndMonth = EndDate.Month;
    int EndYear = EndDate.Year;

    if (StartDay == 31 || IsLastDayOfFebruary(StartDate))
    {
        StartDay = 30;
    }

    if (StartDay == 30 && EndDay == 31)
    {
        EndDay = 30;
    }

    return ((EndYear - StartYear) * 360) + ((EndMonth - StartMonth) * 30) + (EndDay - StartDay);
}

private bool IsLastDayOfFebruary(DateTime date)
{
    return date.Month == 2 && date.Day == DateTime.DaysInMonth(date.Year, date.Month);
}

答案 1 :(得分:1)

我有同样的需求,我在这个phpexcel库的第51行的函数中找到了解决方案 dateDiff360

这是计算的类代码的一部分

import pygame
import random

# --- classes --- (UpperCaseNames)

class Test(pygame.sprite.Sprite):

    def __init__(self, w):
        super().__init__()

        self.image = pygame.image.load("index.png")
        self.image = pygame.transform.scale(self.image, (w, w))
        self.rect = self.image.get_rect()

        self.last = pygame.time.get_ticks()

# --- main ----

level = 1
cooldown = 1000

# - init -

pygame.init()
screen = pygame.display.set_mode((600, 600))

# - items -

background = pygame.Surface(screen.get_size())
background.fill((0, 0, 0))

screen.blit(background, (0,0))

all_sprites_list = pygame.sprite.Group()

for x in range(10):
    item = Test(random.randint(40, 60))
    item.rect.x = 40 * random.randint(0, 10)
    item.rect.y = 0
    all_sprites_list.add(item)

# - mainloop -

clock = pygame.time.Clock()

running = True

while running:

    now = pygame.time.get_ticks()

    for item in all_sprites_list:
        item.rect.y += level

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        if event.type == pygame.MOUSEBUTTONDOWN:
            for item in all_sprites_list:
                if item.rect.collidepoint(event.pos):
                    item.kill()

    pygame.display.flip()
    all_sprites_list.clear(screen, background)
    all_sprites_list.draw(screen)
    all_sprites_list.update()
    clock.tick(30)

pygame.quit()    

答案 2 :(得分: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;
    }

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

private static readonly int[] table = new int[]{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

答案 3 :(得分:0)

测试下一个

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

    if (IsLastDayOfMonth(a) && IsLastDayOfMonth(b)) {
        dayB = Math.min(30, dayB);
    } else if (dayA == 30 && dayB ==31) {
        DayB = 30;
    }

    if (IsLastDayOfMonth(a))
        dayA = 30;

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

private static bool IsLastDayOfMonth(DateTime date)
{
    int lastDay = DateTime.DaysInMonth(date.Year, date.Month);
    return date.Day == lastDay;
}