web-dev-qa-db-fra.com

UnsupportedOperationException - Pourquoi ne pouvez-vous pas appeler toInstant () sur un Java.sql.Date?

La classe Java.util.Date Possède une méthode appelée toInstant() qui convertit l'instance Date en Java.time.Instant.

La classe Java.sql.Date Étend la classe Java.util.Date, Mais lorsque j'essaie d'appeler toInstant() sur un Java.sql.Date, Je reçois un UnsupportedOperationException.

Pourquoi toInstant() est-elle une opération non prise en charge sur Java.sql.Date?

Et quelle est la "bonne" façon de convertir un Java.sql.Date En un Java.time.Instant?

42
Andrew Mairose

Vérifiez le JavaDoc

Puisque sql.Date n'a pas de composante temporelle, il n'est pas possible de le convertir en time.Instant

Cette méthode lève toujours une exception UnsupportedOperationException et ne doit pas être utilisée car les valeurs de date SQL n'ont pas de composant d'heure.

23
Yassin Hajaj

Le mappage correct entre Java.sql.Date et Java.time est LocalDate:

LocalDate date = sqlDate.toLocalDate();

Si vous devez vraiment, vous pouvez alors dériver un Instant, bien que les informations supplémentaires (temps) seront arbitraires. Par exemple:

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

Java.sql.Date n'a que des composants Date (date, mois et année). Il n'a PAS les deux composants Date et heure. toInstant requiert les deux composants Date/Time, donc toInstant sur l'instance Java.sql.Date lève l'exception UnsupportedOperationException.

Java.util.Date OR Java.sql.Timestamp a les deux composants Date/Time donc toInstant () fonctionne!

Vous pouvez faire comme ça:

// Time is 00:00:00.000

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

Mise à jour:

Instant.ofEpochMilli(sqlDate.getTime());

// OR
new Java.util.Date(sqlDate.getTime()).toInstant();

Renvoie le même résultat car toInstant () appelle Instant.ofEpochMilli (getTime ()) en interne.

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

Les réponses données jusqu'à présent se concentrent sur le fait que Java.sql.Date N'a pas d'informations sur l'heure. C'est correct mais ce n'est pas la raison réelle ou suffisante pour laquelle ce type ne peut pas offrir une conversion directe en Instant. Malheureusement, la documentation de Java-8 fait la même erreur pour laisser les utilisateurs penser que le problème est simplement dû à des informations temporelles manquantes.

Conceptuellement, le type Java.sql.Date Représente un type local. Il modélise une date de calendrier qui peut être différente dans n'importe quelle région de notre globe. Mais un Instant est le même sur notre globe. Les utilisateurs ont donc besoin d'un fuseau horaire ou d'un décalage de fuseau horaire pour effectuer la conversion.

Tragiquement, le type Java.sql.Date Hérite de Java.util.Date Qui est un type global (instantané). Cependant, cet héritage dénote vraiment l'héritage d'implémentation, et non l'héritage de type. Une raison de plus pour considérer que la conception de ces anciennes classes JDBC est cassée. Il est donc en effet possible d'utiliser le hack pour encapsuler le Java.sql.Date Via sa méthode getTime() à l'intérieur d'une instance de Java.util.Date Qui permet enfin la conversion directe en un instant. Mais: Cette conversion utilise implicitement le fuseau horaire par défaut du système.

Alors, comment convertir correctement de manière pédante? Considérons à nouveau la documentation de Java-8 qui pointe ici dans la bonne direction:

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