2013-08-12 6 views
6

Mam tablicę obiektów java.util.Date. Próbuję znaleźć średnią.Uzyskaj średnią z dwóch java.util.Date

Na przykład, jeśli mam 2 obiekty daty o 7:40 i 7:50. Powinienem otrzymać obiekt o średniej randce o godzinie 7:45.

Podejście Mam na myśli to nieefektywne:

  1. do pętli wszystkich terminach
  2. różnica znaleźć między 0000 i czas
  3. dodać, że czas diff do całkowitej
  4. divide że przez całkowita liczba
  5. przekształcić ten czas na obiekt daty

Czy jest to łatwiejsza funkcja?

+1

brzmi dobrze, jak o konwersji wszystkie daty do milisekund następnie przyjmując średnią i przekształcenie go z powrotem do daty? (myDate.getTime() + myDate1.getTime())/2 –

+2

Oczekiwanie na żarty ze średniej daty ... ok, nvm. Konwertuj wszystkie obiekty 'Date' na milisekundy, weź średnią, a następnie przekonwertuj z powrotem na obiekt' Date'. – abiessu

+0

Koniec jest już blisko! 2036 wkrótce! – DwB

Odpowiedz

20

Zasadniczo można po prostu dodać "millis od epoki Unix" wszystkich obiektów Date i znaleźć średnią z nich. Teraz trudnym krokiem jest uniknięcie przepełnienia. Dostępne opcje:

  1. Podziel przez znaną ilość (na przykład 1000), aby uniknąć przepełnienia; zmniejsza to dokładność o znaną kwotę (w tym przypadku do drugiej), ale kończy się niepowodzeniem, jeśli masz więcej niż 1000 pozycji.
  2. Podziel każdą wartość miliona według liczby dat, które uśredniasz; to zawsze będzie działać, ale ma trudny do zrozumienia zmniejszenie dokładności
  3. Zastosowanie BigInteger zamiast

Przykładem podejścia 1:

long totalSeconds = 0L; 
for (Date date : dates) { 
    totalSeconds += date.getTime()/1000L; 
} 
long averageSeconds = totalSeconds/dates.size(); 
Date averageDate = new Date(averageSeconds * 1000L); 

przykładem podejścia 3:

BigInteger total = BigInteger.ZERO; 
for (Date date : dates) { 
    total = total.add(BigInteger.valueOf(date.getTime())); 
} 
BigInteger averageMillis = total.divide(BigInteger.valueOf(dates.size())); 
Date averageDate = new Date(averageMillis.longValue()); 
+0

Dobra rada, jest trudniejsza niż się wydaje. – AlexWien

+0

Przez długie sekundy do przepełnienia potrzebujesz milionów (około 7 milionów zrobi to) –

0

Istnieje już odpowiedź tutaj: Sum two dates in Java

Po prostu musisz podsumować wszystkie obiekty z datami, używając getTime(), a następnie podzielić je przez liczbę obiektów i przekonwertować z powrotem na obiekt Date. Gotowe.

+0

Tak, ale to wymaga dzielenia dużych liczb długich. Co, jeśli to się nie uda? – raaj

0

Aby uniknąć przepełnienia w caluclation średniego czasu:

sortuj wg daty;
wartość sklepu z pierwszą datą w time0;

Obliczyć średnią deltaTimes przez odejmowanieg pierwszego czasu0 ze wszystkich czasów. Następnie podsumuj i podziel.

Wynik = new Date(time0 + avgDeltas);

+0

Jak powinny być sortowane daty? wcześniej czy później? –

0

Spróbuj tego. Tutaj każda data konwertuje na długą wartość moja getTime(). To zwróci wartość milisekundy. Następnie możemy kontynuować.

SimpleDateFormat sdf = new SimpleDateFormat("HH:mma"); 
    Date date1=sdf.parse("7:40AM"); 
    Date date2=sdf.parse("7:50AM"); 
    long date1InMilSec=date1.getTime(); 
    long date2InMilSec=date2.getTime(); 
    System.out.println("Average "+sdf.format((date1InMilSec+date2InMilSec)/2)); 
1

Z dużą ilością dat, zsumowanie wszystkich dat razem z pewnością spowoduje przepełnienie.Jeśli chcesz, aby zapobiec, że należy zrobić to w ten sposób (w kodzie pseudo):

var first = dates.getFirst 
var sumOfDifferences = 0 
loop over all dates 
    for each date sumOfDifferences += date - first 
var averageDate = first + sumOfDifferences/countOfDates 

To nigdy nie będzie można uruchomić w przelew.

+0

Nigdy nie mów nigdy ;-) – Sebastian

+1

Oczekiwanie, że to rozwiązanie będzie działać, opiera się na dwóch założeniach: (1) daty zbliżają się do siebie w czasie (2) nie masz dat z bajillionem. Jeśli którekolwiek z tych założeń jest nieważne, może być konieczne użycie BigIntegers. – Gladclef

0

Po java 8 został opublikowany, można użyć

Date avgDate = new Date(LongStream.of(datesAsLongArray).sum()/datesAsLongArray.length * 1000); 
+0

Co ważniejsze w Javie 8 nie używałbyś 'java.util.Date' ... – assylias

Powiązane problemy