考虑到周末和假日,将日期工作日添加到日期

给定日期和假期列表,如何将给定的工作日数添加到此日期? 对于较小的问题有很多解决方案,没有考虑假期(例如参见添加天数到日期但不包括周末 )。

编辑:我正在寻找O(1)或至少线性(假日数量)的解决方案。

请帮助谢谢konstantin

接近O(1)(没有初始时间)

如果你真的想要一个O(1)解决方案,我希望你不要考虑初始化fase。

初始化:

  • 构建可查询范围内有效返回值的所有日期的排序列表。 (使用类似Rik Garner答案中的代码)
  • 使用上面列表中的日期构建哈希表,其中日期为关键,列表中的索引为值

初始化代码,只需要一次,然后缓存结果。

查询/计算

List validWorkdays = // ; Dictionary lookupIndexOfValidWorkday = // ; DateTime AddWorkdays(DateTime start, int count) { var startIndex = lookupIndexOfValidWorkday[start]; return validWorkDays[startIndex + count]; } 

关于从字典中检索 :

获取或设置此属性的值接近O(1)操作。

O(n)假期数量

假设假期列表从最旧到最新排序。 ( 工作日公式的积分 )

 DateTime AddBusinessDay(DateTime start, int count, IEnumerable holidays) { int daysToAdd = count + ((count/ 5) * 2) + ((((int)start.DayOfWeek + (count % 5)) >= 5) ? 2 : 0); var end = start.AddDays(daysToAdd); foreach(var dt in holidays) { if (dt >= start && dt <= end) { end = end.AddDays(1); if (end.DayOfWeek == DayOfWeek.Saterday) { end = end.AddDays(2); } } } return end; } 

可以优化该方法。

创建一个只计算结果的简单公式非常困难,就像您链接的问题中的答案一样。 因为当您调整假期时,您需要考虑可能属于您的范围的新假期。 对于周末,您知道它们之间存在固定的间隔。

 using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; namespace DateThing { class Program { static void Main(string[] args) { var holidays = new List() { new DateTime(2010, 12, 25), new DateTime(2010, 12, 26) }; var futureDate = CalculateFutureDate(DateTime.Today, 20, holidays); } static DateTime CalculateFutureDate(DateTime fromDate, int numberofWorkDays, ICollection holidays) { var futureDate = fromDate; for (var i = 0; i < numberofWorkDays; i++ ) { if (futureDate.DayOfWeek == DayOfWeek.Saturday || futureDate.DayOfWeek == DayOfWeek.Sunday || (holidays != null && holidays.Contains(futureDate))) futureDate = futureDate.AddDays(1); // Increase FutureDate by one because of condition futureDate = futureDate.AddDays(1); // Add a working day } return futureDate; } } } 

试试这个……

  private DateTime CalculateFutureDate(DateTime fromDate, int numberofWorkDays, ICollection holidays) { var futureDate = fromDate; var daterange = Enumerable.Range(1, numberofWorkDays * 2); var dateSet = daterange.Select (d => futureDate.AddDays(d)); var dateSetElim = dateSet.Except(holidays).Except(dateSet.Where( s =>s.DayOfWeek == DayOfWeek.Sunday).Except(dateSet.Where (s=>s.DayOfWeek==DayOfWeek.Saturday) )); //zero-based array futureDate = dateSetElim.ElementAt(numberofWorkDays-1); return futureDate; } 

//下面的代码正常工作……如果您有任何疑虑,请告诉我

 DateTime AddBusinessDays(int noofDays, DateTime dtCurrent) { var holidays = new List() { new DateTime(2013, 10, 22), new DateTime(2013, 10, 28)}; DateTime tempdt = new DateTime(dtCurrent.Year, dtCurrent.Month, dtCurrent.Day); // if starting day is non working day adjust to next working day tempdt = ExcludeNotWorkingDay(tempdt, holidays); // if starting day is non working day adjust to next working day then minus 1 day in noofadding days if (tempdt.Date > dtCurrent.Date && !(noofDays == 0)) noofDays = noofDays - 1; while (noofDays > 0) { tempdt = tempdt.AddDays(1); // if day is non working day adjust to next working day tempdt = ExcludeNotWorkingDay(tempdt, holidays); noofDays = noofDays - 1; } return tempdt; } DateTime ExcludeNotWorkingDay(DateTime dtCurrent, List holidays) { while (!IsWorkDay(dtCurrent, holidays)) { dtCurrent = dtCurrent.AddDays(1); } return dtCurrent; } bool IsWorkDay(DateTime dtCurrent, List holidays) { if ((dtCurrent.DayOfWeek == DayOfWeek.Saturday || dtCurrent.DayOfWeek == DayOfWeek.Sunday || holidays.Contains(dtCurrent))) { return false; } else { return true; } } 

或许这样的事情

 using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DateThing { class Program { static void Main(string[] args) { var holidays = new List() { new DateTime(2010, 12, 25), new DateTime(2010, 12, 26) }; var workDays = GetNumberOfWorkDays(DateTime.Today, new DateTime(2011, 1, 1), holidays); } static int GetNumberOfWorkDays(DateTime fromDate, DateTime toDate, ICollection holidays) { var days = 0; for (var i = fromDate; i < toDate; ) { if (i.DayOfWeek != DayOfWeek.Saturday && i.DayOfWeek != DayOfWeek.Sunday && (holidays != null && !holidays.Contains(i))) days++; i = i.AddDays(1); } return days; } } }