Дней между двумя датами. Где ошибка в датах?

Я пытаюсь рассчитать количество дней между двумя датами. Вот мой код:

public class Main {
    public static void main(String[] args) {
        SimpleDateFormat format = new SimpleDateFormat("dd.MM.yyyy");
        Date date1 = null;
        Date date2 = null;
        String str1 = "01.01.1900";
        String str2 = "16.06.2017";
        try{
            date1 = format.parse(str1);
            date2 = format.parse(str2);
        } catch (Exception e){
            e.printStackTrace();
        }
        long i1 = date2.getTime() - date1.getTime();
        System.out.println(i1/86400000);//milisec to days
    }
}

Результат: 42899 дней.

НО, если мы перепроверим это вычитание в EXCEL, результат будет 42901 введите здесь описание изображения

Пожалуйста, кто-нибудь может объяснить мне, где истинный результат?


person Stanly T    schedule 17.06.2017    source источник
comment
Я не могу более настоятельно рекомендовать использование устаревшего класса java.util.Date. Вместо этого вам следует заглянуть в пакет java.time и найти класс, наиболее подходящий для вашего варианта использования (вероятно, LocalDate в данном случае).   -  person Joe C    schedule 17.06.2017
comment
Вы должны протестировать свой код, используя более близкие даты, например 01.01.1900 и 02.01.1900. Может быть, тогда вы обнаружите, в чем проблема (или, может быть, Excel считает что-то другое, чем вы).   -  person Mateusz Korwel    schedule 17.06.2017
comment
такая же разница в 2 дня   -  person Stanly T    schedule 17.06.2017
comment
результаты моих тестов: 01.01.2017 - 16.06.2017 = (java: 165) (excel: 166), но 01.06.2017 - 16.06.2017 = (java: 15) (excel: 15)   -  person Stanly T    schedule 17.06.2017
comment
Ваше предположение, что в каждом дне 86400000 миллисекунды, является упрощением; это не учитывает переход на летнее время.   -  person Codor    schedule 17.06.2017


Ответы (2)


Java округляет результат при делении целых чисел, поэтому я думаю, что вы потеряли здесь день:

System.out.println(i1/86400000);//milisec to days

После того, как я попробовал Java 8 API, он показывает мне 42900 дней (обратите внимание, что ни Java 8, ни Excel не включают последний день в диапазон):

LocalDate from = LocalDate.of(1900, Month.JANUARY, 1);
LocalDate to = LocalDate.of(2017, Month.JUNE, 16);
long daysBetween = ChronoUnit.DAYS.between(from, to);

Другой день был рассчитан Excel неправильно из-за ошибки, как описано здесь. Итак, отвечая на ваш вопрос: вы потеряли один день при округлении, а еще один день был неправильно добавлен Excel.

person Danylo Zatorsky    schedule 17.06.2017
comment
Неправильно. Excel также не включает дату окончания. Проблема в Excel, который неправильно считает 1900 год високосным. Это не. См.: Есть ли в Excel ошибка, связанная с датами? --- Тем не менее, вы правы в отношении проблемы округления, но вы не не объясняет, почему возникает проблема с округлением, т. е. что это вызвано потерей часов при переходе на летнее время. - person Andreas; 17.06.2017
comment
@Andreas Спасибо, что указали на это - я обновил свой ответ. - person Danylo Zatorsky; 17.06.2017

Используйте Joda Time. Он имеет лучший API, чем то, что доступно в стандартной библиотеке Java. Вот мой код для вашего случая:

package com.example;

import org.joda.time.DateTime;
import org.joda.time.Days;

public class Main{
 public static void main(String[] args) {

    DateTime start = new DateTime(1900, 1, 1, 0, 0, 0, 0);
    DateTime end = new DateTime(2017, 6, 16, 0, 0, 0, 0);

    // calculate  days between two dates 
    int days = Days.daysBetween(start, end).getDays();

    System.out.println("Days = " + days);
 }
}

И результат Days = 42900

person Elvira Parpalac    schedule 17.06.2017
comment
Почему вы звоните minusDays(1)? Это просто для того, чтобы искусственно получить тот же неверный результат, что и в Excel? - person Andreas; 17.06.2017
comment
О, я сожалею об этом. Я чувствую, что был немного небрежным. Спасибо за комментарий! Код поправлю) - person Elvira Parpalac; 17.06.2017
comment
Joda-Time находится в состоянии обслуживания, официальная рекомендация Joda-Time — перейти на java.time. Тем не менее, это лучший выбор, чем давно устаревший java.util.Date. - person Ole V.V.; 17.06.2017