610 Stimmen

Konvertiere java.util.Date in java.time.LocalDate

Was ist der beste Weg, ein java.util.Date-Objekt in das neue JDK 8/JSR-310 java.time.LocalDate umzuwandeln?

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

981voto

JodaStephen Punkte 57302

Kurze Antwort

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

Erklärung

Trotz seines Namens repräsentiert java.util.Date einen Zeitpunkt auf der Zeitleiste und nicht ein "Datum". Die tatsächlichen Daten, die im Objekt gespeichert sind, sind ein long-Zähler von Millisekunden seit 1970-01-01T00:00Z (Mitternacht zu Beginn von 1970 GMT/UTC).

Die äquivalente Klasse zu java.util.Date in JSR-310 ist Instant und somit gibt es eine praktische Methode toInstant() zur Konvertierung:

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

Ein Objekt vom Typ java.util.Date hat kein Konzept von Zeitzone. Dies mag seltsam erscheinen, wenn Sie toString() auf ein java.util.Date aufrufen, da das toString relativ zu einer Zeitzone ist. Diese Methode verwendet jedoch tatsächlich die Standardzeitzone von Java, um die Zeichenkette bereitzustellen. Die Zeitzone ist kein Teil des tatsächlichen Zustands von java.util.Date.

Ein Instant enthält ebenfalls keine Informationen über die Zeitzone. Daher ist es notwendig, beim Konvertieren von einem Instant zu einem lokalen Datum eine Zeitzone anzugeben. Das kann die Standardzeitzone sein - ZoneId.systemDefault() - oder es kann eine Zeitzone sein, die Ihre Anwendung steuert, z. B. eine Zeitzone aus Benutzereinstellungen. Verwenden Sie die Methode atZone(), um die Zeitzone anzuwenden:

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

Ein ZonedDateTime enthält Zustände, die aus dem lokalen Datum und der Uhrzeit, der Zeitzone und dem Offset von GMT/UTC bestehen. Daher kann das Datum - LocalDate - leicht extrahiert werden und zwar mithilfe von toLocalDate():

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

Java 9 Antwort

In Java SE 9 wurde eine neue Methode hinzugefügt, die diese Aufgabe leicht vereinfacht:

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

Diese neue Alternative ist direkter, erzeugt weniger Müll und sollte daher besser performen.

186voto

Oliv Punkte 9469

Der bessere Weg ist:

Datum datum = ...;
Instant.ofEpochMilli(datum.getTime()).atZone(ZoneId.systemDefault()).toLocalDate()

Vorteile dieser Version:

  • funktioniert unabhängig davon, ob die Eingabe eine Instanz von java.util.Date ist oder eine Unterklasse von java.sql.Date ist (im Gegensatz zur Methode von @JodaStephen). Dies ist häufig bei aus JDBC stammenden Daten der Fall. java.sql.Date.toInstant() wirft immer eine Ausnahme.

  • es ist das gleiche für JDK8 und JDK7 mit JSR-310-Backport

Ich persönlich verwende eine Hilfsklasse (die jedoch nicht rückwärtskompatibel ist):

/**
 * Dienstprogramme zur Konvertierung zwischen den alten und neuen JDK-Datentypen
 * (zwischen {@code java.util.Date} und {@code java.time.*}).
 * 
 * 
 * Alle Methoden sind nullsicher.
 */
public class DateConvertUtils {

    /**
     * Ruft {@link #asLocalDate(Date, ZoneId)} mit der systemeigenen Zeitzone auf.
     */
    public static LocalDate asLocalDate(java.util.Date datum) {
        return asLocalDate(datum, ZoneId.systemDefault());
    }

    /**
     * Erstellt {@link LocalDate} aus {@code java.util.Date} oder dessen Unterklasse. Nullsicher.
     */
    public static LocalDate asLocalDate(java.util.Date datum, ZoneId zone) {
        if (datum == null)
            return null;

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

    /**
     * Ruft {@link #asLocalDateTime(Date, ZoneId)} mit der systemeigenen Zeitzone auf.
     */
    public static LocalDateTime asLocalDateTime(java.util.Date datum) {
        return asLocalDateTime(datum, ZoneId.systemDefault());
    }

    /**
     * Erstellt {@link LocalDateTime} aus {@code java.util.Date} oder dessen Unterklasse. Nullsicher.
     */
    public static LocalDateTime asLocalDateTime(java.util.Date datum, ZoneId zone) {
        if (datum == null)
            return null;

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

    /**
     * Ruft {@link #asUtilDate(Object, ZoneId)} mit der systemeigenen Zeitzone auf.
     */
    public static java.util.Date asUtilDate(Object datum) {
        return asUtilDate(datum, ZoneId.systemDefault());
    }

    /**
     * Erstellt ein {@link java.util.Date} aus verschiedenen Datumsobjekten. Ist nullsicher. Derzeit werden unterstützt:
     * {@link java.util.Date}
     * {@link java.sql.Date}
     * {@link java.sql.Timestamp}
     * {@link java.time.LocalDate}
     * {@link java.time.LocalDateTime}
     * {@link java.time.ZonedDateTime}
     * {@link java.time.Instant}
     * 
     * 
     * @param zone Zeitzone, wird nur verwendet, wenn das Eingabeobjekt LocalDate oder LocalDateTime ist.
     * 
     * @return {@link java.util.Date} (genau diese Klasse, nicht eine Unterklasse wie java.sql.Date)
     */
    public static java.util.Date asUtilDate(Object datum, ZoneId zone) {
        if (datum == null)
            return null;

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

        throw new UnsupportedOperationException("Weiß nicht, wie man " + datum.getClass().getName() + " in java.util.Date konvertiert");
    }

    /**
     * Erstellt ein {@link Instant} aus {@code java.util.Date} oder dessen Unterklasse. Nullsicher.
     */
    public static Instant asInstant(Date datum) {
        if (datum == null)
            return null;
        else
            return Instant.ofEpochMilli(datum.getTime());
    }

    /**
     * Ruft {@link #asZonedDateTime(Date, ZoneId)} mit der systemeigenen Zeitzone auf.
     */
    public static ZonedDateTime asZonedDateTime(Date datum) {
        return asZonedDateTime(datum, ZoneId.systemDefault());
    }

    /**
     * Erstellt {@link ZonedDateTime} aus {@code java.util.Date} oder dessen Unterklasse. Nullsicher.
     */
    public static ZonedDateTime asZonedDateTime(Date datum, ZoneId zone) {
        if (datum == null)
            return null;
        else
            return asInstant(datum).atZone(zone);
    }

}

Die Methode asLocalDate() hier ist nullsicher, verwendet toLocalDate(), wenn die Eingabe eine java.sql.Date ist (sie kann vom JDBC-Treiber überschrieben werden, um Zeitprobleme oder unnötige Berechnungen zu vermeiden), andernfalls verwendet sie die oben genannte Methode.

26voto

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

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

21voto

dhalsim2 Punkte 926

Wenn Sie Java 8 verwenden, ist @JodaStephen's Antwort offensichtlich die beste. Wenn Sie jedoch mit dem JSR-310-Backport arbeiten, müssen Sie leider etwas Ähnliches tun:

Datum input = new Date();
Kalender kal = Calendar.getInstance();
kal.setTime(input);
LocalDate datum = LocalDate.of(kal.get(Calendar.YEAR),
        kal.get(Calendar.MONTH) + 1,
        kal.get(Calendar.DAY_OF_MONTH));

16voto

Gustavo Punkte 1247
LocalDate ld = new java.sql.Date( new java.util.Date().getTime() ).toLocalDate();

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X