Free cookie consent management tool by TermsFeed Policy Generator

source: branches/RemoveBackwardsCompatibility/HeuristicLab.ExtLibs/HeuristicLab.EPPlus/4.0.3/EPPlus-4.0.3/FormulaParsing/Excel/Functions/DateTime/Yearfrac.cs

Last change on this file was 12074, checked in by sraggl, 9 years ago

#2341: Added EPPlus-4.0.3 to ExtLibs

File size: 3.9 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Globalization;
4using System.Linq;
5using System.Text;
6using OfficeOpenXml.FormulaParsing.Exceptions;
7using OfficeOpenXml.FormulaParsing.ExpressionGraph;
8
9namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime
10{
11    public class Yearfrac : ExcelFunction
12    {
13        public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context)
14        {
15            var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray();
16            ValidateArguments(functionArguments, 2);
17            var date1Num = ArgToDecimal(functionArguments, 0);
18            var date2Num = ArgToDecimal(functionArguments, 1);
19            if (date1Num > date2Num) //Switch to make date1 the lowest date
20            {
21                var t = date1Num;
22                date1Num = date2Num;
23                date2Num = t;
24                var fa = functionArguments[1];
25                functionArguments[1] = functionArguments[0];
26                functionArguments[0] = fa;
27            }
28            var date1 = System.DateTime.FromOADate(date1Num);
29            var date2 = System.DateTime.FromOADate(date2Num);
30
31            var basis = 0;
32            if (functionArguments.Count() > 2)
33            {
34                basis = ArgToInt(functionArguments, 2);
35                ThrowExcelErrorValueExceptionIf(() => basis < 0 || basis > 4, eErrorType.Num);
36            }
37            var func = context.Configuration.FunctionRepository.GetFunction("days360");
38            var calendar = new GregorianCalendar();
39            switch (basis)
40            {
41                case 0:
42                    var d360Result = System.Math.Abs(func.Execute(functionArguments, context).ResultNumeric);
43                    // reproducing excels behaviour
44                    if (date1.Month == 2 && date2.Day==31)
45                    {
46                        var daysInFeb = calendar.IsLeapYear(date1.Year) ? 29 : 28;
47                        if (date1.Day == daysInFeb) d360Result++; 
48                    }
49                    return CreateResult(d360Result / 360d, DataType.Decimal);
50                case 1:
51                    return CreateResult(System.Math.Abs((date2 - date1).TotalDays / CalculateAcutalYear(date1, date2)), DataType.Decimal);
52                case 2:
53                    return CreateResult(System.Math.Abs((date2 - date1).TotalDays / 360d), DataType.Decimal);
54                case 3:
55                    return CreateResult(System.Math.Abs((date2 - date1).TotalDays / 365d), DataType.Decimal);
56                case 4:
57                    var args = functionArguments.ToList();
58                    args.Add(new FunctionArgument(true));
59                    double? result = System.Math.Abs(func.Execute(args, context).ResultNumeric / 360d);
60                    return CreateResult(result.Value, DataType.Decimal);
61                default:
62                    return null;
63            }
64        }
65
66        private double CalculateAcutalYear(System.DateTime dt1, System.DateTime dt2)
67        {
68            var calendar = new GregorianCalendar();
69            var perYear = 0d;
70            var nYears = dt2.Year - dt1.Year + 1;
71            for (var y = dt1.Year; y <= dt2.Year; ++y)
72            {
73                perYear += calendar.IsLeapYear(y) ? 366 : 365;
74            }
75            if (new System.DateTime(dt1.Year + 1, dt1.Month, dt1.Day) >= dt2)
76            {
77                nYears = 1;
78                perYear = 365;
79                if (calendar.IsLeapYear(dt1.Year) && dt1.Month <= 2)
80                    perYear = 366;
81                else if (calendar.IsLeapYear(dt2.Year) && dt2.Month > 2)
82                    perYear = 366;
83                else if (dt2.Month == 2 && dt2.Day == 29)
84                    perYear = 366;
85            }
86            return perYear/(double) nYears; 
87        }
88    }
89}
Note: See TracBrowser for help on using the repository browser.