| using System; |
| using System.Collections.Generic; |
| using System.Linq; |
| using OfficeOpenXml.FormulaParsing.ExpressionGraph; |
| using OfficeOpenXml.Utils; |
| |
| namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime; |
| |
| public class Workday : ExcelFunction { |
| public override CompileResult Execute( |
| IEnumerable<FunctionArgument> arguments, |
| ParsingContext context) { |
| ValidateArguments(arguments, 2); |
| var startDate = System.DateTime.FromOADate(ArgToInt(arguments, 0)); |
| var nWorkDays = ArgToInt(arguments, 1); |
| var resultDate = System.DateTime.MinValue; |
| var workdaysCounted = 0; |
| var tmpDate = startDate; |
| // first move forward to the first monday |
| while (tmpDate.DayOfWeek != DayOfWeek.Monday && (nWorkDays - workdaysCounted) > 0) { |
| if (!IsHoliday(tmpDate)) { |
| workdaysCounted++; |
| } |
| tmpDate = tmpDate.AddDays(1); |
| } |
| // then calculate whole weeks |
| var nWholeWeeks = (nWorkDays - workdaysCounted) / 5; |
| tmpDate = tmpDate.AddDays(nWholeWeeks * 7); |
| workdaysCounted += nWholeWeeks * 5; |
| |
| // calculate the rest |
| while (workdaysCounted < nWorkDays) { |
| tmpDate = tmpDate.AddDays(1); |
| if (!IsHoliday(tmpDate)) { |
| workdaysCounted++; |
| } |
| } |
| resultDate = AdjustResultWithHolidays(tmpDate, arguments); |
| return CreateResult(resultDate.ToOADate(), DataType.Date); |
| } |
| |
| private System.DateTime AdjustResultWithHolidays( |
| System.DateTime resultDate, |
| IEnumerable<FunctionArgument> arguments) { |
| if (arguments.Count() == 2) { |
| return resultDate; |
| } |
| var holidays = arguments.ElementAt(2).Value as IEnumerable<FunctionArgument>; |
| if (holidays != null) { |
| foreach (var arg in holidays) { |
| if (ConvertUtil.IsNumeric(arg.Value)) { |
| var dateSerial = ConvertUtil.GetValueDouble(arg.Value); |
| var holidayDate = System.DateTime.FromOADate(dateSerial); |
| if (!IsHoliday(holidayDate)) { |
| resultDate = resultDate.AddDays(1); |
| } |
| } |
| } |
| } else { |
| var range = arguments.ElementAt(2).Value as ExcelDataProvider.IRangeInfo; |
| if (range != null) { |
| foreach (var cell in range) { |
| if (ConvertUtil.IsNumeric(cell.Value)) { |
| var dateSerial = ConvertUtil.GetValueDouble(cell.Value); |
| var holidayDate = System.DateTime.FromOADate(dateSerial); |
| if (!IsHoliday(holidayDate)) { |
| resultDate = resultDate.AddDays(1); |
| } |
| } |
| } |
| } |
| } |
| return resultDate; |
| } |
| |
| private bool IsHoliday(System.DateTime date) { |
| return date.DayOfWeek == DayOfWeek.Saturday || date.DayOfWeek == DayOfWeek.Sunday; |
| } |
| } |