Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I have items with the properties :

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

And I want to calculate the total of the difference between all the datetimes of each client with group by , but this :

  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();

Doesn't work since Sum doesn't work well for TimeSpan , which is the return value of the difference between two DateTimes object .

Any suggestion how can I get the total TimeSpan of each client ?

Thanks

like image 286
JAN Avatar asked May 28 '15 06:05

JAN


1 Answers

Enumerable.Sum is just an extension method you call on an IEnumerable. There is nothing special to it so you can easily create another extension method that sums timespans:

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);
    }
}

Assuming your class definition is

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;
    }
}

You can write the same code you would for the numeric types:

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();

You can also use Enumerable.Aggregate directly:

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

The code can be uglier but you can do a lot more than simple addition.

like image 183
Panagiotis Kanavos Avatar answered Nov 04 '22 18:11

Panagiotis Kanavos