2014-02-16 225 views
1

我有一个要求,即通过将主开始和结束日期时间与多个“忽略”开始和结束日期时间对进行比较,以找出“有效”时间范围。通过在主日期范围内使用多个日期范围来获取时间范围

可能有任何数量的这些“忽略”对,它们的范围可以介于初始Start和结束DateTime对之间,甚至可以完全覆盖。

实施例的输入和预期输出下面(使用简单的时间表示现在):

实施例1对

Main Start: 04:00 
Main End : 14:00 

Ignore Pair 1: 03:00 - 06:00 
Ignore Pair 2: 05:00 - 09:00 
Ignore Pair 3: 12:00 - 13:00 

Expected Result: Timespan(4 'Valid' Hours) 

实施例2

Main Start: 04:00 
Main End : 14:00 

Ignore Pair 1: 03:00 - 12:00 

Expected Result: Timespan(2 'Valid' Hours) 

实施例3

Main Start: 04:00 
Main End : 14:00 

Ignore Pair 1: 03:00 - 20:00 

Expected Result: Timespan(0 'Valid' Hours) 

例4

Main Start: 04:00 
Main End : 14:00 

Ignore Pair 1: 08:00 - 12:00 

Expected Result: Timespan(6 'Valid' Hours) 

道歉,如果有什么不合理的,请让我知道是否有什么需要更详细说明。

+1

OK,你有什么已经尝试过? – MarcinJuraszek

+0

第一次尝试就是在时间跨度上把所有这些“忽略跨度”都打翻,并从主要开始和结束跨度中减去它,但是这并没有考虑2个忽略跨度实际上与对方重叠的可能性(如例1) – JakeJ

+0

第二次尝试是尝试将忽略日期对分组为非重叠对,因此在示例1中,对1和对2将变为03:00至09:00,然后变为04:00至09:00 if你包括主要的开始,但是我无法弄清楚在技术上如何去做(这个想法仍然在我的脑海中,想着它) – JakeJ

回答

1

这应该给你一个有效范围的列表。这是没有优化的第一个简单划痕。代码应该用评论来解释自己。如果您想获得“有效”时间量,只需在结果中添加范围Console.WriteLine("{0} valid hours", valid.Sum(r => (r.End - r.Start).TotalHours)); 它是在假设下编码的,范围经过验证(开始<结束)!

类用于存储时间范围:

class TimeRange 
{ 
    public DateTime Start { get; set; } 
    public DateTime End { get; set; } 

    public TimeRange() 
    { 

    } 
    public TimeRange(TimeSpan todayStart, TimeSpan todayEnd) 
    { 
     Start = DateTime.Today + todayStart; 
     End = DateTime.Today + todayEnd; 
    } 
} 

Testcode:

static void Main(string[] args) 
{ 
    var main = new TimeRange(new TimeSpan(4, 0, 0), new TimeSpan(14, 0, 0)); 
    var except = new List<TimeRange>{ 
     new TimeRange(new TimeSpan(3, 0, 0), new TimeSpan(6, 0, 0)), 
     new TimeRange(new TimeSpan(5, 0, 0), new TimeSpan(9, 0, 0)), 
     new TimeRange(new TimeSpan(12, 0, 0), new TimeSpan(13, 0, 0)) 
    }; 

    var valid = GetFreeSlots(main, except); 
} 

算法:

private static List<TimeRange> GetFreeSlots(TimeRange main, List<TimeRange> except) 
{ 
    // 1. ignore Ranges outside 
    except = except.Where(e => main.Start < e.End && main.End > e.Start).ToList(); 

    // 2. shrink the main timerange from overlapping ranges 
    while (true) 
    { 
     var x = except.FirstOrDefault(e => e.Start <= main.Start); 
     if (x != null) 
     { 
      if (x.End >= main.End) 
      { 
       return new List<TimeRange>(); 
      } 
      main.Start = x.End; 
      except.Remove(x); 
     } 
     else 
      break; 
    } 

    while (true) 
    { 
     var x = except.FirstOrDefault(e => e.End >= main.End); 
     if (x != null) 
     { 
      main.End = x.Start; 
      except.Remove(x); 
     } 
     else 
      break; 
    } 

    if (!except.Any()) 
    { 
     return new List<TimeRange> { main }; 
    } 

    // 3. add range[start main to start of the 1. exception] to the list of valid ranges and shrink the main time range to start = end of the 1. exception and go through the procedure again      
    except.OrderBy(e => e.Start); 
    var valid = new List<TimeRange>{new TimeRange{Start = main.Start, End = except[0].Start}}; 
    main.Start = except[0].End; 
    except.RemoveAt(0); 
    return valid.Union(GetFreeSlots(main, except)).ToList(); 
} 
+0

真棒,我会在我的代码现在试试这个! – JakeJ

+0

这工作perferctly,非常感谢你! – JakeJ