简体   繁体   English

C# 如何计算不包括特定日期(节假日)的工作日

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

I read some questions/answers related to functions in C# to calculate the working days (Days from Mondays to Fridays);我阅读了一些与 C# 中的功能相关的问题/答案来计算工作日(周一至周五的天数); some uses an extended code to achieve that.有些人使用扩展代码来实现这一点。

I have a data table with more than 50,000 rows and I required an effective method to calculate this information.我有一个超过 50,000 行的数据表,我需要一种有效的方法来计算这些信息。

Based on @MiBols answer a more efficient solution will be to use a HashSet<DateTime> instead of a List<DateTime> where search is then in O(1) :基于@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)));
}
/// <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)));
}

I created this extension that basically takes two dates and a list of dates to exclude (Holidays).我创建了这个扩展,它基本上需要两个日期和一个要排除的日期列表(假期)。 Surprisingly this method is very fast and has a validation to exclude the time from the DateTime when compare against the list of exclusions.令人惊讶的是,此方法非常快,并且具有在与排除列表进行比较时从 DateTime 中排除时间的验证。

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));

        }

I did a mix of two soutions above, inverting the expression to verify workDay and checking if the difference is negative.我混合了上述两种方法,反转表达式以验证 workDay 并检查差异是否为负。

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;
}

While using Gilad Green answer, I found how to get the list of holiday dates so you wouldn't need to make them yourself.在使用Gilad Green答案时,我发现了如何获取假期日期列表,这样您就不需要自己制作了。

Following live2 answer on Business/Holiday date handling , you may get a list of holiday dates.在关于商务/假期日期处理live2回答之后,您可能会获得假期日期列表。

Nuget Nuget

PM> install-package Nager.Date PM> 安装包 Nager.Date

Example:例子:

Get all publicHolidays of a year获取一年中的所有公共假期

var publicHolidays = DateSystem.GetPublicHoliday(2018, CountryCode.DE); var publicHolidays = DateSystem.GetPublicHoliday(2018, CountryCode.DE);

You may check if needed country exists in this registry here: https://date.nager.at/Country您可以在此处检查此注册表中是否存在所需的国家/地区: https://date.nager.at/Country

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM