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

我需要确定两个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; 

再一次感谢你的帮助。

当然,您可以使用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 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)); } 

花点时间,到达当天结束时的分钟数(即晚上7点)。

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

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

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

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

尝试以下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; } 
 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 } 

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

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

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

 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; 

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

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

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

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

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

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

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