获取重叠间隔的持续时间

Get the duration of the overlapping intervals

我有一个 TimeSpans 列表,我想获取所有重叠 TimeSpans 的持续时间。 (见图)

在这种情况下,持续时间必须是 2.5 小时,而不是 3 小时。有人有想法吗?

示例:

"Administratief"是40分钟的约会。 "Tafel dekken" 是 30 分钟的约会,但它与 "Administratief" 重叠,因此持续时间为 40 分钟 + "Tafel dekken" 的 10 分钟。你有 30 分钟的 "Prolongeren",所以在这种情况下,持续时间必须是 80 分钟。

假设您有开始时间和持续时间,您可以通过获取最短开始时间和最长结束时间然后计算差值来执行此操作:

DateTime minStart = timeList.Min(l => l.StartTime);
DateTime maxEnd = timeList.Max(l => l.EndTime);

TimeSpan duration = maxEnd - minStart;

如果您没有直接的结束时间,那么 EndTime 属性 必须从 StartTimeDuration:

public DateTime EndTime
{
    get { return this.StartTime.Add(this.Duration); }
}

这将获取约会的总持续时间,并且不会考虑约会中存在间隙的情况。您需要首先将列表处理成约会重叠或连续的子列表。像这样的伪代码:

var orderedAppointments = appointments.OrderBy(a => a.StartTime);
foreach (var appointment in orderedAppointments)
{
    if (first appointment)
        add to new sub list and add sub list to list of lists
    else if (appointment.StartTime <= subList.Max(s => s.EndTime))
        add to existing sub list
    else
        add to new sub list and add sub list to list of lists
}

然后你可以使用初始代码获取每个子列表的总持续时间。

一种不需要排序列表的简单但低效的算法 (O(n²))。
首先,合并所有重叠区间,然后汇总区间长度(向下滚动):

struct TimeRange
{
    DateTime Start;
    DateTime End;

    public TimeRange(DateTime start, DateTime end)
    {
        Start = start;
        End = end;
    }

    public TimeSpan Duration
    {
        get
        {
            return End-Start;
        }
    }

    public static bool Overlap(TimeRange tr1, TimeRange tr2)
    {
        return (tr2.Start <= tr1.End && tr1.Start <= tr2.End);
    }

    public static TimeRange Merge(TimeRange tr1, TimeRange tr2)
    {
        return new TimeSpan(
            (tr1.Start < tr2.Start) ? tr1.Start : tr2.Start,
            (tr1.End > tr2.End) ? tr1.End : tr2.End
        );
    }
}



List<TimeRange> timeRanges; // A *copy* of your data list

for(int i = 0; i < timeRanges.Count; i++)
{
    for(int j = i+1; j < timeRanges.Count; j++)
    {
        if(TimeRange.Overlap(timeRanges[i],timeRanges[j])
        {
            timeRanges[i] = TimeRange.Merge(timeRanges[i],timeRanges[j]);
            timeRanges.RemoveAt(j);
            j--;
        }
    }
}

TimeSpan totalDuration = TimeSpan.Zero;
foreach(TimeRange in timeRanges)
{
    totalDuration += timeRanges.Duration;
}