2012-04-13 6 views
5

Ho un database che ha le seguenti record in un campo DateTime:Come posso calcolare la media di un campo DateTime con una query LINQ?

2012-04-13 08:31:00.000 
2012-04-12 07:53:00.000 
2012-04-11 07:59:00.000 
2012-04-10 08:16:00.000 
2012-04-09 15:11:00.000 
2012-04-08 08:28:00.000 
2012-04-06 08:26:00.000 

Voglio correre una query LINQ to SQL per ottenere il tempo medio dai record di cui sopra. Ho provato il seguente:

(From o In MYDATA Select o.SleepTo).Average() 

Poiché "SleepTo" è un campo datetime, viene visualizzato un errore su Average(). Se stavo cercando di ottenere la media di dire un numero intero, la query linq sopra funziona.

Cosa devo fare per farlo funzionare per un periodo di tempo?

+0

Hai un valore SleepFrom per caso? – yamen

+0

Proverei a creare il mio metodo di estensione per quello. – frenchie

risposta

1

Il provider LINQ del database non sembra capire come eseguire le medie in date assolute. Il che, se ci pensate, ha senso (la media è una somma divisa per un conteggio - qual è la somma?).

Quindi, se non siete in grado di eseguire il seguente:

(From o In MYDATA Select o.SleepTo).Sum()

allora non sarà in grado di fare anche .Average().

Dal momento che ciò che si desidera è in realtà il tempo medio di SleepTo, è necessario per ottenere solo la componente temporale della data un periodo (meno mezzanotte ora forse) e medio che. Per caso hai SleepFrom?

Nel frattempo, si potrebbe trovare questo post illuminante: LINQ Average TimeSpan?

+0

Ho provato Sum ma non mi piacciono neanche le date. I dati nel mio esempio sono le volte che mi sono svegliato. Sto cercando di ottenere il tempo medio che mi sono svegliato. – Jade

+0

Questo è il mio punto, la somma non funzionerà, quindi anche la media non funzionerà. Il tuo miglior risultato è quello di eliminare il componente del giorno e ottenere il tempo. Trasformalo in un intervallo di tempo da mezzanotte e poi puoi ottenere la media. Questo ti darà il tuo risveglio medio (AM). Vedi il link che ho postato. – yamen

+0

Aggiornato la mia risposta per chiedere informazioni sul fatto che tu abbia 'SleepFrom' (che rende tutto semplice) o se vuoi solo il tempo da mezzanotte? Cioè, vuoi sapere il tempo medio in cui ti alzi o la quantità media che dormi? – yamen

8

Internamente, ogni DateTime è davvero memorizzato come un certo numero di zecche. La proprietà Ticks di un DateTime è definita come il "numero di intervalli di 100 nanosecondi che sono trascorsi dalle 12:00:00 di mezzanotte, 1 gennaio 0001." (Vedi http://msdn.microsoft.com/en-us/library/system.datetime.ticks.aspx)

È possibile convertire i DateTimes in tick, quindi in media, quindi riconvertire in un datetime.

var averageTicks = (long) dates.Select(d => d.Ticks).Average(); 
var averageDate = new DateTime(averageTicks); 

Usando le strutture dati e la formattazione, sarebbe simile a questa:

var averageTicks = (long)(from o in MYDATA select o.SleepTo.Ticks).Average(); 
var averageDate = new DateTime(averageTicks); 

Se si desidera ottenere il tempo medio di ogni valore SleepTo (ignorando la componente data), è possibile ottenere il zecche del proprio tempo:

var averageTicks = (long)(from o in MYDATA select o.SleepTo.TimeOfDay.Ticks).Average(); 
var averageTime = new TimeSpan(averageTicks); 
+0

Questo non darà la risposta desiderata, poiché la domanda si riferisce al tempo * medio * per SleepTo, non al DateTime medio. Raccomanderei seriamente la conversione di SleepTo in TimeSpan da mezzanotte (o persino le zecche da mezzanotte) e poi la media, altrimenti tutte le risposte sono sbagliate. – yamen

+0

L'esempio del codice e l'ultima domanda nel post originale di Jade mi hanno portato a credere che lui o lei stessero chiedendo aiuto per la media di 'DateTime's. Sulla base del tuo suggerimento, @yamen, ho aggiunto un nuovo snippet per calcolare la media dei componenti del tempo. Grazie! –

+0

Buona aggiunta, svalutato! – yamen

4

Qui ci sono un paio di metodi di estensioni che possono aiutare con questo ... C'è un problema centrale, in cui se avete un sacco di DateTimes in un elenco la media di un LINQ del le zecche (long vars) traboccherà.

public static long Average(this IEnumerable<long> longs) 
    { 
     long count = longs.Count(); 
     long mean = 0; 
     foreach (var val in longs) 
     { 
      mean += val/count; 
     } 
     return mean; 
    } 

    public static DateTime Average(this IEnumerable<DateTime> dates) 
    { 
     return new DateTime(dates.Select(x => x.Ticks).Average()); 
    } 
+0

+1. Grazie. Questo è un miglioramento della risposta accettata, quando il numero di elementi è sufficientemente grande. – MickyD

+0

Grazie mille! Bel miglioramento! – klutch1991

+0

Penso che questo possa accumulare un errore dal momento che stai usando una divisione intera per val/count. Prova a usare Media con nuovo [] {3l, 5l, 7l} - la media corretta è 5, ottieni 4. Credo che dovresti usare il doppio per la matematica intermedia. Preferisco anche usare Linq estendendo Linq perché è più difficile da capire :) public static long Average (questo IEnumerable long) { \t \t var count = longs.Count(); \t \t return (long) (longs.Aggregate (0.0, (r, l) => r + = (double) l/count)); } – NetMage