C# Linq连接和/或筛选日期时间评估?
我有一个时钟事件列表,问题是我不知道事件是打卡还是打卡。我的班级看起来像这样C# Linq连接和/或筛选日期时间评估?,c#,linq,C#,Linq,我有一个时钟事件列表,问题是我不知道事件是打卡还是打卡。我的班级看起来像这样 private class TimeClock { public string EmployeeID { get; set; } public DateTime ShiftDate { get; set; } public DateTime TimeStamp { get; set; } } 给定一个具体的员工ID和轮班日期,我需要确定他们什么时候上班。这可以通过简单的
private class TimeClock
{
public string EmployeeID { get; set; }
public DateTime ShiftDate { get; set; }
public DateTime TimeStamp { get; set; }
}
给定一个具体的员工ID和轮班日期,我需要确定他们什么时候上班。这可以通过简单的<评估来完成
var allShifts = (from p1 in punches
join p2 in punches
on new { p1.EmployeeID, p1.ShiftDate } equals
new { p2.EmployeeID, p2.ShiftDate }
where p1.TimeStamp < p2.TimeStamp
select new Shift
{
EmployeeID = p1.EmployeeID,
Hours = p2.TimeStamp.Subtract(p1.TimeStamp).TotalHours
}).ToList();
这很有效,但如果员工一天打卡打卡次数超过一次,显然会出现故障。在这种情况下,我希望看到返回两个班次,一个用于第一次打卡,另一个用于第二次打卡
我感谢你的帮助。
Derrick您可以按员工和日期对穿孔进行分组。然后,您可以从每组中选择打孔对和打孔对,并计算总小时数:
from p in punches
group p by new { p.EmployeeID, p.ShiftDate } into g
let punch = g.First()
select new Shift
{
EmployeeID = punch.EmployeeID,
FirstName = punch.FirstName,
LastName = punch.LastName,
TimeClockID = punch.TimeClockID,
Hours = g.OrderBy(p => p.TimeStamp)
.Select((p,i) => new {Punch = p, Index = i})
.GroupBy(x => x.Index / 2)
.Select(inOut => new {
PunchInTime = inOut.First().Punch.TimeStamp,
PunchOutTime = inOut.Last().Punch.TimeStamp
})
.Sum(x => x.PunchOutTime.Subtract(x.PunchInTime).TotalHours)
}).ToList();
以下是选择输入输出对的工作原理
按时间戳显示当前日期的员工订单记录
在{punch,Index}对象上使用punch对象及其在穿孔有序列表中的索引投影每个穿孔组
按索引/2对这些对象进行分组,因此索引是一个整数,则此除法将为两个连续的穿孔生成相同的值,例如,对于索引0、1、2、3、4、5,您将有分组键值0、0、1、1、2、2
从每组两个穿孔计算总小时数的总和注意,inOut是两个匿名对象的分组{Punch,Index}
您可以按员工和日期对穿孔进行分组。然后,您可以从每组中选择打孔对和打孔对,并计算总小时数:
from p in punches
group p by new { p.EmployeeID, p.ShiftDate } into g
let punch = g.First()
select new Shift
{
EmployeeID = punch.EmployeeID,
FirstName = punch.FirstName,
LastName = punch.LastName,
TimeClockID = punch.TimeClockID,
Hours = g.OrderBy(p => p.TimeStamp)
.Select((p,i) => new {Punch = p, Index = i})
.GroupBy(x => x.Index / 2)
.Select(inOut => new {
PunchInTime = inOut.First().Punch.TimeStamp,
PunchOutTime = inOut.Last().Punch.TimeStamp
})
.Sum(x => x.PunchOutTime.Subtract(x.PunchInTime).TotalHours)
}).ToList();
以下是选择输入输出对的工作原理
按时间戳显示当前日期的员工订单记录
在{punch,Index}对象上使用punch对象及其在穿孔有序列表中的索引投影每个穿孔组
按索引/2对这些对象进行分组,因此索引是一个整数,则此除法将为两个连续的穿孔生成相同的值,例如,对于索引0、1、2、3、4、5,您将有分组键值0、0、1、1、2、2
从每组两个穿孔计算总小时数的总和注意,inOut是两个匿名对象的分组{Punch,Index}
如果您稍微调整了换档模式:
public class TimeClock
{
public int EmployeeId { get; set; }
public int TimeClockId { get; set; }
public DateTime TimeStamp { get; set; }
}
public class Shift
{
public TimeClock PunchIn { get; set; }
public TimeClock PunchOut { get; set; }
public int EmployeeId { get; set; }
public bool HasShiftEnded
{
get { return PunchIn != null && PunchOut != null; }
}
public double? DurationInHours
{
get
{
if (HasShiftEnded)
return (PunchOut.TimeStamp - PunchIn.TimeStamp).TotalHours;
return null;
}
}
}
您可以使用以下LINQ查询:
var shifts = punches
.Where (x => x.EmployeeId == 1 )
.OrderBy (x => x.TimeStamp)
.Select ((x, i) => new { Index = i, Punch = x })
.GroupBy (x => x.Index / 2)
.Select (x => x.Select (v => v.Punch))
.Select (x => new Shift
{
EmployeeId = x.ElementAt(0).EmployeeId,
PunchIn = x.ElementAt(0),
PunchOut = x.ElementAtOrDefault(1)
});
以下哪项功能:
按员工id或任何其他标准(如轮班日期)过滤穿孔。
按时间顺序排列筛选的项目
将此列表拆分为包含两个相邻项的多个列表。
对于两个项目的每个列表-创建一个新班次。未加盖PunchOut印章的班次不完整或正在进行中。
以下是一个您可以尝试的方法。如果您稍微调整换档模式:
public class TimeClock
{
public int EmployeeId { get; set; }
public int TimeClockId { get; set; }
public DateTime TimeStamp { get; set; }
}
public class Shift
{
public TimeClock PunchIn { get; set; }
public TimeClock PunchOut { get; set; }
public int EmployeeId { get; set; }
public bool HasShiftEnded
{
get { return PunchIn != null && PunchOut != null; }
}
public double? DurationInHours
{
get
{
if (HasShiftEnded)
return (PunchOut.TimeStamp - PunchIn.TimeStamp).TotalHours;
return null;
}
}
}
您可以使用以下LINQ查询:
var shifts = punches
.Where (x => x.EmployeeId == 1 )
.OrderBy (x => x.TimeStamp)
.Select ((x, i) => new { Index = i, Punch = x })
.GroupBy (x => x.Index / 2)
.Select (x => x.Select (v => v.Punch))
.Select (x => new Shift
{
EmployeeId = x.ElementAt(0).EmployeeId,
PunchIn = x.ElementAt(0),
PunchOut = x.ElementAtOrDefault(1)
});
以下哪项功能:
按员工id或任何其他标准(如轮班日期)过滤穿孔。
按时间顺序排列筛选的项目
将此列表拆分为包含两个相邻项的多个列表。
对于两个项目的每个列表-创建一个新班次。未加盖PunchOut印章的班次不完整或正在进行中。
这是一个你可以试试的方法。我想打孔机的时钟ID应该是递增的。所以最小的一个是第一个在拳,最大的一个是最后一个在拳@AmarDuplantier但OP需要计算总小时数每位员工是否有自己的计时器ID计数器?如果是,则带有奇数ID号的时钟是打卡,而偶数ID号表示打卡。编辑:没关系,看到你的编辑了。TimeClockID是时钟位置的物理指示器,我已经更新了代码,谢谢你到目前为止的想法。我想打孔机的TimeClockID的顺序应该是递增的。所以最小的一个是第一个在拳,最大的一个是最后一个在拳@AmarDuplantier但OP需要计算总小时数每位员工是否有自己的计时器ID计数器?如果是,则带有奇数ID号的时钟是打卡,而偶数ID号表示打卡。编辑:没关系,看到你的编辑了。TimeClockID是时钟位置的物理指示器,我已经更新了代码,谢谢你到目前为止的想法。谢谢你,这是一个巨大的帮助,肯定回答了我的问题。然而,在我的例子中,我简化了小时数的计算,因为我认为它不相关。实际上,它看起来更像Hours=getHoursp1.TimeStamp,p2。TimeStamp@FrumRoll请参见上次编辑:我使用打孔时间和打孔时间向匿名对象添加了投影。你可以调用你的函数,而不是在最后一步简单地减去那些值。你的最终编辑对我有用。小时数不是双倍的,所以我必须为Sum创建一个扩展方法,但它工作得很好。我可能不得不开始更频繁地在GroupBy中思考。再次感谢-德里克谢谢,这是一个巨大的帮助,当然回答了我的问题,因为它被问到。然而,在我的例子中,我简化了小时数的计算,因为我认为它不相关。实际上,它看起来更像Hours=getHoursp1.TimeStamp,p2。TimeStamp@FrumRoll请参见上次编辑:我使用打孔时间和打孔时间向匿名对象添加了投影。你可以打电话
l你的函数,而不是简单地减去最后一步的值。你的最终编辑对我有用。小时数不是双倍的,所以我必须为Sum创建一个扩展方法,但它工作得很好。我可能不得不开始更频繁地在GroupBy中思考。再次感谢-德里克