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 "는 시간대가없는 일"을 말한다. 그럼 왜에서 변환 DateInstantLocalDate요구 atZone(ZoneId.systemDefault())?
구스타보

8
@Gustavo : LocalDateLocalDateTime없습니다 "상점 또는 시간 또는 시간대 대표"할 (참조 :의 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.