Проблемы при расчете разницы между днями

Я новичок в программировании, поэтому это может быть глупый вопрос, но я не могу найти никакого решения. Я хочу рассчитать разницу (в днях) между датами. В большинстве случаев это работает, но когда меняется месяц, я получаю странные решения.
Первый пример:
today - 30 сентября 2018 = 78 дней,
today - 31 сентября 2018 = 79 дней (??),
today - 1 октября 2018 = 80 дней
Второй пример:
today - 31 августа 2018 = 49 дней,
today - 1 сентября 2018 = 49 дней

Код

private static int[] abstandTage(GregorianCalendar date1, ArrayList<GregorianCalendar> csvDate)
{
    int[] abstand = new int[csvDate.size()];
    int i = 0;
    while ( i < csvDate.size() )
    {
        long diffInMillis = csvDate.get(i).getTimeInMillis() - date1.getTimeInMillis();
        long tage = diffInMillis / 1000 / 60 / 60 / 24;
        abstand[i] = (int) tage;
        i++ ;
    }

    return abstand;
}

date1 - это предопределенная дата, csvDate - это список с датами. Кто-нибудь может мне помочь?

заранее спасибо Алекс

Лучше не использовать давно устаревший и плохо спроектированный класс GregorianCalendar и лучше позволить библиотечному методу делать вычисления за вас. Например, ChronoUnit.DAYS.between(), передача двух экземпляров LocalDate. Эти классы находятся в java.time, современный API даты и времени Java.

Ole V.V. 13.07.2018 13:02

Я бы рекомендовал программировать против интерфейса, изменив подпись на int[] abstandTage(GregorianCalendar date1, List<GregorianCalendar> csvDate), подробнее об этом здесь.

Glains 13.07.2018 13:05

Результаты неожиданные, согласен. С сегодняшнего дня (13 июля) по 30 сентября должно быть 79 дней. До 1 сентября должно быть 50 дней. Похоже, сентябрьские дни неправильные? Как вы создаете объекты GregorianCalendar? Не могли бы вы создать минимальный, полный и проверяемый пример, пожалуйста?

Ole V.V. 13.07.2018 13:06

Возможный дубликат Разница в днях между двумя датами на Java?

Peter Walser 13.07.2018 17:10

Возможный почти дубликат Создание объекта даты Java из года, месяца, дня

Ole V.V. 14.07.2018 11:36
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
5
62
3

Ответы 3

Массив различий можно рассчитать с помощью ChronoUnit. Вы также можете использовать поток для дальнейшего упрощения вашей реализации:

private static int[] abstandTage(GregorianCalendar date1,
          ArrayList<GregorianCalendar> csvDate) {

    return csvDate.stream()
            .mapToInt(csvdate -> (int) 
               ChronoUnit.DAYS.between(date1.toZonedDateTime(), csvdate.toZonedDateTime()))
            .toArray();
}

Если мы не можем избежать класса GregorianCalendar, это правильный путь. Еще лучше, если бы вызывающий абонент передал LocalDate или другой современный класс даты и времени.

Ole V.V. 13.07.2018 13:03

Это произойдет, если вы создадите свои объекты GregorianCalendar, например, new GregorianCalendar(2018, 7, 13) для 13 июля. GregorianCalendar использует странную нумерацию месяцев, поэтому вы не получите 13 июля.

Решение состоит в том, чтобы выбросить этот давно устаревший и плохо спроектированный класс и создать свои даты, используя, например, LocalDate.of(2018, 7, 13) или даже лучше, LocalDate.of(2018, Month.JULY, 13). Затем используйте ChronoUnit.DAYS.between для определения количества дней между датами.

Ссылка на сайт:Учебник Oracle: Дата и время объясняет, как использовать java.time, современный API даты и времени Java.

Благодаря вашему комментарию (странная нумерация) я нашел решение. Тем не менее, я собираюсь попробовать способ, который вы предложили здесь, с Chronounit. Спасибо за ваши старания! Очень признателен.

dribble290 13.07.2018 13:51

@ dribble290 Старые унаследованные классы даты и времени действительно представляют собой чертовски ужасный беспорядок. Sun, Oracle и JCP по какой-то причине согласились заменить их на java.time. Собственно, по причинам многие. Вы не пожалеете, что приняли java.time.

Basil Bourque 14.07.2018 06:34

Как упоминалось выше, вам нужно будет использовать здесь LocalDate:

SimpleDateformat sdf = new SimpleDateFormat("yyyyMMdd");
Date date1 = sdf.parse("20180713);
Date date2 = sdf.parse("20180930");
LocalDate startDate = 
date1.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
LocalDate endDate = 
date2.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
long days = ChronoUnit.DAYS.between(startDate, endDate);
return days;

Преобразование с григорианского на дату выполняется с помощью:

Date newDate = new Date(date1.getTime());

Спасибо за желание внести свой вклад. Да, для LocalDate´, but when you can use LocalDate` от java.time, не вижу никаких причин для использования старомодного Date или печально известного проблемного SimpleDateFormat. Используйте исключительно java.time. Тоже проще.

Ole V.V. 13.07.2018 18:58

Как отмечает Оле В.В. прокомментировал, ужасно неприятные старые классы даты и времени, такие как java.util.Date и java.text.SimpleDateFormat, теперь являются наследие, вытесненными классами java.time, встроенными в Java 8 и более поздних версий. См. Руководство от Oracle. Не смешивайте устаревшие классы были полностью вытеснены java.time, поэтому нет необходимости когда-либо смешивать.

Basil Bourque 14.07.2018 06:29

Другие вопросы по теме