C# - 两个日期时间之间的持续时间(分钟)

时间:2010-09-30 21:41:42

标签: c# datetime duration

我需要确定两个DateTimes之间的持续时间,以分钟为单位。

然而,有一点点扭曲:

  • 排除周末
  • 只计算分钟数 这是在上午7:00到下午7:00之间。 例如:[09/30/2010 6:39:00 PM] - [09/30/2010 7:39:00 PM] = 21 Minutes

我只是很难想出一个体面的方式来做这件事,如果有人能提出建议,我会很感激。

感谢。


编辑:

我最终选择了dtb的解决方案。只有一个特殊情况需要注意:如果结束时间是晚上7点之后,则计算从上午7点到实际结束时间的分钟数。

这是我修改它的方式:

var minutes = from day in start.DaysInRangeUntil(end)
                where !day.IsWeekendDay()
                let st = Helpers.Max(day.AddHours(7), start)
                let en = (day.DayOfYear == end.DayOfYear ? 
                            end :
                            Helpers.Min(day.AddHours(19), end)
                            )
                select (en - st).TotalMinutes;

再次感谢您的帮助。

9 个答案:

答案 0 :(得分:23)

当然,您可以使用LINQ:

DateTime a = new DateTime(2010, 10, 30, 21, 58, 29);
DateTime b = a + new TimeSpan(12, 5, 54, 24, 623);

var minutes = from day in a.DaysInRangeUntil(b)
              where !day.IsWeekendDay()
              let start = Max(day.AddHours( 7), a)
              let end   = Min(day.AddHours(19), b)
              select (end - start).TotalMinutes;

var result = minutes.Sum();

// result == 6292.89

(注意:您可能需要检查我完全忽略的很多极端情况。)

助手方法:

static IEnumerable<DateTime> DaysInRangeUntil(this DateTime start, DateTime end)
{
    return Enumerable.Range(0, 1 + (int)(end.Date - start.Date).TotalDays)
                     .Select(dt => start.Date.AddDays(dt));
}

static bool IsWeekendDay(this DateTime dt)
{
    return dt.DayOfWeek == DayOfWeek.Saturday
        || dt.DayOfWeek == DayOfWeek.Sunday;
}

static DateTime Max(DateTime a, DateTime b)
{
    return new DateTime(Math.Max(a.Ticks, b.Ticks));
}

static DateTime Min(DateTime a, DateTime b)
{
    return new DateTime(Math.Min(a.Ticks, b.Ticks));
}

答案 1 :(得分:5)

记下你的开始时间,得到那天结束的分钟数(即晚上7点)。

然后从第二天早上7点开始计算最后一天的天数(不包括截至结束日期的任何时间)。

计算已经过了多少(如果有的话)周末。 (对于每个周末,将天数减少2)。

从那里做一些简单的数学计算得出天数的总分钟数。

在最后一天和开始日加时间添加额外时间。

答案 2 :(得分:4)

尝试以下DiffRange功能。

public static DateTime DayStart(DateTime date)
{
    return date.Date.AddHours(7);
}

public static DateTime DayEnd(DateTime date)
{
    return date.Date.AddHours(19);
}

public static TimeSpan DiffSingleDay(DateTime start, DateTime end)
{
    if ( start.Date != end.Date ) {
        throw new ArgumentException();
    }

    if (start.DayOfWeek == DayOfWeek.Saturday || start.DayOfWeek == DayOfWeek.Sunday )
    {
        return TimeSpan.Zero;
    }

    start = start >= DayStart(start) ? start : DayStart(start);
    end = end <= DayEnd(end) ? end : DayEnd(end);
    return end - start;
}

public static TimeSpan DiffRange(DateTime start, DateTime end)
{
    if (start.Date == end.Date)
    {
        return DiffSingleDay(start, end);
    }

    var firstDay = DiffSingleDay(start, DayEnd(start));
    var lastDay = DiffSingleDay(DayStart(end), end);

    var middle = TimeSpan.Zero;
    var current = start.AddDays(1);
    while (current.Date != end.Date)
    {
        middle = middle + DiffSingleDay(current.Date, DayEnd(current.Date));
        current = current.AddDays(1);
    }

    return firstDay + lastDay + middle;
}

答案 3 :(得分:1)

我确信我错过了一些东西。

  TimeSpan CalcBusinessTime(DateTime a, DateTime b)
  {
     if (a > b)
     {
        DateTime tmp = a;
        a = b;
        b = tmp;
     }

     if (a.TimeOfDay < new TimeSpan(7, 0, 0))
        a = new DateTime(a.Year, a.Month, a.Day, 7, 0, 0);
     if (b.TimeOfDay > new TimeSpan(19, 0, 0))
        b = new DateTime(b.Year, b.Month, b.Day, 19, 0, 0);

     TimeSpan sum = new TimeSpan();
     TimeSpan fullDay = new TimeSpan(12, 0, 0);
     while (a < b)
     {
        if (a.DayOfWeek != DayOfWeek.Saturday && a.DayOfWeek != DayOfWeek.Sunday)
        {
           sum += (b - a < fullDay) ? b - a : fullDay;
        }
        a = a.AddDays(1);
     }

     return sum;
  } 

答案 4 :(得分:1)

这是一个非常难的问题。对于一个基本的,直截了当的方法,我写了下面的代码:

DateTime start = new DateTime(2010, 01, 01, 21, 00, 00);
DateTime end = new DateTime(2010, 10, 01, 14, 00, 00);

// Shift start date's hour to 7 and same for end date
// These will be added after doing calculation:
double startAdjustmentMinutes = (start - start.Date.AddHours(7)).TotalMinutes;
double endAdjustmentMinutes = (end - end.Date.AddHours(7)).TotalMinutes;

// We can do some basic
// mathematical calculation to find weekdays count:
// divide by 7 multiply by 5 gives complete weeks weekdays
// and adding remainder gives the all weekdays:
int weekdaysCount = (((int)((end.Date - start.Date).Days / 7) * 5) 
          + ((end.Date - start.Date).Days % 7));
// so we can multiply it by minutes between 7am to 7 pm
int minutes = weekdaysCount * (12 * 60);

// after adding adjustment we have the result:
int result = minutes + startAdjustmentMinutes + endAdjustmentMinutes;

我知道这在程序上并不美观,但我不知道在开始和结束之间迭代几天和几小时是否合适。

答案 5 :(得分:1)

static int WorkPeriodMinuteDifference(DateTime start, DateTime end)
{
    //easier to only have to work in one direction.
    if(start > end)
        return WorkPeriodMinuteDifference(end, start);
    //if weekend, move to start of next Monday.
    while((int)start.DayOfWeek % 6 == 0)
        start = start.Add(new TimeSpan(1, 0, 0, 0)).Date;
    while((int)end.DayOfWeek % 6 == 0)
        end = end.Add(new TimeSpan(1, 0, 0, 0)).Date;
    //Move up to 07:00 or down to 19:00
    if(start.TimeOfDay.Hours < 7)
        start = new DateTime(start.Year, start.Month, start.Day, 7, 0, 0);
    else if(start.TimeOfDay.Hours > 19)
        start = new DateTime(start.Year, start.Month, start.Day, 19, 0, 0);
    if(end.TimeOfDay.Hours < 7)
        end = new DateTime(end.Year, end.Month, end.Day, 7, 0, 0);
    else if(end.TimeOfDay.Hours > 19)
        end = new DateTime(end.Year, end.Month, end.Day, 19, 0, 0);

    TimeSpan difference = end - start;

    int weeks = difference.Days / 7;
    int weekDays = difference.Days % 7;
    if(end.DayOfWeek < start.DayOfWeek)
        weekDays -= 2;

    return (weeks * 5 * 12 * 60) + (weekDays * 12 * 60) + difference.Hours * 60 + difference.Minutes
}

答案 6 :(得分:1)

我的实施:)我们的想法是快速计算总周数,并逐日走完剩余的一周......

public TimeSpan Compute(DateTime start, DateTime end)
{
    // constant start / end times per day
    TimeSpan sevenAM = TimeSpan.FromHours(7);
    TimeSpan sevenPM = TimeSpan.FromHours(19);

    if( start >= end )
    {
        throw new Exception("invalid date range");
    }

    // total # of weeks
    int completeWeeks = ((int)(end - start).TotalDays) / 7;

    // starting total
    TimeSpan total = TimeSpan.FromHours(completeWeeks * 12 * 5);

    // adjust the start date to be exactly "completeWeeks" past its original start
    start = start.AddDays(completeWeeks * 7);

    // walk days from the adjusted start to end (at most 7), accumulating time as we can...
    for(
        // start at midnight
        DateTime dt = start.Date;

        // continue while there is time left
        dt < end;

        // increment 1 day at a time
        dt = dt.AddDays(1)
    )
    {
        // ignore weekend
        if( (dt.DayOfWeek == DayOfWeek.Saturday) ||
             (dt.DayOfWeek == DayOfWeek.Sunday) )
        {
            continue;
        }

        // get the start/end time for each day...
        // typically 7am / 7pm unless we are at the start / end date
        TimeSpan dtStartTime = ((dt == start.Date) && (start.TimeOfDay > sevenAM)) ?
            start.TimeOfDay : sevenAM;
        TimeSpan dtEndTime = ((dt == end.Date) && (end.TimeOfDay < sevenPM)) ?
            end.TimeOfDay : sevenPM;

        if( dtStartTime < dtEndTime )
        {
            total = total.Add(dtEndTime - dtStartTime);
        }
    }

    return total;
}

答案 7 :(得分:1)

使用TimeSpan.TotalMinutes,减去非工作日,减去多余的时间。

答案 8 :(得分:0)

我不会写任何代码,但有一个DateTime你可以告诉星期几,因此你知道你的范围内有多少个周末,所以你可以知道周末有多少分钟。

所以它不会那么难......当然必须有一个最佳的单线解决方案......但我认为你可以解决这个问题。

我忘了提到你也知道晚上7点到早上7点之间的会议纪要,所以你所要做的就是减去你得到的时差所需的分钟数。