将开始和持续时间与时隙合并

时间:2014-06-18 07:53:14

标签: c# time merge

我有一个包含多个电视广播的数据文件,其开始和持续时间以分钟为单位,我必须将其与另一个包含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
  7. 文件2:

    1. timeslot | 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
    14. 现在我要做的是,对于每次出现的文件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;
      }
      

1 个答案:

答案 0 :(得分:1)

我接近这个的方法是将输入数据文件的解析与找到所需时间段的逻辑分开。

就找到正确的时间段的逻辑而言,您可以使用以下内容作为开始。它实现了你在上面详述的逻辑,即"出现的时间段"包含最多的时间"必须选择进入 - 如果事件完全覆盖多个时隙,则应选择最后一个完全覆盖的时隙":

更新 - 支持晚上'时区我已经引入了一个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实例。我将把这部分留给你,因为我相信你自己创建解析代码会对你有所帮助。