1 | using System;
|
---|
2 | using System.Collections.Generic;
|
---|
3 | using System.Globalization;
|
---|
4 | using System.Linq;
|
---|
5 | using System.Text;
|
---|
6 | using OfficeOpenXml.FormulaParsing.ExpressionGraph;
|
---|
7 |
|
---|
8 | namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime
|
---|
9 | {
|
---|
10 | public class Days360 : ExcelFunction
|
---|
11 | {
|
---|
12 | private enum Days360Calctype
|
---|
13 | {
|
---|
14 | European,
|
---|
15 | Us
|
---|
16 | }
|
---|
17 | public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context)
|
---|
18 | {
|
---|
19 | ValidateArguments(arguments, 2);
|
---|
20 | var numDate1 = ArgToDecimal(arguments, 0);
|
---|
21 | var numDate2 = ArgToDecimal(arguments, 1);
|
---|
22 | var dt1 = System.DateTime.FromOADate(numDate1);
|
---|
23 | var dt2 = System.DateTime.FromOADate(numDate2);
|
---|
24 |
|
---|
25 | var calcType = Days360Calctype.Us;
|
---|
26 | if (arguments.Count() > 2)
|
---|
27 | {
|
---|
28 | var european = ArgToBool(arguments, 2);
|
---|
29 | if(european) calcType = Days360Calctype.European;
|
---|
30 | }
|
---|
31 |
|
---|
32 | var startYear = dt1.Year;
|
---|
33 | var startMonth = dt1.Month;
|
---|
34 | var startDay = dt1.Day;
|
---|
35 | var endYear = dt2.Year;
|
---|
36 | var endMonth = dt2.Month;
|
---|
37 | var endDay = dt2.Day;
|
---|
38 |
|
---|
39 | if (calcType == Days360Calctype.European)
|
---|
40 | {
|
---|
41 | if (startDay == 31) startDay = 30;
|
---|
42 | if (endDay == 31) endDay = 30;
|
---|
43 | }
|
---|
44 | else
|
---|
45 | {
|
---|
46 | var calendar = new GregorianCalendar();
|
---|
47 | var nDaysInFeb = calendar.IsLeapYear(dt1.Year) ? 29 : 28;
|
---|
48 |
|
---|
49 | // If the investment is EOM and (Date1 is the last day of February) and (Date2 is the last day of February), then change D2 to 30.
|
---|
50 | if (startMonth == 2 && startDay == nDaysInFeb && endMonth == 2 && endDay == nDaysInFeb)
|
---|
51 | {
|
---|
52 | endDay = 30;
|
---|
53 | }
|
---|
54 | // If the investment is EOM and (Date1 is the last day of February), then change D1 to 30.
|
---|
55 | if (startMonth == 2 && startDay == nDaysInFeb)
|
---|
56 | {
|
---|
57 | startDay = 30;
|
---|
58 | }
|
---|
59 | // If D2 is 31 and D1 is 30 or 31, then change D2 to 30.
|
---|
60 | if (endDay == 31 && (startDay == 30 || startDay == 31))
|
---|
61 | {
|
---|
62 | endDay = 30;
|
---|
63 | }
|
---|
64 | // If D1 is 31, then change D1 to 30.
|
---|
65 | if (startDay == 31)
|
---|
66 | {
|
---|
67 | startDay = 30;
|
---|
68 | }
|
---|
69 | }
|
---|
70 | var result = (endYear*12*30 + endMonth*30 + endDay) - (startYear*12*30 + startMonth*30 + startDay);
|
---|
71 | return CreateResult(result, DataType.Integer);
|
---|
72 | }
|
---|
73 |
|
---|
74 | private int GetNumWholeMonths(System.DateTime dt1, System.DateTime dt2)
|
---|
75 | {
|
---|
76 | var startDate = new System.DateTime(dt1.Year, dt1.Month, 1).AddMonths(1);
|
---|
77 | var endDate = new System.DateTime(dt2.Year, dt2.Month, 1);
|
---|
78 | return ((endDate.Year - startDate.Year)*12) + (endDate.Month - startDate.Month);
|
---|
79 | }
|
---|
80 | }
|
---|
81 | }
|
---|