using System; using System.Collections.Generic; using System.Linq; using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; using OfficeOpenXml.Utils; namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime { public class Workday : ExcelFunction { public override CompileResult Execute(IEnumerable 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 arguments) { if (arguments.Count() == 2) return resultDate; var holidays = arguments.ElementAt(2).Value as IEnumerable; 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; } } }