Question java.util.Date vs java.sql.Date


java.util.Date contre java.sql.Date: quand utiliser lequel et pourquoi?


450
2018-02-21 13:16


origine


Réponses:


Félicitations, vous avez frappé ma bête noire favorite avec JDBC: Gestion de la classe date.

Fondamentalement, les bases de données prennent généralement en charge au moins Trois des formes de champs datetime qui sont la date, l'heure et l'horodatage. Chacun de ceux-ci ont une classe correspondante dans JDBC et chacun d'eux s'étend java.util.Date. La sémantique rapide de chacun de ces trois éléments 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. aditionellement sql.Date n'est pas lié aux fuseaux horaires.
  • java.sql.Time correspond à SQL TIME et comme il devrait être évident, ne contient que des informations sur heure, minutes, secondes et millisecondes.
  • java.sql.Timestamp correspond à SQL TIMESTAMP qui est la date exacte à la nanoseconde (Notez que util.Date ne supporte que les millisecondes!) avec une précision personnalisable.

L'un des bogues les plus courants lors de l'utilisation de pilotes JDBC par rapport à ces trois types est que les types ne sont pas gérés correctement. Cela signifie que sql.Date est spécifique au fuseau horaire, sql.Time contient l'année en cours, le mois et le jour et cetera et cetera.

Enfin: Lequel utiliser?

Dépend du type de SQL du champ, vraiment. PreparedStatement a des paramètres pour les trois valeurs, #setDate() être celui pour 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 normal util.Date à la plupart des pilotes JDBC qui le dévoreront volontiers comme s’il était du type correct, mais lorsque vous demandez les données par la suite, vous remarquerez peut-être que des éléments vous manquent.

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

Ce que je dis que sauver les millisecondes / nanosecondes en tant que longues plaines et les convertir à tous les objets que vous utilisez (prise joda-time obligatoire). Une méthode piratée consiste à stocker le composant de date en tant que composant long et temps comme un autre, par exemple en ce moment 20100221 et 154536123. Ces nombres magiques peuvent être utilisés dans les requêtes SQL et seront portables de la base de données à l'autre. vous permettra d'éviter cette partie de JDBC / Java Date API: s entièrement.


540
2018-02-21 13:46



EDIT TARD: À partir de Java 8, vous ne devez utiliser ni java.util.Date ni java.sql.Date si vous pouvez tout éviter, préférez plutôt utiliser le java.time package (basé sur Joda) plutôt qu'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 voulez pas introduire de dépendances dans les bibliothèques de bases de données pour les applications / modules qui ne traitent pas explicitement avec JDBC.

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

  • C'est mutable, ce qui signifie que vous devez en faire une copie défensive chaque fois que vous le transmettez ou que vous le retournez d'une méthode.

  • Il ne gère pas très bien les dates, ce qui fait reculer les gens comme le vôtre, pensez que les classes de gestion des dates devraient.

  • Maintenant, parce que j.u.D ne fait pas très bien son boulot, le Calendar les cours ont été introduits. Ils sont également mutables et terribles pour travailler, et devraient être évités si vous n'avez pas le choix.

  • Il existe de meilleures alternatives, comme le API Joda Time (qui pourrait même faire en Java 7 et devenir la nouvelle API officielle de gestion des dates - une recherche rapide dit que ça ne va pas).

Si vous pensez qu'il est trop compliqué 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 mette habituellement dans j.u.D lors de leur passage, pour la sécurité de type et la documentation.


52
2018-02-21 17:46



Le seul moment pour utiliser java.sql.Date est dans un PreparedStatement.setDate. Sinon, utilisez java.util.Date. C'est dire que ResultSet.getDate retourne un java.sql.Date mais il peut être attribué directement à un java.util.Date.


17
2018-02-21 13:21



J'ai eu le même problème, la façon la plus simple de trouver la date du jour dans une instruction préparée est la suivante:

preparedStatement.setDate(1, new java.sql.Date(new java.util.Date().getTime()));

9
2017-07-16 20:16



La classe java.util.Date dans Java représente un moment particulier dans le temps (par exemple, Nov 25 16:30:45 2013 jusqu'à millisecondes), mais le type de données DATE dans le DB représente une date seulement (par exemple, 2013 25 novembre). Pour vous empêcher de fournir un objet java.util.Date à la base de données par erreur, 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 (alors les heures et les minutes seront 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 (de sorte qu'il est facile de construire à partir d'un java.util.Date), mais il lèvera une exception si vous essayez de lui demander des heures (pour appliquer son concept d'être un date seulement). Le pilote DB 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
2017-11-22 04:26