Gibt es eine einfache Möglichkeit, ein LocalDate
(eingeführt mit Java 8) in ein java.util.Date
Objekt zu konvertieren?
Mit 'einfach' meine ich einfacher als dies:
Date date = Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
was mir ein wenig umständlich erscheint.
Da wir uns nur für den Datumsteil interessieren und es in keinem der Objekte Zeitzoneninformationen gibt, warum sollten wir dann explizit Zeitzonen einführen? Die Mitternachtszeit und die Standardzeitzone des Systems sollten implizit für die Konvertierung verwendet werden.
Das gibt es tatsächlich. Es gibt eine statische Methode valueOf im Objekt java.sql.Date
, die genau das tut. Wir haben also
java.util.Date date = java.sql.Date.valueOf(localDate);
und das war's. Keine explizite Einstellung von Zeitzonen, da die lokale Zeitzone implizit übernommen wird.
Aus der Doku:
Das angegebene LocalDate wird als das lokale Datum in der lokalen Zeitzone interpretiert.
Das java.sql.Date
ist eine Unterklasse von java.util.Date
, so dass das Ergebnis auch ein java.util.Date
ist.
Und für die umgekehrte Operation gibt es eine toLocalDate Methode in der java.sql.Date Klasse. Wir haben also:
LocalDate ld = new java.sql.Date(date.getTime()).toLocalDate();
Gibt es eine einfache Möglichkeit, ein LocalDate (eingeführt mit Java 8) in ein java.util.Date Objekt zu konvertieren? Mit 'einfach', meine ich einfacher als dies Nö. Sie haben es richtig und so prägnant wie möglich gemacht.
java.util.Date.from( // Convert from modern java.time class to troublesome old legacy class. DO NOT DO THIS unless you must, to inter operate with old code not yet updated for java.time.
myLocalDate // `LocalDate` class represents a date-only, without time-of-day and without time zone nor offset-from-UTC.
.atStartOfDay( // Let java.time determine the first moment of the day on that date in that zone. Never assume the day starts at 00:00:00.
ZoneId.of( "America/Montreal" ) // Specify time zone using proper name in `continent/region` format, never 3-4 letter pseudo-zones such as “PST”, “CST”, “IST”.
) // Produce a `ZonedDateTime` object.
.toInstant() // Extract an `Instant` object, a moment always in UTC.
)
Lesen Sie unten die Probleme, und denken Sie dann darüber nach. Wie könnte es noch einfacher sein? Wenn Sie mich fragen, um wie viel Uhr ein Datum beginnt, wie könnte ich sonst antworten als mit "Wo?"? Ein neuer Tag beginnt in Paris FR früher als in Montréal CA, und noch früher in Kolkata IN, und noch früher in Auckland NZ, alles unterschiedliche Zeitpunkte.
Bei der Konvertierung eines reinen Datums (LocalDate
) in eine Datumszeit müssen wir also eine Zeitzone (ZoneId
) anwenden, um einen zonierten Wert (ZonedDateTime
) zu erhalten, und dann in UTC (Instant
) wechseln, um der Definition eines java.util.Date
zu entsprechen.
Erstens: Vermeiden Sie, wann immer es möglich ist, die alten, veralteten Datums-Zeit-Klassen wie java.util.Date
. Sie sind schlecht entworfen, verwirrend und lästig. Sie wurden nicht ohne Grund von den java.time-Klassen verdrängt, und zwar aus vielen Gründen.
Aber wenn es sein muss, können Sie in/aus java.time-Typen in die alten konvertieren. Achten Sie auf neue Konvertierungsmethoden, die den alten Klassen hinzugefügt wurden.
java.util.Date
→ java.time.LocalDate
Denken Sie daran, dass java.util.Date
eine falsche Bezeichnung ist, da es ein Datum plus eine Tageszeit in UTC darstellt. Im Gegensatz dazu stellt die Klasse LocalDate einen reinen Datumswert ohne Uhrzeit und Zeitzone dar.
Der Wechsel von java.util.Date
zu java.time bedeutet eine Konvertierung in die entsprechende Klasse java.time.Instant
. Die Klasse Instant
repräsentiert einen Moment auf der Zeitachse in UTC mit einer Auflösung von Nanosekunden (bis zu neun (9) Stellen eines Dezimalbruchs).
Instant instant = myUtilDate.toInstant();
Die Klasse LocalDate
stellt einen reinen Datumswert ohne Uhrzeit und ohne Zeitzone dar.
Die Zeitzone ist entscheidend für die Bestimmung eines Datums. Zu jedem beliebigen Zeitpunkt variiert das Datum rund um den Globus je nach Zeitzone. Zum Beispiel ist ein paar Minuten nach Mitternacht in Paris Frankreich ein neuer Tag, während es in Montréal Québec noch "gestern" ist.
Also müssen wir diesen Instant
in eine Zeitzone verschieben. Wir wenden ZoneId
an, um eine ZonedDateTime
zu erhalten.
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );
Von dort aus fragen wir nach einem reinen Datum, einem LocalDate
.
LocalDate ld = zdt.toLocalDate();
java.time.LocalDate
→ java.util.Date
Der Wechsel in die andere Richtung, von einem java.time.LocalDate
zu einem java.util.Date
bedeutet, dass wir von einem reinen Datum zu einer Datumszeit übergehen. Wir müssen also eine Tageszeit angeben. Wahrscheinlich wollen Sie den ersten Moment des Tages wählen. Nehmen Sie nicht an, dass dies 00:00:00
ist. Anomalien wie die Sommerzeit (DST) bedeuten, dass der erste Moment eine andere Zeit sein kann, wie zum Beispiel 01:00:00
. Lassen Sie java.time diesen Wert durch den Aufruf von atStartOfDay
auf dem LocalDate
bestimmen.
ZonedDateTime zdt = myLocalDate.atStartOfDay( z );
Jetzt extrahiere eine Instant
.
Instant instant = zdt.toInstant();
Konvertieren Sie diese Instant
in java.util.Date
durch Aufruf von from( Instant )
.
java.util.Date d = java.util.Date.from( instant );
Das java.time Framework ist in Java 8 und höher eingebaut. Diese Klassen ersetzen die lästigen alten legacy Datum-Zeit-Klassen wie java.util.Date
, Calendar
, & SimpleDateFormat
.
Das Joda-Time Projekt, das sich jetzt im Wartungsmodus befindet, rät zur Migration auf die java.time Klassen.
Weitere Informationen finden Sie im Oracle Tutorial. Und suchen Sie bei Stack Overflow nach vielen Beispielen und Erklärungen. Die Spezifikation ist JSR 310.
Sie können java.time-Objekte direkt mit Ihrer Datenbank austauschen. Verwenden Sie einen JDBC-Treiber, der mit JDBC 4.2 oder höher kompatibel ist. Sie brauchen keine Strings und keine java.sql.*
-Klassen.
Wo erhält man die java.time-Klassen?
Interval
, YearWeek
, YearQuarter
, und more.Sie können das java.util.Date
-Objekt in ein String
-Objekt umwandeln, das das Datum als yyyy-mm-dd formatiert.
LocalDate hat eine parse
Methode, die es in ein LocalDate
Objekt umwandelt. Der String muss ein gültiges Datum darstellen und wird mit DateTimeFormatter.ISO_LOCAL_DATE geparst.
Datum zu LocalDate
LocalDate.parse(Date.toString())