2013-05-22 8 views
11

Se ho un array di valori DateTime:Come trovare una data/tempo medio nella matrice di valori DateTime

List<DateTime> arrayDateTimes; 

Qual è il modo per trovare il DateTime media tra di loro?

Per esempio, se ho:

2003-May-21 15:00:00 
2003-May-21 19:00:00 
2003-May-21 20:00:00 

la media dovrebbe essere:

2003-May-21 18:00:00 
+2

+1 bella domanda. Vedi questo http://42zone.blogspot.com/2011/09/c-how-to-calculate-multiple-datetime.html, appena testato e funziona con oltre 38.000 date. – Habib

+0

nota che alcune risposte preservano le informazioni sul fuso orario e altre no .. – Cel

risposta

9

Se avete un grande elenco è possibile utilizzare sotto metodo

var count = dates.Count; 
double temp = 0D; 
for (int i = 0; i < count; i++) 
{ 
    temp += dates[i].Ticks/(double)count; 
} 
var average = new DateTime((long)temp); 
+6

Lancia un'eccezione di overflow con una lista grande. –

+0

** date [i] .Ticks/count ** restituirà 0 se count> Ticks – Uzzy

+0

Console.WriteLine (ticks/(ticks + 1)); Console.WriteLine (ticks/long.MaxValue); Cosa verrebbe stampato? – Uzzy

0
class Program 
{ 
    static void Main(string[] args) 
    { 
     List<DateTime> dates = new List<DateTime>(){ 
     new DateTime(2003, 5, 21, 16, 0, 0), new DateTime(2003, 5, 21, 17, 0, 0), 
     new DateTime(2003, 5, 21, 18, 0, 0), new DateTime(2003, 5, 21, 19, 0, 0), 
     new DateTime(2003, 5, 21, 20, 0, 0), new DateTime(2003, 5, 21, 16, 0, 0), 
     new DateTime(2003, 5, 21, 17, 0, 0), new DateTime(2003, 5, 21, 18, 0, 0), 
     new DateTime(2003, 5, 21, 19, 0, 0), new DateTime(2003, 5, 21, 20, 0, 0), 
     new DateTime(2003, 5, 21, 16, 0, 0), new DateTime(2003, 5, 21, 17, 0, 0), 
     new DateTime(2003, 5, 21, 18, 0, 0), new DateTime(2003, 5, 21, 19, 0, 0), 
     new DateTime(2003, 5, 21, 20, 0, 0), new DateTime(2003, 5, 21, 16, 0, 0), 
     new DateTime(2003, 5, 21, 18, 0, 0), new DateTime(2003, 5, 21, 19, 0, 0), 
     new DateTime(2003, 5, 21, 20, 0, 0), new DateTime(2003, 5, 21, 16, 0, 0), 
     new DateTime(2003, 5, 21, 18, 0, 0), new DateTime(2003, 5, 21, 19, 0, 0), 
     new DateTime(2003, 5, 21, 20, 0, 0), new DateTime(2003, 5, 21, 16, 0, 0), 
     new DateTime(2003, 5, 21, 18, 0, 0), new DateTime(2003, 5, 21, 19, 0, 0), 
     new DateTime(2003, 5, 21, 20, 0, 0), new DateTime(2003, 5, 21, 16, 0, 0), 
     new DateTime(2003, 5, 21, 18, 0, 0), new DateTime(2003, 5, 21, 19, 0, 0), 
     new DateTime(2003, 5, 21, 20, 0, 0), new DateTime(2003, 5, 21, 16, 0, 0), 
     new DateTime(2003, 5, 21, 18, 0, 0), new DateTime(2003, 5, 21, 19, 0, 0), 
     new DateTime(2003, 5, 21, 20, 0, 0), new DateTime(2003, 5, 21, 16, 0, 0), 
     new DateTime(2003, 5, 21, 18, 0, 0), new DateTime(2003, 5, 21, 19, 0, 0), 
     new DateTime(2003, 5, 21, 20, 0, 0), new DateTime(2003, 5, 21, 16, 0, 0), 
    }; 

     var averageDate = dates.Average(); 

     Console.WriteLine(averageDate); 

     Console.ReadKey(); 
    } 

} 

public static class Extensions 
{ 
    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

Ovviamente non lo faccio con 3 valori :) Il tuo metodo traboccherà con circa 20 date. – c00000fd

+0

@ c00000fd: 40 datetimes e un metodo di estensione dopo, non c'è più overflow. –

+1

Sì, grazie. Anche se è già stato suggerito da @Damith sopra. – c00000fd

5

Questo non dovrebbe eccedere, presuppone il datetim es sono ordinati però:

var first = dates.First().Ticks; 
var average = new DateTime(first + (long) dates.Average(d => d.Ticks - first)); 

Quanto sopra, infatti, trabocca con elenchi più grandi e spazi vuoti più ampi. Penso che potresti usare i secondi per il migliore intervallo . (di nuovo, ordinati per primi) Inoltre, questo potrebbe non essere il metodo più performante, ma comunque completato con date 10M relativamente veloci per me. Non sono sicuro che sia più facile da leggere o meno, YYMV.

var first = dates.First(); 
var average = first.AddSeconds(dates.Average(d => (d - first).TotalSeconds)); 
+0

Non sono sicuro di seguirlo. Le zecche sono di tipo lungo. Un segno di spunta futuro, meno un segno di spunta passato, darà un numero relativamente piccolo, e non dovrebbe mai avere la possibilità di traboccare. – neouser99

+0

Hmm. Sì, potresti avere un punto. Fammi controllare ... – c00000fd

+0

Penso che sia un'opzione piuttosto buona. Hai bisogno di testare per essere sicuro :) –

0

Fonte: Tratto da Here e modificato un po '.

List<DateTime> dates = new List<DateTime>(); 
//Add dates 
for (int i = 1; i <= 28; i++) //days 
    for (int j = 1; j <= 12; j++) //month 
     for (int k = 1900; k <= 2013; k++) //year 
      dates.Add(new DateTime(k, j, i, 1, 2, 3)); //over 38000 dates 

allora si può fare:

var averageDateTime = DateTime 
          .MinValue 
          .AddSeconds 
          ((dates 
           .Sum(r => (r - DateTime.MinValue).TotalSeconds)) 
            /dates.Count); 
Console.WriteLine(averageDateTime.ToString("yyyy-MMM-dd HH:mm:ss")); 

uscita in: 1956-Dec-29 06:09:25

Originariamente il codice da questo articolo è stato come:

double totalSec = 0; 
for (int i = 0; i < dates.Count; i++) 
{ 
    TimeSpan ts = dates[i].Subtract(DateTime.MinValue); 
    totalSec += ts.TotalSeconds; 
} 
double averageSec = totalSec/dates.Count; 
DateTime averageDateTime = DateTime.MinValue.AddSeconds(averageSec); 
1

Il codice:

è sbagliato. Media = (x1 + x2 + ... xn)/N non (x1/N + x2/N + ... XN/N)

Prova:

var avg=new DateTime((long)dates.Select(d => d.Ticks).Average()); 
Problemi correlati