听起来 LINQ 在这里应该可以很好地工作。我制作了一个简短的示例,使用我的Noda Time库,因为它比 .NET 对“一天中的时间”有更好的支持,但如有必要,您可以对其进行调整。
这个想法基本上是你有两个周期集合,你只对交集感兴趣 - 你可以找到任何计划周期与任何移动周期的交集 - 很容易通过使用一个不相交的周期来打折0 长度周期。
这是完整的代码,它确实给出了 7 小时 30 分钟的总时间:
using System;
using System.Collections.Generic;
using System.Linq;
using NodaTime;
class Test
{
static void Main()
{
var schedule = new List<TimePeriod>
{
new TimePeriod(new LocalTime(7, 30), new LocalTime(12, 0)),
new TimePeriod(new LocalTime(13, 30), new LocalTime(17, 0)),
};
var movements = new List<TimePeriod>
{
new TimePeriod(new LocalTime(6, 50), new LocalTime(6, 55)),
new TimePeriod(new LocalTime(7, 0), new LocalTime(11, 45)),
new TimePeriod(new LocalTime(13, 45), new LocalTime(17, 05))
};
var durations = from s in schedule
from m in movements
select s.Intersect(m).Duration;
var total = durations.Aggregate((current, next) => current + next);
Console.WriteLine(total);
}
}
class TimePeriod
{
private readonly LocalTime start;
private readonly LocalTime end;
public TimePeriod(LocalTime start, LocalTime end)
{
if (start > end)
{
throw new ArgumentOutOfRangeException("end");
}
this.start = start;
this.end = end;
}
public LocalTime Start { get { return start; } }
public LocalTime End { get { return end; } }
public Duration Duration { get { return Period.Between(start, end)
.ToDuration(); } }
public TimePeriod Intersect(TimePeriod other)
{
// Take the max of the start-times and the min of the end-times
LocalTime newStart = start > other.start ? start : other.start;
LocalTime newEnd = end < other.end ? end : other.end;
// When the two don't actually intersect, just return an empty period.
// Otherwise, return the appropriate one.
if (newEnd < newStart)
{
newEnd = newStart;
}
return new TimePeriod(newStart, newEnd);
}
}