UnsupportedOperationException – Warum können Sie toInstant() nicht für ein java.sql.Date aufrufen?

Lesezeit: 6 Minuten

Benutzer-Avatar
Andreas Mairose

Das java.util.Date Klasse hat eine Methode namens toInstant() das konvertiert die Date Beispiel zu a java.time.Instant.

Das java.sql.Date Klasse erweitert die java.util.Date Klasse, aber wenn ich versuche anzurufen toInstant() auf einen java.sql.Dateich erhalte eine UnsupportedOperationException.

Warum ist toInstant() eine nicht unterstützte Operation auf java.sql.Date?

Und wie konvertiert man a java.sql.Date zu einem java.time.Instant?

Die richtige Zuordnung zwischen java.sql.Date und java.time ist LocalDate:

LocalDate date = sqlDate.toLocalDate();

Wenn es wirklich sein musskönnen Sie dann ein ableiten Instant, obwohl die zusätzlichen Informationen (Zeit) willkürlich sein werden. Zum Beispiel:

Instant i = date.atStartOfDay(ZoneOffset.UTC).toInstant();

  • Ich wünschte, ich könnte zwei Antworten akzeptieren … Dies beantwortet den zweiten Teil meiner Frage perfekt, aber die Hauptfrage war, warum Sie nicht anrufen können toInstant() auf einen java.sql.Date, also musste ich die Antwort von @YassinHajaj akzeptieren. Diese Antwort braucht mehr Upvotes.

    – Andreas Mairose

    6. April 2016 um 13:26 Uhr


  • Seit date ein LocalDate (lokale Zeitzone) ist, sollte die Konvertierung in Instant (was UTC ist) nicht die lokale Zeitzone angeben?: Instant i = date.atStartOfDay(ZoneId.systemDefault()).toInstant()

    – Curtis Yallop

    29. Oktober 2021 um 16:38 Uhr

Benutzer-Avatar
Yassin Hajaj

Laut dem JavaDoc

Seit sql.Date keine Zeitkomponente hat, gibt es keine Möglichkeit, sie umzuwandeln time.Instant

Diese Methode löst immer eine UnsupportedOperationException aus und sollte nicht verwendet werden, da SQL-Datumswerte keine Zeitkomponente haben.

  • Nun ist die Frage warum es wurde so konzipiert. Man könnte sich vorstellen, dass die Zeitangaben standardmäßig auf 0 gesetzt sind. In der Mailingliste kann ich nichts finden.

    – Tunaki

    5. April 2016 um 19:58 Uhr


  • @Tunaki Die Logik lässt mich denken, dass es an der Elternklasse liegt util.Date hat ein Publikum toInstant Methode, die von der untergeordneten Klasse nicht verwendet werden sollte. Also anstatt es zu machen final (um die Vererbungslogik beizubehalten), bevorzugten sie die Option, sie zu überschreiben und unbrauchbar zu machen.

    – Yassin Hajaj

    5. April 2016 um 20:02 Uhr


  • @Tunaki wahrscheinlich, weil, wie Sie betonen, jede Konvertierung in einen Instant die willkürliche Einstellung einiger Daten (Zeit, Zeitzone) erfordern würde.

    – Assylias

    6. April 2016 um 7:24 Uhr

  • Aber Instant mit der gleichen Logik, dass java.util.Date Verwendungen korrekte und logische Ergebnisse liefern würden, während eine Verletzung des Polymorphievertrags vermieden würde. Oracle hat da eine sehr kopfkratzende Wahl getroffen.

    – Haroldo_OK

    24. Juni um 12:15 Uhr

Benutzer-Avatar
Lok

java.sql.Datum unterstützt nur Datumskomponenten (Datum, Monat, Jahr). Zeitkomponenten (Stunde, Minute, Sekunde, Millisekunde) werden NICHT unterstützt. zuInstant erfordert sowohl Date- als auch Time-Komponenten, daher löst toInstant auf der java.sql.Date-Instanz eine UnsupportedOperationException-Ausnahme aus.

zuInstant Java doc

Diese Methode löst immer eine UnsupportedOperationException aus und sollte nicht verwendet werden, da SQL-Datumswerte keine Zeitkomponente haben.

java.util.Date ODER java.sql.Timestamp hat beide Date/Time-Komponenten, also funktioniert toInstant()!

Sie können Folgendes tun:

// Time is 00:00:00.000

new java.util.Date(sqlDate.getTime()).toInstant() 

Aktualisiert:

Instant.ofEpochMilli(sqlDate.getTime());

// and
new java.util.Date(sqlDate.getTime()).toInstant();

gibt das gleiche Ergebnis zurück, da die Methode toInstant() intern Instant.ofEpochMilli(getTime()) aufruft.

public Instant toInstant() {
    return Instant.ofEpochMilli(getTime());
}

  • Was ist “richtiger”? Instant.ofEpochMilli(sqlDate.getTime()); oder new java.util.Date(sqlDate.getTime()).toInstant();

    – Andreas Mairose

    5. April 2016 um 19:44 Uhr

  • Sie können ein java.sql.Date nicht in ein Instant umwandeln, ohne eine Zeitzone anzugeben. Der Aufruf von getTime() an einem java.sql.Date ist bedeutungslos. Wie in anderen Kommentaren erwähnt, ist java.sql.Date nur ein LocalDate und stellt keinen Zeitpunkt dar.

    – Alexander Kiel

    29. November 2017 um 8:19 Uhr

  • Ich habe Instant nicht am Java-SQL-Datum angerufen. Ich habe toInstant am Java-Utility-Datum angerufen und es ist für den Fall in Ordnung.

    – Lok

    29. November 2017 um 15:02 Uhr

Die bisher gegebenen Antworten konzentrieren sich bisher auf das Detail, das java.sql.Date hat keine Zeitangaben. Das ist richtig, aber nicht der wirkliche oder hinreichende Grund, warum dieser Typ keine direkte Konvertierung anbieten kann Instant. Leider die Dokumentation von Java-8 macht den gleichen Fehler, Benutzer glauben zu lassen, dass das Problem nur auf fehlende Zeitinformationen zurückzuführen ist.

Begrifflich der Typ java.sql.Date stellt einen lokalen Typ dar. Es modelliert ein Kalenderdatum, das in jeder Region unseres Globus unterschiedlich sein kann. Aber ein Instant ist das gleiche auf unserem Globus herum. Benutzer benötigen also eine Zeitzone oder einen Zeitzonen-Offset, um die Konvertierung durchzuführen.

Tragischerweise der Typ java.sql.Date erbt von java.util.Date das ist ein globaler Typ (instant-like). Diese Vererbung bezeichnet jedoch wirklich die Implementierungsvererbung und nicht die Typvererbung. Ein Grund mehr, das Design dieser alten JDBC-Klassen als kaputt anzusehen. Daher ist es tatsächlich möglich, den Hack zum Wrappen zu verwenden java.sql.Date über seine Methode getTime() innerhalb einer Instanz von java.util.Date was endlich die direkte Umwandlung in einen Augenblick ermöglicht. Aber: Diese Konvertierung verwendet implizit die Standardzeitzone des Systems.

Wie konvertiert man also richtig umständlich? Betrachten wir die Dokumentation von Java-8 wieder was hier in die richtige Richtung weist:

java.sql.Date sqlDate = ...;
LocalDate calendarDate = sqlDate.toLocalDate();
ZonedDateTime zdt = calendarDate.atStartOfDay(ZoneId.of("Europe/Paris"));
Instant instant = zdt.toInstant();

Wenn Sie keine Zeit in Ihrem Datum haben – konvertieren Sie es in Millis:

Instant.ofEpochMilli(date.getTime())
   .atZone(ZoneId.systemDefault())
   .toLocalDate();

Benutzer-Avatar
Chris Lewold

Die Implementierung von java.sql.Date (imho) ist wirklich nicht perfekt.

Um java.util.Date in LocalDate zu konvertieren, ist das Web voll von Codeblöcken wie diesen:

dateToConvert.toInstant()
  .atZone(ZoneId.systemDefault())
  .toLocalDate();
  • Der obige Code funktioniert perfekt für java.util.Date, da er toInstant() implementiert. (Wie erwartet “return Instant.ofEpochMilli(getTime())”)
  • Da java.sql.Date eine Unterklasse von java.util.Date ist, weiß Code, der mit dem Date-Objekt arbeitet, jetzt möglicherweise, dass er mit einem java.sql.Date arbeitet. (Hey – das ist ein Aspekt der Objektorientierung, richtig??). Wenn es also java.util.Date Code bekommt, funktioniert es gut, wenn es java.sql.Date bekommt, schlägt es fehl.
  • Code könnte jetzt explizit nach dem Datumstyp suchen und dann (wenn er auf java.sql.Date ausgeführt wird) einen Downcast zu java.sql.Date durchführen und die Methode toLocalDate() verwenden. Unnötig zu sagen, dass das hässlich ist.

Als Entwickler möchte ich, dass eine Methode ordnungsgemäß funktioniert – toLocalDate (intern mit veralteten Methoden) existiert nur für java.sql.Date und kann daher nicht für java.util.Date verwendet werden, und toInstant schlägt für java.sql.Date fehl.

Ich habe meinen Konvertierungscode „Datum in LocalDate“ wie folgt geändert:

public static LocalDate asLocalDate(java.util.Date date) {
    return date == null ? null : LocalDate.ofInstant(Instant.ofEpochMilli(date.getTime()), ZoneId.systemDefault());
}

Dies funktioniert unabhängig vom übergebenen Datumstyp. Im Grunde bedeutet es “rufen Sie nicht java.util.Date.toInstant() auf, da Sie möglicherweise ein java.sql.Date erhalten, das dann Ihren Code beschädigt.

Ich verstehe wirklich nicht, warum sie solche Fallen absichtlich im JDK implementieren.

1180210cookie-checkUnsupportedOperationException – Warum können Sie toInstant() nicht für ein java.sql.Date aufrufen?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy