2013-08-12 3 views
6

У меня есть массив объектов java.util.Date. Я пытаюсь найти среднее.Получить среднее из двух java.util.Date

Например, если у меня есть 2 объекта с 7:40 до 7:50 утра. Я должен получить объект средней даты 7:45 утра.

Подход, который я имею в виду неэффективен:

  1. цикла через все даты
  2. разница находки между 0000 и временем
  3. добавить, что время диф к общим
  4. разделяйте что к общее кол-во
  5. конвертировать это время на объект объекта

Есть ли более простая функция для этого?

+1

звучит хорошо, как о преобразовании всех дат в миллисекунды затем усредняя и преобразования его обратно в дату? (myDate.getTime() + myDate1.getTime())/2 –

+2

В ожидании шуток средней оценки ... ok, nvm. Преобразуйте все объекты 'Date' в миллисекунды, возьмите среднее, а затем конвертируйте обратно в объект' Date'. – abiessu

+0

Конец близок! 2036 скоро! – DwB

ответ

20

Ну, в принципе, вы можете просто добавить «миллионы с эпохи Unix» всех объектов и найти среднее значение из них. Теперь сложный бит избегает переполнения. Возможные варианты:

  1. Разделите на известное количество (например, 1000), чтобы избежать переполнения; это уменьшает точность на известную сумму (в этом случае на вторую), но будет терпеть неудачу, если у вас более 1000 позиций.
  2. Разделите каждое значение миллиса на количество дат, которые вы усредняете; это всегда будет работать, но имеет жесткий для понимания снижения точности
  3. Использование BigInteger вместо

Пример подхода 1:

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

Примером подхода 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

хорошая точка, более плотная, чем кажется. – AlexWien

+0

В течение долгих секунд до переполнения вам понадобятся миллионы (около 7 миллионов сделают это) –

0

Здесь уже есть ответ: Sum two dates in Java

Вам просто нужно суммировать все свои объекты даты с помощью getTime(), а затем разделить его на количество объектов и преобразовать их обратно в объект Date. Готово.

+0

Да, но это связано с разделением больших длинных чисел. Что, если это испортится? – raaj

0

Чтобы избежать переполнения в caluclation среднего времени:

сортировать по дате;
хранить стоимость первой даты в time0;

Caluclate среднее значение deltaTimes путем вычитанияg первый раз0 из всех времен. Затем подведите итоги и разделите.

Результат = new Date(time0 + avgDeltas);

+0

как сортировать даты? раньше или позже или наоборот? –

0

Попробуйте это. Здесь каждый день конвертируется в длинное значение моего getTime(). Это вернет значение mil-second. Тогда мы можем продолжить.

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

С большим количеством дат, взяв сумму всех дат вместе, безусловно, перейдет в переполнение.Если вы хотите, чтобы предотвратить, что вы должны сделать это так (в псевдокоде):

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

Это никогда не заставит вас работать в перелив.

+0

Никогда не говорите никогда ;-) – Sebastian

+1

Ожидание, что это решение будет работать, основано на двух предположениях: (1) даты близки друг к другу по времени (2) у вас нет дат на байон. Если одно из этих допущений недействительно, возможно, вам придется использовать BigIntegers. – Gladclef

0

После того, как Java 8 опубликован, вы можете использовать

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

Самое главное, что с Java 8 вы не будете использовать 'java.util.Date' ... – assylias

Смежные вопросы