Ява: Как рассчитать среднее число дней через несколько дат, которые являются строками? - PullRequest
0 голосов
/ 09 октября 2019

Я написал программу, которая всегда вычисляет разницу дней между двумя датами. Теперь я хочу подвести итог всех дней различий и разделить их на счетчик, чтобы получить средний день. Кто-нибудь может мне помочь? Есть ли способ даже избежать цикла for-Loop.

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class AVGDateCalculation {
    public static void main (String [] args) throws ParseException{
    String formatted =
            "2014-04-28 ,2014-04-28 ,"
            + "2015-10-26 ,2015-10-30 ,"
            + "2015-07-30 ,2015-07-30 ,"
            + "2015-04-14 ,2015-04-20 ,"
            + "2013-11-14 ,2013-11-18 ,"
            + "2014-04-16 ,2014-04-22 ,"
            + "2014-11-19 ,2014-11-21 ,"
            + "2019-10-01 ,2019-10-01 ";

                String[] parts = formatted.split(",");

                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                int count = 0;
                int a;
                long difference = 0L;
                float daysBetween = 0.00f;
                float averageDays = 0.00f;
                Date dateBefore = null;
                Date dateAfter = null;
                for (a = 0; a<parts.length; a+=1) {
                    dateBefore = sdf.parse(parts[a++]);
                    count++;
                    dateAfter = sdf.parse(parts[a+=0]);
                    difference = dateAfter.getTime() - dateBefore.getTime();
                    daysBetween = (difference / (1000*60*60*24));    
                    averageDays = (count / daysBetween);

                    System.out.println(String.valueOf(dateAfter) + " - " + `String.valueOf(dateBefore));`
                    System.out.println(String.valueOf(dateAfter.getTime()) + " - " + String.valueOf(dateBefore.getTime()));
                    System.out.println(String.valueOf(daysBetween));
                    System.out.println(String.valueOf(averageDays) + " days");
                    System.out.println(String.valueOf(count));
                }

    }
}

Ответы [ 3 ]

3 голосов
/ 09 октября 2019

Я бы предпочел использовать LocalDate вместо SimpleDateFormat, потому что там вы можете легче вычислить разницу и многие другие вещи. Чтобы разделить даты, которые появляются попарно, вы можете использовать регулярное выражение, разделяющее вашу строку при каждой второй запятой.

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.LongSummaryStatistics;
import java.util.function.Function;
import java.util.regex.Pattern;

public class Test{

    public static void main(String[] args){
        String formatted
                = "2014-04-28 ,2014-04-28 ,"
                + "2015-10-26 ,2015-10-30 ,"
                + "2015-07-30 ,2015-07-30 ,"
                + "2015-04-14 ,2015-04-20 ,"
                + "2013-11-14 ,2013-11-18 ,"
                + "2014-04-16 ,2014-04-22 ,"
                + "2014-11-19 ,2014-11-21 ,"
                + "2019-10-01 ,2019-10-01 ";
        //a formater for your date pattern
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        //a function to calculate the date differnce for a given pair of dates of form "2014-04-28 ,2014-04-28"
        Function<String,Long> dateDiff = s ->  ChronoUnit.DAYS.between(
                        LocalDate.parse(s.split(",")[0].trim(), dtf), 
                        LocalDate.parse(s.split(",")[1].trim(), dtf));
        //split your original string at each second ',' with below regex
        LongSummaryStatistics statistics = Pattern.compile("(?<!\\G[\\d -]+),")
                .splitAsStream(formatted)
                .mapToLong(s -> dateDiff.apply(s))
                .summaryStatistics();  
        System.out.println(statistics);
    }
}

Статистика содержит сумму, количество, минимум, максимум и среднее. Если вас интересует только среднее значение, вы также можете вызвать его напрямую

    double average = Pattern.compile("(?<!\\G[\\d -]+),")
                .splitAsStream(formatted)
                .mapToLong(s -> dateDiff.apply(s))
                .average().getAsDouble(); 
3 голосов
/ 09 октября 2019

tl; др

ChronoUnit                               // An enum delineating granularities of time.
.DAYS                                    // `DAYS` is one of the objects pre-defined on that enum.
.between(                                // Calculates elapsed time.
    LocalDate.parse( "2015-10-26" ) ,    // `LocalDate` represents a date-only value, without time-of-day, without time zone.
    LocalDate.parse( "2015-10-30" )      // `LocalDate` by default parses strings that comply with standard ISO 8601 formats.
)                                        // Returns a `long`, the number of days elapsed. Uses Half-Open approach, where the beginning is *inclusive* while the ending is *exclusive*. 

См. Этот код, запущенный на IdeOne.com .

4

Неверный класс

Класс java.util.Date представляет момент в UTC, а не дату. Кроме того, этот ужасный класс был вытеснен несколько лет назад современными java.time классами.

Table of date-time types in Java, both modern and legacy

LocalDate

Класс LocalDate представляет значение только для даты без времени суток и без часовой пояс или смещение от UTC .

Ваши входы соответствуют ISO 8601, поэтому вы можете анализировать напрямую. Нет необходимости определять шаблон форматирования.

LocalDate start = LocalDate.parse( "2015-10-26" ) ;

Рассчитать прошедшее время, используя Period.

Period p = Period.of( start , stop ) ;

Или запросить количество дней.

long days = ChronoUnit.DAYS.between( start , stop ) ;

О java.time

Фреймворк java.time встроен в Java 8 и более поздние версии. Эти классы вытесняют старые классные устаревшие классы даты и времени, такие как java.util.Date, Calendar и & SimpleDateFormat.

Чтобы узнать больше, см. Oracle Tutorial . И поиск переполнения стека для многих примеров и объяснений. Спецификация: JSR 310 .

Проект Joda-Time , теперь в режиме обслуживания , рекомендует перейти на java.time классы.

Вы можете обмениваться java.time объектами напрямую с вашей базой данных. Используйте драйвер JDBC , совместимый с JDBC 4.2 или более поздней версии. Нет необходимости в строках, нет необходимости в java.sql.* классах.

Где получить классы java.time?

  • Java SE 8 , Java SE 9 , Java SE 10, Java SE 11 и более поздние версии - часть стандартного Java API с связанной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и JavaSE 7
    • Большинство функций java.time перенесено в Java 6 & 7 в ThreeTen-Backport .
  • Android
    • Более поздние версии реализации связки Android java.time классы.
    • Для более ранних версий Android (<26) проект <a href="https://github.com/JakeWharton/ThreeTenABP" rel="nofollow noreferrer"> ThreeTenABP адаптируется ThreeTen-Backport (упомянуто выше). См. Как использовать ThreeTenABP… .

ThreeTen-Extra Проект расширяет java.time дополнительными классами. Этот проект является полигоном для возможных будущих дополнений к java.time. Здесь вы можете найти несколько полезных классов, таких как Interval, YearWeek, YearQuarter и more .

1 голос
/ 10 октября 2019

Следуя вашему комментарию под моим первым ответом и предполагая, что у вас всегда есть четное количество дат в вашей исходной строке, вот другой подход.

Кратко резюмируя:

  • разделите ввод по каждой запятой,
  • вычислите разницу для каждой второй пары, повторив цикл for в два шага (i = i+2),
  • сохранить различия в списке,
  • вычислить среднее значение, сложив значения в списке и разделив на размер списка

Надеюсь, это понятно. Не стесняйтесь спрашивать, если что-то не ясно.

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class Test2{

    public static void main(String[] args) throws ParseException {    
            String formatted =    "2014-04-28 ,2014-04-28 ,"
                                + "2015-10-26 ,2015-10-30 ,"
                                + "2015-07-30 ,2015-07-30 ,"
                                + "2015-04-14 ,2015-04-20 ,"
                                + "2013-11-14 ,2013-11-18 ,"
                                + "2014-04-16 ,2014-04-22 ,"
                                + "2014-11-19 ,2014-11-21 ,"
                                + "2019-10-01 ,2019-10-01 ";

            List<Long> diffs = getDifferences(formatted);
            System.out.println(diffs);
            double averageDiff = averge(diffs);
            System.out.println(averageDiff);
    }
    public static List<Long> getDifferences(String input) throws ParseException{
        List<Long> differences = new ArrayList<>();
        String[] dates = input.split(",");
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        for(int i = 0; i<dates.length; i = i+2){
            differences.add(differenceBetween(sdf.parse(dates[i+1]),sdf.parse(dates[i])));
        }
        return differences;
    }
    public static long differenceBetween(Date date1, Date date2){
        long MILLIS_PER_DAY = 24 * 3600 * 1000;
        long msDiff= date1.getTime() - date2.getTime();
        long daysDiff = Math.round(msDiff / ((double)MILLIS_PER_DAY));
        return daysDiff;
    }
    public static double averge(List<Long> diffs){
        double sum = 0;
        for(Long d : diffs){
            sum += d;
        }
        return sum/diffs.size();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...