Programing

Java 8 : 두 LocalDateTime의 차이 계산

lottogame 2020. 4. 22. 08:09
반응형

Java 8 : 두 LocalDateTime의 차이 계산


둘 사이의 차이를 계산하려고합니다 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. 따라서 알고리즘은 음수도 처리해야합니다.

질문은 어떤 사이트에서 어떤 결과를 얻었는지에 대한 것이 아니며 올바른 알고리즘을 알아야하며 올바른 결과가 필요합니다.


불행히도 시간에 걸쳐있는 기간 클래스가없는 것처럼 보이므로 직접 계산해야 할 수도 있습니다.

불행히도 날짜 및 시간 클래스에는 그 정도를 단순화하는 많은 유틸리티 메소드가 있습니다. 가장 빠른 것은 아니지만 차이를 계산하는 방법은 다음과 같습니다.

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

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


이 작업을 수행하는 가장 좋은 방법은 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


다음은 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)));

더 간단해야합니다!

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

그리고 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

다음은 귀하의 질문에 대한 매우 간단한 답변입니다. 효과가있다.

import java.time.*;
import java.util.*;
import java.time.format.DateTimeFormatter;
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();

       int hr = cd.getHour() - bd.getHour();
       int mn = cd.getMinute() - bd.getMinute();

       Period time = Period.between(bd.toLocalDate(),cd.toLocalDate());

       System.out.print("Age is: "+time.getYears()+ " years,"+time.getMonths()+ " months, " +time.getDays()+ " days, "+hr+ " hours, " +mn+ " minutes old");
    }
}

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 값에 관계없이 모든 테스트에 성공합니다.


많은 답변에 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

참고 URL : https://stackoverflow.com/questions/25747499/java-8-calculate-difference-between-two-localdatetime

반응형