C#如何计算排除特定日期的工作日(节假日)

C# How to calculate working days excluding specific dates (Holidays)

我看了一些questions/answersC#函数相关的计算工作日(周一到周五);有些人使用扩展代码来实现这一点。

我有一个超过 50,000 行的数据table,我需要一种有效的方法来计算这些信息。

/// <summary> Get working days between two dates (Excluding a list of dates - Holidays) </summary>
/// <param name="dtmCurrent">Current date time</param>
/// <param name="dtmFinishDate">Finish date time</param>
/// <param name="lstExcludedDates">List of dates to exclude (Holidays)</param>
public static int fwGetWorkingDays(this DateTime dtmCurrent, DateTime dtmFinishDate, List<DateTime> lstExcludedDates)
{
    Func<DateTime, bool> workDay = currentDate =>
            (
                currentDate.DayOfWeek == DayOfWeek.Saturday ||
                currentDate.DayOfWeek == DayOfWeek.Sunday ||
                lstExcludedDates.Exists(evalDate => evalDate.Date.Equals(currentDate.Date))
            );

    return Enumerable.Range(0, 1 + (dtmFinishDate - dtmCurrent).Days).Count(intDay => workDay(dtmCurrent.AddDays(intDay)));
}

我创建了这个扩展,它基本上需要两个日期和一个要排除的日期列表(假期)。 令人惊讶的是,这种方法非常快,并且在与排除列表进行比较时,可以通过验证从 DateTime 中排除时间。

基于@MiBols 的回答,一个更有效的解决方案是使用 HashSet<DateTime> 而不是 List<DateTime>,然后在 O(1):

中进行搜索
/// <summary> Get working days between two dates (Excluding a list of dates - Holidays) </summary>
/// <param name="dtmCurrent">Current date time</param>
/// <param name="dtmFinishDate">Finish date time</param>
/// <param name="excludedDates">Collection of dates to exclude (Holidays)</param>
public static int fwGetWorkingDays(this DateTime dtmCurrent, DateTime dtmFinishDate, 
                                   HashSet<DateTime> excludedDates)
{
    Func<DateTime, bool> workDay = currentDate => (
        currentDate.DayOfWeek == DayOfWeek.Saturday ||
        currentDate.DayOfWeek == DayOfWeek.Sunday ||
        excludedDates.Contains(currentDate.Date));

    return Enumerable.Range(0, 1 + (dtmFinishDate - dtmCurrent).Days)
        .Count(intDay => workDay(dtmCurrent.AddDays(intDay)));
}

我混合了上面的两个解决方案,反转表达式以验证工作日并检查差异是否为负。

public static int GetWorkingDaysUntil(this DateTime dtmCurrent, DateTime dtmFinishDate, HashSet<DateTime> excludedDates)
{
    Func<DateTime, bool> workDay = currentDate => !(currentDate.DayOfWeek == DayOfWeek.Saturday ||
                                                    currentDate.DayOfWeek == DayOfWeek.Sunday ||
                                                    excludedDates.Contains(currentDate.Date));

    var daysDifference = (dtmFinishDate - dtmCurrent).Days;

    return daysDifference > 0 ?
                Enumerable.Range(0, 1 + daysDifference).Count(intDay => workDay(dtmCurrent.AddDays(intDay))) :
                0;
}
public static int ToBusinessWorkingDays(this DateTime start, DateTime due, DateTime[] holidays)
        {
            return Enumerable.Range(0, (due - start).Days)
                            .Select(a => start.AddDays(a))
                            .Where(a => a.DayOfWeek != DayOfWeek.Sunday)
                            .Where(a => a.DayOfWeek != DayOfWeek.Saturday)
                            .Count(a => !holidays.Any(x => x == a));

        }