【问题标题】:How do I find the intersect of two sets of non-contiguous Times?如何找到两组不连续时间的交集?
【发布时间】:2012-01-16 16:19:59
【问题描述】:

我正在尝试构建一个工具,该工具可以根据员工计划工作的时间和他们要求下班的时间来计算称为配额的东西。

我的 ShiftSet 对象是一组 Shift 对象,由 StartTime 和 EndTime 组成(均为 time(7) 类型。每个 ShiftSet 对应于一天。

ScheduleExceptions 是员工休假的时间。一天中可以有任意数量的重叠或不重叠的 ScheduleExceptions。它们属于日期时间数据类型。

ShiftSet 示例:
08:00-10:00
10:00-12:00
13:00-15:00
15:00-17:00

同一天的 ScheduleExceptions 示例:
07:30-10:30
14:35-16:00

我需要做的是找出员工一天工作的时间。我能想到的方法是计算 ShiftSet 的交集和 ScheduleExceptions 的倒数。

我将如何处理时间?如果可能,我更喜欢使用 Linq。

【问题讨论】:

  • 请问c#中的time(7)类型是什么?
  • 在 sql 中是时间,但在 c# 中是时间跨度。
  • 您需要查找总时间,还是要查找员工工作的实际开始/结束时间?
  • 您想找到某人一天工作的所有小时数的总和。在您上面的示例中,这将是 8h - 4h25m = 3h35m?
  • 你说你使用时间跨度,但你提到时间(即,DateTime 是合适的)。我TimeSpan没有开始和结束,只有一段时间。

标签: c# asp.net linq entity-framework


【解决方案1】:

CodeProject查看这个很棒的article

对于您的具体问题来说,它可能过于宽泛,但它可能会给您一个很好的起点来解决它。

【讨论】:

    【解决方案2】:

    正如 InBetween 所提到的,有一些库已经解决了这个问题,但它们也解决了许多相关问题。如果您只想解决这个特定问题而不承担其他依赖项,您可以尝试以下方法。

    // Finds ones with absolutely no overlap
    var unmodified = shifts.Where(s => !exceptions.Any(e => s.Start < e.End && s.End > e.Start));
    
    // Finds ones entirely overlapped
    var overlapped = shifts.Where(s => exceptions.Any(e => e.End >= s.End && e.Start <= s.Start));
    
    // Adjusted shifts
    var adjusted = shifts.Where(s => !unmodified.Contains(s) && !overlapped.Contains(s))
                            .Select(s => new Shift
                            {
                                Start = exceptions.Where(e => e.Start <= s.Start && e.End > s.Start).Any() ? exceptions.Where(e => e.Start <= s.Start && e.End > s.Start).First().End : s.Start,
                                End = exceptions.Where(e => e.Start < s.End && e.End >= s.End).Any() ? exceptions.Where(e => e.Start < s.End && e.End >= s.End).First().Start : s.End
                            });
    
    var newShiftSet = unmodified.Union(overlapped).Union(adjusted);
    

    这是一个基本示例,尽管它可以被压缩(尽管可读性较差)和改进。

    【讨论】:

      【解决方案3】:

      我没有测试下面的代码,可能有一些错误,另外我是在textpad中写的,可能有无效字符,想法很简单,我尝试使用有意义的变量。

      var orderedShifts = ShiftSets.OrderBy(x=>x.StartDate).ToList();
      
      var compactShifts = new List<Shift>();
      compactShifts.Add(orderedShifs[0]);
      
      foreach (var item in orderedShift)
      {
          if (item.Start <= compactShifts[compactShifts.Count-1].End 
              && item.End > compactShifts[compactShifts.Count-1].End)
          {
              compactShifts[compactShifts.Count-1].End = item.End;
          } 
          else if (item.Start > compactShifts[compactShifts.Count-1].End)
            compactShifts.Add(item);
      }  
      
      //run similar procedure for schedule exceptions to create compact schedules.
      
      var validShifts = new List<Shift>();
      
      foreach (var item in compactShifts)
      {
         var shiftCheatingPart = compactExceptions
                                .FirstOrDefault(x=>x.Start < item.Start 
                                               && x.End > item.End)
         if (shiftCheatingPart != null)
         {
             if (item.End <= shiftCheatingPart.End)
               continue;
      
             validShifts.Add(new Shift{Start = shiftCheatingPart.End,End = item.End);
         }
      }
      
      var totalTimes = validShifts.Sum(x=>x.End.Sunbtract(x.Start).TotalHours);
      

      【讨论】:

        【解决方案4】:

        一个非常粗略的解决方案是这样的

        void Main()
        {
            var workTime = new List<ShiftSet> {
                new ShiftSet{StartTime= new TimeSpan(8,0,0),EndTime= new TimeSpan(10,0,0)},
                new ShiftSet{StartTime= new TimeSpan(10,0,0),EndTime= new TimeSpan(12,0,0)},
                new ShiftSet{StartTime= new TimeSpan(13,0,0),EndTime= new TimeSpan(15,0,0)},
                new ShiftSet{StartTime= new TimeSpan(15,0,0),EndTime= new TimeSpan(17,0,0)}
                };
        
        
            var missingTime= new List<ShiftSet> {
                new ShiftSet{StartTime= new TimeSpan(7,30,0),EndTime= new TimeSpan(10,30,0)},
                new ShiftSet{StartTime= new TimeSpan(14,35,0),EndTime= new TimeSpan(16,0,0)}
                };
        
        
            Console.WriteLine(workTime.Sum(p=>p.Shift()) - missingTime.Sum(p=>p.Shift()));
        }
        
        
        public class ShiftSet 
        {
            public TimeSpan StartTime {get;set;}
            public TimeSpan EndTime {get;set;}
        
            public double Shift() {return (EndTime-StartTime).TotalMinutes;}
        }
        

        我以分钟为单位计算工作时间,因此我可以使用 linq 更轻松地求和

        我还缺少我认为不属于 ShiftSet 类的特定班次信息

        Because the employee is not scheduled to work from 7:30 to 8:00, we would not include that time

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-09-28
          • 2014-03-06
          • 1970-01-01
          • 2013-07-25
          相关资源
          最近更新 更多