Java 8: разница между двумя LocalDateTime в нескольких единицах


266

Я пытаюсь вычислить разницу между двумя LocalDateTime.

Вывод должен быть в формате y years m months d days h hours m minutes s seconds. Вот что я написал:

import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.ZoneId;

public class Main {

    static final int MINUTES_PER_HOUR = 60;
    static final int SECONDS_PER_MINUTE = 60;
    static final int SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR;

    public static void main(String[] args) {
        LocalDateTime toDateTime = LocalDateTime.of(2014, 9, 9, 19, 46, 45);
        LocalDateTime fromDateTime = LocalDateTime.of(1984, 12, 16, 7, 45, 55);

        Period period = getPeriod(fromDateTime, toDateTime);
        long time[] = getTime(fromDateTime, toDateTime);

        System.out.println(period.getYears() + " years " + 
                period.getMonths() + " months " + 
                period.getDays() + " days " +
                time[0] + " hours " +
                time[1] + " minutes " +
                time[2] + " seconds.");


    }

    private static Period getPeriod(LocalDateTime dob, LocalDateTime now) {
        return Period.between(dob.toLocalDate(), now.toLocalDate());
    }

    private static long[] getTime(LocalDateTime dob, LocalDateTime now) {
        LocalDateTime today = LocalDateTime.of(now.getYear(),
                now.getMonthValue(), now.getDayOfMonth(), dob.getHour(), dob.getMinute(), dob.getSecond());
        Duration duration = Duration.between(today, now);

        long seconds = duration.getSeconds();

        long hours = seconds / SECONDS_PER_HOUR;
        long minutes = ((seconds % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE);
        long secs = (seconds % SECONDS_PER_MINUTE);

        return new long[]{hours, minutes, secs};
    }
}

Вывод, который я получаю 29 years 8 months 24 days 12 hours 0 minutes 50 seconds. Я проверил свой результат с этого сайта (со значениями 12/16/1984 07:45:55и 09/09/2014 19:46:45). Следующий скриншот показывает результат:

Конвертер эпох

Я вполне уверен, что поля после значения месяца неправильно в моем коде. Любое предложение будет очень полезным.

Обновить

Я проверил свой результат с другого сайта, и полученный результат отличается. Вот оно: Рассчитайте продолжительность между двумя датами (результат: 29 лет, 8 месяцев, 24 дня, 12 часов, 0 минут и 50 секунд).

Обновить

Поскольку я получил два разных результата с двух разных сайтов, мне интересно, является ли алгоритм моих расчетов законным или нет. Если я использую следующие два LocalDateTimeобъекта:

LocalDateTime toDateTime = LocalDateTime.of(2014, 9, 10, 6, 40, 45);
LocalDateTime fromDateTime = LocalDateTime.of(1984, 12, 16, 7, 45, 55);

Тогда выходной: 29 years 8 months 25 days -1 hours -5 minutes -10 seconds.

По этой ссылке так и должно быть 29 years 8 months 24 days 22 hours, 54 minutes and 50 seconds. Поэтому алгоритм должен обрабатывать и отрицательные числа.

Обратите внимание, что вопрос не в том, какой сайт дал мне какой результат, мне нужно знать правильный алгоритм и иметь правильные результаты.


Просто предположение, но может Period.between()применить округление?
Томас

3
Я только что посмотрел на код еще раз, и кажется, что веб-сайт не так (Попробуйте рассчитать самостоятельно). Если вы опустите дату, то есть разницу в году, месяце и дне, вы получите время начала 7:45:55и время окончания 19:46:45(или 7:46:45PM). Таким образом, разница между этими двумя значениями составляет 12 часов, 0 минут и 50 секунд, а не 23 часа, 34 минуты и 12 секунд. Таким образом, ваш фактический расчет кажется верным, по крайней мере, в части времени.
Томас

1
Интересное явление на этом сайте: добавьте 10 лет к дате начала, а разница в часах изменится с 23 на 8 - это, безусловно, признак ошибки.
Томас

8
Обратите внимание, что, поскольку LocalDateTimeнет часового пояса, не может быть уникального ответа. Даже если вы предполагаете, что начальный и конечный часовые пояса совпадают, в некоторых зонах даты, такие как 2014-09-09, будут в летнее или летнее время, а в других - нет. Это может скинуть вещи на час. Таким образом, вычисление разницы со вторым не имеет смысла, если это не разрешено.
Стюарт Маркс

2
Понимаете ли вы, что использование LocalDateTimeдает нереальные результаты, поскольку в этом классе намеренно отсутствует какое-либо понятие о часовом поясе или смещении от UTC? Для реальных значений, назначить временную зону с помощью ZoneIdдля использования ZonedDateTime.
Базилик Бурк

Ответы:


163

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

К счастью, у классов даты и времени есть много вспомогательных методов, которые до некоторой степени упрощают это. Вот способ вычислить разницу, хотя и не обязательно самый быстрый:

LocalDateTime fromDateTime = LocalDateTime.of(1984, 12, 16, 7, 45, 55);
LocalDateTime toDateTime = LocalDateTime.of(2014, 9, 10, 6, 40, 45);

LocalDateTime tempDateTime = LocalDateTime.from( fromDateTime );

long years = tempDateTime.until( toDateTime, ChronoUnit.YEARS );
tempDateTime = tempDateTime.plusYears( years );

long months = tempDateTime.until( toDateTime, ChronoUnit.MONTHS );
tempDateTime = tempDateTime.plusMonths( months );

long days = tempDateTime.until( toDateTime, ChronoUnit.DAYS );
tempDateTime = tempDateTime.plusDays( days );


long hours = tempDateTime.until( toDateTime, ChronoUnit.HOURS );
tempDateTime = tempDateTime.plusHours( hours );

long minutes = tempDateTime.until( toDateTime, ChronoUnit.MINUTES );
tempDateTime = tempDateTime.plusMinutes( minutes );

long seconds = tempDateTime.until( toDateTime, ChronoUnit.SECONDS );

System.out.println( years + " years " + 
        months + " months " + 
        days + " days " +
        hours + " hours " +
        minutes + " minutes " +
        seconds + " seconds.");

//prints: 29 years 8 months 24 days 22 hours 54 minutes 50 seconds.

Основная идея заключается в следующем: создать временную дату начала и завершить полные годы. Затем скорректируйте эту дату по количеству лет, чтобы начальная дата была меньше года после окончания. Повторите это для каждой единицы времени в порядке убывания.

Наконец, отказ от ответственности : я не учел разные часовые пояса (обе даты должны быть в одном часовом поясе), а также не проверял / не проверял, как переход на летнее время или другие изменения в календаре (например, изменения часового пояса в Самоа) повлиять на этот расчет. Так что используйте с осторожностью.


1
У вас та же самая основная идея, поэтому мое возражение, но, пожалуйста, попробуйте использовать тот же ввод, иначе другой результат сбивает с толку.
Мено Хохшильд

@MenoHochschild он является тот же входом, просто взят из обновлений , где OP имеет проблемы с отрицательным разом. ;)
Томас

1
Хороший алгоритм, но неправильный тип (см. Заявление Томаса об отказе от ответственности). Перед выполнением расчета необходимо преобразовать переменные LocalDateTime в ZonedDateTime, например, используя часовой пояс по умолчанию (или любой часовой пояс, который вам нужен): ZonedDateTime fromZonedDateTime = fromDateTime.atZone (ZoneId.systemDefault ());
Тристан

2
@Thomas Ваш пример также использует Java 8 - и вопрос помечен как java-8. На самом деле ваш пример даже использует ChronoUnit:), но делает работу "вручную".
Евгений Бересовский

3
@EugeneBeresovsky о да, ты прав. Полностью пропустил это;) - Кроме того, вам все равно придется вычесть более крупные единицы из интервала, поскольку, например long minutes = ChronoUnit.MINUTES.between(fromDate, toDate);, вернет число больше 59 для любого интервала не менее 1 часа - и это не то, что хочет ОП. Принимая это во внимание, вы не сможете просто сделать 6 звонков ChronoUnit#between()и сделать это.
Томас

503

Я нашел лучший способ сделать это с ChronoUnit.

long minutes = ChronoUnit.MINUTES.between(fromDate, toDate);
long hours = ChronoUnit.HOURS.between(fromDate, toDate);

Дополнительная документация здесь: https://docs.oracle.com/javase/tutorial/datetime/iso/period.html


8
Я не вижу реального улучшения. По сравнению с принятым ответом Томаса, вы просто замените tempDateTime.until( toDateTime, ChronoUnit.YEARS)на ChronoUnit.YEARS.between(fromDate, toDate). Но важные дополнительные строки, такие как tempDateTime.plusYears( years )и т. Д., Полностью отсутствуют в вашем ответе, поэтому это не помогает ОП. Полный алгоритм имеет значение!
Мено Хохшильд

9
Мне это нравится больше, поскольку оно более лаконично и более читабельно. Это лучший способ найти разницу между двумя датами.
Сомайя Кумбера

7
@SomaiahKumbera Нет, вы полностью упускаете критическую точку. ОП не хочет длительности только в одной единице, но в нескольких единицах , и поэтому этот ответ вообще не является реальным ответом. Озабоченность ОП просто не рассматривается. Пожалуйста, будьте любезны, прочитайте еще раз вопрос. (Похоже, многие авторы неправильно поняли вопрос).
Мено Хохшильд

126
@MenoHochschild, я думаю, что на самом деле ты упустил критическую точку. ОП получила ответ более года назад. 36 тысяч человек, которые рассматривают этот вопрос, не заботятся о конкретном вопросе ОП. Их привел Google, и мой ответ дал им то, что они искали - чистое и простое решение для получения разницы между двумя датами.
Сатнам

10
Мне понадобилась разница в секундах между двумя датами и я начал внедрять собственное решение. Вскоре это кажется сложным, и я взял на Google. Сатнамный ответ может не отвечать на вопрос ОП, но наверняка мне очень помог, и я держал пари, что многие другие, как я.
Джулиан

43

Вот один пример использования Duration и TimeUnit для получения формата «чч: мм: сс».

Duration dur = Duration.between(localDateTimeIni, localDateTimeEnd);
long millis = dur.toMillis();

String.format("%02d:%02d:%02d", 
        TimeUnit.MILLISECONDS.toHours(millis),
        TimeUnit.MILLISECONDS.toMinutes(millis) - 
        TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)),
        TimeUnit.MILLISECONDS.toSeconds(millis) - 
        TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));

2
Это на самом деле можно сделать это следующим образом : String.format("%02d:%02d:%02d",dur.toHoursPart(), dur.toMinutesPart(), dur.toSecondsPart());. Методы part дают правильные числа для построения строки. Я думаю, что это более читабельно.
Daantie

Примечание к моему предыдущему комментарию: методы обработки деталей доступны только в JDK 9 и выше.
Daantie

40

Это должно быть проще!

Duration.between(startLocalDateTime, endLocalDateTime).toMillis();

1
Я считаю, что это фактически семантически правильное решение, начиная с Java 8. И до этой версии JodaTime делает то же самое.
Вракафл

9

TL; DR

Duration duration = Duration.between(start, end);
duration = duration.minusDays(duration.toDaysPart()); // essentially "duration (mod 1 day)"
Period period = Period.between(start.toLocalDate(), end.toLocalDate());

а затем использовать методы period.getYears(), period.getMonths(), period.getDays(), duration.toHoursPart(), duration.toMinutesPart(), duration.toSecondsPart().


Расширенный ответ

Я отвечу на исходный вопрос, то есть как получить разницу во времени между двумя значениями LocalDateTimesв годах, месяцах, днях, часах и минутах, чтобы «сумма» (см. Примечание ниже) всех значений для разных единиц была равна сумме временная разница, и таким образом, что значение в каждом блоке меньше , чем следующий больше единицы, то есть minutes < 60, hours < 24и так далее.

Учитывая два LocalDateTimes startи end, например,

LocalDateTime start = LocalDateTime.of(2019, 11, 29, 17, 15);
LocalDateTime end = LocalDateTime.of(2020, 11, 30, 18, 44);

мы можем представить абсолютный промежуток времени между двумя с Durationпомощью «возможно» Duration.between(start, end). Но самая большая единица, которую мы можем извлечь из - Durationэто дни (как временная единица, эквивалентная 24 часам) - см. Примечание ниже для объяснения. Чтобы использовать более крупные единицы (месяцы, годы), мы можем представить это Durationс помощью пары ( Period, Duration), где Periodизмеряет разницу с точностью до дней, а символ Durationпредставляет остаток:

Duration duration = Duration.between(start, end);
duration = duration.minusDays(duration.toDaysPart()); // essentially "duration (mod 1 day)"
Period period = Period.between(start.toLocalDate(), end.toLocalDate());

Теперь мы можем просто использовать методы, определенные для Periodи Durationизвлекать отдельные единицы:

System.out.printf("%d years, %d months, %d days, %d hours, %d minutes, %d seconds",
        period.getYears(), period.getMonths(), period.getDays(), duration.toHoursPart(),
        duration.toMinutesPart(), duration.toSecondsPart());
1 years, 0 months, 1 days, 1 hours, 29 minutes, 0 seconds

или, используя формат по умолчанию:

System.out.println(period + " + " + duration);
P1Y1D + PT1H29M

Обратите внимание на годы, месяцы и дни

Обратите внимание, что в java.timeконцепции «единицы», такие как «месяц» или «год», не представляют фиксированное абсолютное временное значение - они зависят от даты и календаря, как показано в следующем примере:

LocalDateTime
        start1 = LocalDateTime.of(2020, 1, 1, 0, 0),
        end1 = LocalDateTime.of(2021, 1, 1, 0, 0),
        start2 = LocalDateTime.of(2021, 1, 1, 0, 0),
        end2 = LocalDateTime.of(2022, 1, 1, 0, 0);
System.out.println(Period.between(start1.toLocalDate(), end1.toLocalDate()));
System.out.println(Duration.between(start1, end1).toDays());
System.out.println(Period.between(start2.toLocalDate(), end2.toLocalDate()));
System.out.println(Duration.between(start2, end2).toDays());
P1Y
366
P1Y
365

5

Существует некоторая проблема для кода Tapas Bose и кода Thomas. Если разница во времени отрицательна, массив получает отрицательные значения. Например, если

LocalDateTime toDateTime = LocalDateTime.of(2014, 9, 10, 6, 46, 45);
LocalDateTime fromDateTime = LocalDateTime.of(2014, 9, 9, 7, 46, 45);

возвращает 0 лет 0 месяцев 1 дней -1 часов 0 минут 0 секунд.

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

Я предлагаю разделить экземпляры LocalDateTime на экземпляры LocalDate и LocalTime. После этого мы можем получить экземпляры Java 8 Period и Duration. Экземпляр Duration разделяется на количество дней и значение времени в течение дня (<24 ч) с последующей коррекцией значения периода. Когда второе значение LocalTime находится перед значением firstLocalTime, необходимо сократить период на один день.

Вот мой способ вычисления разницы LocalDateTime:

private void getChronoUnitForSecondAfterFirst(LocalDateTime firstLocalDateTime, LocalDateTime secondLocalDateTime, long[] chronoUnits) {
    /*Separate LocaldateTime on LocalDate and LocalTime*/
    LocalDate firstLocalDate = firstLocalDateTime.toLocalDate();
    LocalTime firstLocalTime = firstLocalDateTime.toLocalTime();

    LocalDate secondLocalDate = secondLocalDateTime.toLocalDate();
    LocalTime secondLocalTime = secondLocalDateTime.toLocalTime();

    /*Calculate the time difference*/
    Duration duration = Duration.between(firstLocalDateTime, secondLocalDateTime);
    long durationDays = duration.toDays();
    Duration throughoutTheDayDuration = duration.minusDays(durationDays);
    Logger.getLogger(PeriodDuration.class.getName()).log(Level.INFO,
            "Duration is: " + duration + " this is " + durationDays
            + " days and " + throughoutTheDayDuration + " time.");

    Period period = Period.between(firstLocalDate, secondLocalDate);

    /*Correct the date difference*/
    if (secondLocalTime.isBefore(firstLocalTime)) {
        period = period.minusDays(1);
        Logger.getLogger(PeriodDuration.class.getName()).log(Level.INFO,
                "minus 1 day");
    }

    Logger.getLogger(PeriodDuration.class.getName()).log(Level.INFO,
            "Period between " + firstLocalDateTime + " and "
            + secondLocalDateTime + " is: " + period + " and duration is: "
            + throughoutTheDayDuration
            + "\n-----------------------------------------------------------------");

    /*Calculate chrono unit values and  write it in array*/
    chronoUnits[0] = period.getYears();
    chronoUnits[1] = period.getMonths();
    chronoUnits[2] = period.getDays();
    chronoUnits[3] = throughoutTheDayDuration.toHours();
    chronoUnits[4] = throughoutTheDayDuration.toMinutes() % 60;
    chronoUnits[5] = throughoutTheDayDuration.getSeconds() % 60;
}

Вышеуказанный метод может быть использован для вычисления разницы любых локальных значений даты и времени, например:

public long[] getChronoUnits(String firstLocalDateTimeString, String secondLocalDateTimeString) {
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    LocalDateTime firstLocalDateTime = LocalDateTime.parse(firstLocalDateTimeString, formatter);
    LocalDateTime secondLocalDateTime = LocalDateTime.parse(secondLocalDateTimeString, formatter);

    long[] chronoUnits = new long[6];
    if (secondLocalDateTime.isAfter(firstLocalDateTime)) {
        getChronoUnitForSecondAfterFirst(firstLocalDateTime, secondLocalDateTime, chronoUnits);
    } else {
        getChronoUnitForSecondAfterFirst(secondLocalDateTime, firstLocalDateTime, chronoUnits);
    }
    return chronoUnits;
}

Для описанного выше метода удобно написать модульный тест (оба они являются членами класса PeriodDuration). Вот код:

@RunWith(Parameterized.class)
public class PeriodDurationTest {

private final String firstLocalDateTimeString;
private final String secondLocalDateTimeString;
private final long[] chronoUnits;

public PeriodDurationTest(String firstLocalDateTimeString, String secondLocalDateTimeString, long[] chronoUnits) {
    this.firstLocalDateTimeString = firstLocalDateTimeString;
    this.secondLocalDateTimeString = secondLocalDateTimeString;
    this.chronoUnits = chronoUnits;
}

@Parameters
public static Collection<Object[]> periodValues() {
    long[] chronoUnits0 = {0, 0, 0, 0, 0, 0};
    long[] chronoUnits1 = {0, 0, 0, 1, 0, 0};
    long[] chronoUnits2 = {0, 0, 0, 23, 0, 0};
    long[] chronoUnits3 = {0, 0, 0, 1, 0, 0};
    long[] chronoUnits4 = {0, 0, 0, 23, 0, 0};
    long[] chronoUnits5 = {0, 0, 1, 23, 0, 0};
    long[] chronoUnits6 = {29, 8, 24, 12, 0, 50};
    long[] chronoUnits7 = {29, 8, 24, 12, 0, 50};
    return Arrays.asList(new Object[][]{
        {"2015-09-09 21:46:44", "2015-09-09 21:46:44", chronoUnits0},
        {"2015-09-09 21:46:44", "2015-09-09 22:46:44", chronoUnits1},
        {"2015-09-09 21:46:44", "2015-09-10 20:46:44", chronoUnits2},
        {"2015-09-09 21:46:44", "2015-09-09 20:46:44", chronoUnits3},
        {"2015-09-10 20:46:44", "2015-09-09 21:46:44", chronoUnits4},
        {"2015-09-11 20:46:44", "2015-09-09 21:46:44", chronoUnits5},
        {"1984-12-16 07:45:55", "2014-09-09 19:46:45", chronoUnits6},
        {"2014-09-09 19:46:45", "1984-12-16 07:45:55", chronoUnits6}
    });
}

@Test
public void testGetChronoUnits() {
    PeriodDuration instance = new PeriodDuration();
    long[] expResult = this.chronoUnits;
    long[] result = instance.getChronoUnits(this.firstLocalDateTimeString, this.secondLocalDateTimeString);
    assertArrayEquals(expResult, result);
}

}

Все тесты успешны независимо от того, указано ли значение первого LocalDateTime до и для каких-либо значений LocalTime.


Я не могу воспроизвести ваше заявление о том, что код Томаса, использующий ваши данные выше, производит смешанные знаки. Мой вывод: «0 лет 0 месяцев 0 дней 23 часа 0 минут 0 секунд». И я проверил только сейчас.
Мено Хохшильд

Спасибо за комментарий. Я тщательно протестировал код Томаса, действительно, он работает правильно! Магия выполняется LocalDateTime до тех пор, пока метод не исправит хроно-единицы. Отрицательные значения в коде Томаса появляются, если первый DateTime позже второго. Но это можно легко исправить, например, как я делал в приведенном выше коде. Еще раз спасибо.
Геннадий Коломоец

Ну, код Томаса и моя библиотека Time4J, использующие один и тот же алгоритм для вычисления длительностей, могут давать отрицательные знаки, но только для всей продолжительности. Это решающий момент! Знак относится ко всей продолжительности и, следовательно, описывает, является ли начало более поздним, чем конец, и никогда не относится к компонентам с одной продолжительностью. Смешанные знаки здесь невозможны и могут помешать такой интерпретации начала относительно конца (в качестве контрольного примера можно привести Joda-Time-period или java.time.Periodгде пользователи могут применять / создавать такие смешанные знаки из-за разного внутреннего дизайна).
Мено Хохшильд

5

И версия @Thomas в Groovy с принимает нужные единицы в списке вместо жесткого кодирования значений. Эта реализация (которую можно легко перенести на Java - я сделал объявление функции явным) делает подход Thomas более пригодным для повторного использования.

def fromDateTime = LocalDateTime.of(1968, 6, 14, 0, 13, 0)
def toDateTime = LocalDateTime.now()
def listOfUnits = [
    ChronoUnit.YEARS, ChronoUnit.MONTHS, ChronoUnit.DAYS,
    ChronoUnit.HOURS, ChronoUnit.MINUTES, ChronoUnit.SECONDS,
    ChronoUnit.MILLIS]

println calcDurationInTextualForm(listOfUnits, fromDateTime, toDateTime)    

String calcDurationInTextualForm(List<ChronoUnit> listOfUnits, LocalDateTime ts, LocalDateTime to)
{
    def result = []

    listOfUnits.each { chronoUnit ->
        long amount = ts.until(to, chronoUnit)
        ts = ts.plus(amount, chronoUnit)

        if (amount) {
            result << "$amount ${chronoUnit.toString()}"
        }
    }

    result.join(', ')
}

На момент написания этой статьи приведенный выше код возвращается 47 Years, 8 Months, 9 Days, 22 Hours, 52 Minutes, 7 Seconds, 140 Millis. И, для ввода @Gennady Kolomoets, код возвращается 23 Hours.

Когда вы предоставляете список единиц, он должен быть отсортирован по размеру единиц (самый большой сначала):

def listOfUnits = [ChronoUnit.WEEKS, ChronoUnit.DAYS, ChronoUnit.HOURS]
// returns 2495 Weeks, 3 Days, 8 Hours

4

Вот очень простой ответ на ваш вопрос. Оно работает.

import java.time.*;
import java.util.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;

public class MyClass {
public static void main(String args[]) {
    DateTimeFormatter T = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm");
    Scanner h = new Scanner(System.in);

    System.out.print("Enter date of birth[dd/mm/yyyy hh:mm]: ");
    String b = h.nextLine();

    LocalDateTime bd = LocalDateTime.parse(b,T);
    LocalDateTime cd = LocalDateTime.now();

    long minutes = ChronoUnit.MINUTES.between(bd, cd);
    long hours = ChronoUnit.HOURS.between(bd, cd);

    System.out.print("Age is: "+hours+ " hours, or " +minutes+ " minutes old");
}
}

1
Я должен упомянуть, что это не точно. попробуй с этим. это говорит, что разница в 1 минуту. LocalDateTime bd = LocalDateTime.of (2019, 11, 26, 15, 03, 55); LocalDateTime cd = LocalDateTime.of (2019, 11, 26, 15, 04, 45);
Марк Амабиле

Я ввел время прошлой ночью и получил Age is: 0 years,0 months, 1 days, -10 hours, -48 minutes old. Я не думаю, что это то, что было желательно.
Оле В.В.

@ OleV.V. Исправлена ​​эта проблема
SavedBeau

1

Joda времени

Так как для многих ответов требовалась поддержка API 26, а для min API было 23, я решил это следующим кодом:

import org.joda.time.Days

LocalDate startDate = Something
LocalDate endDate = Something
// The difference would be exclusive of both dates, 
// so in most of use cases we may need to increment it by 1
Days.daysBetween(startDate, endDate).days

1
Проект Joda-Time находится в режиме обслуживания, его создатель Стивен Коулборн продолжил создавать классы java.time, определенные в JSR 310. Большая часть функций java.time перенесена на Java 6 и 7 в ThreeTen. Backport проект. Далее адаптирован для раннего Android в проекте ThreeTenABP .
Базилик Бурк

1

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

LocalDateTime fromDateTime = LocalDateTime.of(2014, 9, 9, 7, 46, 45);
LocalDateTime toDateTime = LocalDateTime.of(2014, 9, 10, 6, 46, 45);

Period period = Period.between(fromDateTime.toLocalDate(), toDateTime.toLocalDate());
Duration duration = Duration.between(fromDateTime.toLocalTime(), toDateTime.toLocalTime());

if (duration.isNegative()) {
    period = period.minusDays(1);
    duration = duration.plusDays(1);
}
long seconds = duration.getSeconds();
long hours = seconds / SECONDS_PER_HOUR;
long minutes = ((seconds % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE);
long secs = (seconds % SECONDS_PER_MINUTE);
long time[] = {hours, minutes, secs};
System.out.println(period.getYears() + " years "
            + period.getMonths() + " months "
            + period.getDays() + " days "
            + time[0] + " hours "
            + time[1] + " minutes "
            + time[2] + " seconds.");

Примечание: сайт https://www.epochconverter.com/date-difference теперь правильно рассчитывает разницу во времени.

Спасибо всем за обсуждение и предложения.


Спасибо за ответ. Для часов и меньше вы можете извлечь выгоду из toHours, toMinutesи toSecondsметоды Duration. С Java 9 даже больше от toMinutesPart()а toSecondsPart(). И я не вижу смысла в том, чтобы оборачивать часы, минуты и секунды в массив только для того, чтобы убрать их снова. В общем, хороший ответ, хотя.
Оле В.В.

Спустя более пяти лет я отвечаю на мой вопрос. Вопрос был опубликован с учетной записью с другим именем, названием и местоположением, похоже, нет большого сходства? Не то чтобы это имело какое-то значение, просто интересно.
Оле В.В.

«После более чем пяти лет я отвечаю на свой вопрос». Я полагаю, что я был ОП :)
Тапас Бозе
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.