java.util.Date
vs java.sql.Date
: wann und warum?
Herzlichen Glückwunsch, Sie haben mit JDBC meinen Lieblings-Pet-Peeve getroffen: Umgang mit Datumsklassen.
Grundsätzlich unterstützen Datenbanken normalerweise mindestens drei Arten von Datums- / Uhrzeitfeldern: Datum, Uhrzeit und Zeitstempel. Jeder von ihnen hat eine entsprechende Klasse in JDBC und jeder von ihnen wird erweitertjava.util.Date
. Die schnelle Semantik jeder dieser drei ist die folgende:
java.sql.Date
entspricht SQL DATE, dh es werden Jahre, Monate und Tage gespeichert, während Stunde, Minute, Sekunde und Millisekunde ignoriert werden. Darüber hinaus sql.Date
ist nicht an Zeitzonen gebunden.java.sql.Time
entspricht SQL TIME und enthält, wie offensichtlich sein sollte, nur Informationen zu Stunden, Minuten, Sekunden und Millisekunden .java.sql.Timestamp
entspricht SQL TIMESTAMP, dem genauen Datum der Nanosekunde ( beachten Sie, dass util.Date
nur Millisekunden unterstützt werden! ) mit anpassbarer Genauigkeit.Einer der häufigsten Fehler bei der Verwendung von JDBC-Treibern in Bezug auf diese drei Typen ist, dass die Typen falsch behandelt werden. Dies bedeutet, dass dies sql.Date
zeitzonenspezifisch ist und sql.Time
das aktuelle Jahr, den aktuellen Monat und den aktuellen Tag usw. enthält.
Kommt wirklich auf den SQL-Typ des Feldes an. PreparedStatement
hat Setter für alle drei Werte, #setDate()
die für sql.Date
, #setTime()
für sql.Time
und #setTimestamp()
für sql.Timestamp
.
Beachten Sie, dass Sie bei Verwendung der meisten JDBC-Treibern ps.setObject(fieldIndex, utilDateObject);
tatsächlich einen normalen util.Date
Wert geben können, der ihn gerne verschlingt, als wäre er vom richtigen Typ. Wenn Sie die Daten anschließend anfordern, werden Sie möglicherweise feststellen, dass Ihnen tatsächlich etwas fehlt.
Was ich damit sagen möchte , dass Sie die Millisekunden / Nanosekunden als einfache Longs speichern und sie in die von Ihnen verwendeten Objekte konvertieren ( obligatorischer Joda-Time-Plug ). Eine hackige Möglichkeit, die durchgeführt werden kann, besteht darin, die Datumskomponente als eine lange und eine Zeitkomponente als eine andere zu speichern. Diese lauten derzeit beispielsweise 20100221 und 154536123. Diese magischen Zahlen können in SQL-Abfragen verwendet werden und können von der Datenbank in eine andere und portiert werden Damit können Sie diesen Teil der JDBC / Java-Datums-API: s vollständig vermeiden.
LATE EDIT: Ab Java 8 sollten Sie weder verwenden
java.util.Date
nochjava.sql.Date
wenn Sie es überhaupt vermeiden können, und stattdessen lieber dasjava.time
Paket (basierend auf Joda) als irgendetwas anderes verwenden. Wenn Sie nicht mit Java 8 arbeiten, finden Sie hier die ursprüngliche Antwort:java.sql.Date
- wenn Sie Methoden / Konstruktoren von Bibliotheken aufrufen, die sie verwenden (wie JDBC). Nicht anders. Sie möchten keine Abhängigkeiten in die Datenbankbibliotheken für Anwendungen / Module einführen, die sich nicht explizit mit JDBC befassen.java.util.Date
- bei Verwendung von Bibliotheken, die es verwenden. Ansonsten so wenig wie möglich aus mehreren Gründen:Es ist veränderlich, was bedeutet, dass Sie jedes Mal, wenn Sie es an eine Methode übergeben oder von einer Methode zurückgeben, eine defensive Kopie davon erstellen müssen.
Es geht nicht sehr gut mit Datumsangaben um, was Leute wie Ihre wirklich rückwärts denken, dass Datumsbehandlungsklassen dies tun sollten.
Nun, weil juD seine Arbeit nicht sehr gut macht, wurden die schrecklichen
Calendar
Klassen eingeführt. Sie sind auch veränderlich und schrecklich zu bearbeiten und sollten vermieden werden, wenn Sie keine Wahl haben.Es gibt bessere Alternativen, wie die Joda Time API (
die es möglicherweise sogar in Java 7schafftund zur neuen offiziellen API für die Datumsverarbeitung wird- eine schnelle Suche sagt, dass dies nicht der Fall ist).Wenn Sie der Meinung sind, dass es übertrieben ist, eine neue Abhängigkeit wie Joda einzuführen, ist
long
es gar nicht so schlecht, sie für Zeitstempelfelder in Objekten zu verwenden, obwohl ich sie normalerweise selbst in juD einwickle, wenn ich sie weitergebe, zur Typensicherheit und als Dokumentation.quelle
java.sql.Date
mitPreparedStatement
etc! Wenn Sie es jedoch weitergeben, verwenden Sie ein,LocalDate
das Sie mitjava.sql.Date.valueOf
undjava.sql.Date.valueOf
beim Festlegen konvertieren, und konvertieren Sie es so früh wie möglich mitjava.sql.Date.toLocalDate
- wieder, weil Sie java.sql so wenig wie möglich einbeziehen möchten und weil es veränderbar ist.Die einzige Zeit zu verwenden
java.sql.Date
ist in aPreparedStatement.setDate
. Andernfalls verwenden Siejava.util.Date
. Es ist bezeichnend, dassResultSet.getDate
a zurückgegeben wird,java.sql.Date
aber es kann direkt a zugewiesen werdenjava.util.Date
.quelle
java.sql.Date
kann,java.util.Date
wenn das erstere das letztere erweitert? Was ist der Punkt, den Sie versuchen zu machen?Ich hatte das gleiche Problem. Der einfachste Weg, das aktuelle Datum in eine vorbereitete Erklärung einzufügen, ist folgender:
quelle
tl; dr
Verwenden Sie keine.
java.time.Instant
ersetztjava.util.Date
java.time.LocalDate
ersetztjava.sql.Date
Weder
Beide Klassen sind schrecklich, fehlerhaft im Design und in der Implementierung. Vermeiden Sie wie das
Pest-Coronavirus .Verwenden Sie stattdessen java.time- Klassen, die in JSR 310 definiert sind. Diese Klassen sind ein branchenführendes Framework für die Arbeit mit der Datums- und Uhrzeitbehandlung. Dieser supplant völlig die blutigen schreckliches Erbe Klassen wie
Date
,Calendar
,SimpleDateFormat
, und so weiter .java.util.Date
Der erste
java.util.Date
soll einen Moment in UTC darstellen, dh einen Versatz von UTC von null Stunden-Minuten-Sekunden.java.time.Instant
Jetzt ersetzt durch
java.time.Instant
.java.time.OffsetDateTime
Instant
ist die grundlegende Bausteinklasse von java.time . Verwenden Sie für mehr FlexibilitätOffsetDateTime
set toZoneOffset.UTC
für denselben Zweck: einen Moment in UTC darstellen.Sie können dieses Objekt mithilfe
PreparedStatement::setObject
von JDBC 4.2 oder höher an eine Datenbank senden .Abrufen.
java.sql.Date
Die
java.sql.Date
Klasse ist auch schrecklich und veraltet.Diese Klasse soll nur ein Datum ohne Tageszeit und ohne Zeitzone darstellen. Leider erbt diese Klasse in einem schrecklichen Hack eines Entwurfs, von
java.util.Date
dem ein Moment dargestellt wird (ein Datum mit Uhrzeit in UTC). Diese Klasse gibt also lediglich vor, nur ein Datum zu sein, während sie tatsächlich eine Tageszeit und einen impliziten Versatz von UTC enthält. Das verursacht so viel Verwirrung. Verwenden Sie niemals diese Klasse.java.time.LocalDate
Verwenden Sie stattdessen, um
java.time.LocalDate
nur ein Datum (Jahr, Monat, Tag des Monats) ohne Tageszeit oder Zeitzone oder Versatz zu verfolgen.An die Datenbank senden.
Abrufen.
Über java.time
Das java.time- Framework ist in Java 8 und höher integriert. Diese Klassen verdrängen die lästigen alten Legacy - Datum-Zeit - Klassen wie
java.util.Date
,Calendar
, &SimpleDateFormat
.Weitere Informationen finden Sie im Oracle-Lernprogramm . Suchen Sie im Stapelüberlauf nach vielen Beispielen und Erklärungen. Die Spezifikation ist JSR 310 .
Das Joda-Time- Projekt, das sich jetzt im Wartungsmodus befindet , empfiehlt die Migration zu den Klassen java.time .
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 . Keine Notwendigkeit für Zeichenfolgen, keine Notwendigkeit für
java.sql.*
Klassen.Woher bekomme ich die java.time-Klassen?
quelle
Die Klasse java.util.Date in Java repräsentiert einen bestimmten Zeitpunkt (z. B. 2013, 25. November, 16:30:45 Uhr bis auf Millisekunden), aber der Datentyp DATE in der Datenbank repräsentiert nur ein Datum (z. 2013, 25. November). Um zu verhindern, dass Sie versehentlich ein java.util.Date-Objekt für die Datenbank bereitstellen, können Sie in Java keinen SQL-Parameter direkt auf java.util.Date setzen:
Sie können dies jedoch weiterhin mit Gewalt / Absicht tun (dann werden Stunden und Minuten vom DB-Treiber ignoriert). Dies geschieht mit der Klasse java.sql.Date:
Ein java.sql.Date-Objekt kann einen Moment in der Zeit speichern (so dass es einfach ist, aus einem java.util.Date zu konstruieren), löst jedoch eine Ausnahme aus, wenn Sie versuchen, es nach den Stunden zu fragen (um sein Konzept, ein zu sein, durchzusetzen nur Datum). Es wird erwartet, dass der DB-Treiber diese Klasse erkennt und nur 0 für die Stunden verwendet. Versuche dies:
quelle
java.util.Date
repräsentiert einen bestimmten Zeitpunkt mit Millisekundengenauigkeit. Es repräsentiert sowohl Datums- als auch Zeitinformationen ohne Zeitzone. Die Klasse java.util.Date implementiert die Schnittstelle Serializable, Cloneable und Comparable. Es wird vererbtjava.sql.Date
,java.sql.Time
undjava.sql.Timestamp
Schnittstellen.java.sql.Date
erweitert die Klasse java.util.Date, die ein Datum ohne Zeitangabe darstellt und nur beim Umgang mit Datenbanken verwendet werden sollte. Um der Definition von SQL DATE zu entsprechen, müssen die von einerjava.sql.Date
Instanz umschlossenen Millisekundenwerte "normalisiert" werden, indem die Stunden, Minuten, Sekunden und Millisekunden in der bestimmten Zeitzone, der die Instanz zugeordnet ist, auf Null gesetzt werden.Es erbt alle öffentlichen Methoden
java.util.Date
wiegetHours()
,getMinutes()
,getSeconds()
,setHours()
,setMinutes()
,setSeconds()
. Dajava.sql.Date
die Zeitinformationen nicht gespeichert werden, werden alle Zeitoperationen von überschriebenjava.util.Date
und alle diese Methoden werden ausgelöst,java.lang.IllegalArgumentException
wenn sie aufgerufen werden, wie aus den Implementierungsdetails hervorgeht.quelle