Pitfall getDate()

Lange kein JDBC mehr gemacht und prompt in die Date-Time-Timestamp-Falle getappt.

1. Date vs. Timestamp

Haben wir in der Datenbank z. B. PostgreSQL ein Date, dann ist es auch nur ein Datum ohne Zeit. In Oracle hingegen sagt DATE, dass wir auch eine Zeit anbei haben.
Besitzt nun die Datenbank-Spalte einen Zeitanteil und man benutzt java.sql.ResultSet.getDate(String), dann erhält man ein java.sql.Date nur mit einem Datum. Ruft man java.sql.ResultSet.getTimestamp(String) auf, dann erhält man ein java.sql.Timestamp, der ein java.util.Date ist und klaglos dem Konstruktor in meinem Row-Mapper übergeben wird.

Dieser Timestamp besitzt nun einen Zeitanteil wie gewünscht, bring aber einen Gotcha mit. Das Gemeine an der Sache ist, dass dieser Timestamp nicht kommutativ bzgl. der equals() Methode ist.


public boolean Timestamp.equals(java.lang.Object ts) {
if (ts instanceof Timestamp) {
return this.equals((Timestamp)ts);
} else {
return false;
}
}

Siehe hierzu auch Martin Odersky: How to Write an Equality Method in Java bzw. Joshua Bloch: Effective Java Programming.

Mittlerweile benutze ich, wenn es geht, ein Long in der Datenbank, bzw. eine String-Repräsentanz wie z. B. „yyyyDDMMHH24MI“. Letzeres ist zwar langsamer, aber vernünftig zu lesen, wenn man wie ich gerne in die DB selbst schaut.

Das kann man auch sehr schön als org.hibernate.usertype.UserType modellieren CalendarUserType -> long.

Aber es gibt durchaus auch andere Weisen, damit umzugehen Convert a java.sql.Timestamp Object to a java.util.Date Object?. 😀

2. java.sql.ResultSet.getDate(…, Calendar)

Gibt man bei obiger Methode keinen Calendar an, dann wird der der VM benutzt. Das zeitigt zum Teil üble Fehler, besonders wenn der Hosting-Dienstleister virtualisert oder ein neues Blech mit geänderter Timezone usw. hinstellt. Man sollte hier „immer“ den richtigen Calendar explizit übergeben. In der Praxis habe ich das bisher sehr selten gesehen und wundere mich, warum das alles überhaupt funktioniert.