I am trying to build a tool that calculates something called quota based upon when employees are scheduled to work and when they request off.
我正在尝试构建一个工具,根据员工安排工作的时间和请求时间来计算配额。
My ShiftSet object is a set of Shift objects which consist of a StartTime and EndTime (both of type time(7). Each ShiftSet corresponds to a day.
我的ShiftSet对象是一组Shift对象,由StartTime和EndTime组成(类型为time(7)。每个ShiftSet对应一天。
ScheduleExceptions are times that an employee has off. There can be any number of overlapping or non-overlapping ScheduleExceptions in a day. They are of the datetime data type.
ScheduleExceptions是员工关闭的时间。一天中可以有任意数量的重叠或不重叠的ScheduleExceptions。它们是日期时间数据类型。
An example of a ShiftSet:
08:00-10:00
10:00-12:00
13:00-15:00
15:00-17:00
ShiftSet的一个示例:08:00-10:00 10:00-12:00 13:00-15:00 15:00-17:00
An example of ScheduleExceptions for that same day:
07:30-10:30
14:35-16:00
同一天的ScheduleExceptions示例:07:30-10:30 14:35-16:00
What I need to do is to find the amount of time that the employee is working on a day. The way I can figure to do this is to calculate the intersection of ShiftSet and the inverse of ScheduleExceptions.
我需要做的是找出员工一天工作的时间。我可以想象的方法是计算ShiftSet和ScheduleExceptions的反转的交集。
How would I do this with time? I would prefer to use Linq if possible.
我该怎么做时间?如果可能的话,我更愿意使用Linq。
4 个解决方案
#1
2
As InBetween mentioned, there are libraries out there that have solved this problem, but they solve many related problems as well. If you are wanting to just tackle this particular problem without taking on another dependency, you can try the following.
正如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);
It's a basic example, though it could be compacted (albeit less-readable) and improved.
这是一个基本的例子,虽然它可以被压缩(虽然不太可读)并得到改进。
#2
3
Check out this great article at CodeProject
在CodeProject上查看这篇精彩的文章
It's probably way too broad for your specific problem but it will probably give you a good starting point on how to solve it.
对于您的具体问题,它可能过于宽泛,但它可能会为您提供一个如何解决问题的良好起点。
#3
0
I didn't test bellow code, may be there is some bugs, Also I wrote it in textpad may be there are invalid characters, Idea is simple, and I try to use meaningful variables.
我没有测试下面的代码,可能是有一些bug,我在textpad中写的可能是有无效的字符,Idea很简单,我尝试使用有意义的变量。
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
0
A very crude solution would be something like
一个非常粗糙的解决方案就像是
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;}
}
I calculate a worktime in minutes so I can sum more easily using linq
我用分钟计算一个工作时间,所以我可以使用linq更容易地求和
I am also missing specific shift information which I think don't belong with ShiftSet
class
我也缺少我认为不属于ShiftSet类的特定班次信息
Because the employee is not scheduled to work from 7:30 to 8:00, we would not include that time
由于员工未安排在7:30到8:00工作,我们不会包含该时间
#1
2
As InBetween mentioned, there are libraries out there that have solved this problem, but they solve many related problems as well. If you are wanting to just tackle this particular problem without taking on another dependency, you can try the following.
正如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);
It's a basic example, though it could be compacted (albeit less-readable) and improved.
这是一个基本的例子,虽然它可以被压缩(虽然不太可读)并得到改进。
#2
3
Check out this great article at CodeProject
在CodeProject上查看这篇精彩的文章
It's probably way too broad for your specific problem but it will probably give you a good starting point on how to solve it.
对于您的具体问题,它可能过于宽泛,但它可能会为您提供一个如何解决问题的良好起点。
#3
0
I didn't test bellow code, may be there is some bugs, Also I wrote it in textpad may be there are invalid characters, Idea is simple, and I try to use meaningful variables.
我没有测试下面的代码,可能是有一些bug,我在textpad中写的可能是有无效的字符,Idea很简单,我尝试使用有意义的变量。
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
0
A very crude solution would be something like
一个非常粗糙的解决方案就像是
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;}
}
I calculate a worktime in minutes so I can sum more easily using linq
我用分钟计算一个工作时间,所以我可以使用linq更容易地求和
I am also missing specific shift information which I think don't belong with ShiftSet
class
我也缺少我认为不属于ShiftSet类的特定班次信息
Because the employee is not scheduled to work from 7:30 to 8:00, we would not include that time
由于员工未安排在7:30到8:00工作,我们不会包含该时间