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 = ???
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 = ???
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.
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.
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));
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.