仅使用LINQ

时间:2018-02-20 19:32:35

标签: c# linq

我只想使用LINQ执行以下操作。

我有一个包含用户进出时间的时间表条目列表。该课程如下:

public class TimeSheetLog
{
   public Guid EmployeeId { get; set; }
   public DateTime ClockInTimeStamp { get; set; }
   public DateTime ClockOutTimeStamp { get; set; }
}

我传递的List<TimeSheetLog>()包含了从年初到现在的所有日志。

我试图计算1月份的总工作时间 - 无论员工如何。另请注意,我有一个名为GetTimeDifferenceInMinutes()的函数,它计算两个日期/时间值之间的分钟数。

这是我目前所拥有的,但我觉得整个事情只能使用LINQ来完成。

public static int GetTotalTimeWorked(List<TimeSheetLog> logs, DateTime startDate, DateTime endDate)
{
   // I'm passing 1/1/2018 for startDate and 1/31/2018 for endDate to this function
   var totalTimeWorkedInMinutes = 0;

   var januaryLogs = logs.Where(x => x.ClockInTimeStamp >= startDate && 
   x.ClockOutTimeStamp <= endDate);

   foreach(var item in januaryLogs)
   {
      totalTimeWorkedInMinutes += GetTimeDifferenceInMinutes(item.ClockInTimeStamp, itemClockOutTimeStamp);
   }

   return totalTimeWorkedInMinutes;
}

5 个答案:

答案 0 :(得分:2)

var logsFilteredByDate = logs.Where(x => x.ClockInTimeStamp >= startDate &&
    x.ClockOutTimeStamp <= endDate);
var totalTimeWorkedInMinutes = logsFilteredByDate.Sum(x => 
    GetTimeDifferenceInMinutes(x.ClockInTimeStamp, x.ClockOutTimeStamp));

或者,将它全部合并到一个查询中,这是不必要的,更难阅读,

var totalTimeWorkedInMinutes = logs.Where(x => x.ClockInTimeStamp >= startDate &&
    x.ClockOutTimeStamp <= endDate)
    .Sum(x => 
        GetTimeDifferenceInMinutes(x.ClockInTimeStamp, x.ClockOutTimeStamp));

答案 1 :(得分:0)

你需要总和

var tot = januaryLogs.Sum(item=>GetTimeDifferenceInMinutes(item.ClockInTimeStamp, itemClockOutTimeStamp));

答案 2 :(得分:0)

你不能在Sum中做Where和Sum并做DateTime Subtract,所以

decimal total = logs.Where(x => x.ClockInTimeStamp >= startDate && x.ClockOutTimeStamp <= endDate).Sum(x.ClockOutTimeStamp.Subtract(x.ClockInTimeStamp).TotalMinutes);

答案 3 :(得分:0)

另一种选择是使用.Aggregate函数。

public static int GetTotalTimeWorked(List<TimeSheetLog> logs, DateTime startDate, DateTime endDate)
{
    var totalTimeWorkedInMinutes = 0;

    return logs.Where(x => x.ClockInTimeStamp >= startDate && x.ClockOutTimeStamp <= endDate)
        .Aggregate(totalTimeWorkedInMinutes, (total, item) => total + GetTimeDifferenceInMinutes(item.ClockInTimeStamp, item.ClockOutTimeStamp));

}

答案 4 :(得分:0)

问题似乎很容易,直到你意识到时间表可能会持续数月。因此,如果有人在1月31日上班并在2月1日结束时, 你必须计算部分时间表 ,这样做是正确的。

这是我的解决方案:

public static class ExtensionMethods
{
    static public double TotalMinutes(this IEnumerable<TimeSheetLog> input, DateTime startPeriod, DateTime endPeriod)
    {
        return TimeSpan.FromTicks
        (
            input
            .Where( a=>
                a.ClockOutTimeStamp >= startPeriod &&
                a.ClockInTimeStamp <= endPeriod
            )
            .Select( a=>
                Math.Min(a.ClockOutTimeStamp.Ticks, endPeriod.Ticks) - 
                Math.Max(a.ClockInTimeStamp.Ticks, startPeriod.Ticks)
            )
            .Sum()
        )
        .TotalMinutes;
    }
}

逻辑:

  1. 查找至少部分与感兴趣的时段重叠的所有时间表。
  2. 将开始时间计算为时间时间或时间段开始时间,以较晚者为准。
  3. 将结束时间计算为时钟输出时间或时段结束时间,以较早者为准。
  4. 将开始和结束时间的差异作为刻度。 Sum()这些。
  5. 要完成所有这些数学运算,我们会将所有时间戳转换为Ticks,因为您无法获取两个日期时间的Max()。我们可以很好地添加滴答,然后在返回之前将总数转换回几分钟。
  6. 测试程序(注意第一个时间表跨越1月和2月):

    public class Program
    {
        static public List<TimeSheetLog> testData = new List<TimeSheetLog>
        {
            new TimeSheetLog
            {
                ClockInTimeStamp = DateTime.Parse("1/1/2018 9:00 am"),
                ClockOutTimeStamp = DateTime.Parse("1/1/2018 5:00 pm")
    
            },
            new TimeSheetLog
            {
                ClockInTimeStamp = DateTime.Parse("1/2/2018 9:00 am"),
                ClockOutTimeStamp = DateTime.Parse("1/2/2018 5:00 pm")
    
            },
            new TimeSheetLog
            {
                ClockInTimeStamp = DateTime.Parse("1/31/2018 6:00 pm"),
                ClockOutTimeStamp = DateTime.Parse("2/1/2018 9:00 am")
    
            },
            new TimeSheetLog
            {
                ClockInTimeStamp = DateTime.Parse("2/3/2018 9:00 am"),
                ClockOutTimeStamp = DateTime.Parse("2/3/2018 5:00 pm")
    
            }
        };
    
    
        public static void Main()
        {
            var startPeriod = new DateTime(2018, 1, 1);
            var endPeriod = new DateTime(2018, 1, 31, 23, 59, 59, 9999); 
            Console.WriteLine( testData.TotalMinutes(startPeriod, endPeriod).ToString("0.00") );
        }
    }
    

    输出:

    1320.00
    

    ......这是正确的。

    See my code on DotNetFiddle