java.util.Date를 java.time.LocalDate로 변환


494

java.util.Date객체를 새로운 JDK 8 / JSR-310 으로 변환하는 가장 좋은 방법은 무엇입니까 java.time.LocalDate?

Date input = new Date();
LocalDate date = ???

답변:


828

짧은 답변

Date input = new Date();
LocalDate date = input.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

설명

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

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

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

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

은 Instant또한 시간대에 대한 정보가 포함되어 있지 않습니다. 따라서에서 Instant날짜를 현지 날짜 로 변환하려면 시간대를 지정해야합니다. 기본 영역 ZoneId.systemDefault()일 수도 있고 사용자 기본 설정의 시간대와 같이 응용 프로그램이 제어하는 ​​시간대 일 수도 있습니다. atZone()시간대를 적용 하는 방법을 사용하십시오 .

Date input = new Date();
Instant instant = input.toInstant();
ZonedDateTime zdt = instant.atZone(ZoneId.systemDefault());

A ZonedDateTime에는 현지 날짜 및 시간, 시간대 및 GMT / UTC의 오프셋으로 구성된 상태가 포함됩니다. 따라서 다음과 같이 날짜를 LocalDate쉽게 추출 할 수 있습니다 toLocalDate().

Date input = new Date();
Instant instant = input.toInstant();
ZonedDateTime zdt = instant.atZone(ZoneId.systemDefault());
LocalDate date = zdt.toLocalDate();

자바 9 답변

Java SE 9 에는이 작업을 약간 단순화 하는 새로운 방법 이 추가되었습니다.

Date input = new Date();
LocalDate date = LocalDate.ofInstant(input.toInstant(), ZoneId.systemDefault());

이 새로운 대안은 더 직접적이고 가비지가 적으므로 더 나은 성능을 발휘해야합니다.


14
나는 LocalDate.from(Instant.ofEpochMilli(date.getTime()))그것이 당신과 동등하지만 더 직접적이라고 생각했습니다.
— Marko Topolnik

9
컴파일하지만 실행되지 않는 @MarkoTopolnik Instant에는 시간대가 포함되어 있지 않으므로 LocalDate를 얻을 수있는 방법이 없습니다.
— JodaStephen

11
@assylias sqlDate.toLocalDate ()를 사용하십시오!
— JodaStephen

25
@JodaStephen Date은 시간대 개념이 없으며 시간대에 Instant대한 정보도 포함하지 않습니다. LocalDateAPI "는 시간대가없는 일"을 말한다. 그럼 왜에서 변환 Date에 Instant에 LocalDate요구 atZone(ZoneId.systemDefault())?
— 구스타보

8
@Gustavo : LocalDate및 LocalDateTime없습니다 "상점 또는 시간 또는 시간대 대표"할 (참조 :의 javadoc을). 클래스는 저장하지 않지만 클래스는 Local날짜 및 / 또는 시간을 나타내므로 현지 날짜 / 시간으로 의 변환 은 시간대를 의미합니다.
— Cuga

158

더 좋은 방법은 다음과 같습니다.

Date date = ...;
Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDate()

이 버전의 장점 :

  • 입력이 인스턴스 java.util.Date이거나 java.sql.Date(@JodaStephen의 방식과 달리) 하위 클래스에 관계없이 작동합니다 . 이는 JDBC에서 시작된 데이터와 공통입니다. java.sql.Date.toInstant()항상 예외가 발생합니다.

  • JSR-310 백 포트가있는 JDK8 및 JDK7과 동일

개인적으로 유틸리티 클래스를 사용하지만 백 포트와 호환되지는 않습니다.

/**
 * Utilities for conversion between the old and new JDK date types 
 * (between {@code java.util.Date} and {@code java.time.*}).
 * 
 * <p>
 * All methods are null-safe.
 */
public class DateConvertUtils {

    /**
     * Calls {@link #asLocalDate(Date, ZoneId)} with the system default time zone.
     */
    public static LocalDate asLocalDate(java.util.Date date) {
        return asLocalDate(date, ZoneId.systemDefault());
    }

    /**
     * Creates {@link LocalDate} from {@code java.util.Date} or it's subclasses. Null-safe.
     */
    public static LocalDate asLocalDate(java.util.Date date, ZoneId zone) {
        if (date == null)
            return null;

        if (date instanceof java.sql.Date)
            return ((java.sql.Date) date).toLocalDate();
        else
            return Instant.ofEpochMilli(date.getTime()).atZone(zone).toLocalDate();
    }

    /**
     * Calls {@link #asLocalDateTime(Date, ZoneId)} with the system default time zone.
     */
    public static LocalDateTime asLocalDateTime(java.util.Date date) {
        return asLocalDateTime(date, ZoneId.systemDefault());
    }

    /**
     * Creates {@link LocalDateTime} from {@code java.util.Date} or it's subclasses. Null-safe.
     */
    public static LocalDateTime asLocalDateTime(java.util.Date date, ZoneId zone) {
        if (date == null)
            return null;

        if (date instanceof java.sql.Timestamp)
            return ((java.sql.Timestamp) date).toLocalDateTime();
        else
            return Instant.ofEpochMilli(date.getTime()).atZone(zone).toLocalDateTime();
    }

    /**
     * Calls {@link #asUtilDate(Object, ZoneId)} with the system default time zone.
     */
    public static java.util.Date asUtilDate(Object date) {
        return asUtilDate(date, ZoneId.systemDefault());
    }

    /**
     * Creates a {@link java.util.Date} from various date objects. Is null-safe. Currently supports:<ul>
     * <li>{@link java.util.Date}
     * <li>{@link java.sql.Date}
     * <li>{@link java.sql.Timestamp}
     * <li>{@link java.time.LocalDate}
     * <li>{@link java.time.LocalDateTime}
     * <li>{@link java.time.ZonedDateTime}
     * <li>{@link java.time.Instant}
     * </ul>
     * 
     * @param zone Time zone, used only if the input object is LocalDate or LocalDateTime.
     * 
     * @return {@link java.util.Date} (exactly this class, not a subclass, such as java.sql.Date)
     */
    public static java.util.Date asUtilDate(Object date, ZoneId zone) {
        if (date == null)
            return null;

        if (date instanceof java.sql.Date || date instanceof java.sql.Timestamp)
            return new java.util.Date(((java.util.Date) date).getTime());
        if (date instanceof java.util.Date)
            return (java.util.Date) date;
        if (date instanceof LocalDate)
            return java.util.Date.from(((LocalDate) date).atStartOfDay(zone).toInstant());
        if (date instanceof LocalDateTime)
            return java.util.Date.from(((LocalDateTime) date).atZone(zone).toInstant());
        if (date instanceof ZonedDateTime)
            return java.util.Date.from(((ZonedDateTime) date).toInstant());
        if (date instanceof Instant)
            return java.util.Date.from((Instant) date);

        throw new UnsupportedOperationException("Don't know hot to convert " + date.getClass().getName() + " to java.util.Date");
    }

    /**
     * Creates an {@link Instant} from {@code java.util.Date} or it's subclasses. Null-safe.
     */
    public static Instant asInstant(Date date) {
        if (date == null)
            return null;
        else
            return Instant.ofEpochMilli(date.getTime());
    }

    /**
     * Calls {@link #asZonedDateTime(Date, ZoneId)} with the system default time zone.
     */
    public static ZonedDateTime asZonedDateTime(Date date) {
        return asZonedDateTime(date, ZoneId.systemDefault());
    }

    /**
     * Creates {@link ZonedDateTime} from {@code java.util.Date} or it's subclasses. Null-safe.
     */
    public static ZonedDateTime asZonedDateTime(Date date, ZoneId zone) {
        if (date == null)
            return null;
        else
            return asInstant(date).atZone(zone);
    }

}

asLocalDate()여기 방법은 널 안전한 사용이다 toLocalDate()입력되면 java.sql.Date(이것은 않도록 시간대 문제 나 불필요한 계산에 JDBC 드라이버에 의해 오버라이드 될 수있다), 그렇지 않으면 전술 한 방법을 사용한다.


12
이것이 더 좋은 방법이라면 매우 추악하고 장황합니다. 너무 아프다.
— ceklock

3
허용 된 답변과 비교하여 더 나은 이유를 설명합니다. 그렇습니다, 그것은 추악하지만, 그것이 쓴 이유 DateConvertUtils입니다.
— Oliv November

새 API에서 전환 클래스를 구현하지 않은 이유를 이해할 수 없습니다.
— ceklock

@ceklock, 그들은 않았다 아닌 변환 클래스,하지만 같은 변환 방법의 몇 가지를 구현 Date.toInstant().
— Ole VV

2
개발자가 다음을 수행 할 수 있도록 확장 기능으로 패키지화하는 Kotlin 라이브러리가 있습니까? 날짜 x = ...; x.asLocalDate ();
— 마크 애쉬 워스

20
LocalDate localDate = LocalDate.parse( new SimpleDateFormat("yyyy-MM-dd").format(date) );

7
여기서 SimpleDateFormat인스턴스는 현재 스레드로 제한 됩니다. 그것은되어 사용되는 스레드 안전한 방법. 이제 SimpleDateFormat(그것을 필요로하는 내부 데이터 구조 모든 계정) '의 인스턴스를 생성하기위한 비용'으로 알려져있다하지만 당신은 할 수 공유하고 있기 때문에, (그것에 접근을 동기화하지 않음) '싱글'로 하나 가 참으로 스레드 - 아니다 안전한. ( 이 코드의 '오염') 이 스레드의 수명주기를 담당 하는 경우ThreadLocal 해결책이 작동 할 수 있지만 거의 발생하지 않습니다. 어색한. 피가 입니다 사용하는 이유 . ThreadSimpleDateFormatjavax.time
— David Bullock

6
이 접근 방식에는 많은 비용 SimpleDateFormat이 발생 합니다. '고가' (버려짐), 중간 문자열 (버려짐) 및 파싱 비용. 그것은이다 솔루션,하지만하지 않는 것이 좋습니다.
— David Bullock

2
@ceklock 그러나 더 이상 스레드 안전하지 않다는 문제가 발생합니다.
— flup

4
@ceklock SimpleDateFormat은 한 번에 하나의 날짜 만 처리 할 수 ​​있습니다. 동시에 사용하면 엉망인 결과가 나옵니다. 예, 중요합니다. 전역 변수에 SimpleDateFormat의 단일 인스턴스를 만들지 마십시오.
— flup

19

Java 8을 사용하는 경우 @JodaStephen의 답변이 가장 좋습니다. 그러나 JSR-310 백 포트로 작업하는 경우 불행히도 다음과 같은 작업을 수행해야합니다.

Date input = new Date();
Calendar cal = Calendar.getInstance();
cal.setTime(input);
LocalDate date = LocalDate.of(cal.get(Calendar.YEAR),
        cal.get(Calendar.MONTH) + 1,
        cal.get(Calendar.DAY_OF_MONTH));

4
사실이 아닙니다. @ JodaStephen의 답변은 여전히 ​​작동합니다. java.util.Date를 Instant로 변환하는 다른 방법이 필요합니다. 이를 위해 당신은 org.threeten.bp.DateTimeUtils.toInstant를 사용할 수 있습니다 : threeten.org/threetenbp/apidocs/org/threeten/bp/…
— Christian Ciach

3
백 포트를 사용할 때 DateTimeUtils를 사용할 수 없었지만 ThreeTen Backport 1.0 이상을 사용하는 모든 사람이 사용할 수있는 것이 맞습니다. 지적 해 주셔서 감사합니다.
— dhalsim2

14
LocalDate ld = new java.sql.Date( new java.util.Date().getTime() ).toLocalDate();

1
그리고 가장 간단한 실현 : LocalDate.of (getYear () + 1900, getMonth () + 1, getDate ())
— Grigory Kislin

그래도 줄은 더 이상 사용되지 않습니다 : |
— TheRealChx101

8

한 줄로 변환 할 수 있습니다.

public static LocalDate getLocalDateFromDate(Date date){
   return LocalDate.from(Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()));
}

나는이 방법을 사용하여이 같은 오류가 발생합니다 : java.time.DateTimeException을 : 2018-01-31T11 : 54 : TemporalAccessor에서 LOCALDATE를 가져올 수 없습니다 유형 java.time.Instant의 27.964Z
— 루이지 루비노

@LuigiRubino 지적 해 주셔서 감사합니다. 업데이트 된 답변을 참조하십시오. Zone을 더 일찍 추가하는 것을 잊었습니다.
— Sahil Chhabra

8

먼저, 날짜를 인스턴트로 쉽게 변환 할 수 있습니다

Instant timestamp = new Date().toInstant(); 

그런 다음 ofInstant () 메소드를 사용하여 jdk 8에서 Instant를 임의의 날짜 API로 변환 할 수 있습니다.

LocalDateTime date = LocalDateTime.ofInstant(timestamp, ZoneId.systemDefault()); 

localDate, localDateTime, localTime 포함
— Shedom Wei

여기서 ZoneId를 지정한다는 것은 무엇을 의미합니까? API에서 Date-> Instant를 가져 와서 1970 년부터 UTC로 밀리 초로 생각할 수 있습니다. 시간대로 변환되지 않은 api의 관점에서 해당 LocalDate (yyyy-mm-dd)를 가져 오려면 ZoneOffset.UTC를 사용하여 현지 시간 대로이 순간 오프셋을 사용하지 않아야합니다. ZoneId.systemDefault ()의 예제가 날짜 형식 서버를 바꾸고 있지 않습니까? 전의. instant는 2018-10-20 0:00을 나타내고 UTC에서 America / Los_Angeles로 옮겨 2018-10-20 대신 현지 날짜 2018-10-19에 표시됩니까?
— Michał Ziobro

import java.sql.Date파일에 있으면 발생 합니다 : 항상 던지는 toInstant()방법 java.sql.Date.
— Oliv

4
Date input = new Date();
LocalDateTime  conv=LocalDateTime.ofInstant(input.toInstant(), ZoneId.systemDefault());
LocalDate convDate=conv.toLocalDate();

Date인스턴스는 동안 날짜도 함께 시간을 포함하지 LocalDate않습니다. 따라서 먼저 LocalDateTime메서드 를 사용하여 변환 한 다음 시간ofInstant() 없이 원한다면 인스턴스를로 변환 할 수 있습니다.LocalDate


1
public static LocalDate Date2LocalDate(Date date) {
        return LocalDate.parse(date.toString(), DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz yyyy"))

이 형식은 Date#tostring

    public String toString() {
        // "EEE MMM dd HH:mm:ss zzz yyyy";
        BaseCalendar.Date date = normalize();
        StringBuilder sb = new StringBuilder(28);
        int index = date.getDayOfWeek();
        if (index == BaseCalendar.SUNDAY) {
            index = 8;
        }
        convertToAbbr(sb, wtb[index]).append(' ');                        // EEE
        convertToAbbr(sb, wtb[date.getMonth() - 1 + 2 + 7]).append(' ');  // MMM
        CalendarUtils.sprintf0d(sb, date.getDayOfMonth(), 2).append(' '); // dd

        CalendarUtils.sprintf0d(sb, date.getHours(), 2).append(':');   // HH
        CalendarUtils.sprintf0d(sb, date.getMinutes(), 2).append(':'); // mm
        CalendarUtils.sprintf0d(sb, date.getSeconds(), 2).append(' '); // ss
        TimeZone zi = date.getZone();
        if (zi != null) {
            sb.append(zi.getDisplayName(date.isDaylightTime(), TimeZone.SHORT, Locale.US)); // zzz
        } else {
            sb.append("GMT");
        }
        sb.append(' ').append(date.getYear());  // yyyy
        return sb.toString();
    }

0

JBoss EAP 6에서 @JodaStephen의 구현에 문제가 있었으므로 http://docs.oracle.com/javase/tutorial/datetime/iso/legacy.html 의 Oracle Java Tutorial에 따라 변환을 다시 작성했습니다 .

    Date input = new Date();
    GregorianCalendar gregorianCalendar = (GregorianCalendar) Calendar.getInstance();
    gregorianCalendar.setTime(input);
    ZonedDateTime zonedDateTime = gregorianCalendar.toZonedDateTime();
    zonedDateTime.toLocalDate();

-2

이 간단한 1 줄의 문제점은 무엇입니까?

new LocalDateTime(new Date().getTime()).toLocalDate();

Java는 기본 유형 long에서 toLocalDate ()를 호출 할 수 없다고 불평합니다. 실제 Date 객체를 사용했습니다. 아마도 문지름이 있습니까 ??
— TheGeeko61

-8

아래 솔루션 으로이 질문을 해결했습니다.

  import org.joda.time.LocalDate;
  Date myDate = new Date();
  LocalDate localDate = LocalDate.fromDateFields(myDate);
  System.out.println("My date using Date" Nov 18 11:23:33 BRST 2016);
  System.out.println("My date using joda.time LocalTime" 2016-11-18);

이 경우 localDate는 "yyyy-MM-dd"형식으로 날짜를 인쇄합니다


1
문제는 java.timeJoda Time이 아니라 JDK8 의 클래스를 사용하는 솔루션을 찾고 있습니다.
— pioto
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.