确定两个DateTimes之间的差异,仅计算开放时间

时间:2011-02-15 15:56:36

标签: c# datetime

对于我们在C#中的支持软件,我需要确定两个DateTime之间的时间跨度,但我只想要计算开放时间(即工作日从09:00到17:00)。

因此,例如,如果第一个DateTime是15/02/2011 16:00而第二个是16/02/2011 10:00,则该方法将返回2个小时。

非常感谢任何帮助!

7 个答案:

答案 0 :(得分:23)

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

答案 1 :(得分:10)

我们走了,在这个问题上花了一段时间。 :)

有空间来检测假期(如果您编写的功能可以检查DateTime是否是假日),检测日期之间的周末,并处理超过数小时。

该算法用于计算从开始到业务开始以及从业务开始到结束时间的时间,然后计算两者之间的天数。落在同一天是一个特例。

警告:我做了一些基本的测试,但可能没有得到所有的角落案例。

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

答案 2 :(得分:4)

使用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();

我假设所有MinuteSecond都为零。否则(dt2 - dt1).Hours会给出意想不到的价值。

答案 3 :(得分:1)

试着看看这是一个类似的问题:Calculating the elapsed working hours between 2 datetime

答案 4 :(得分:1)

你可以试试这个算法:

  1. 计算总小时数(比如TotalHours =(Date2 - Date1).TotalHours)
  2. 计算假期(假期,包括周末及其他假期)
  3. 计算工作日数((Date2-Date1).TotalDays - Holidays)as int
  4. 工作时间= TotalHours - 24 *假期 - 16 * WorkingDays

    (16 =第二天下午5点至9点之间的时差)

答案 5 :(得分:0)

试试这个

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

    }
}

}

我试过了,它正在运作:)

答案 6 :(得分:0)

这是一种提供分钟级精度并支持通宵时间范围的方法,可以建立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;
}

用法示例:

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