开发者

Determine the difference between two DateTimes, only counting opening hours

For our support software in C#, I need to determine the time span between two DateTimes, but I only want opening hours counted (i.e. weekdays from 09:00 to 17:00).

So, for instance, if the first DateTime is 15/02/2011 16:00 and the 开发者_如何学Pythonsecond is 16/02/2011 10:00, the method shall return 2 hours.

Any help is greatly appreciated!


DateTime start = DateTime.Parse("15/02/2011 16:00");
DateTime end = DateTime.Parse("16/02/2011 10:00");

int count = 0;

for (var i = start; i < end; i = i.AddHours(1))
{
    if (i.DayOfWeek != DayOfWeek.Saturday && i.DayOfWeek != DayOfWeek.Sunday)
    {
        if (i.TimeOfDay.Hours >= 9 && i.TimeOfDay.Hours < 17)
        {
            count++;
        }
    }
}

Console.WriteLine(count);


Here we go, spent a while on this one for you. :)

Has room to detect holidays (if you write a function that checks whether a DateTime is a holiday), detects weekends in between the dates, and handles more than just hours.

The algorithm is to compute how much time is from the start til close of business and from the start of business to the end time, and then compute how many days are in between. Falling on the same date is a special case.

Caveat: I did some basic testing but probably didn't get all corner cases.

    public static TimeSpan BusinessTimeDelta(DateTime start, DateTime stop)
    {
        if (start == stop)
            return TimeSpan.Zero;

        if (start > stop)
        {
            DateTime temp = start;
            start = stop;
            stop = temp;
        }

        // First we are going to truncate these DateTimes so that they are within the business day.

        // How much time from the beginning til the end of the day?
        DateTime startFloor = StartOfBusiness(start);
        DateTime startCeil = CloseOfBusiness(start);
        if (start < startFloor) start = startFloor;
        if (start > startCeil) start = startCeil;

        TimeSpan firstDayTime = startCeil - start;
        bool workday = true; // Saves doublechecking later
        if (!IsWorkday(start))
        {
            workday = false;
            firstDayTime = TimeSpan.Zero;
        }

        // How much time from the start of the last day til the end?
        DateTime stopFloor = StartOfBusiness(stop);
        DateTime stopCeil = CloseOfBusiness(stop);
        if (stop < stopFloor) stop = stopFloor;
        if (stop > stopCeil) stop = stopCeil;

        TimeSpan lastDayTime = stop - stopFloor;
        if (!IsWorkday(stop))
            lastDayTime = TimeSpan.Zero;

        // At this point all dates are snipped to within business hours.

        if (start.Date == stop.Date)
        {
            if (!workday) // Precomputed value from earlier
                return TimeSpan.Zero;

            return stop - start;
        }

        // At this point we know they occur on different dates, so we can use
        // the offset from SOB and COB.

        TimeSpan timeInBetween = TimeSpan.Zero;
        TimeSpan hoursInAWorkday = (startCeil - startFloor);

        // I tried cool math stuff instead of a for-loop, but that leaves no clean way to count holidays.
        for (DateTime itr = startFloor.AddDays(1); itr < stopFloor; itr = itr.AddDays(1))
        {
            if (!IsWorkday(itr))
                continue;

            // Otherwise, it's a workday!
            timeInBetween += hoursInAWorkday;
        }

        return firstDayTime + lastDayTime + timeInBetween;
    }

    public static bool IsWorkday(DateTime date)
    {
        // Weekend
        if (date.DayOfWeek == DayOfWeek.Saturday || date.DayOfWeek == DayOfWeek.Sunday)
            return false;

        // Could add holiday logic here.

        return true;
    }

    public static DateTime StartOfBusiness(DateTime date)
    {
        return new DateTime(date.Year, date.Month, date.Day, 9, 0, 0);
    }

    public static DateTime CloseOfBusiness(DateTime date)
    {
        return new DateTime(date.Year, date.Month, date.Day, 17, 0, 0);
    }


Use LINQ:

DateTime dt1 = new DateTime(2010, 10, 1, 16, 0, 0);
DateTime dt2 = new DateTime(2010, 10, 2, 10, 0, 0);

int hours = Enumerable.Range(1, (dt2 - dt1).Hours)
                 .Where(h =>
                    {
                        var dt = dt1.AddHours(h);
                        return dt.DayOfWeek != DayOfWeek.Saturday
                               && dt.DayOfWeek != DayOfWeek.Sunday
                               && dt.Hour >= 9 && dt.Hour <= 17;
                    }).Count();

Here I assume all Minute and Second are zero. Otherwise (dt2 - dt1).Hours will give unexpected value.


You can try this Algorithm:

  1. Calculate total No Of Hours (lets say TotalHours = (Date2 - Date1).TotalHours)
  2. Calculate No of Holidays (holidays, includes weekends & other holidays)
  3. Calcualte No of Working days ( (Date2-Date1).TotalDays - Holidays) as int

Working Hours = TotalHours - 24*holidays - 16*WorkingDays

(16 = Time difference between 5pm and 9am the next day)


try this

namespace ConsoleApplication1
{
class Program
{
    static void Main(string[] args)
    {
        var date1 = new DateTime(2010, 10, 12, 12, 00, 00);
        var date2 = new DateTime(2010, 10, 14, 15, 00, 00);

        var hr1 = ((date1.Hour > 9) && (date1.Hour < 17)) ? 17 - date1.Hour : 0;
        var hr2 = ((date2.Hour > 9) && (date2.Hour < 17)) ? 17 - date2.Hour : 0;

        var middleHours = ((date2.Date -  date1.Date).Days -1) * 8 ;

        Console.WriteLine(hr1+hr2+ middleHours);
        Console.ReadKey();

    }
}

}

I have try it, and it is working :)


Here's a method that provides minute-level precision and supports overnight time ranges, building off the accepted answer by Oleg Rudckivsky.

/// <summary>
/// Counts the number of minutes between <paramref name="from"/> and <paramref name="to"/>
/// that fall between <paramref name="rangeStart"/> and <paramref name="rangeEnd"/>.
/// </summary>
/// <returns>The total minutes spanned between the given range.</returns>
public static int GetMinutesInRange(DateTime from, DateTime to, TimeSpan rangeStart, TimeSpan rangeEnd) {
    int minutes = 0;
    bool overnight = rangeStart > rangeEnd;
    for (var m = from; m < to; m = m.AddMinutes(1)) {
        if (overnight) {
            if (rangeStart <= m.TimeOfDay || m.TimeOfDay < rangeEnd) {
                minutes++;
            }
        } else {
            if (rangeStart <= m.TimeOfDay) {
                if (m.TimeOfDay < rangeEnd) {
                    minutes++;
                } else {
                    break;
                }
            }
        }
    }
    return minutes;
}

Example usage:

DateTime from = new DateTime(1990, 1, 1, 6, 30, 0);  // 7:30 AM
DateTime to = new DateTime(1990, 1, 1, 13, 30, 0);   // 1:30 PM
TimeSpan rangeStart = new TimeSpan(9, 0, 0);  // 9 AM
TimeSpan rangeEnd = new TimeSpan(17, 0, 0);   // 5 PM

// Results in 270 (4.5 hours)
int minutes = GlobalHelpers.GetMinutesInRange(from, to, rangeStart, rangeEnd);
0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜