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

时间:2010-12-08 04:47:08

标签: c# .net date

给出日期和假期列表,如何将给定的工作日数添加到此日期?对于较小的问题有很多解决方案,没有考虑到假期(例如参见Adding Days to a Date but Excluding Weekends)。

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

请帮忙 谢谢 康斯坦丁

5 个答案:

答案 0 :(得分:1)

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

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

初始化:

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

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

查询/计算

 List<DateTime> validWorkdays = // ;
 Dictionary<DateTime, int> lookupIndexOfValidWorkday = // ;

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

Concerning the retrieve from the dictionary

  

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

O(n)假期数

假设假期列表从最旧到最新排序。 (Credits for weekdays formula

DateTime AddBusinessDay(DateTime start, int count, IEnumerable<DateTime> 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;
}    

可以优化此方法。

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

答案 1 :(得分:0)

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<DateTime>()
                               {
                                   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<DateTime> 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;
        }
    }
}

答案 2 :(得分:0)

试试这个......

 private DateTime CalculateFutureDate(DateTime fromDate, int numberofWorkDays, ICollection<DateTime> 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;
    }

答案 3 :(得分:0)

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

DateTime AddBusinessDays(int noofDays, DateTime dtCurrent)
    {
        var holidays = new List<DateTime>() { 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<DateTime> holidays)
    {
        while (!IsWorkDay(dtCurrent, holidays))
        {
            dtCurrent = dtCurrent.AddDays(1);
        }
        return dtCurrent;
    }
    bool IsWorkDay(DateTime dtCurrent, List<DateTime> holidays)
    {
        if ((dtCurrent.DayOfWeek == DayOfWeek.Saturday || dtCurrent.DayOfWeek == DayOfWeek.Sunday ||
             holidays.Contains(dtCurrent)))
        {
            return false;
        }
        else
        {
            return true;
        }
    }

答案 4 :(得分:-1)

这样的事可能

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<DateTime>()
                               {
                                   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<DateTime> 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;
        }
    }


}