起始时间和持续时间与时隙合并

本文关键字:时隙 合并 持续时间 时间 | 更新日期: 2023-09-27 18:09:01

我有一个包含几个电视广播的数据文件,它们的开始和持续时间以分钟为单位,我必须将它与另一个包含大约2小时时间段的文件合并。下面是它的样例:

File1:

  1. 日期|开始|持续时间
  2. 19/05/2014 | 15:25:00 | 55
  3. 19/05/2014 | 16:20:00 | 30
  4. 19/05/2014 | 16:50:00 | 25
  5. 19/05/2014 | 17:15:00 | 55
  6. 19/05/2014 | 18:10:00 | 30

File2:

  1. 时隙| timeslot_info
  2. 05:00 - 07:00|info_to_merge
  3. 07:00 - 09:00|info_to_merge
  4. 09:00 - 11:00|info_to_merge
  5. 11:00 - 13:00|info_to_merge
  6. 13:00 - 15:00|info_to_merge
  7. 15:00 - 17:00|info_to_merge
  8. 17:00 - 19:00|info_to_merge
  9. 19:00 - 21:00|info_to_merge
  10. 21:00 - 23:00|info_to_merge
  11. 23:00 - 25:00|info_to_merge
  12. 25:00 - 27:00|info_to_merge
  13. 27:00 - 29:00|info_to_merge

现在我要做的是,对于文件1的每次出现,根据这些规则找到文件2对应的时间段:—必须选择事件"包含最多"的时间段—如果事件完全覆盖多个时隙,则应选择最后一个完全覆盖的时隙

我已经尝试了很多繁重的代码,但我找不到如何推断正确的时隙。我想到了一个逻辑,我正在浏览第一个文件的每次出现,并尝试为其分配一个时隙键,以便进一步匹配,但没有更多:

private string GetTimeSlot(string line)
{
    string result = "";
    string[] tab = line.Split(''t');
    string start = tab[LogsStartTimeColumnIndex];
    string[] starttab = start.Split(':');
    TimeSpan StartTime = new TimeSpan(Int32.Parse(starttab[0]), Int32.Parse(starttab[1]), Int32.Parse(starttab[2]));
    TimeSpan Duration = new TimeSpan(0, Int32.Parse(tab[LogsDurationColumnIndex], 0), 0);
    TimeSpan EndTime = StartTime + Duration;

    //don't know how to do it from here..
    return result;
}

起始时间和持续时间与时隙合并

我的方法是将输入数据文件的解析与找到所需Timeslot的逻辑分开。

根据查找正确Timeslot的逻辑,您可以使用以下代码作为开始。它实现了你在上面详细说明的逻辑,即"必须选择事件"最多包含"的时隙-如果事件完全覆盖多个时隙,则应选择最后一个完全覆盖的时隙":

UPDATED -为了支持'night'时隙我引入了一个TimeInHours类来表示Timespan之前在做什么

public class TimeslotsFinder
{
    private readonly IEnumerable<Timeslot> _allTimeslots;
    public TimeslotsFinder(IEnumerable<Timeslot> allTimeslots)
    {
        _allTimeslots = allTimeslots;
    }
    public Timeslot FindTimeslot(Broadcast broadcast)
    {
        var found = _allTimeslots
            .Select(t => new { Timeslot = t, DurationInTimeslot = DurationInTimeslot(broadcast, t) })
            .Where(x => x.DurationInTimeslot > TimeInHours.Zero)
            .OrderByDescending(x => x.DurationInTimeslot.Value)
            .ThenByDescending(x => x.Timeslot.Start.Value)
            .FirstOrDefault();
        return found == null ? null : found.Timeslot;
    }
    private static TimeInHours DurationInTimeslot(Broadcast broadcast, Timeslot timeslot)
    {
        if (!(InTimeslot(broadcast, timeslot) || CoversEntireTimeslot(broadcast, timeslot))) return TimeInHours.Zero;
        var endToUse = broadcast.EndTime >= timeslot.End
                        ? timeslot.End
                        : broadcast.EndTime;
        var startToUse = broadcast.StartTime <= timeslot.Start
                        ? timeslot.Start
                        : broadcast.StartTime;
        return endToUse.Subtract(startToUse);
    }
    private static bool InTimeslot(Broadcast broadcast, Timeslot timeslot)
    {
        var startsInTimeslot = timeslot.Start <= broadcast.StartTime && broadcast.StartTime < timeslot.End;
        var endsInTimeslot = timeslot.End < broadcast.EndTime && broadcast.EndTime <= timeslot.End;
        return startsInTimeslot || endsInTimeslot;
    }
    private static bool CoversEntireTimeslot(Broadcast broadcast, Timeslot timeslot)
    {
        return broadcast.StartTime <= timeslot.Start && broadcast.EndTime >= timeslot.End;
    }
}
上面的逻辑显然使用了这些类:

这些也被更新为使用TimeInHours类

public class Broadcast
{
    public DateTime StartDateTime { get; set; }
    public TimeSpan Duration { get; set; }
    public TimeInHours StartTime
    {
        get
        {
            return TimeInHours.FromTimeSpan(StartDateTime.TimeOfDay);
        }
    }
    public TimeInHours EndTime
    {
        get
        {
            return TimeInHours.FromTimeSpan(StartDateTime.Add(Duration).TimeOfDay);
        }
    }
}
public class Timeslot
{
    public TimeInHours Start { get; set; }
    public TimeInHours End { get; set; }
    public TimeInHours Duration
    {
        get
        {
            return End.Subtract(Start);
        }
    }
}
public class TimeInHours
{
    public TimeInHours(int value)
    {
        Value = value;
    }
    public int Value { get; private set; }
    public TimeInHours Subtract(TimeInHours x)
    {
        return new TimeInHours(Value - x.Value);
    }
    public static TimeInHours FromTimeSpan(TimeSpan ts)
    {
        return new TimeInHours(ts.Hours);
    }
    public static TimeInHours Zero
    {
        get
        {
            return new TimeInHours(0);
        }
    }
    public static bool operator < (TimeInHours t1, TimeInHours t2)
    {
        return t1.Value < t2.Value;
    }
    public static bool operator >(TimeInHours t1, TimeInHours t2)
    {
        return t1.Value > t2.Value;
    }
    public static bool operator <=(TimeInHours t1, TimeInHours t2)
    {
        return t1.Value <= t2.Value;
    }
    public static bool operator >=(TimeInHours t1, TimeInHours t2)
    {
        return t1.Value >= t2.Value;
    }
}

你可以这样测试这个逻辑:

也更新为使用TimeInHours类

        var timeslots = new List<Timeslot>
        {
            new Timeslot{Start = new TimeInHours(5), End = new TimeInHours(7)},
            new Timeslot{Start = new TimeInHours(7), End = new TimeInHours(9)},
            new Timeslot{Start = new TimeInHours(9), End = new TimeInHours(11)},
            new Timeslot{Start = new TimeInHours(11), End = new TimeInHours(13)},
            new Timeslot{Start = new TimeInHours(13), End = new TimeInHours(15)},
            new Timeslot{Start = new TimeInHours(15), End = new TimeInHours(17)},
            new Timeslot{Start = new TimeInHours(17), End = new TimeInHours(19)},
            new Timeslot{Start = new TimeInHours(19), End = new TimeInHours(21)},
            new Timeslot{Start = new TimeInHours(21), End = new TimeInHours(23)},
            new Timeslot{Start = new TimeInHours(23), End = new TimeInHours(25)},
        };
        var finder = new TimeslotsFinder(timeslots);
        var broadcast = new Broadcast { StartDateTime = DateTime.Parse("19/05/2014 09:00"), Duration = TimeSpan.FromMinutes(250) };
        var timeslot = finder.FindTimeslot(broadcast);

有了这个逻辑,接下来就只需要解析数据文件来创建所需的BroadcastTimeslot实例。我将把这部分留给您,因为我相信您自己创建解析代码将对您有益。