web-dev-qa-db-fra.com

java.util.Date vs Java.sql.Date

Java.util.Date vs Java.sql.Date: quand utiliser lequel et pourquoi?

484
flybywire

Félicitations, vous avez frappé ma bête noire préférée avec JDBC: Gestion des cours de date.

Fondamentalement, les bases de données supportent généralement au moins trois formes de champs de date/heure qui sont la date, l'heure et l'horodatage. Chacun de ceux-ci a une classe correspondante dans JDBC et chacun d'eux s'étend Java.util.Date. La sémantique rapide de chacun de ces trois est la suivante:

  • Java.sql.Date correspond à SQL DATE, ce qui signifie qu'il stocke années, mois et jours tandis que heure, minute, seconde et milliseconde sont ignorés. De plus, _sql.Date_ n'est pas lié aux fuseaux horaires.
  • Java.sql.Time correspond à SQL TIME et, comme il est évident, ne contient que des informations sur heure, minutes, secondes et millisecondes.
  • Java.sql.Timestamp correspond à SQL TIMESTAMP, qui correspond à une date exacte à la nanoseconde (notez que _util.Date_ ne prend en charge que des millisecondes!) avec une précision personnalisable.

L'un des problèmes les plus courants lors de l'utilisation de pilotes JDBC par rapport à ces trois types est que les types sont mal gérés. Cela signifie que _sql.Date_ est spécifique à un fuseau horaire, _sql.Time_ contient l'année, le mois et le jour en cours, et cetera et cetera.

Enfin: lequel utiliser?

Dépend du type SQL du champ, vraiment. PreparedStatement a des réglages pour les trois valeurs, #setDate() étant celui de _sql.Date_, #setTime() pour _sql.Time_ et #setTimestamp() pour _sql.Timestamp_ .

Notez que si vous utilisez ps.setObject(fieldIndex, utilDateObject);, vous pouvez réellement donner un _util.Date_ normal à la plupart des pilotes JDBC qui le dévoreront comme s'il était du type correct, mais lorsque vous demanderez les données par la suite, vous remarquerez peut-être que vous manquez des choses.

Je dis vraiment qu’aucune des dates ne devrait être utilisée du tout.

Ce que je suis en train de dire qui économise les millisecondes/nanosecondes sous forme de texte normal et les convertit en tous les objets que vous utilisez (plugin joda-time obligatoire). Une solution simple consiste à stocker le composant de date sous la forme d'un composant long et le composant l'un par rapport à l'autre, par exemple actuellement, il s'agirait des valeurs 20100221 et 154536123. Ces nombres magiques peuvent être utilisés dans des requêtes SQL et seront portables d'une base de données à une autre. vous permettra d'éviter cette partie de l'API JDBC/Java Date: s entièrement.

569
Esko

LATE EDIT: À partir de Java 8, vous ne devez utiliser ni _Java.util.Date_ ni _Java.sql.Date_ si vous le pouvez à tous l'évitent et préfèrent utiliser plutôt le package Java.time (basé sur Joda) plutôt que toute autre chose. Si vous n'êtes pas sur Java 8, voici la réponse d'origine:


Java.sql.Date - lorsque vous appelez des méthodes/constructeurs de bibliothèques qui l'utilisent (comme JDBC). Pas autrement. Vous ne souhaitez pas introduire de dépendances dans les bibliothèques de bases de données pour des applications/modules qui ne traitent pas explicitement de JDBC.

Java.util.Date - lors de l'utilisation de bibliothèques qui l'utilisent. Sinon, le moins possible, pour plusieurs raisons:

  • Il est modifiable, ce qui signifie que vous devez en faire une copie défensive chaque fois que vous le transmettez ou que vous le renvoyez depuis une méthode.

  • Il ne gère pas très bien les dates, ce qui fait que les personnes rétrogrades comme le vôtre pensent que les cours de manipulation des dates devraient l'être.

  • Maintenant, parce que j.u.D ne fait pas très bien son travail, les classes horribles Calendar ont été introduites. Ils sont également instables et difficiles à utiliser. Ils doivent être évités si vous n’avez pas le choix.

  • Il existe de meilleures alternatives, comme Joda Time API (qui pourrait même le rendre dans Java 7 et devenir la nouvelle API officielle de traitement des dates - un recherche rapide dit que ce ne sera pas).

Si vous croyez qu'il est exagéré d'introduire une nouvelle dépendance comme Joda, longs ne sont pas si mauvais à utiliser pour les champs d'horodatage dans les objets, bien que je les ai moi-même généralement enveloppés dans un texte lorsque je les distribue, pour des raisons de sécurité et Documentation.

58
gustafc

Le seul moment pour utiliser Java.sql.Date est dans un PreparedStatement.setDate. Sinon, utilisez Java.util.Date. Il est révélateur que ResultSet.getDate renvoie un Java.sql.Date mais il peut être affecté directement à un Java.util.Date.

19
Paul Tomblin

J'ai eu le même problème, la façon la plus simple que j'ai trouvée d'insérer la date du jour dans une déclaration préparée est la suivante:

preparedStatement.setDate(1, new Java.sql.Date(new Java.util.Date().getTime()));
10
Israelm

La classe Java.util.Date dans Java représente un moment particulier (p. Ex., 25 nov. 2013, 16:30:45 en millisecondes), mais le type de données DATE dans le DB représente une date seulement (par exemple, le 25 novembre 2013). Pour vous empêcher de fournir par erreur un objet Java.util.Date à la base de données, Java ne vous permet pas de définir directement un paramètre SQL sur Java.util.Date:

PreparedStatement st = ...
Java.util.Date d = ...
st.setDate(1, d); //will not work

Mais cela vous permet toujours de le faire par force/intention (les heures et les minutes seront alors ignorées par le pilote de la base de données). Ceci est fait avec la classe Java.sql.Date:

PreparedStatement st = ...
Java.util.Date d = ...
st.setDate(1, new Java.sql.Date(d.getTime())); //will work

Un objet Java.sql.Date peut stocker un moment dans le temps (il est donc facile de construire à partir d'un fichier Java.util.Date), mais émettra une exception si vous essayez de lui demander le nombre d'heures (pour appliquer son concept de date seulement). Le pilote de base de données doit reconnaître cette classe et utiliser simplement 0 pour les heures. Essaye ça:

public static void main(String[] args) {
  Java.util.Date d1 = new Java.util.Date(12345);//ms since 1970 Jan 1 midnight
  Java.sql.Date d2 = new Java.sql.Date(12345);
  System.out.println(d1.getHours());
  System.out.println(d2.getHours());
}
2
Kent Tong