开发者

please help optimize this loop

i need to calculate the number of workdays between two dates. a workday is any day between Monday through Friday except for holidays. the code below does this, but it uses a loop. does anyone see a way to get rid of the loop or at least optimize it?

thanks konstantin


using System;
using System.Linq;

namespace consapp
{
    static class Program
    {
        static void Main(string[] args)
        {
            var holidays = new DateTime[] { new DateTime(2010, 11, 23), new DateTime(2010, 11, 30) };

            var date_start = new DateTime(2010, 12, 3);
            var date_end = date_start.AddDays(-9.9);
            var duration = (date_end - date_start).Duration();

            for (var d = date_end; d < date_start; d = d.Date.AddDays(1))
            {
                if (holidays.Contains(d.Date) || d.DayOfWeek == DayOfWeek.Saturday || d.DayOfWeek == DayOfWeek.Sunday)
                {
                    duration -= TimeSpan.FromDays(1) - d.Time开发者_JS百科OfDay;
                }
            }
            Console.WriteLine(duration);
        }
    }
}


I would investigate an algorithm like the following. (Sorry no code provided.)

  1. Count the number of full 7-day weeks between your start and end date. You should be able to do this with .NET DateTime and TimeSpan objects.
  2. For each full 7-day week, add 5 days to your result.
  3. Figure out the partial weeks including your start and end dates.
  4. Loop through your holidays and reduce your result by 1 for each holiday between your start and end date. Looping is better here because there are likely far fewer holidays to loop over than days between your start and end date.

Have fun!

EDIT: For source code, check out this answer: Calculate the number of business days between two dates?


Is performance really problematic here? Unless profiling suggests otherwise I'd guess this code doesn't really slow down your application. It's performance should be fine unless you calculate the workdays for thousands of long intervals per second.

If your holiday list is much larger than just two dates then convert it into a HashSet<T> which has O(1) lookup time.

And of course you can turn around the code. So you don't loop over the days in the interval, but over the holidays. Then you just calculate the number of week-days in the interval(should be simple math) and subtract the number of holidays that fall on a week-day.

If it's really necessary you can pre-calculate the workdays since some fixed date, and then subtract the lookup result from the beginning of the period from the lookup result from the end of the period.


if you want faster code, don't loop over each day in the range:

remove from your list of holidays all holidays that fall on sunday or saturday, then use the timespan methods to give you the number of days between the two dates. With a little math (think about integer division by 7) you can get the number of mon-thursday days in that range, subtract the number of holidays that don't fall on the weekend from that number and you are done.


Just roll with it as is. This is not going to waste much time since the bounds are small. When you have some working code, move on. No need to mercilessly optimise code for no reason.


just because I started this as a fun puzzle, here's the code:

    [Test]
    public void TestDateTime() {
        var start = DateTime.Now.Date;
        var end = DateTime.Now.Date.AddDays(35);
        var workdays = (end - start).Days - ((end - start).Days/7)*2 
            - (((end - start).Days%7==0)?0:(((int)start.DayOfWeek==0)?1:Math.Max(Math.Min((int)start.DayOfWeek + (end - start).Days%7 - 6, 2), 0)));
        new []{DateTime.Now.AddDays(19), DateTime.Now.AddDays(20)}.ToList().ForEach(
            x => { if (x.DayOfWeek != DayOfWeek.Saturday && x.DayOfWeek != DayOfWeek.Sunday) workdays--; });
        Console.Out.WriteLine("workdays = {0}", workdays);
    }

Christmas day and Boxing day are included as holidays.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜