在C#中模拟Excel的YearFrac

如何在C#应用程序中获得与Excel YearFrac函数相同的结果?

计算两个date之间所有天数(start_date和end_date)所代表的年份分数。 使用YEARFRAC工作表函数来确定分配给特定术语的全年福利或义务的比例。

这是一个很好的片段 。

YearFrac函数的algorithm实际上非常复杂。 也许这篇文章可以为您提供更多的细节。

您可以直接使用Excel的function来计算YearFrac 。 微软表示你不应该使用它 ,但它工作得很好。 如果您需要与Excel 100%的兼容性,这个解决scheme是很难打败的。 您需要向您的项目添加一个对Microsoft.Office.Interop.Excel的引用,以便此代码进行编译。

 static void Main() { var excel = new Microsoft.Office.Interop.Excel.Application(); Microsoft.Office.Interop.Excel.WorksheetFunction wsf = excel.WorksheetFunction; var start = new DateTime(1999, 11, 1); var end = new DateTime(1999, 1, 11); for (var basis = 0; basis != 5; basis++) { Console.WriteLine(wsf.YearFrac(start, end, basis)); } } 

YEARFRAC的签名是YEARFRAC(Date startDate,Date endDate,int约定)。 计算YEARFRAC的方法取决于惯例。

对于惯例= 2,YEARFRAC将使用ACT / 360方法计算YEARFRAC。 ACT / 360的实现可以在svn.finmath.netfind,特别是DayCountConvention_ACT_360.java

对于惯例= 3,YEARFRAC将使用ACT / 365方法计算YEARFRAC。 ACT / 365的实现可以在svn.finmath.netfind,特别是DayCountConvention_ACT_365.java

对于约定= 4,YEARFRAC将使用30E / 360方法计算YEARFRAC。 可以在svn.finmath.net上find30E / 360的实现,特别是DayCountConvention_30E_360.java

对于convention = 1,文档声称YEARFRAC是使用ACT / ACT惯例计算的。 不过,ACT / ACT有多个版本,我相信许多金融产品的标准是ACT / ACT ISDA。 我发现YEARFRAC与ACT / ACT IDSA约定有less许差别! ACT / ACT IDSA的实现可以在DayCountConvention_ACT_ACT_ISDA.javafind

我还没有检查过其他行为/行为版本,但是我不会依赖YEARFRAC ACT / ACT的模拟,但是当不清楚它们实现什么样的方法时…

我可以build议:

  public static double Yearfrac(DateTime startDate,DateTime endDate,DayCount daycount=DayCount.ActAct) { var nbDaysInPeriod = (double)(endDate - startDate).Days; switch(daycount) { case (DayCount.Act360): return nbDaysInPeriod / (double)360; case (DayCount.Act365): return nbDaysInPeriod / (double)365; case (DayCount.ActAct): return GetActAct(startDate,endDate); case (DayCount.Days360): var result = (endDate.Year - startDate.Year) * 360.0 + (endDate.Month - startDate.Month) * 30.0 + (Math.Min(endDate.Day, 30.0) - Math.Min(startDate.Day, 30.0)); return result/360; default: return nbDaysInPeriod / (double)365; } } public static double GetActAct(DateTime startDate, DateTime endDate) { // Reproduce Excel Yearfrac as per http://www.dwheeler.com/yearfrac/excel-ooxml-yearfrac.pdf var nbDaysInPeriod = (double)(endDate - startDate).Days; if(startDate.Year==endDate.Year || (endDate.Year-1==startDate.Year&&(startDate.Month>endDate.Month||startDate.Month==endDate.Month&&(startDate.Day>=endDate.Day)))) { var den = 365.0; if (startDate.Year == endDate.Year && DateTime.IsLeapYear(startDate.Year)) { den++; } else { if (endDate.Day == 29 && endDate.Month == 2) { den++; } else { if (DateTime.IsLeapYear(startDate.Year)) { var feb = new DateTime(startDate.Year, 2, 29); if (startDate<=feb && feb<=endDate) den++; } else { if (DateTime.IsLeapYear(endDate.Year)) { var feb = new DateTime(endDate.Year, 2, 29); if (startDate <= feb && feb <= endDate) den++; } } } } } else { var nbYears = endDate.Year - startDate.Year+1; var den = nbYears * 365.0; for (var i=0;i<nbYears;i++) { if (DateTime.IsLeapYear(startDate.Year + i)) den++; } den /= nbYears; return nbDaysInPeriod / den; } return nbDaysInPeriod / 365.0; }