如何找到两组不连续时间的交集

本文关键字:时间 不连续 两组 何找 | 更新日期: 2023-09-27 18:20:31

我正在尝试构建一个工具,根据员工计划工作的时间和他们请求休假的时间来计算配额。

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

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

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的倒数的交集。

我该如何利用时间做到这一点?如果可能的话,我更愿意用林克。

如何找到两组不连续时间的交集

查看CodeProject上的这篇精彩文章

对于你的具体问题来说,它可能太宽泛了,但它可能会给你一个解决问题的好起点

正如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);

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

我没有测试下面的代码,可能有一些错误,而且我在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);

一种非常粗糙的溶液可能类似

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