使用 group by 时如何对 Linq 中两个日期时间之间的减法时间跨度求和?

How to sum Timespan of subtraction between two datetimes in Linq when using group by?

我的物品具有以下属性:

public int ClientId {get;set;}
public DateTime StartDateTime{get;set;}
public DateTime EndDateTime{get;set;}

我想用 group by 计算每个客户的所有日期时间之间的差异总和,但是这个:

  var retVal  = (from t items group t by ClientId  into z     
                              select new
                              {
                                  ClientId = z.Key,
                                  TimeSpanClientTotal = z.Sum(h => (h.EndDateTime - h.StartDateTime))
                                  }).ToList();

不起作用,因为 Sum 不适用于 TimeSpan ,这是两个 DateTime 对象之间的差异的 return 值。

关于如何获得每个客户端的总时间跨度的任何建议?

谢谢

您可以使用.TotalMilliseconds 属性

var retVal  = (from t items group t by ClientId  into z     
                              select new
                              {
                                  ClientId = z.Key,
                                  TimeSpanClientTotal = z.Sum(h => (h.EndDateTime - h.StartDateTime).TotalMilliseconds)
                                  }).ToList();

你可以这样写:

 h.EndDateTime.Subtract(h.StartDateTime).TotalDays();

Enumerable.Sum 只是您在 IEnumerable 上调用的扩展方法。它没有什么特别之处,因此您可以轻松创建另一种扩展方法来计算时间跨度:

static class TimeSpanExtensions
{
    public static TimeSpan Sum<TSource>(this IEnumerable<TSource> enumerable,
                                             Func<TSource,TimeSpan?> func )
    {
        return enumerable.Aggregate(TimeSpan.Zero, (total, it) =>
                                                    total+=(func(it)??TimeSpan.Zero);
    }
}

假设您的 class 定义是

class Record
{
    public int ClientId { get; set; }
    public DateTime StartDateTime { get; set; }
    public DateTime EndDateTime { get; set; }

    public Record(int clientId, DateTime startDateTime, DateTime endDateTime)
    {
        ClientId = clientId;
        StartDateTime = startDateTime;
        EndDateTime = endDateTime;
    }
}

您可以编写与数字类型相同的代码:

var items = new[] {
    new Record(1, DateTime.Now, DateTime.Now.AddHours(1)),
    new Record(1, DateTime.Now, DateTime.Now.AddHours(1)),
    new Record(1, DateTime.Now, DateTime.Now.AddHours(1))};
var total=items.Sum(h=>(h.EndDateTime-h.StartDateTime));

var grouped= (from t in items
                group t by t.ClientId into z
                select new
                {
                    ClientId = z.Key,
                    TimeSpanClientTotal = z.Sum(h => (h.EndDateTime - h.StartDateTime))
                }).ToList();

也可以直接使用Enumerable.Aggregate

var total= items.Aggregate(TimeSpan.Zero, (current, it) => 
                               current += (it.EndDateTime-it.StartDateTime));

代码可能更丑陋,但您可以做的不仅仅是简单的加法。

就我而言,所有建议的解决方案均无效。它们导致了与 LINQ 限制相关的错误。所以,我的解决方法是这样的:

var appointments = (from apps in DbContext.ClientAppointments
                           where apps.StartDate.Value.Date == date.Date
                           select new
                           {
                               SpecialistId = apps.SpecialistId,
                               Duration = (apps.EndDate.Value - apps.StartDate.Value).TotalSeconds
                           }).ToList();

        var result = (from apps in appointments
                     group apps by apps.SpecialistId into g
                     select new AppointmentsDurationDailyDto
                      {
                          SpecialistId = g.Key ?? 0,
                          Date = date.Date,
                          Duration = g.Sum(apps => apps.Duration)
                      }).ToList();

在此解决方案中,首先 .ToList(); 对在客户端上进行下一个分组语句很重要。如果您需要获得 TimeSpan Duration,您可以使用 TimeSpan.FromSeconds(Duration)

轻松将其转换回来