简体   繁体   English

计算两个日期之间的工作日数?

[英]Calculate the number of business days between two dates?

In C#, how can I calculate the number of business (or weekdays) days between two dates?在 C# 中,如何计算两个日期之间工作日(或工作日)天数?

I've had such a task before and I've got the solution.我以前有过这样的任务,我已经找到了解决方案。 I would avoid enumerating all days in between when it's avoidable, which is the case here.我会避免列举可以避免的所有日子,这里就是这种情况。 I don't even mention creating a bunch of DateTime instances, as I saw in one of the answers above.正如我在上面的一个答案中看到的那样,我什至没有提到创建一堆 DateTime 实例。 This is really waste of processing power.这真的是在浪费处理能力。 Especially in the real world situation, when you have to examine time intervals of several months.尤其是在现实世界的情况下,当您必须检查几个月的时间间隔时。 See my code, with comments, below.请参阅下面的我的代码和注释。

    /// <summary>
    /// Calculates number of business days, taking into account:
    ///  - weekends (Saturdays and Sundays)
    ///  - bank holidays in the middle of the week
    /// </summary>
    /// <param name="firstDay">First day in the time interval</param>
    /// <param name="lastDay">Last day in the time interval</param>
    /// <param name="bankHolidays">List of bank holidays excluding weekends</param>
    /// <returns>Number of business days during the 'span'</returns>
    public static int BusinessDaysUntil(this DateTime firstDay, DateTime lastDay, params DateTime[] bankHolidays)
    {
        firstDay = firstDay.Date;
        lastDay = lastDay.Date;
        if (firstDay > lastDay)
            throw new ArgumentException("Incorrect last day " + lastDay);

        TimeSpan span = lastDay - firstDay;
        int businessDays = span.Days + 1;
        int fullWeekCount = businessDays / 7;
        // find out if there are weekends during the time exceedng the full weeks
        if (businessDays > fullWeekCount*7)
        {
            // we are here to find out if there is a 1-day or 2-days weekend
            // in the time interval remaining after subtracting the complete weeks
            int firstDayOfWeek = (int) firstDay.DayOfWeek;
            int lastDayOfWeek = (int) lastDay.DayOfWeek;
            if (lastDayOfWeek < firstDayOfWeek)
                lastDayOfWeek += 7;
            if (firstDayOfWeek <= 6)
            {
                if (lastDayOfWeek >= 7)// Both Saturday and Sunday are in the remaining time interval
                    businessDays -= 2;
                else if (lastDayOfWeek >= 6)// Only Saturday is in the remaining time interval
                    businessDays -= 1;
            }
            else if (firstDayOfWeek <= 7 && lastDayOfWeek >= 7)// Only Sunday is in the remaining time interval
                businessDays -= 1;
        }

        // subtract the weekends during the full weeks in the interval
        businessDays -= fullWeekCount + fullWeekCount;

        // subtract the number of bank holidays during the time interval
        foreach (DateTime bankHoliday in bankHolidays)
        {
            DateTime bh = bankHoliday.Date;
            if (firstDay <= bh && bh <= lastDay)
                --businessDays;
        }

        return businessDays;
    }

Edit by Slauma, August 2011由 Slauma 编辑,2011 年 8 月

Great answer!很好的答案! There is little bug though.虽然有小错误。 I take the freedom to edit this answer since the answerer is absent since 2009.由于回答者自 2009 年以来一直缺席,因此我可以自由编辑此答案。

The code above assumes that DayOfWeek.Sunday has the value 7 which is not the case.上面的代码假定DayOfWeek.Sunday的值为7 ,但事实并非如此。 The value is actually 0 .该值实际上是0 It leads to a wrong calculation if for example firstDay and lastDay are both the same Sunday.例如,如果firstDaylastDay都是同一个星期日,则会导致计算错误。 The method returns 1 in this case but it should be 0 .在这种情况下,该方法返回1但它应该是0

Easiest fix for this bug: Replace in the code above the lines where firstDayOfWeek and lastDayOfWeek are declared by the following:此错误的最简单修复方法:替换上面的代码中firstDayOfWeeklastDayOfWeek由以下声明的行:

int firstDayOfWeek = firstDay.DayOfWeek == DayOfWeek.Sunday 
    ? 7 : (int)firstDay.DayOfWeek;
int lastDayOfWeek = lastDay.DayOfWeek == DayOfWeek.Sunday
    ? 7 : (int)lastDay.DayOfWeek;

Now the result is:现在结果是:

  • Friday to Friday -> 1周五至周五 -> 1
  • Saturday to Saturday -> 0周六至周六 -> 0
  • Sunday to Sunday -> 0周日至周日 -> 0
  • Friday to Saturday -> 1周五至周六 -> 1
  • Friday to Sunday -> 1周五至周日 -> 1
  • Friday to Monday -> 2周五至周一 -> 2
  • Saturday to Monday -> 1周六至周一 -> 1
  • Sunday to Monday -> 1周日至周一 -> 1
  • Monday to Monday -> 1周一至周一 -> 1

Ok.好的。 I think it's time to post the right answer:我认为是时候发布正确答案了:

public static double GetBusinessDays(DateTime startD, DateTime endD)
{
    double calcBusinessDays =
        1 + ((endD - startD).TotalDays * 5 -
        (startD.DayOfWeek - endD.DayOfWeek) * 2) / 7;

    if (endD.DayOfWeek == DayOfWeek.Saturday) calcBusinessDays--;
    if (startD.DayOfWeek == DayOfWeek.Sunday) calcBusinessDays--;

    return calcBusinessDays;
}

Original Source:原始来源:

http://alecpojidaev.wordpress.com/2009/10/29/work-days-calculation-with-c/ http://alecpojidaev.wordpress.com/2009/10/29/work-days-calculation-with-c/

I know this question is already solved, but I thought I could provide a more straightforward-looking answer that may help other visitors in the future.我知道这个问题已经解决了,但我想我可以提供一个更直接的答案,这可能会在未来帮助其他访问者。

Here's my take at it:这是我的看法:

public int GetWorkingDays(DateTime from, DateTime to)
{
    var dayDifference = (int)to.Subtract(from).TotalDays;
    return Enumerable
        .Range(1, dayDifference)
        .Select(x => from.AddDays(x))
        .Count(x => x.DayOfWeek != DayOfWeek.Saturday && x.DayOfWeek != DayOfWeek.Sunday);
}

This was my original submission:这是我的原始提交:

public int GetWorkingDays(DateTime from, DateTime to)
{
    var totalDays = 0;
    for (var date = from; date < to; date = date.AddDays(1))
    {
        if (date.DayOfWeek != DayOfWeek.Saturday
            && date.DayOfWeek != DayOfWeek.Sunday)
            totalDays++;
    }

    return totalDays;
}

Define an Extension Method on DateTime like so:在 DateTime 上定义一个扩展方法,如下所示:

public static class DateTimeExtensions
{
    public static bool IsWorkingDay(this DateTime date)
    {
        return date.DayOfWeek != DayOfWeek.Saturday
            && date.DayOfWeek != DayOfWeek.Sunday;
    }
}

Then, use is within a Where clause to filter a broader list of dates:然后,在 Where 子句中使用 is 来过滤更广泛的日期列表:

var allDates = GetDates(); // method which returns a list of dates

// filter dates by working day's  
var countOfWorkDays = allDates
     .Where(day => day.IsWorkingDay())
     .Count() ;

I used the following code to also take in to account bank holidays:我使用以下代码也考虑了银行假期:

public class WorkingDays
{
    public List<DateTime> GetHolidays()
    {
        var client = new WebClient();
        var json = client.DownloadString("https://www.gov.uk/bank-holidays.json");
        var js = new JavaScriptSerializer();
        var holidays = js.Deserialize <Dictionary<string, Holidays>>(json);
        return holidays["england-and-wales"].events.Select(d => d.date).ToList();
    }

    public int GetWorkingDays(DateTime from, DateTime to)
    {
        var totalDays = 0;
        var holidays = GetHolidays();
        for (var date = from.AddDays(1); date <= to; date = date.AddDays(1))
        {
            if (date.DayOfWeek != DayOfWeek.Saturday
                && date.DayOfWeek != DayOfWeek.Sunday
                && !holidays.Contains(date))
                totalDays++;
        }

        return totalDays;
    }
}

public class Holidays
{
    public string division { get; set; }
    public List<Event> events { get; set; }
}

public class Event
{
    public DateTime date { get; set; }
    public string notes { get; set; }
    public string title { get; set; }
}

And Unit Tests:和单元测试:

[TestClass]
public class WorkingDays
{
    [TestMethod]
    public void SameDayIsZero()
    {
        var service = new WorkingDays();

        var from = new DateTime(2013, 8, 12);

        Assert.AreEqual(0, service.GetWorkingDays(from, from));

    }

    [TestMethod]
    public void CalculateDaysInWorkingWeek()
    {
        var service = new WorkingDays();

        var from = new DateTime(2013, 8, 12);
        var to = new DateTime(2013, 8, 16);

        Assert.AreEqual(4, service.GetWorkingDays(from, to), "Mon - Fri = 4");

        Assert.AreEqual(1, service.GetWorkingDays(from, new DateTime(2013, 8, 13)), "Mon - Tues = 1");
    }

    [TestMethod]
    public void NotIncludeWeekends()
    {
        var service = new WorkingDays();

        var from = new DateTime(2013, 8, 9);
        var to = new DateTime(2013, 8, 16);

        Assert.AreEqual(5, service.GetWorkingDays(from, to), "Fri - Fri = 5");

        Assert.AreEqual(2, service.GetWorkingDays(from, new DateTime(2013, 8, 13)), "Fri - Tues = 2");
        Assert.AreEqual(1, service.GetWorkingDays(from, new DateTime(2013, 8, 12)), "Fri - Mon = 1");
    }

    [TestMethod]
    public void AccountForHolidays()
    {
        var service = new WorkingDays();

        var from = new DateTime(2013, 8, 23);

        Assert.AreEqual(0, service.GetWorkingDays(from, new DateTime(2013, 8, 26)), "Fri - Mon = 0");

        Assert.AreEqual(1, service.GetWorkingDays(from, new DateTime(2013, 8, 27)), "Fri - Tues = 1");
    }
}

I searched a lot for a, easy to digest, algorithm to calculate the working days between 2 dates, and also to exclude the national holidays, and finally I decide to go with this approach:我搜索了很多,易于消化的算法来计算两个日期之间的工作日,并排除国定假日,最后我决定采用这种方法:

public static int NumberOfWorkingDaysBetween2Dates(DateTime start,DateTime due,IEnumerable<DateTime> holidays)
        {
            var dic = new Dictionary<DateTime, DayOfWeek>();
            var totalDays = (due - start).Days;
            for (int i = 0; i < totalDays + 1; i++)
            {
                if (!holidays.Any(x => x == start.AddDays(i)))
                    dic.Add(start.AddDays(i), start.AddDays(i).DayOfWeek);
            }

            return dic.Where(x => x.Value != DayOfWeek.Saturday && x.Value != DayOfWeek.Sunday).Count();
        } 

Basically I wanted to go with each date and evaluate my conditions:基本上我想去每个日期并评估我的条件:

  1. Is not Saturday不是星期六
  2. Is not Sunday不是星期天
  3. Is not national holiday不是国定假日

but also I wanted to avoid iterating dates.但我也想避免重复日期。

By running and measuring the time need it to evaluate 1 full year, I go the following result:通过运行和测量评估 1 整年所需的时间,我得出以下结果:

static void Main(string[] args)
        {
            var start = new DateTime(2017, 1, 1);
            var due = new DateTime(2017, 12, 31);

            var sw = Stopwatch.StartNew();
            var days = NumberOfWorkingDaysBetween2Dates(start, due,NationalHolidays());
            sw.Stop();

            Console.WriteLine($"Total working days = {days} --- time: {sw.Elapsed}");
            Console.ReadLine();

            // result is:
           // Total working days = 249-- - time: 00:00:00.0269087
        }

Edit: a new method more simple:编辑:一种更简单的新方法:

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

        }

This solution avoids iteration, works for both +ve and -ve weekday differences and includes a unit test suite to regression against the slower method of counting weekdays.该解决方案避免了迭代,适用于 +ve 和 -ve 工作日差异,并包括一个单元测试套件,用于针对较慢的工作日计数方法进行回归。 I've also include a concise method to add weekdays also works in the same non-iterative way.我还提供了一种添加工作日的简洁方法,也可以以相同的非迭代方式工作。

Unit tests cover a few thousand date combinations in order to exhaustively test all start/end weekday combinations with both small and large date ranges.单元测试涵盖了数千个日期组合,以便详尽地测试具有小日期范围和大日期范围的所有开始/结束工作日组合。

Important : We make the assumption that we are counting days by excluding the start date and including the end date.重要提示:我们假设我们通过排除开始日期并包括结束日期来计算天数。 This is important when counting weekdays as the specific start/end days that you include/exclude affect the result.这在计算工作日时很重要,因为您包含/排除的特定开始/结束日期会影响结果。 This also ensures that the difference between two equal days is always zero and that we only include full working days as typically you want the answer to be correct for any time on the current start date (often today) and include the full end date (eg a due date).这也确保两个相等天之间的差异始终为零,并且我们只包括完整工作日,因为通常您希望答案在当前开始日期(通常是今天)的任何时间都是正确的,并包括完整的结束日期(例如到期日)。

NOTE: This code needs an additional adjustment for holidays but in keeping with the above assumption, this code must exclude holidays on the start date.注意:此代码需要针对假期进行额外调整,但与上述假设一致,此代码必须在开始日期排除假期。

Add weekdays:添加工作日:

private static readonly int[,] _addOffset = 
{
  // 0  1  2  3  4
    {0, 1, 2, 3, 4}, // Su  0
    {0, 1, 2, 3, 4}, // M   1
    {0, 1, 2, 3, 6}, // Tu  2
    {0, 1, 4, 5, 6}, // W   3
    {0, 1, 4, 5, 6}, // Th  4
    {0, 3, 4, 5, 6}, // F   5
    {0, 2, 3, 4, 5}, // Sa  6
};

public static DateTime AddWeekdays(this DateTime date, int weekdays)
{
    int extraDays = weekdays % 5;
    int addDays = weekdays >= 0
        ? (weekdays / 5) * 7 + _addOffset[(int)date.DayOfWeek, extraDays]
        : (weekdays / 5) * 7 - _addOffset[6 - (int)date.DayOfWeek, -extraDays];
    return date.AddDays(addDays);
}

Compute weekday difference:计算工作日差异:

static readonly int[,] _diffOffset = 
{
  // Su M  Tu W  Th F  Sa
    {0, 1, 2, 3, 4, 5, 5}, // Su
    {4, 0, 1, 2, 3, 4, 4}, // M 
    {3, 4, 0, 1, 2, 3, 3}, // Tu
    {2, 3, 4, 0, 1, 2, 2}, // W 
    {1, 2, 3, 4, 0, 1, 1}, // Th
    {0, 1, 2, 3, 4, 0, 0}, // F 
    {0, 1, 2, 3, 4, 5, 0}, // Sa
};

public static int GetWeekdaysDiff(this DateTime dtStart, DateTime dtEnd)
{
    int daysDiff = (int)(dtEnd - dtStart).TotalDays;
    return daysDiff >= 0
        ? 5 * (daysDiff / 7) + _diffOffset[(int) dtStart.DayOfWeek, (int) dtEnd.DayOfWeek]
        : 5 * (daysDiff / 7) - _diffOffset[6 - (int) dtStart.DayOfWeek, 6 - (int) dtEnd.DayOfWeek];
}

I found that most other solutions on stack overflow were either slow (iterative) or overly complex and many were just plain incorrect.我发现大多数其他关于堆栈溢出的解决方案要么很慢(迭代),要么过于复杂,而且很多都是完全不正确的。 Moral of the story is ... Don't trust it unless you've exhaustively tested it!!这个故事的寓意是......除非你已经彻底测试过,否则不要相信它!

Unit tests based on NUnit Combinatorial testing and ShouldBe NUnit extension.基于NUnit 组合测试ShouldBe NUnit 扩展的单元测试。

[TestFixture]
public class DateTimeExtensionsTests
{
    /// <summary>
    /// Exclude start date, Include end date
    /// </summary>
    /// <param name="dtStart"></param>
    /// <param name="dtEnd"></param>
    /// <returns></returns>
    private IEnumerable<DateTime> GetDateRange(DateTime dtStart, DateTime dtEnd)
    {
        Console.WriteLine(@"dtStart={0:yy-MMM-dd ddd}, dtEnd={1:yy-MMM-dd ddd}", dtStart, dtEnd);

        TimeSpan diff = dtEnd - dtStart;
        Console.WriteLine(diff);

        if (dtStart <= dtEnd)
        {
            for (DateTime dt = dtStart.AddDays(1); dt <= dtEnd; dt = dt.AddDays(1))
            {
                Console.WriteLine(@"dt={0:yy-MMM-dd ddd}", dt);
                yield return dt;
            }
        }
        else
        {
            for (DateTime dt = dtStart.AddDays(-1); dt >= dtEnd; dt = dt.AddDays(-1))
            {
                Console.WriteLine(@"dt={0:yy-MMM-dd ddd}", dt);
                yield return dt;
            }
        }
    }

    [Test, Combinatorial]
    public void TestGetWeekdaysDiff(
        [Values(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 20, 30)]
        int startDay,
        [Values(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 20, 30)]
        int endDay,
        [Values(7)]
        int startMonth,
        [Values(7)]
        int endMonth)
    {
        // Arrange
        DateTime dtStart = new DateTime(2016, startMonth, startDay);
        DateTime dtEnd = new DateTime(2016, endMonth, endDay);

        int nDays = GetDateRange(dtStart, dtEnd)
            .Count(dt => dt.DayOfWeek != DayOfWeek.Saturday && dt.DayOfWeek != DayOfWeek.Sunday);

        if (dtEnd < dtStart) nDays = -nDays;

        Console.WriteLine(@"countBusDays={0}", nDays);

        // Act / Assert
        dtStart.GetWeekdaysDiff(dtEnd).ShouldBe(nDays);
    }

    [Test, Combinatorial]
    public void TestAddWeekdays(
        [Values(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 20, 30)]
        int startDay,
        [Values(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 20, 30)]
        int weekdays)
    {
        DateTime dtStart = new DateTime(2016, 7, startDay);
        DateTime dtEnd1 = dtStart.AddWeekdays(weekdays);     // ADD
        dtStart.GetWeekdaysDiff(dtEnd1).ShouldBe(weekdays);  

        DateTime dtEnd2 = dtStart.AddWeekdays(-weekdays);    // SUBTRACT
        dtStart.GetWeekdaysDiff(dtEnd2).ShouldBe(-weekdays);
    }
}

Well this has been beaten to death.好吧,这已经被打死了。 :) However I'm still going to provide another answer because I needed something a bit different. :) 但是我仍然会提供另一个答案,因为我需要一些不同的东西。 This solution is different in that it returns a Business TimeSpan between the start and end, and you can set the business hours of the day, and add holidays.此解决方案的不同之处在于它返回开始和结束之间的 Business TimeSpan ,您可以设置一天的营业时间,并添加假期。 So you can use it to calculate if it happens within a day, across days, over weekends, and even holidays.因此,您可以使用它来计算它是否在一天内、几天内、周末甚至节假日发生。 And you can get just the business days or not by just getting what you need from the returned TimeSpan object.您可以通过从返回的 TimeSpan 对象中获取所需的内容来获取或不获取工作日。 And the way it uses lists of days, you can see how very easy it would be to add the list of non-work days if it's not the typical Sat and Sun.并且它使用日期列表的方式,您可以看到如果不是典型的周六和周日,添加非工作日列表是多么容易。 And I tested for a year, and it seems super fast.而且我测试了一年,感觉超级快。

I just hope the pasting of the code is accurate.我只希望代码的粘贴是准确的。 But I know it works.但我知道它有效。

public static TimeSpan GetBusinessTimespanBetween(
    DateTime start, DateTime end,
    TimeSpan workdayStartTime, TimeSpan workdayEndTime,
    List<DateTime> holidays = null)
{
    if (end < start)
        throw new ArgumentException("start datetime must be before end datetime.");

    // Just create an empty list for easier coding.
    if (holidays == null) holidays = new List<DateTime>();

    if (holidays.Where(x => x.TimeOfDay.Ticks > 0).Any())
        throw new ArgumentException("holidays can not have a TimeOfDay, only the Date.");

    var nonWorkDays = new List<DayOfWeek>() { DayOfWeek.Saturday, DayOfWeek.Sunday };

    var startTime = start.TimeOfDay;

    // If the start time is before the starting hours, set it to the starting hour.
    if (startTime < workdayStartTime) startTime = workdayStartTime;

    var timeBeforeEndOfWorkDay = workdayEndTime - startTime;

    // If it's after the end of the day, then this time lapse doesn't count.
    if (timeBeforeEndOfWorkDay.TotalSeconds < 0) timeBeforeEndOfWorkDay = new TimeSpan();
    // If start is during a non work day, it doesn't count.
    if (nonWorkDays.Contains(start.DayOfWeek)) timeBeforeEndOfWorkDay = new TimeSpan();
    else if (holidays.Contains(start.Date)) timeBeforeEndOfWorkDay = new TimeSpan();

    var endTime = end.TimeOfDay;

    // If the end time is after the ending hours, set it to the ending hour.
    if (endTime > workdayEndTime) endTime = workdayEndTime;

    var timeAfterStartOfWorkDay = endTime - workdayStartTime;

    // If it's before the start of the day, then this time lapse doesn't count.
    if (timeAfterStartOfWorkDay.TotalSeconds < 0) timeAfterStartOfWorkDay = new TimeSpan();
    // If end is during a non work day, it doesn't count.
    if (nonWorkDays.Contains(end.DayOfWeek)) timeAfterStartOfWorkDay = new TimeSpan();
    else if (holidays.Contains(end.Date)) timeAfterStartOfWorkDay = new TimeSpan();

    // Easy scenario if the times are during the day day.
    if (start.Date.CompareTo(end.Date) == 0)
    {
        if (nonWorkDays.Contains(start.DayOfWeek)) return new TimeSpan();
        else if (holidays.Contains(start.Date)) return new TimeSpan();
        return endTime - startTime;
    }
    else
    {
        var timeBetween = end - start;
        var daysBetween = (int)Math.Floor(timeBetween.TotalDays);
        var dailyWorkSeconds = (int)Math.Floor((workdayEndTime - workdayStartTime).TotalSeconds);

        var businessDaysBetween = 0;

        // Now the fun begins with calculating the actual Business days.
        if (daysBetween > 0)
        {
            var nextStartDay = start.AddDays(1).Date;
            var dayBeforeEnd = end.AddDays(-1).Date;
            for (DateTime d = nextStartDay; d <= dayBeforeEnd; d = d.AddDays(1))
            {
                if (nonWorkDays.Contains(d.DayOfWeek)) continue;
                else if (holidays.Contains(d.Date)) continue;
                businessDaysBetween++;
            }
        }

        var dailyWorkSecondsToAdd = dailyWorkSeconds * businessDaysBetween;

        var output = timeBeforeEndOfWorkDay + timeAfterStartOfWorkDay;
        output = output + new TimeSpan(0, 0, dailyWorkSecondsToAdd);

        return output;
    }
}

And here is test code: Note that you just have to put this function in a class called DateHelper for the test code to work.这是测试代码:请注意,您只需将此函数放在一个名为DateHelper的类中,测试代码就可以工作。

[TestMethod]
public void TestGetBusinessTimespanBetween()
{
    var workdayStart = new TimeSpan(8, 0, 0);
    var workdayEnd = new TimeSpan(17, 0, 0);

    var holidays = new List<DateTime>()
    {
        new DateTime(2018, 1, 15), // a Monday
        new DateTime(2018, 2, 15) // a Thursday
    };

    var testdata = new[]
    {
        new
        {
            expectedMinutes = 0,
            start = new DateTime(2016, 10, 19, 9, 50, 0),
            end = new DateTime(2016, 10, 19, 9, 50, 0)
        },
        new
        {
            expectedMinutes = 10,
            start = new DateTime(2016, 10, 19, 9, 50, 0),
            end = new DateTime(2016, 10, 19, 10, 0, 0)
        },
        new
        {
            expectedMinutes = 5,
            start = new DateTime(2016, 10, 19, 7, 50, 0),
            end = new DateTime(2016, 10, 19, 8, 5, 0)
        },
        new
        {
            expectedMinutes = 5,
            start = new DateTime(2016, 10, 19, 16, 55, 0),
            end = new DateTime(2016, 10, 19, 17, 5, 0)
        },
        new
        {
            expectedMinutes = 15,
            start = new DateTime(2016, 10, 19, 16, 50, 0),
            end = new DateTime(2016, 10, 20, 8, 5, 0)
        },
        new
        {
            expectedMinutes = 10,
            start = new DateTime(2016, 10, 19, 16, 50, 0),
            end = new DateTime(2016, 10, 20, 7, 55, 0)
        },
        new
        {
            expectedMinutes = 5,
            start = new DateTime(2016, 10, 19, 17, 10, 0),
            end = new DateTime(2016, 10, 20, 8, 5, 0)
        },
        new
        {
            expectedMinutes = 0,
            start = new DateTime(2016, 10, 19, 17, 10, 0),
            end = new DateTime(2016, 10, 20, 7, 5, 0)
        },
        new
        {
            expectedMinutes = 545,
            start = new DateTime(2016, 10, 19, 12, 10, 0),
            end = new DateTime(2016, 10, 20, 12, 15, 0)
        },
        // Spanning multiple weekdays
        new
        {
            expectedMinutes = 835,
            start = new DateTime(2016, 10, 19, 12, 10, 0),
            end = new DateTime(2016, 10, 21, 8, 5, 0)
        },
        // Spanning multiple weekdays
        new
        {
            expectedMinutes = 1375,
            start = new DateTime(2016, 10, 18, 12, 10, 0),
            end = new DateTime(2016, 10, 21, 8, 5, 0)
        },
        // Spanning from a Thursday to a Tuesday, 5 mins short of complete day.
        new
        {
            expectedMinutes = 1615,
            start = new DateTime(2016, 10, 20, 12, 10, 0),
            end = new DateTime(2016, 10, 25, 12, 5, 0)
        },
        // Spanning from a Thursday to a Tuesday, 5 mins beyond complete day.
        new
        {
            expectedMinutes = 1625,
            start = new DateTime(2016, 10, 20, 12, 10, 0),
            end = new DateTime(2016, 10, 25, 12, 15, 0)
        },
        // Spanning from a Friday to a Monday, 5 mins beyond complete day.
        new
        {
            expectedMinutes = 545,
            start = new DateTime(2016, 10, 21, 12, 10, 0),
            end = new DateTime(2016, 10, 24, 12, 15, 0)
        },
        // Spanning from a Friday to a Monday, 5 mins short complete day.
        new
        {
            expectedMinutes = 535,
            start = new DateTime(2016, 10, 21, 12, 10, 0),
            end = new DateTime(2016, 10, 24, 12, 5, 0)
        },
        // Spanning from a Saturday to a Monday, 5 mins short complete day.
        new
        {
            expectedMinutes = 245,
            start = new DateTime(2016, 10, 22, 12, 10, 0),
            end = new DateTime(2016, 10, 24, 12, 5, 0)
        },
        // Spanning from a Saturday to a Sunday, 5 mins beyond complete day.
        new
        {
            expectedMinutes = 0,
            start = new DateTime(2016, 10, 22, 12, 10, 0),
            end = new DateTime(2016, 10, 23, 12, 15, 0)
        },
        // Times within the same Saturday.
        new
        {
            expectedMinutes = 0,
            start = new DateTime(2016, 10, 22, 12, 10, 0),
            end = new DateTime(2016, 10, 23, 12, 15, 0)
        },
        // Spanning from a Saturday to the Sunday next week.
        new
        {
            expectedMinutes = 2700,
            start = new DateTime(2016, 10, 22, 12, 10, 0),
            end = new DateTime(2016, 10, 30, 12, 15, 0)
        },
        // Spanning a year.
        new
        {
            expectedMinutes = 143355,
            start = new DateTime(2016, 10, 22, 12, 10, 0),
            end = new DateTime(2017, 10, 30, 12, 15, 0)
        },
        // Spanning a year with 2 holidays.
        new
        {
            expectedMinutes = 142815,
            start = new DateTime(2017, 10, 22, 12, 10, 0),
            end = new DateTime(2018, 10, 30, 12, 15, 0)
        },
    };

    foreach (var item in testdata)
    {
        Assert.AreEqual(item.expectedMinutes,
            DateHelper.GetBusinessTimespanBetween(
                item.start, item.end,
                workdayStart, workdayEnd,
                holidays)
                .TotalMinutes);
    }
}

Here's some code for that purpose, with swedish holidays but you can adapt what holidays to count.这是用于此目的的一些代码,其中包含瑞典假期,但您可以调整要计算的假期。 Note that I added a limit you might want to remove, but it was for a web-based system and I didnt want anyone to enter some huge date to hog the process请注意,我添加了一个您可能想要删除的限制,但它是针对基于 Web 的系统的,我不希望任何人输入一些巨大的日期来占用该过程

  public static int GetWorkdays(DateTime from ,DateTime to)
    {
        int limit = 9999;
        int counter = 0;
        DateTime current = from;
        int result = 0;

        if (from > to)
        {
            DateTime temp = from;
            from = to;
            to = temp;
        }

        if (from >= to)
        {
            return 0;
        }


        while (current <= to && counter < limit)
        {
            if (IsSwedishWorkday(current))
            {
                result++;
            }
            current = current.AddDays(1);
            counter++;

        }
        return result;
    }


    public static bool IsSwedishWorkday(DateTime date)
    {
        return (!IsSwedishHoliday(date) && date.DayOfWeek != DayOfWeek.Saturday && date.DayOfWeek != DayOfWeek.Sunday);
    }

    public static bool IsSwedishHoliday(DateTime date)
    {
        return (
        IsSameDay(GetEpiphanyDay(date.Year), date) ||
        IsSameDay(GetMayDay(date.Year), date) ||
        IsSameDay(GetSwedishNationalDay(date.Year), date) ||
        IsSameDay(GetChristmasDay(date.Year), date) ||
        IsSameDay(GetBoxingDay(date.Year), date) ||
        IsSameDay(GetGoodFriday(date.Year), date) ||
        IsSameDay(GetAscensionDay(date.Year), date) ||
        IsSameDay(GetAllSaintsDay(date.Year), date) ||
        IsSameDay(GetMidsummersDay(date.Year), date) ||
        IsSameDay(GetPentecostDay(date.Year), date) ||
        IsSameDay(GetEasterMonday(date.Year), date) ||
        IsSameDay(GetNewYearsDay(date.Year), date) ||
        IsSameDay(GetEasterDay(date.Year), date)
        );
    }

    // Trettondagen
    public static DateTime GetEpiphanyDay(int year)
    {
        return new DateTime(year, 1, 6);
    }

    // Första maj
    public static DateTime GetMayDay(int year)
    {
        return new DateTime(year,5,1);
    }

    // Juldagen
    public static DateTime GetSwedishNationalDay(int year)
    {
        return new DateTime(year, 6, 6);
    }


    // Juldagen
    public static DateTime GetNewYearsDay(int year)
    {
        return new DateTime(year,1,1);
    }

    // Juldagen
    public static DateTime GetChristmasDay(int year)
    {
        return new DateTime(year,12,25);
    }

    // Annandag jul
    public static DateTime GetBoxingDay(int year)
    {
        return new DateTime(year, 12, 26);
    }


    // Långfredagen
    public static DateTime GetGoodFriday(int year)
    {
        return GetEasterDay(year).AddDays(-3);
    }

    // Kristi himmelsfärdsdag
    public static DateTime GetAscensionDay(int year)
    {
        return GetEasterDay(year).AddDays(5*7+4);
    }

    // Midsommar
    public static DateTime GetAllSaintsDay(int year)
    {
        DateTime result = new DateTime(year,10,31);
        while (result.DayOfWeek != DayOfWeek.Saturday)
        {
            result = result.AddDays(1);
        }
        return result;
    }

    // Midsommar
    public static DateTime GetMidsummersDay(int year)
    {
        DateTime result = new DateTime(year, 6, 20);
        while (result.DayOfWeek != DayOfWeek.Saturday)
        {
            result = result.AddDays(1);
        }
        return result;
    }

    // Pingstdagen
    public static DateTime GetPentecostDay(int year)
    {
        return GetEasterDay(year).AddDays(7 * 7);
    }

    // Annandag påsk
    public static DateTime GetEasterMonday(int year)
    {
        return GetEasterDay(year).AddDays(1);
    }
    public static DateTime GetEasterDay(int y)
    {
        double c;
        double n;
        double k;
        double i;
        double j;
        double l;
        double m;
        double d;
        c = System.Math.Floor(y / 100.0);
        n = y - 19 * System.Math.Floor(y / 19.0);
        k = System.Math.Floor((c - 17) / 25.0);
        i = c - System.Math.Floor(c / 4) - System.Math.Floor((c - k) / 3) + 19 * n + 15;
        i = i - 30 * System.Math.Floor(i / 30);
        i = i - System.Math.Floor(i / 28) * (1 - System.Math.Floor(i / 28) * System.Math.Floor(29 / (i + 1)) * System.Math.Floor((21 - n) / 11));
        j = y + System.Math.Floor(y / 4.0) + i + 2 - c + System.Math.Floor(c / 4);
        j = j - 7 * System.Math.Floor(j / 7);
        l = i - j;
        m = 3 + System.Math.Floor((l + 40) / 44);// month
        d = l + 28 - 31 * System.Math.Floor(m / 4);// day

        double days = ((m == 3) ? d : d + 31);

        DateTime result = new DateTime(y, 3, 1).AddDays(days-1);

        return result;
    }

Works and without loops有效且无循环

This method doesn't use any loops and is actually quite simple.此方法不使用任何循环,实际上非常简单。 It expands the date range to full weeks since we know that each week has 5 business days.它将日期范围扩展到整周,因为我们知道每周有 5 个工作日。 It then uses a lookup table to find the number of business days to subtract from the start and end to get the right result.然后,它使用查找表查找要从开始和结束中减去的工作日数,以获得正确的结果。 I've expanded out the calculation to help show what's going on, but the whole thing could be condensed into a single line if needed.我已经扩展了计算以帮助显示正在发生的事情,但如果需要,整个事情可以浓缩成一行。

Anyway, this works for me and so I thought I'd post it here in case it might help others.无论如何,这对我有用,所以我想我会把它贴在这里以防它可能对其他人有所帮助。 Happy coding.快乐编码。

Calculation计算

  • t : Total number of days between dates (1 if min = max) t:日期之间的总天数(如果 min = max,则为 1)
  • a + b : Extra days needed to expand total to full weeks a + b :需要额外的天数才能将总数扩展到整周
  • k : 1.4 is number of weekdays per week, ie, (t / 7) * 5 k : 1.4 是每周的工作日数,即 (t / 7) * 5
  • c : Number of weekdays to subtract from the total c : 要从总数中减去的工作日数
  • m : A lookup table used to find the value of "c" for each day of the week m:用于查找一周中每一天的“c”值的查找表

Culture文化

Code assumes a Monday to Friday work week.代码假定为周一至周五工作周。 For other cultures, such as Sunday to Thursday, you'll need to offset the dates prior to calculation.对于其他文化,例如周日到周四,您需要在计算之前抵消日期。

Method方法

public int Weekdays(DateTime min, DateTime max) 
{       
        if (min.Date > max.Date) throw new Exception("Invalid date span");
        var t = (max.AddDays(1).Date - min.Date).TotalDays;
        var a = (int) min.DayOfWeek;
        var b = 6 - (int) max.DayOfWeek;
        var k = 1.4;
        var m = new int[]{0, 0, 1, 2, 3, 4, 5}; 
        var c = m[a] + m[b];
        return (int)((t + a + b) / k) - c;
}

Here's a quick sample code.这是一个快速示例代码。 It's a class method, so will only work inside of your class.这是一个类方法,所以只能在你的类内部工作。 If you want it to be static , change the signature to private static (or public static ).如果您希望它是static ,请将签名更改为private static (或public static )。

    private IEnumerable<DateTime> GetWorkingDays(DateTime sd, DateTime ed)
    {
        for (var d = sd; d <= ed; d = d.AddDays(1))
            if (d.DayOfWeek != DayOfWeek.Saturday && d.DayOfWeek != DayOfWeek.Sunday)
                yield return d;
    }

This method creates a loop variable d , initializes it to the start day, sd , then increments by one day each iteration ( d = d.AddDays(1) ).此方法创建一个循环变量d ,将其初始化为开始日期sd ,然后每次迭代递增一天( d = d.AddDays(1) )。

It returns the desired values using yield , which creates an iterator .它使用yield返回所需的值,这会创建一个iterator The cool thing about iterators is that they don't hold all of the values of the IEnumerable in memory, only calling each one sequentially.迭代器很酷的一点是它们不会将IEnumerable的所有值都保存在内存中,而只会依次调用每个值。 This means that you can call this method from the dawn of time to now without having to worry about running out of memory.这意味着您可以从一开始到现在调用此方法,而不必担心内存不足。

I think none of the above answers are actually correct.我认为以上答案实际上都不正确。 None of them solves all the special cases such as when the dates starts and ends on the middle of a weekend, when the date starts on a Friday and ends on next Monday, etc. On top of that, they all round the calculations to whole days, so if the start date is in the middle of a saturday for example, it will substract a whole day from the working days, giving wrong results...它们都没有解决所有特殊情况,例如日期从周末开始和结束的时间,日期从星期五开始到下星期一结束的时间等等。最重要的是,它们都将计算全部四舍五入天,所以如果开始日期在星期六中间,例如,它会从工作日中减去一整天,给出错误的结果......

Anyway, here is my solution that is quite efficient and simple and works for all cases.无论如何,这是我的解决方案,它非常有效和简单,适用于所有情况。 The trick is just to find the previous Monday for start and end dates, and then do a small compensation when start and end happens during the weekend:诀窍就是找到前一个星期一的开始和结束日期,然后在周末开始和结束发生时做一个小的补偿:

public double WorkDays(DateTime startDate, DateTime endDate){
        double weekendDays;

        double days = endDate.Subtract(startDate).TotalDays;

        if(days<0) return 0;

        DateTime startMonday = startDate.AddDays(DayOfWeek.Monday - startDate.DayOfWeek).Date;
        DateTime endMonday = endDate.AddDays(DayOfWeek.Monday - endDate.DayOfWeek).Date;

        weekendDays = ((endMonday.Subtract(startMonday).TotalDays) / 7) * 2;

        // compute fractionary part of weekend days
        double diffStart = startDate.Subtract(startMonday).TotalDays - 5;
        double diffEnd = endDate.Subtract(endMonday).TotalDays - 5;

        // compensate weekenddays
        if(diffStart>0) weekendDays -= diffStart;
        if(diffEnd>0) weekendDays += diffEnd;

        return days - weekendDays;
    }
using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            DateTime start = new DateTime(2014, 1, 1);
            DateTime stop = new DateTime(2014, 12, 31);

            int totalWorkingDays = GetNumberOfWorkingDays(start, stop);

            Console.WriteLine("There are {0} working days.", totalWorkingDays);
        }

        private static int GetNumberOfWorkingDays(DateTime start, DateTime stop)
        {
            TimeSpan interval = stop - start;

            int totalWeek = interval.Days / 7;
            int totalWorkingDays = 5 * totalWeek;

            int remainingDays = interval.Days % 7;


            for (int i = 0; i <= remainingDays; i++)
            {
                DayOfWeek test = (DayOfWeek)(((int)start.DayOfWeek + i) % 7);
                if (test >= DayOfWeek.Monday && test <= DayOfWeek.Friday)
                    totalWorkingDays++;
            }

            return totalWorkingDays;
        }
    }
}

Here is the function which we can use to calculate business days between two date.这是我们可以用来计算两个日期之间的工作日的函数。 I'm not using holiday list as it can vary accross country/region.我没有使用假期列表,因为它可能因国家/地区而异。

If we want to use it anyway we can take third argument as list of holiday and before incrementing count we should check that list does not contains d如果我们无论如何都想使用它,我们可以将第三个参数作为假期列表,在增加计数之前,我们应该检查列表不包含 d

public static int GetBussinessDaysBetweenTwoDates(DateTime StartDate,   DateTime EndDate)
    {
        if (StartDate > EndDate)
            return -1;

        int bd = 0;

        for (DateTime d = StartDate; d < EndDate; d = d.AddDays(1))
        {
            if (d.DayOfWeek != DayOfWeek.Saturday && d.DayOfWeek != DayOfWeek.Sunday)
                bd++;
        }

        return bd;
    }

This method returns the number of business days between two dates:此方法返回两个日期之间的工作日数:

Here I use the DayOfWeek enum for checking weekends.在这里,我使用 DayOfWeek 枚举来检查周末。

        private static int BusinessDaysLeft(DateTime first, DateTime last)
        {
            var count = 0;

            while (first.Date != last.Date)
            {
                if(first.DayOfWeek != DayOfWeek.Saturday && first.DayOfWeek != DayOfWeek.Sunday)
                    count++;
                
                first = first.AddDays(1);
            }

            return count;
        }

I'll just share my solution.我只是分享我的解决方案。 It worked for me, maybe I just don't notice/know that theres a bug.它对我有用,也许我只是没有注意到/知道存在错误。 I started by getting the first incomplete week if there's any.我从第一个不完整的一周开始,如果有的话。 a complete week was from sunday for saturday, so if the (int)_now.DayOfWeek was not 0(Sunday), the first week was incomplete.完整的一周是从星期日到星期六,所以如果 (int)_now.DayOfWeek 不为 0(星期日),则第一周是不完整的。

I just subtract 1 to first weeks count for the first week's saturday then add it to new count;我只是将第一周星期六的第一周计数减去 1,然后将其添加到新计数中;

Then I get the last incomplete week, then subtract 1 for it's sunday then add to new count.然后我得到最后一个不完整的一周,然后减去 1 因为它是星期天,然后添加到新计数。

Then finally, the number of complete weeks multiply by 5(weekdays) was added to new count.最后,将完整周数乘以 5(工作日)添加到新计数中。

public int RemoveNonWorkingDays(int numberOfDays){

            int workingDays = 0;

            int firstWeek = 7 - (int)_now.DayOfWeek;

            if(firstWeek < 7){

                if(firstWeek > numberOfDays)
                    return numberOfDays;

                workingDays += firstWeek-1;
                numberOfDays -= firstWeek;
            }


            int lastWeek = numberOfDays % 7;

            if(lastWeek > 0){

                numberOfDays -= lastWeek;
                workingDays += lastWeek - 1;

            }

            workingDays += (numberOfDays/7)*5;

            return workingDays;
        }

I was having trouble finding a solid TSQL version of this code.我很难找到该代码的可靠 TSQL 版本。 Below is essentially a conversion of the C# code here with addition of the Holiday table which should be used to pre-calculate holidays.下面本质上是C# 代码的转换,其中添加了应用于预先计算假期的假期表。

CREATE TABLE dbo.Holiday
(
    HolidayDt       DATE NOT NULL,
    Name            NVARCHAR(50) NOT NULL,
    IsWeekday       BIT NOT NULL,
    CONSTRAINT PK_Holiday PRIMARY KEY (HolidayDt)
)
GO
CREATE INDEX IDX_Holiday ON Holiday (HolidayDt, IsWeekday)

GO

CREATE function dbo.GetBusinessDays
(
     @FirstDay  datetime,
     @LastDay   datetime
) 
RETURNS INT
 AS
BEGIN
    DECLARE @BusinessDays INT, @FullWeekCount INT 
    SELECT  @FirstDay = CONVERT(DATETIME,CONVERT(DATE,@FirstDay))
        ,   @LastDay = CONVERT(DATETIME,CONVERT(DATE,@LastDay))

    IF @FirstDay > @LastDay
        RETURN NULL;

    SELECT @BusinessDays = DATEDIFF(DAY, @FirstDay, @LastDay) + 1 
    SELECT @FullWeekCount = @BusinessDays / 7;

    -- find out if there are weekends during the time exceedng the full weeks
    IF @BusinessDays > (@FullWeekCount * 7)
    BEGIN
    -- we are here to find out if there is a 1-day or 2-days weekend
    -- in the time interval remaining after subtracting the complete weeks
        DECLARE @firstDayOfWeek INT, @lastDayOfWeek INT;
        SELECT @firstDayOfWeek = DATEPART(DW, @FirstDay), @lastDayOfWeek = DATEPART(DW, @LastDay);

        IF @lastDayOfWeek < @firstDayOfWeek
                SELECT @lastDayOfWeek = @lastDayOfWeek + 7;

        IF @firstDayOfWeek <= 6 
            BEGIN
                IF (@lastDayOfWeek >= 7) --Both Saturday and Sunday are in the remaining time interval
                    BEGIN 
                        SELECT @BusinessDays = @BusinessDays - 2
                    END
                ELSE IF @lastDayOfWeek>=6 --Only Saturday is in the remaining time interval
                    BEGIN
                        SELECT @BusinessDays = @BusinessDays - 1
                    END

            END
        ELSE IF @firstDayOfWeek <= 7 AND @lastDayOfWeek >=7 -- Only Sunday is in the remaining time interval
        BEGIN 
            SELECT @BusinessDays = @BusinessDays - 1
        END
    END

    -- subtract the weekends during the full weeks in the interval
    DECLARE @Holidays INT;
    SELECT  @Holidays = COUNT(*) 
    FROM    Holiday 
    WHERE   HolidayDt BETWEEN @FirstDay AND @LastDay 
    AND     IsWeekday = CAST(1 AS BIT)

    SELECT @BusinessDays = @BusinessDays - (@FullWeekCount + @FullWeekCount) -- - @Holidays

    RETURN @BusinessDays
END
    int BusinessDayDifference(DateTime Date1, DateTime Date2)
    {
        int Sign = 1;
        if (Date2 > Date1)
        {
            Sign = -1;
            DateTime TempDate = Date1;
            Date1 = Date2;
            Date2 = TempDate;
        }
        int BusDayDiff = (int)(Date1.Date - Date2.Date).TotalDays;
        if (Date1.DayOfWeek == DayOfWeek.Saturday)
            BusDayDiff -= 1;
        if (Date2.DayOfWeek == DayOfWeek.Sunday)
            BusDayDiff -= 1;
        int Week1 = GetWeekNum(Date1);
        int Week2 = GetWeekNum(Date2);
        int WeekDiff = Week1 - Week2;
        BusDayDiff -= WeekDiff * 2;
        foreach (DateTime Holiday in Holidays)
            if (Date1 >= Holiday && Date2 <= Holiday)
                BusDayDiff--;
        BusDayDiff *= Sign;
        return BusDayDiff;
    }

    private int GetWeekNum(DateTime Date)
    {
        return (int)(Date.AddDays(-(int)Date.DayOfWeek).Ticks / TimeSpan.TicksPerDay / 7);
    }

Here is one very simple solution for this problem.这是此问题的一个非常简单的解决方案。 We have starting date, end date and "for loop" for encreasing the day and calculating to see if it's a workday or a weekend by converting to string DayOfWeek.我们有开始日期、结束日期和“for 循环”,用于增加日期并通过转换为字符串 DayOfWeek 来计算是工作日还是周末。

class Program
{
    static void Main(string[] args)
    {
        DateTime day = new DateTime();
        Console.Write("Inser your end date (example: 01/30/2015): ");
        DateTime endDate = DateTime.Parse(Console.ReadLine());
        int numberOfDays = 0;
        for (day = DateTime.Now.Date; day.Date < endDate.Date; day = day.Date.AddDays(1))
        {
            string dayToString = Convert.ToString(day.DayOfWeek);
            if (dayToString != "Saturday" && dayToString != "Sunday") numberOfDays++;
        }
        Console.WriteLine("Number of working days (not including local holidays) between two dates is "+numberOfDays);
    }
}

Based on the comment marked as answer and patch recommended , as well as -> This version wants to convert the Days to Business-Hours ... Considers Same day hours as well.根据标记为 answer 和 patch Recommended 的评论,以及 -> 此版本希望将 Days 转换为 Business-Hours ... 也考虑同一天的时间。

 /// <summary>
    /// Calculates number of business days, taking into account:
    ///  - weekends (Saturdays and Sundays)
    ///  - bank holidays in the middle of the week
    /// </summary>
    /// <param name="firstDay">First day in the time interval</param>
    /// <param name="lastDay">Last day in the time interval</param>
    /// <param name="bankHolidays">List of bank holidays excluding weekends</param>
    /// <returns>Number of business hours during the 'span'</returns>
    public static int BusinessHoursUntil(DateTime firstDay, DateTime lastDay, params DateTime[] bankHolidays)
    {
        var original_firstDay = firstDay;
        var original_lastDay = lastDay;
        firstDay = firstDay.Date;
        lastDay = lastDay.Date;
        if (firstDay > lastDay)
            return -1; //// throw new ArgumentException("Incorrect last day " + lastDay);

        TimeSpan span = lastDay - firstDay;
        int businessDays = span.Days + 1;
        int fullWeekCount = businessDays / 7;
        // find out if there are weekends during the time exceedng the full weeks
        if (businessDays > fullWeekCount * 7)
        {
            // we are here to find out if there is a 1-day or 2-days weekend
            // in the time interval remaining after subtracting the complete weeks
            int firstDayOfWeek = firstDay.DayOfWeek == DayOfWeek.Sunday ? 7 : (int)firstDay.DayOfWeek;
            int lastDayOfWeek = lastDay.DayOfWeek == DayOfWeek.Sunday ? 7 : (int)lastDay.DayOfWeek;

            if (lastDayOfWeek < firstDayOfWeek)
                lastDayOfWeek += 7;
            if (firstDayOfWeek <= 6)
            {
                if (lastDayOfWeek >= 7)// Both Saturday and Sunday are in the remaining time interval
                    businessDays -= 2;
                else if (lastDayOfWeek >= 6)// Only Saturday is in the remaining time interval
                    businessDays -= 1;
            }
            else if (firstDayOfWeek <= 7 && lastDayOfWeek >= 7)// Only Sunday is in the remaining time interval
                businessDays -= 1;
        }

        // subtract the weekends during the full weeks in the interval
        businessDays -= fullWeekCount + fullWeekCount;

        if (bankHolidays != null && bankHolidays.Any())
        {
            // subtract the number of bank holidays during the time interval
            foreach (DateTime bankHoliday in bankHolidays)
            {
                DateTime bh = bankHoliday.Date;
                if (firstDay <= bh && bh <= lastDay)
                    --businessDays;
            }
        }

        int total_business_hours = 0;
        if (firstDay.Date == lastDay.Date)
        {//If on the same day, go granular with Hours from the Orginial_*Day values
            total_business_hours = (int)(original_lastDay - original_firstDay).TotalHours;
        }
        else
        {//Convert Business-Days to TotalHours
            total_business_hours = (int)(firstDay.AddDays(businessDays).AddHours(firstDay.Hour) - firstDay).TotalHours;
        }
        return total_business_hours;
    }

I just improved @Alexander and @Slauma answer to support a business week as a parameter, for cases where saturday is a business day, or even cases where there is just a couple of days of the week that are considered business days:我刚刚改进了@Alexander 和@Slauma 的答案,以支持将工作日作为参数,对于星期六是工作日的情况,甚至是一周中只有几天被认为是工作日的情况:

/// <summary>
/// Calculate the number of business days between two dates, considering:
///  - Days of the week that are not considered business days.
///  - Holidays between these two dates.
/// </summary>
/// <param name="fDay">First day of the desired 'span'.</param>
/// <param name="lDay">Last day of the desired 'span'.</param>
/// <param name="BusinessDaysOfWeek">Days of the week that are considered to be business days, if NULL considers monday, tuesday, wednesday, thursday and friday as business days of the week.</param>
/// <param name="Holidays">Holidays, if NULL, considers no holiday.</param>
/// <returns>Number of business days during the 'span'</returns>
public static int BusinessDaysUntil(this DateTime fDay, DateTime lDay, DayOfWeek[] BusinessDaysOfWeek = null, DateTime[] Holidays = null)
{
    if (BusinessDaysOfWeek == null)
        BusinessDaysOfWeek = new DayOfWeek[] { DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Wednesday, DayOfWeek.Thursday, DayOfWeek.Friday };
    if (Holidays == null)
        Holidays = new DateTime[] { };

    fDay = fDay.Date;
    lDay = lDay.Date;

    if (fDay > lDay)
        throw new ArgumentException("Incorrect last day " + lDay);

    int bDays = (lDay - fDay).Days + 1;
    int fullWeekCount = bDays / 7;
    int fullWeekCountMult = 7 - WeekDays.Length;
    //  Find out if there are weekends during the time exceedng the full weeks
    if (bDays > (fullWeekCount * 7))
    {
        int fDayOfWeek = (int)fDay.DayOfWeek;
        int lDayOfWeek = (int)lDay.DayOfWeek;

        if (fDayOfWeek > lDayOfWeek)
            lDayOfWeek += 7;

        // If they are the same, we already covered it right before the Holiday subtraction
        if (lDayOfWeek != fDayOfWeek)
        {
            //  Here we need to see if any of the days between are considered business days
            for (int i = fDayOfWeek; i <= lDayOfWeek; i++)
                if (!WeekDays.Contains((DayOfWeek)(i > 6 ? i - 7 : i)))
                    bDays -= 1;
        }
    }

    //  Subtract the days that are not in WeekDays[] during the full weeks in the interval
    bDays -= (fullWeekCount * fullWeekCountMult);
    //  Subtract the number of bank holidays during the time interval
    bDays = bDays - Holidays.Select(x => x.Date).Count(x => fDay <= x && x <= lDay);

    return bDays;
}

I believe this could be a simpler way:我相信这可能是一种更简单的方法:

    public int BusinessDaysUntil(DateTime start, DateTime end, params DateTime[] bankHolidays)
    {
        int tld = (int)((end - start).TotalDays) + 1; //including end day
        int not_buss_day = 2 * (tld / 7); //Saturday and Sunday
        int rest = tld % 7; //rest.

        if (rest > 0)
        {
            int tmp = (int)start.DayOfWeek - 1 + rest;
            if (tmp == 6 || start.DayOfWeek == DayOfWeek.Sunday) not_buss_day++; else if (tmp > 6) not_buss_day += 2;
        }

        foreach (DateTime bankHoliday in bankHolidays)
        {
            DateTime bh = bankHoliday.Date;
            if (!(bh.DayOfWeek == DayOfWeek.Saturday || bh.DayOfWeek == DayOfWeek.Sunday) && (start <= bh && bh <= end))
            {
                not_buss_day++;
            }
        }
        return tld - not_buss_day;
    }

Here's yet another idea - this method allows to specify any working week and holidays.这是另一个想法 - 此方法允许指定任何工作周和假期。

The idea here is that we find the core of the date range from the first first working day of the week to the last weekend day of the week.这里的想法是我们找到从一周的第一个工作日到一周的最后一个周末的日期范围的核心。 This enables us to calculate the whole weeks easily ( without iterating over all of the dates).这使我们能够轻松地计算整个星期(无需遍历所有日期)。 All we need to do then is to add the working days that fall before the start and end of this core range.然后我们需要做的就是添加这个核心范围开始和结束之前的工作日。

public static int CalculateWorkingDays(
    DateTime startDate, 
    DateTime endDate, 
    IList<DateTime> holidays, 
    DayOfWeek firstDayOfWeek,
    DayOfWeek lastDayOfWeek)
{
    // Make sure the defined working days run contiguously
    if (lastDayOfWeek < firstDayOfWeek)
    {
        throw new Exception("Last day of week cannot fall before first day of week!");
    }

    // Create a list of the days of the week that make-up the weekend by working back
    // from the firstDayOfWeek and forward from lastDayOfWeek to get the start and end
    // the weekend
    var weekendStart = lastDayOfWeek == DayOfWeek.Saturday ? DayOfWeek.Sunday : lastDayOfWeek + 1;
    var weekendEnd = firstDayOfWeek == DayOfWeek.Sunday ? DayOfWeek.Saturday : firstDayOfWeek - 1;
    var weekendDays = new List<DayOfWeek>();

    var w = weekendStart;
    do {
        weekendDays.Add(w);
        if (w == weekendEnd) break;
        w = (w == DayOfWeek.Saturday) ? DayOfWeek.Sunday : w + 1;
    } while (true);


    // Force simple dates - no time
    startDate = startDate.Date;
    endDate = endDate.Date;

    // Ensure a progessive date range
    if (endDate < startDate)
    {
        var t = startDate;
        startDate = endDate;
        endDate = t;
    }

    // setup some working variables and constants
    const int daysInWeek = 7;           // yeah - really!
    var actualStartDate = startDate;    // this will end up on startOfWeek boundary
    var actualEndDate = endDate;        // this will end up on weekendEnd boundary
    int workingDaysInWeek = daysInWeek - weekendDays.Count;

    int workingDays = 0;        // the result we are trying to find
    int leadingDays = 0;        // the number of working days leading up to the firstDayOfWeek boundary
    int trailingDays = 0;       // the number of working days counting back to the weekendEnd boundary

    // Calculate leading working days
    // if we aren't on the firstDayOfWeek we need to step forward to the nearest
    if (startDate.DayOfWeek != firstDayOfWeek)
    {
        var d = startDate;
        do {
            if (d.DayOfWeek == firstDayOfWeek || d >= endDate)
            {
                actualStartDate = d;
                break;  
            }
            if (!weekendDays.Contains(d.DayOfWeek))
            {
                leadingDays++;
            }
            d = d.AddDays(1);
        } while(true);
    }

    // Calculate trailing working days
    // if we aren't on the weekendEnd we step back to the nearest
    if (endDate >= actualStartDate && endDate.DayOfWeek != weekendEnd)
    {
        var d = endDate;
        do {
            if (d.DayOfWeek == weekendEnd || d < actualStartDate)
            {
                actualEndDate = d;
                break;  
            }
            if (!weekendDays.Contains(d.DayOfWeek))
            {
                trailingDays++;
            }
            d = d.AddDays(-1);
        } while(true);
    }

    // Calculate the inclusive number of days between the actualStartDate and the actualEndDate
    var coreDays = (actualEndDate - actualStartDate).Days + 1;
    var noWeeks =  coreDays / daysInWeek;

    // add together leading, core and trailing days
    workingDays +=  noWeeks * workingDaysInWeek;
    workingDays += leadingDays;
    workingDays += trailingDays;

    // Finally remove any holidays that fall within the range.
    if (holidays != null)
    {
        workingDays -= holidays.Count(h => h >= startDate && (h <= endDate));
    }

    return workingDays;
}

Since I can't comment.因为我不能评论。 There is one more issue with the accepted solution where bank holidays are subtracted even when they are situated in the weekend.公认的解决方案还有一个问题,即即使银行假期位于周末,银行假期也会被扣除。 Seeing how other input is checked, it is only fitting that this is as well.看看如何检查其他输入,这也是合适的。

The foreach should therefore be:因此,foreach 应该是:

    // subtract the number of bank holidays during the time interval
    foreach (DateTime bankHoliday in bankHolidays)
    {
        DateTime bh = bankHoliday.Date;

        // Do not subtract bank holidays when they fall in the weekend to avoid double subtraction
        if (bh.DayOfWeek == DayOfWeek.Saturday || bh.DayOfWeek == DayOfWeek.Sunday)
                continue;

        if (firstDay <= bh && bh <= lastDay)
            --businessDays;
    }

Here is an approach if you are using MVC.如果您使用 MVC,这是一种方法。 I have also calculated national holidays or any festive days to be excluded by fetching it from holidayscalendar which you will need to make one.我还计算了国定假日或任何要排除的节日,方法是从你需要制作的 holidayscalendar 中获取它。

        foreach (DateTime day in EachDay(model))
        {
            bool key = false;
            foreach (LeaveModel ln in holidaycalendar)
            {
                if (day.Date == ln.Date && day.DayOfWeek != DayOfWeek.Saturday && day.DayOfWeek != DayOfWeek.Sunday)
                {
                    key = true; break;
                }
            }
            if (day.DayOfWeek == DayOfWeek.Saturday || day.DayOfWeek == DayOfWeek.Sunday)
            {
                key = true;
            }
            if (key != true)
            {
                leavecount++;
            }
        }

Leavemodel is a list here Leavemodel 是这里的列表

Here is an helper function I wrote for that task.这是我为该任务编写的辅助函数。
it also returns the count of weekends via the out parameter.它还通过out参数返回周末计数。
if you wish you can customize the "weekend" days in run time for countries that use different weekend days or to include holidays trough the weekendDays[] optional parameter :如果您希望可以为使用不同周末的国家/地区自定义运行时的“周末”天数,或者通过周末天weekendDays[]可选参数包括假期:

public static int GetNetworkDays(DateTime startDate, DateTime endDate,out int totalWeekenDays, DayOfWeek[] weekendDays = null)
{
    if (startDate >= endDate)
    {
        throw new Exception("start date can not be greater then or equel to end date");
    }

    DayOfWeek[] weekends = new DayOfWeek[] { DayOfWeek.Sunday, DayOfWeek.Saturday };
    if (weekendDays != null)
    {
        weekends = weekendDays;
    }

    var totaldays = (endDate - startDate).TotalDays + 1; // add one to include the first day to
    var counter = 0;
    var workdaysCounter = 0;
    var weekendsCounter = 0;

    for (int i = 0; i < totaldays; i++)
    {

        if (weekends.Contains(startDate.AddDays(counter).DayOfWeek))
        {
            weekendsCounter++;
        }
        else
        {
            workdaysCounter++;
        }

        counter++;
    }

    totalWeekenDays = weekendsCounter;
    return workdaysCounter;
}

I came up with the following solution我想出了以下解决方案

var dateStart = new DateTime(2019,01,10);
var dateEnd = new DateTime(2019,01,31);

var timeBetween = (dateEnd - dateStart).TotalDays + 1;
int numberOf7DayWeeks = (int)(timeBetween / 7);
int numberOfWeekendDays = numberOf7DayWeeks * 2;
int workingDays =(int)( timeBetween - numberOfWeekendDays);

if(dateStart.DayOfWeek == DayOfWeek.Saturday || dateEnd.DayOfWeek == DayOfWeek.Sunday){
    workingDays -=2;
}       
if(dateStart.DayOfWeek == DayOfWeek.Sunday || dateEnd.DayOfWeek == DayOfWeek.Saturday){
    workingDays -=1;
}

You just have to iterate through each day in the time range and subtract a day from the counter if its a Saturday or a Sunday.您只需要遍历时间范围内的每一天,如果是星期六或星期日,则从计数器中减去一天。

    private float SubtractWeekend(DateTime start, DateTime end) {
        float totaldays = (end.Date - start.Date).Days;
        var iterationVal = totalDays;
        for (int i = 0; i <= iterationVal; i++) {
            int dayVal = (int)start.Date.AddDays(i).DayOfWeek;
            if(dayVal == 6 || dayVal == 0) {
                // saturday or sunday
                totalDays--;
            }
        }
        return totalDays;
    }

Yet another approach for calculating business days, not considering holidays, but taking into account the time of day returning a fractional amount of days:计算工作日的另一种方法,不考虑假期,但考虑返回一小部分天数的一天中的时间:

public static double GetBusinessDays(DateTime startD, DateTime endD)
{
    while (IsWeekend(startD))
        startD = startD.Date.AddDays(1);

    while (IsWeekend(endD))
        endD = endD.Date.AddDays(-1);

    var bussDays = (endD - startD).TotalDays -
        (2 * ((int)(endD - startD).TotalDays / 7)) -
        (startD.DayOfWeek > endD.DayOfWeek ? 2 : 0);

    return bussDays;
}

public static bool IsWeekend(DateTime d)
{
    return d.DayOfWeek == DayOfWeek.Saturday || d.DayOfWeek == DayOfWeek.Sunday;
}

You can fiddle with it here: https://rextester.com/ASHRS53997你可以在这里摆弄它: https ://rextester.com/ASHRS53997

public static int CalculateBusinessDaysInRange(this DateTime startDate, DateTime endDate, params DateTime[] holidayDates)
{
    endDate = endDate.Date;
    if(startDate > endDate)
        throw new ArgumentException("The end date can not be before the start date!", nameof(endDate));
    int accumulator = 0;
    DateTime itterator = startDate.Date;
    do 
    {
        if(itterator.DayOfWeek != DayOfWeek.Saturday && itterator.DayOfWeek != DayOfWeek.Sunday && !holidayDates.Any(hol => hol.Date == itterator))
        { accumulator++; }
    } 
    while((itterator = itterator.AddDays(1)).Date <= endDate);
    return accumulator
}

I'm only posting this because despite all of the excellent answers that have been given, none of the math made sense to me.我只是发布这个,因为尽管给出了所有优秀的答案,但数学对我来说没有任何意义。 This is definitely a KISS method that should work and be fairly maintainable.这绝对是一个应该有效且相当可维护的 KISS 方法。 Granted if you are calculating ranges that are greater than 2-3 months this will not be the most effective way.当然,如果您计算的范围大于 2-3 个月,这将不是最有效的方法。 We simply determine if it is a Saturday or Sunday or the date is a given holiday date.我们只是确定它是星期六还是星期日,或者日期是给定的假期日期。 If it's not we add a business day.如果不是,我们添加一个工作日。 If it is then everything is fine.如果是,那么一切都很好。

I'm sure this could be even more so simplified with LINQ, but this way is much easier to understand.我确信这可以使用 LINQ 更加简化,但这种方式更容易理解。

Here's another example you can choose the weekend dates as well,这是另一个示例,您也可以选择周末日期,

  public int GetBuisnessDays(DateTime StartDate, DateTime EndDate)
    {
        int counter = 0;

        if (StartDate.Date == EndDate.Date)
        {
            if (StartDate.DayOfWeek != DayOfWeek.Saturday && StartDate.DayOfWeek != DayOfWeek.Friday)
                return 1;
            return 0;
        }

        while (StartDate <= EndDate)
        {
            if (StartDate.DayOfWeek != DayOfWeek.Saturday && StartDate.DayOfWeek != DayOfWeek.Friday)
                ++counter;
            StartDate = StartDate.AddDays(1);
        }

        return counter;
    }

So I had a similar task except I had to calculate business days left (from date should not be more than to date), and end date should skip to next business day.所以我有一个类似的任务,除了我必须计算剩下的工作日(从日期不应该超过现在),结束日期应该跳到下一个工作日。

To make it more understandable/readable, I did this in the following steps为了使其更易于理解/阅读,我在以下步骤中执行了此操作

  1. Updated toDate to the next business day if it is on weekend.如果是周末,则将 toDate 更新为下一个工作日。

  2. Find out the number of complete weeks between dates, and for each complete week consider 5 days in running total.找出日期之间的完整周数,并且对于每个完整周,考虑总共 5 天。

  3. Now days left are only different of from and to weekdays (it won't be more than 6 days), so wrote a small loop to get it (skip Saturday and Sunday)现在剩下的天数只与工作日不同(不会超过6天),所以写了一个小循环来获取它(跳过周六和周日)

     public static int GetBusinessDaysLeft(DateTime fromDate, DateTime toDate) { //Validate that startDate should be less than endDate if (fromDate >= toDate) return 0; //Move end date to Monday if on weekends if (toDate.DayOfWeek == DayOfWeek.Saturday || toDate.DayOfWeek == DayOfWeek.Sunday) while (toDate.DayOfWeek != DayOfWeek.Monday) toDate = toDate.AddDays(+1); //Consider 5 days per complete week in between start and end dates int remainder, quotient = Math.DivRem((toDate - fromDate).Days, 7, out remainder); var daysDiff = quotient * 5; var curDay = fromDate; while (curDay.DayOfWeek != toDate.DayOfWeek) { curDay = curDay.AddDays(1); if (curDay.DayOfWeek == DayOfWeek.Saturday || curDay.DayOfWeek == DayOfWeek.Sunday) continue; daysDiff += 1; } return daysDiff; }

Many of the answers are great but they don't take into account the start/end time.许多答案都很棒,但它们没有考虑开始/结束时间。 Here is my improved solutions (in C#) based on this answers but taking into account the start and end time.这是我基于此答案但考虑到开始和结束时间的改进解决方案(在 C# 中)。 For example:例如:

  • Monday 8/2/2021 to Wednesday 8/4/2021 is 2 days - In this case, 8/4/2021 is excluded because the time is not specified and in .Net it automatically assigned to 12:00 AM. 2021 年 8 月 2 日星期一到 2021 年 8 月 4 日星期三为 2 天 - 在这种情况下,2021 年 8 月 4 日被排除在外,因为未指定时间,并且在 .Net 中它自动分配为 12:00 AM。

  • Monday 8/2/2021 12 PM to Wednesday 8/4/2021 12 PM is 2 days. 2021 年 8 月 2 日星期一下午 12 点至 2021 年 8 月 4 日星期三下午 12 点为 2 天。

  • Friday 8/6/2021 12 PM to Tuesday 8/10/2021 6 PM is 2.25 days. 2021 年 8 月 6 日星期五下午 12 点至 2021 年 8 月 10 日星期二下午 6 点为 2.25 天。

     public static double GetWorkingDays(DateTime startDate, DateTime endDate) { // Get next full day from start date and last full day of end date var nextFullStartDate = startDate.AddDays(1).Date; var lastFullEndDate = endDate.Date; // Calculate total days based on start and end's day of week var dayOfWeekFactor = (nextFullStartDate.DayOfWeek - lastFullEndDate.DayOfWeek) * 2; if (lastFullEndDate.DayOfWeek == DayOfWeek.Sunday) { // In .net, day of week for Sunday is 0, we need to change it to 7 dayOfWeekFactor = ((int)nextFullStartDate.DayOfWeek - 7) * 2; } // Calculate working days (ie: Monday, Tuesday, Wednesday, Thursday and Friday) var workingDayCount = ((lastFullEndDate - nextFullStartDate).TotalDays * 5 - dayOfWeekFactor) / 7; // Subtract working days if full start date or last full end date is Sunday // Saturday is not included here because if startDate is Saturday the formula above would have excluded Saturday. If the endDate is Saturday, it would have been excluded too because the time would be Saturday 12:00 AM if (nextFullStartDate.DayOfWeek == DayOfWeek.Sunday || lastFullEndDate.DayOfWeek == DayOfWeek.Sunday) { workingDayCount--; } // Count the real start/end date if (startDate.DayOfWeek != DayOfWeek.Saturday && startDate.DayOfWeek != DayOfWeek.Sunday) { var startDateFraction = (nextFullStartDate - startDate).TotalHours / 24; workingDayCount += startDateFraction; } if (endDate.DayOfWeek != DayOfWeek.Saturday && endDate.DayOfWeek != DayOfWeek.Sunday) { var endDateFraction = (endDate - lastFullEndDate).TotalHours / 24; workingDayCount += endDateFraction; } return workingDayCount; }

By using marinjw library, And solution provided by Alec Pojidaev i created below, this will skip public (you need to specify country) holidays:通过使用marinjw库,以及我在下面创建的 Alec Pojidaev 提供的解决方案,这将跳过公共(您需要指定国家/地区)假期:

public static int GetProcessingTime(this DateTime? FromDate, DateTime? ToDate)
{
    if (FromDate == null) return 0;
    if (ToDate == null) return 0;

    List<DateTime> Holidays = new List<DateTime>();

    int startyear = FromDate.Value.Year;
    int endyear = ToDate.Value.Year;

    //loop years to extract all holidays
    for(int i = startyear; i >= endyear; i++)
    {
        IList<DateTime> Temp = new PolandPublicHoliday().PublicHolidays(i);
        Holidays.AddRange(Temp.ToList());
    }

    //exclude holidays outside of range
    Holidays = Holidays.Where(x => x >= FromDate && x <= ToDate).ToList();

    //exclude holidays that are set to be on sunday/saturday
    Holidays = Holidays.Where(x => x.DayOfWeek != DayOfWeek.Sunday && x.DayOfWeek != DayOfWeek.Saturday).ToList();

    //calculate date difference without sundays and saturdays Value need to be added as I am using nullable DateTime
    double calcBusinessDays = 1 + ((FromDate.Value - ToDate.Value).TotalDays * 5 - (FromDate.Value.DayOfWeek - ToDate.Value.DayOfWeek) * 2) / 7;

    if (FromDate.Value.DayOfWeek == DayOfWeek.Saturday) calcBusinessDays--;
    if (ToDate.Value.DayOfWeek == DayOfWeek.Sunday) calcBusinessDays--;

    //remove left holidays
    if (Holidays!=null)
        calcBusinessDays -= Holidays.Count;

    return (int)calcBusinessDays;
}

 <,-- **Here is the solution for getting working days except for all Sundays and 2nd-4th Saturdays**--> public void GetWorkingDays { DateTime from = new DateTime(2022, 10, 03, 10, 30; 50), DateTime to = new DateTime(2022, 11, 15, 16, 30; 50). Console:WriteLine("From; "+from). Console:WriteLine("To; "+to); Program pgm = new Program(). List<DateTime> allDates1 = pgm,GetDatesBetween(from; to), <;-- //here this above list will print all working days except for all Sundays and 2nd-4th Saturdays --> } <,-- //get List of Between dates--> public List<DateTime> GetDatesBetween(DateTime startDate; DateTime endDate) { List<DateTime> allDates = new List<DateTime>(); List<DateTime> Saturday = GetSaturdayDatesBetween(startDate; endDate). for (DateTime date = startDate. date <= endDate. date = date.AddDays(1)) if (date.DayOfWeek.= DayOfWeek.Sunday &&.Saturday;Contains(date.Date)) { if (date;Date;= endDate,Date) { allDates;Add(date); } else { allDates;Add(endDate). } } return allDates. } <,-- //Get 2nd and 3rd Saturday --> public List<DateTime> GetSaturdayDatesBetween(DateTime from. DateTime to) { List<DateTime> Saturday = new List<DateTime>(), for (DateTime date = from, date <= to. date = date,AddMonths(1)) { var start = new DateTime(from.Year, date.Month, 1. from;Hour. from.Minute, from.Second; from.Millisecond), var end = DateTime.DaysInMonth(from,Year, date.Month), var endDate = new DateTime(date.Year, date.Month, end. date;Hour; date;Minute; date.Second. date.Millisecond); int satCount=0. for (DateTime curDate = start. curDate <= endDate; curDate = curDate;AddDays(1)) { if(curDate.DayOfWeek == DayOfWeek.Saturday) { satCount++; if (satCount == 2 || satCount == 4) { Saturday.Add(curDate.Date); } } } } return Saturday; }

Try this, No iteration through all the days: Worked well so far:试试这个,所有日子都没有迭代:到目前为止效果很好:

  private int CalculateDateDifference(DateTime startdate, DateTime endDate)
    {
        int businessDays = (endDate - startdate).Days;
        var weekendCount = 0;

        if (businessDays > 6)
        {
            weekendCount += 2;
            startdate = startdate.AddDays(7);
            while (startdate <= endDate)
            {
                startdate = startdate.AddDays(7);
                if (startdate <= endDate || ( (int)endDate.DayOfWeek < (int)startdate.DayOfWeek && endDate.DayOfWeek!=DayOfWeek.Sunday))
                    weekendCount += 2;
            }
           
        }
        else if ((int)endDate.DayOfWeek < (int)startdate.DayOfWeek)
        {
            weekendCount += 2;
        }

        //Exclude weekends
        businessDays = businessDays - weekendCount;

        //Check if Last day was on Weekend
        if (endDate.DayOfWeek == DayOfWeek.Saturday) businessDays -= 1;
        if (endDate.DayOfWeek == DayOfWeek.Sunday) businessDays -= 2;


        return businessDays;

    }

Note: This solution assumes startDate is on a Week day.注意:此解决方案假定 startDate 是工作日。 Can be tweaked to handled Weekend start day as well.也可以调整以处理周末开始日。

This is a generic solution.这是一个通用的解决方案。

startdayvalue is day number of start date. startdayvalue 是开始日期的天数。

weekendday_1 is day numner of week end. weekendday_1 是周末的天数。

day number - MON - 1, TUE - 2, ... SAT - 6, SUN -7.天数 - MON - 1, TUE - 2, ... SAT - 6, SUN -7。

difference is difference between two dates..差异是两个日期之间的差异..

Example : Start Date : 4 April, 2013, End Date : 14 April, 2013示例:开始日期:2013 年 4 月 4 日,结束日期:2013 年 4 月 14 日

Difference : 10, startdayvalue : 4, weekendday_1 : 7 (if SUNDAY is a weekend for you.)差异:10,startdayvalue:4,weekendday_1:7(如果 SUNDAY 是您的周末。)

This will give you number of holidays.这将为您提供假期数量。

No of business day = (Difference + 1) - holiday1工作日数 = (差值 + 1) - 假期1

    if (startdayvalue > weekendday_1)
    {

        if (difference > ((7 - startdayvalue) + weekendday_1))
        {
            holiday1 = (difference - ((7 - startdayvalue) + weekendday_1)) / 7;
            holiday1 = holiday1 + 1;
        }
        else
        {
            holiday1 = 0;
        }
    }
    else if (startdayvalue < weekendday_1)
    {

        if (difference > (weekendday_1 - startdayvalue))
        {
            holiday1 = (difference - (weekendday_1 - startdayvalue)) / 7;
            holiday1 = holiday1 + 1;
        }
        else if (difference == (weekendday_1 - startdayvalue))
        {
            holiday1 = 1;
        }
        else
        {
            holiday1 = 0;
        }
    }
    else
    {
        holiday1 = difference / 7;
        holiday1 = holiday1 + 1;
    }
 public enum NonWorkingDays { SaturdaySunday = 0, FridaySaturday = 1 };
        public int getBusinessDates(DateTime dateSt, DateTime dateNd, NonWorkingDays nonWorkingDays = NonWorkingDays.SaturdaySunday)
        {
            List<DateTime> datelist = new List<DateTime>();
            while (dateSt.Date < dateNd.Date)
            {
                datelist.Add((dateSt = dateSt.AddDays(1)));
            }
            if (nonWorkingDays == NonWorkingDays.SaturdaySunday)
            {
                return datelist.Count(d => d.DayOfWeek != DayOfWeek.Saturday &&
                       d.DayOfWeek != DayOfWeek.Friday);
            }
            else
            {
                return datelist.Count(d => d.DayOfWeek != DayOfWeek.Friday &&
                       d.DayOfWeek != DayOfWeek.Saturday);
            }
        }

Check this 1. https://github.com/yatishbalaji/moment-working-days#readme 2. https://www.npmjs.com/package/moment-working-days检查这个 1. https://github.com/yatishbalaji/moment-working-days#readme 2. https://www.npmjs.com/package/moment-working-days

It allows you to calculate working days, considering sequence of date(s).它允许您计算工作日,考虑日期的顺序。 You can customize the week off days, and also declare custom dates for holidays (eg: public holidays) to exclude them from being counted as working day(s)您可以自定义一周的休息日,还可以声明假期(例如:公共假期)的自定义日期,以将其排除在工作日之外

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

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