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:5509/09/2014 19:46:45). 다음 스크린 샷은 출력을 보여줍니다.

획기적인 변환기

월 값 이후의 필드가 내 코드에서 잘못되어 있다고 확신합니다. 어떤 제안이라도 도움이 될 것입니다.

최신 정보

다른 웹 사이트에서 결과를 테스트했는데 결과가 다릅니다. 여기입니다 : 두 날짜 사이의 계산 기간 (29 년, 3 개월 이십사일 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.
Basil Bourque

답변:


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 년 미만이되도록 해당 날짜를 연도 수로 조정하십시오. 각 시간 단위에 대해 내림차순으로 반복하십시오.

마지막으로 면책 조항 : 나는 다른 시간대를 고려하지 않았으며 (두 날짜는 같은 시간대에 있어야 함) 일광 절약 시간이나 달력의 다른 변경 사항 (사모아의 시간대 변경과 같은)을 테스트 / 확인하지 않았습니다. 이 계산에 영향을줍니다. 주의해서 사용하십시오.


1
당신은 동일한 기본 아이디어를 가지고 있으므로 내 의견을 밝히지 만 동일한 입력을 사용해보십시오. 그렇지 않으면 다른 결과가 혼란 스럽습니다.
Meno Hochschild

@MenoHochschild 그것은 이다 다만 영업 이익은 음 (-)의 시간에 문제가 업데이트에서 가져온 동일한 입력은. ;)
Thomas

1
좋은 알고리즘이지만 잘못된 유형입니다 (Thomas 고지 사항 참조). 계산을 수행하기 전에 기본 시간대 (또는 필요한 시간대)를 사용하여 LocalDateTime 변수를 ZonedDateTime으로 변환해야합니다. ZonedDateTime fromZonedDateTime = fromDateTime.atZone (ZoneId.systemDefault ());
Tristan

2
@Thomas 귀하의 예는 Java 8도 사용하고 있으며 질문은 java-8로 태그되어 있습니다. 실제로 귀하의 예제는 ChronoUnit:)를 사용 하고 있지만 "직접 손으로"하는 일입니다.
Eugene Beresovsky 2016 년

3
@EugeneBeresovsky 아, 맞아. ;)-그 외에도, long minutes = ChronoUnit.MINUTES.between(fromDate, toDate);적어도 1 시간 간격마다 59보다 큰 숫자를 반환하기 때문에 간격에서 더 큰 단위를 빼야합니다 . 이는 OP가 원하는 것이 아닙니다. 이를 고려하면 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
나는 실제로 개선되지 않습니다. 수락 된 Thomas의 답변과 비교하면으로 대체 tempDateTime.until( toDateTime, ChronoUnit.YEARS)됩니다 ChronoUnit.YEARS.between(fromDate, toDate). 그러나 tempDateTime.plusYears( years )귀하의 답변에 중요한 추가 행 등이 완전히 누락되어 OP에 도움이되지 않습니다. 완전한 알고리즘이 중요합니다!
Meno Hochschild

9
나는 간결하고 읽기 쉽기 때문에 이것을 좋아합니다. 이것은 두 날짜의 차이를 찾는 가장 좋은 방법입니다.
소 마이 아 쿰 베라

7
@SomaiahKumbera 아니 당신은 중요한 요점을 완전히 그리워. OP는 하나의 단위가 아닌 여러 단위의 기간을 원 하므로이 답변은 실제 답변이 아닙니다. OP의 관심사는 단순히 다루지 않았다. 질문을 다시 읽어 주시기 바랍니다. (많은 지지자들이 그 질문을 오해 한 것 같습니다).
Meno Hochschild 2016 년

125
@MenoHochschild, 나는 당신이 실제로 중요한 포인트를 놓친 사람이라고 생각합니다. OP는 1 년 전에 답변을 받았습니다. 이 질문을보고있는 36 만 명이 OP의 특정 질문에 신경 쓰지 않습니다. 그들은 구글에 의해 여기에 이끌었고 내 대답은 그들이 찾고있는 것을 제공했습니다. 두 날짜의 차이를 얻는 깨끗하고 간단한 솔루션입니다.
satnam

10
두 날짜 시간의 초 차이가 필요했고 내 솔루션을 구현하기 시작했습니다. 곧 복잡해 보였고 Google을 사용했습니다. satnam 답변은 OP 질문에 대답하지 않을 수도 있지만 확실히 많은 도움이되었고 나와 같은 많은 다른 사람들에게 내기를 걸었습니다.
줄리안

43

다음은 Duration 및 TimeUnit을 사용하여 'hh : mm : ss'형식을 가져 오는 단일 예제입니다.

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());있습니다. 부품 방법은 문자열을 작성하는 데 적합한 숫자를 제공합니다. 더 읽기 쉽다고 생각합니다.
Daantie

이전 의견에 대한 참고 사항 : 부품 방법은 JDK 9 이상에서만 사용할 수 있습니다.
Daantie

40

더 간단해야합니다!

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

1
나는 이것이 실제로 Java 8에서 시작하는 의미 론적으로 올바른 솔루션이라고 생각합니다. 그리고 그 버전 이전에 JodaTime은 똑같이 작동합니다.
Vrakfall

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 < 60hours < 24).

예를 들어 2 LocalDateTimes startend

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());

이제 우리는 단지에 정의 된 방법을 사용할 수 있습니다 PeriodDuration개별 단위를 추출하기를 :

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 초라고 생각합니다.

LocalDate 및 LocalTime 인스턴스에서 LocalDateTime 인스턴스를 분리하도록 제안합니다. 그런 다음 Java 8 Period 및 Duration 인스턴스를 얻을 수 있습니다. Duration 인스턴스는 기간 값의 후속 수정으로 일 수와 하루 종일 시간 값 (<24h)으로 구분됩니다. 두 번째 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 값 이전 및 모든 LocalTime 값에 관계없이 모든 테스트에 성공합니다.


위의 입력을 사용하여 Thomas 코드가 혼합 부호를 생성한다는 진술을 재현 할 수 없습니다. 내 출력은 "0 년 0 개월 0 일 23 시간 0 분 0 초."입니다. 그리고 지금 막 테스트했습니다.
Meno Hochschild 2016 년

의견 감사합니다. 나는 Thomas 코드를 철저히 테스트했으며 실제로 제대로 작동하고 있습니다! 마술은 크로노 단위를 수정하는 방법까지 LocalDateTime에 의해 수행됩니다. 첫 번째 DateTime이 두 번째보다 늦으면 Thomas 코드의 음수 값이 나타납니다. 그러나 이것은 예를 들어 위의 코드에서했던 것처럼 쉽게 수정할 수 있습니다. 다시 감사합니다.
Gennady Kolomoets

글쎄, 지속 시간 계산에 동일한 알고리즘을 사용하는 Thomas 코드와 내 라이브러리 Time4J는 음의 부호를 생성 할 수 있지만 전체 지속 기간 동안 만 가능합니다. 그것이 중요한 포인트입니다! 부호는 전체 지속 시간과 관련이 있으므로 시작이 끝보다 늦고 단일 지속 시간 구성 요소와 관련이 없는지 여부를 나타냅니다. 여기서 혼합 부호는 가능하지 않으며 종료에 대한 시작의 해석을 막을 수 있습니다 (카운터 예는 Joda-Time 기간 또는 java.time.Period사용자가 다른 내부 설계로 인해 이러한 혼합 부호를 시행 / 생산할 수있는 경우).
Meno Hochschild

5

그리고 Groovy 의 @Thomas 버전은 값을 하드 코딩하는 대신 목록에서 원하는 단위를 취합니다. 이 구현 (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);
Mark Amabile

나는 어제 시간을 입력하고 얻었다 Age is: 0 years,0 months, 1 days, -10 hours, -48 minutes old. 나는 이것이 바람직한 것이라고 생각하지 않습니다.
Ole VV

@ OleV.V. 해당 문제 수정
SavedBeau

1

조다 타임

많은 답변에 API 26 지원이 필요 했고 최소 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 타임 프로젝트는 제작자 스티븐 Colebourne가 만드는에 간 데, 유지 보수 모드에 java.time의 의 대부분 JSR 310에 정의 된 클래스를 java.time의 기능하면 자바 6 & 7 백 포팅입니다 ThreeTen- 백 포트 프로젝트. ThreeTenABP 프로젝트 에서 초기 Android에 더욱 적합합니다 .
Basil Bourque

1

5 년이 지난 후에 저는 제 질문에 대답합니다. 음수 지속 시간의 문제는 간단한 수정으로 해결할 수 있다고 생각합니다.

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()and 에서 더 많이 제공됩니다 toSecondsPart(). 그리고 나는 시간, 분 및 초를 배열로 감싸서 다시 꺼내는 요점을 보지 못했습니다. 그러나 일반적으로 좋은 대답입니다.
Ole VV

5 년이 지난 후에 저는 제 질문에 대답합니다. 질문이 다른 이름, 직함 및 위치를 가진 계정에서 게시 된 것 같습니다. 그것이 중요하지 않다는 것만 궁금합니다.
Ole VV

"5 년이 지난 후 나는 내 질문에 대답한다"라고 생각합니다. 저는 OP라고 생각합니다.
Tapas Bose
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.