TL; DR
Метод compareTo
не предназначен для этого использования.
Он должен быть индикатором порядка, а не показать разницу во времени.
Решение загадки
Чтобы лучше это понять, можно взглянуть на исходный код LocalDate
.
В любой IDE вы можете выбрать "Go To => Реализация "для просмотра исходного кода.
public int compareTo(ChronoLocalDate other) {
return other instanceof LocalDate ? this.compareTo0((LocalDate)other) : super.compareTo(other);
}
int compareTo0(LocalDate otherDate) {
int cmp = this.year - otherDate.year;
if (cmp == 0) {
cmp = this.month - otherDate.month;
if (cmp == 0) {
cmp = this.day - otherDate.day;
}
}
return cmp;
}
Из приведенного выше исходного кода вы можете узнать, что метод compareTo
не возвращает разницу между датой в днях, а скорее разница между датами в первом параметре, который имеет разницу (это могут быть годы, месяцы или дни).
Какова цель compareTo
Методы
Чтобы понять вышеприведенный код и его назначение,
нужно немного понять, как работает сравнение в Java .
Java Класс LocalDate
реализует ChronoLocalDate
, который является сопоставимым объектом.
Это означает, что этот объект способен сравнивать себя с другим объектом.
Для этого сам класс должен реализовывать интерфейс java.lang.Comparable
для сравнения своих экземпляров.
Как описано в документации по API Java :
Этот интерфейс требует полного упорядочения на объектах каждого класса, который его реализует. Это упорядочение называется естественным упорядочением класса, а метод CompareTo класса называется его естественным методом сравнения.
Более того, подробности метода compareTo
следующие: 1045 *
Сравнивает этот объект с указанным объектом для заказа.
Возвращает отрицательное целое число, ноль или положительное целое число, так как этот объект меньше чем , равно или больше указанного объекта.
Это означает, что для того, чтобы сравнение сработало, нам нужно вернуть целое число, соответствующее приведенному выше правилу. Следовательно, само число не имеет никакого значения, а не является указанием «порядка» объектов. Вот почему метод, как показано выше, не рассчитывает разницу в днях, а скорее ищет непосредственное указание на естественный порядок объектов: сначала в годах, затем в месяцах, а в конце в днях.
Когда вы сравнивали даты с другим монтированием - метод показывал только это.
То же самое применимо, если вы сравниваете дату в 2020 году и дату в 2018 году - в результате вы получите 2 / -2.
Как измерять разницу данных
Мы обнаружили, что compareTo
не предназначен для использования в качестве инструмента измерения разности дат.
Вы можете использовать либо Period
или ChronoUnit
, в зависимости от ваших потребностей.
Из Java Учебник по периоду и продолжительности :
ChronoUnit
ChronoUnit
enum, обсуждаемый во временном пакете, определяет единицы измерения, используемые для измерения времени.
Метод ChronoUnit.between
полезен, когда вы хотите измерить количество времени только в одной единице времени, например днях или секундах.
Метод Между работает со всеми временными объектами, но возвращает сумму только в одной единице.
Период
Чтобы определить количество времени со значениями на основе даты ( годы, месяцы, дни), используйте класс Period
.
Класс Period
предоставляет различные методы get, такие как getMonths
, getDays
и getYears
, чтобы можно было извлечь количество время от периода.
Общий период времени представлен всеми ree единицы вместе: месяцы, дни и годы.
Чтобы представить количество времени, измеренное в одной единице времени, например днях, вы можете использовать метод ChronoUnit.between
.
Вот фрагмент кода, демонстрирующий использование упомянутых выше методов:
jshell> import java.time.LocalDate;
jshell> LocalDate darwinDay = LocalDate.of(2020, 2, 12);
darwinDay ==> 2020-02-12
jshell> LocalDate leapDay = LocalDate.of(2020, 2, 29);
leapDay ==> 2020-02-29
jshell> leapDay.compareTo(darwinDay);
==> 17
jshell> import java.time.Period;
jshell> Period.between(darwinDay, leapDay).getDays();
==> 17
jshell> import java.time.temporal.ChronoUnit;
jshell> ChronoUnit.DAYS.between(darwinDay, leapDay);
==> 17
jshell> LocalDate now = LocalDate.of(2020, 3, 28);
now ==> 2020-03-28
jshell> LocalDate yearAgo = LocalDate.of(2019, 3, 28);
yearAgo ==> 2019-03-28
jshell> yearAgo.compareTo(now);
==> -1
jshell> Period.between(yearAgo, now).getDays();
==> 0
jshell> ChronoUnit.DAYS.between(yearAgo, now);
==> 366