java.time.LocalDateTime과 java.util.Date 간 변환


484

Java 8에는 날짜 및 시간에 대한 완전히 새로운 API가 있습니다. 이 API에서 가장 유용한 클래스 중 하나는 LocalDateTime시간대 독립적 날짜-시간 값을 보유하기위한입니다.

java.util.Date이 목적으로 레거시 클래스 를 사용하는 수백만 줄의 코드가있을 것입니다 . 따라서 이전 코드와 새 코드를 인터페이스 할 때 두 코드 사이를 변환해야합니다. 이를 달성하기위한 직접적인 방법이없는 것처럼 보이면 어떻게 할 수 있습니까?




답변:


706

짧은 답변:

Date in = new Date();
LocalDateTime ldt = LocalDateTime.ofInstant(in.toInstant(), ZoneId.systemDefault());
Date out = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());

설명 : (에 따라 이 문제 에 대한 LocalDate)

이름에도 불구하고 java.util.Date"날짜"가 아니라 타임 라인의 순간을 나타냅니다. 객체 내에 저장된 실제 데이터는 long1970-01-01T00 : 00Z (1970 GMT / UTC 시작시 자정) 이후 밀리 초 수입니다.

java.util.DateJSR-310 과 동등한 클래스 는 다음 Instant과 같이 변환을 제공하는 편리한 방법이 있습니다.

Date input = new Date();
Instant instant = input.toInstant();
Date output = Date.from(instant);

java.util.Date인스턴스는 시간대의 개념이 없습니다. 당신이 호출하면이 이상하게 보일 수도 toString()A의 java.util.Date(가) 때문에, toString시간 영역에 상대적입니다. 그러나이 메소드는 실제로 Java의 기본 시간대를 사용하여 문자열을 제공합니다. 시간대는의 실제 상태의 일부가 아닙니다 java.util.Date.

은 Instant또한 시간대에 대한 정보가 포함되어 있지 않습니다. 따라서에서 Instant날짜를 현지 날짜 로 변환하려면 시간대를 지정해야합니다. 기본 영역 ZoneId.systemDefault()일 수도 있고 사용자 기본 설정의 시간대와 같이 응용 프로그램이 제어하는 ​​시간대 일 수도 있습니다. LocalDateTime인스턴트 및 시간대를 모두 사용하는 편리한 팩토리 방법이 있습니다.

Date in = new Date();
LocalDateTime ldt = LocalDateTime.ofInstant(in.toInstant(), ZoneId.systemDefault());

반대로 LocalDateTime시간대는 atZone(ZoneId)메소드 를 호출하여 지정됩니다 . 그런 ZonedDateTime다음를 다음으로 직접 변환 할 수 있습니다 Instant.

LocalDateTime ldt = ...
ZonedDateTime zdt = ldt.atZone(ZoneId.systemDefault());
Date output = Date.from(zdt.toInstant());

에서 LocalDateTime로 변환 ZonedDateTime하면 예기치 않은 동작이 발생할 가능성이 있습니다. 일광 절약 시간 제로 인해 모든 현지 날짜-시간이 존재하지 않기 때문입니다. 가을 / 가을에는 동일한 현지 날짜-시간이 두 번 발생하는 현지 타임 라인이 겹칩니다. 봄에는 한 시간이 사라지는 간격이 있습니다. atZone(ZoneId)변환이 수행 할 작업 에 대한 자세한 정의 는 Javadoc을 참조하십시오 .

요약하면 a java.util.Date를 a 로 왕복 LocalDateTime하고 다시 a 로 왕복하면 java.util.Date일광 절약 시간 제로 인해 다른 순간으로 끝날 수 있습니다.

추가 정보 : 아주 오래된 날짜에 영향을 줄 또 다른 차이점이 있습니다. java.util.Date1582 년 10 월 15 일에 변경되는 달력을 사용하며, 그 이전의 날짜는 그레고리력 대신 Julian 달력을 사용합니다. 반대로 java.time.*ISO 캘린더 시스템 (Gregorian과 동일)을 항상 사용합니다. 대부분의 경우 ISO 캘린더 시스템이 원하는 것이지만 1582 년 이전의 날짜를 비교할 때 이상한 효과가 나타날 수 있습니다.


5
명확한 설명을 주셔서 감사합니다. 특히 이유를 java.util.Date하지 않습니다 시간대가 포함되어 있지만 중에 인쇄 toString(). 이벤트 공식 문서 는 게시 할 때이를 명확하게 알려주지 않습니다.
— Cherry

경고 : LocalDateTime.ofInstant(date.toInstant()... 순진하게 기대하는 것처럼 행동하지 않습니다. 예를 들어이 방법을 사용 new Date(1111-1900,11-1,11,0,0,0);하게됩니다 1111-11-17 23:53:28. 이전 예제에서 java.sql.Timestamp#toLocalDateTime()결과가 필요한 경우 의 구현을 살펴보십시오 1111-11-11 00:00:00.
— dog

2
아주 오래된 날짜 (1582 년 이전)에 관한 섹션을 추가했습니다. FWIW, java.util.Date의 1111-11-11은 캘린더 시스템의 차이로 인해 java.time의 1111-11-18과 실제 날짜가 같기 때문에 제안 된 수정 사항이 잘못되었을 수 있습니다 (6.5 분 차이). ) 1,900하기 전에 많은 시간이 시간대에 발생
— JodaStephen

2
또한 가치가 그주의해야 할 java.sql.Date#toInstant가 발생합니다 UnsupportedOperationException. 따라서 toInstantRowMapper on에 사용하지 마십시오 java.sql.ResultSet#getDate.
— LazerBass

132

여기에 내가 생각해 낸 것이 있습니다 (그리고 모든 Date Time 수수께끼와 마찬가지로 이상한 시간대-윤년-일광 조정에 따라 반박 될 것입니다 : D)

라운드 트립 : Date<<->>LocalDateTime

주어진: Date date = [some date]

(1) LocalDateTime<< Instant<<Date

    Instant instant = Instant.ofEpochMilli(date.getTime());
    LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneOffset.UTC);

(2) Date<< Instant<<LocalDateTime

    Instant instant = ldt.toInstant(ZoneOffset.UTC);
    Date date = Date.from(instant);

예:

주어진:

Date date = new Date();
System.out.println(date + " long: " + date.getTime());

(1) LocalDateTime<< Instant<< Date:

만들기 Instant에서 Date:

Instant instant = Instant.ofEpochMilli(date.getTime());
System.out.println("Instant from Date:\n" + instant);

만들기 Date에서 Instant(필요는 없습니다 만, 그림) :

date = Date.from(instant);
System.out.println("Date from Instant:\n" + date + " long: " + date.getTime());

만들기 LocalDateTime에서Instant

LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneOffset.UTC);
System.out.println("LocalDateTime from Instant:\n" + ldt);

(2) Date<< Instant<<LocalDateTime

만들기 Instant에서 LocalDateTime:

instant = ldt.toInstant(ZoneOffset.UTC);
System.out.println("Instant from LocalDateTime:\n" + instant);

만들기 Date에서 Instant:

date = Date.from(instant);
System.out.println("Date from Instant:\n" + date + " long: " + date.getTime());

출력은 다음과 같습니다.

Fri Nov 01 07:13:04 PDT 2013 long: 1383315184574

Instant from Date:
2013-11-01T14:13:04.574Z

Date from Instant:
Fri Nov 01 07:13:04 PDT 2013 long: 1383315184574

LocalDateTime from Instant:
2013-11-01T14:13:04.574

Instant from LocalDateTime:
2013-11-01T14:13:04.574Z

Date from Instant:
Fri Nov 01 07:13:04 PDT 2013 long: 1383315184574

2
@ scottb 당신은 나 또는 질문을 제기 한 사람에게 그 문제를 다루고 있습니까? 내 생각에 관해서 는, jdk 8 API에 명시 적으로 변환을 명시하는 것이 좋을 것입니다. 적어도 그렇게 할 수 있습니다. 어쨌든 새로운 Java-8 기능을 포함하고이를 수행하는 방법을 알기 위해 리팩토링 될 라이브러리가 많이 있습니다.
— 코디네이터

4
@scottb 왜 타사 사례가 드문 일입니까? 지독한 공통점. 한 가지 예 : JDBC 4 이하 (5가 아님).
— Raman

5
일반적인 JSR-310 규칙으로서 epoch-millis를 사용하여 유형간에 변환 할 필요가 없습니다. 더 나은 대안은 객체를 사용하여 존재합니다. 아래의 전체 답변을 참조하십시오. 위의 답변은 UTC와 같은 영역 오프셋을 사용하는 경우에만 완전히 유효합니다. 답변의 일부는 America / New_York와 같은 표준 시간대에서 작동하지 않습니다.
— JodaStephen

2
대신에 Instant.ofEpochMilli(date.getTime())할 일date.toInstant()
— 염소

1
@goat toInstant()은 arggggh에 실패한다는 것을 제외하고는 멋지게 보입니다 java.sql.Date! 결국 사용하기가 더 쉽습니다 Instant.ofEpochMilli(date.getTime()).
— vadipp

22

기본 시간대가 필요한 경우 훨씬 편리한 방법입니다.

Date d = java.sql.Timestamp.valueOf( myLocalDateTime );

25
물론, 더 쉽지만 적어도 IMHO와 간단한 날짜 처리와 jdbc 관련 항목을 혼합하는 것을 좋아하지 않습니다.
— Enrico Giurin

9
죄송합니다. 간단한 문제에 대한 끔찍한 해결책입니다. 5를 올림픽 로고의 고리 수와 동일하게 정의하는 것과 같습니다.
— Madbreaks

7

다음은 새 API LocalDateTime에서 java.util.date로 변환 할 때 작동하는 것 같습니다.

Date.from(ZonedDateTime.of({time as LocalDateTime}, ZoneId.systemDefault()).toInstant());

역변환은 (희망적으로) 비슷한 방식으로 달성 될 수 있습니다 ...

그것이 도움이되기를 바랍니다 ...


5

모든 것이 여기에 있습니다 : http://blog.progs.be/542/date-to-java-time

"라운드 트리핑"의 대답은 정확하지 않습니다.

LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneOffset.UTC);

시스템 시간대가 UTC / GMT가 아닌 경우 시간을 변경하십시오!


LocalDateTime에서 두 번 겹치는 가을에 1 년에 1 시간 동안 만 수행하는 경우에만 스프링 포워드 이동은 문제를 일으키지 않습니다. 대부분의 경우 양방향을 올바르게 변환합니다.
— David


3

이것이 가장 간단한 방법인지 또는 가장 좋은 방법인지 또는 함정이 있는지 확실하지 않지만 작동합니다.

static public LocalDateTime toLdt(Date date) {
    GregorianCalendar cal = new GregorianCalendar();
    cal.setTime(date);
    ZonedDateTime zdt = cal.toZonedDateTime();
    return zdt.toLocalDateTime();
}

static public Date fromLdt(LocalDateTime ldt) {
    ZonedDateTime zdt = ZonedDateTime.of(ldt, ZoneId.systemDefault());
    GregorianCalendar cal = GregorianCalendar.from(zdt);
    return cal.getTime();
}

3
에서가는 함정 확실히 거기 LocalDateTime에가 Date. 일광 절약 전환시 a LocalDateTime가 없거나 두 번 발생할 수 있습니다. 각각의 경우에 일어나고 싶은 일을 해결해야합니다.
— Jon Skeet

1
BTW, GregorianCalendar새로운 java.timeAPI를 대체하려는 오래된 어색한 API에 속함
— Vadzim

3

당신이 안드로이드에 있고 threetenbp 를 사용 한다면DateTimeUtils 하는 대신 .

전의:

Date date = DateTimeUtils.toDate(localDateTime.atZone(ZoneId.systemDefault()).toInstant());

Date.fromapi 26 이상에서만 지원되므로 사용할 수 없습니다

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.