0

I am trying to calculate a finishing date when adding a duration to a start date, but skipping weekends and holidays:

DateTime start = DateTime.Now;
TimeSpan duration = TimeSpan.FromHours(100);
List<DateTime> = //List of holidays

DateTime end = ?

For example if it is 11pm on a Friday and I add 2 hours, it would end on 1am Monday morning.

Is there a neat way of doing this?

I have a temporary fix which increments the time by an hour and checks the day of the week, but it is very inefficient.

Original Idea (untested):

public static DateTime calEndDate(DateTime start, TimeSpan duration, List<DateTime> holidays)
        {
            var startDay = start.Day;

            var i = 0;
            var t = 0;
            while (TimeSpan.FromHours(t) < duration)
            {
                var date = start.Add(TimeSpan.FromHours(i));

                if (date.DayOfWeek.ToString() != "Saturday" && date.DayOfWeek.ToString() != "Sunday") //and something like !holidays.contains(start)
                {
                    t++;
                }

                i++;
            }

            return start.Add(TimeSpan.FromHours(t));
        }
    }

However is needs to run over 100 times for different start dates/durations on one asp.net page load. I don't know how to benchmark it, but it doesn't seem like an elegant solution?

Hawke
  • 564
  • 4
  • 19

2 Answers2

1

Here's an algorithm I'd try.

I'm on my phone, and I'll get it wrong, but you should see the logic...

var end = start;
var timeToMidnight = start.Date.AddDays(1) -start;
if ( duration < timeToMidnight ) return start + duration; 
end = endMoment + timeToMidnight;
duration = duration - timeToMidnight;

//Helper method
bool IsLeisure(Datetime dt) => (dt.DayOfWeek == DayOfWeek.Saturday) || (dt.DayOfWeek == DayOfWeek.Sunday) || holidays.Any( h => h.Date == dt.Date);

//We're at the first tick of the new day. Let's move to a work day, if needed.
while(IsLeisure(end)) { end = end.AddDays(1); };

//Now let's process full days of 'duration'
while(duration >= TimeSpan.FromDays(1) ) {
     end = end.AddDays(1);
     if(!IsLeisure(end)) duration = duration - TimeSpan.FromDays(1);
}

//Finally, add the reminder
end = end + duration;

Note: you haven't specified the logic for when start moment is a weekend or a holiday.

tymtam
  • 31,798
  • 8
  • 86
  • 126
-2

Yes there is :

        DateTime currentT = DateTime.Now;
        DateTime _time_ = currentTime.AddHours(10);

Simple and neat.

Saeiddjawadi
  • 312
  • 2
  • 13