java.util.Date
vs java.sql.Date
: quand utiliser quoi et pourquoi?
Félicitations, vous avez frappé ma bête noire préférée avec JDBC: Gestion des classes de date.
Fondamentalement, les bases de données prennent généralement en charge au moins trois formes de champs datetime: date, heure et horodatage. Chacun d'eux a une classe correspondante dans JDBC et chacun d'eux s'étendjava.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 les années, les mois et les jours tandis que l' heure, la minute, la seconde et la milliseconde sont ignorées. De plus, sql.Date
n'est pas lié aux fuseaux horaires.java.sql.Time
correspond à SQL TIME et comme cela devrait être évident, ne contient que des informations sur l' heure, les minutes, les secondes et les millisecondes .java.sql.Timestamp
correspond à SQL TIMESTAMP qui est la date exacte à la nanoseconde ( notez que cela util.Date
ne prend en charge 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 sont traités de manière incorrecte. Cela signifie que le sql.Date
fuseau horaire est spécifique, sql.Time
contient l'année, le mois et le jour en cours et cetera et cetera.
Cela dépend vraiment du type SQL du champ. PreparedStatement
a des setters pour les trois valeurs, #setDate()
étant celle 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 demanderez les données par la suite, vous remarquerez peut-être qu'il vous manque réellement des éléments.
Ce que je dis, c'est que vous enregistrez les millisecondes / nanosecondes en tant que longs et les convertissez en tous les objets que vous utilisez (prise Joda-time obligatoire ). Une manière hacky qui peut être faite est de stocker le composant date comme un composant long et le temps comme un autre, par exemple actuellement 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 et vous permettra d'éviter complètement cette partie de l'API JDBC / Java Date.
MODIFICATION TARDIVE: à partir de Java 8, vous ne devez utiliser ni
java.util.Date
nijava.sql.Date
si vous pouvez l'éviter, et préférez plutôt utiliser lejava.time
package (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 voulez pas introduire de dépendances dans les bibliothèques de base de données pour les applications / modules qui ne traitent pas explicitement avec JDBC.java.util.Date
- lors de l'utilisation des 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 le renvoyez d'une méthode.
Il ne gère pas très bien les dates, ce qui est vrai pour les gens comme les vôtres.
Maintenant, parce que juD ne fait pas très bien son travail, les
Calendar
classes horribles ont été introduites. Ils sont également mutables et horribles à travailler et doivent être évités si vous n'avez pas le choix.Il existe de meilleures alternatives, comme l' API Joda Time (
qui pourrait même devenir Java 7 et devenir la nouvelle API officielle de gestion des dates- une recherche rapide dit que non).Si vous pensez qu'il est exagéré d'introduire une nouvelle dépendance comme Joda, ce
long
n'est pas si mal à utiliser pour les champs d'horodatage dans les objets, bien que moi-même je les enveloppe généralement dans juD lors de leur passage, pour la sécurité des types et comme documentation.la source
java.sql.Date
avecPreparedStatement
etc! Mais lorsque vous le faites circuler, utilisez un fichier queLocalDate
vous convertissez en utilisantjava.sql.Date.valueOf
etjava.sql.Date.valueOf
en le définissant, et reconvertissez-le le plus tôt possible en utilisantjava.sql.Date.toLocalDate
- encore une fois, parce que vous voulez impliquer java.sql le moins possible et parce qu'il est mutable.Le seul moment d'utilisation
java.sql.Date
est dans unPreparedStatement.setDate
. Sinon, utilisezjava.util.Date
. C'est révélateur quiResultSet.getDate
renvoie unjava.sql.Date
mais il peut être affecté directement à unjava.util.Date
.la source
java.sql.Date
puisse être attribué à unjava.util.Date
lorsque le premier étend le second? Quel est le point que vous essayez de faire valoir?J'ai eu le même problème, la manière la plus simple que j'ai trouvée pour insérer la date actuelle dans une déclaration préparée est celle-ci:
la source
tl; dr
N'utilisez ni l'un ni l'autre.
java.time.Instant
remplacejava.util.Date
java.time.LocalDate
remplacejava.sql.Date
Ni
Ces deux classes sont terribles, défectueuses dans leur conception et leur mise en œuvre. Évitez comme le coronavirus de la
peste.Utilisez plutôt les classes java.time , définies dans JSR 310. Ces classes sont un cadre de pointe pour travailler avec la gestion de la date et de l'heure. Ces classes remplacer entièrement les anciens affreux sanglants tels que
Date
,Calendar
,SimpleDateFormat
, et autres.java.util.Date
Le premier
java.util.Date
est censé représenter un moment en UTC, ce qui signifie un décalage par rapport à UTC de zéro heure-minute-seconde.java.time.Instant
Maintenant remplacé par
java.time.Instant
.java.time.OffsetDateTime
Instant
est la classe de base de java.time . Pour plus de flexibilité, utilisezOffsetDateTime
set toZoneOffset.UTC
dans le même but: représenter un moment en UTC.Vous pouvez envoyer cet objet à une base de données à l'aide
PreparedStatement::setObject
de JDBC 4.2 ou version ultérieure.Récupérer.
java.sql.Date
La
java.sql.Date
classe est également terrible et obsolète.Cette classe est censée représenter une date uniquement, sans heure et sans fuseau horaire. Malheureusement, dans un terrible piratage d'un design, cette classe hérite de
java.util.Date
laquelle représente un moment (une date avec l'heure en UTC). Ainsi, cette classe prétend simplement être à date uniquement, tout en portant en fait une heure et un décalage implicite de l'UTC. Cela cause tellement de confusion. N'utilisez jamais cette classe.java.time.LocalDate
Au lieu de cela, utilisez
java.time.LocalDate
pour suivre uniquement une date (année, mois, jour du mois) sans heure, ni fuseau horaire ni décalage.Envoyer à la base de données.
Récupérer.
À propos de java.time
Le framework java.time est intégré à Java 8 et versions ultérieures. Ces classes supplantent les anciens gênants hérités des classes date-heure tels que
java.util.Date
,Calendar
, etSimpleDateFormat
.Pour en savoir plus, consultez le didacticiel Oracle . Et recherchez Stack Overflow pour de nombreux exemples et explications. La spécification est JSR 310 .
Le projet Joda-Time , désormais en mode maintenance , conseille la migration vers les classes java.time .
Vous pouvez échanger des objets java.time directement avec votre base de données. Utilisez un pilote JDBC compatible avec JDBC 4.2 ou version ultérieure. Pas besoin de cordes, pas besoin de
java.sql.*
cours.Où obtenir les classes java.time?
la source
La classe java.util.Date en Java représente un moment particulier dans le temps (par exemple, le 25 novembre 2013 à 16 h 30 min 45 s), mais le type de données DATE dans la base de données représente uniquement une date (par exemple, 25 novembre 2013). 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:
Mais cela vous permet toujours de le faire par force / intention (alors les heures et les minutes seront ignorées par le pilote DB). Cela se fait avec la classe java.sql.Date:
Un objet java.sql.Date peut stocker un instant dans le temps (de sorte qu'il est facile de construire à partir d'un java.util.Date) mais lèvera une exception si vous essayez de lui demander des heures (pour appliquer son concept d'être un date uniquement). Le pilote de base de données devrait reconnaître cette classe et utiliser simplement 0 pour les heures. Essaye ça:
la source
java.util.Date
représente un instant précis dans le temps avec une précision en millisecondes. Il représente à la fois des informations de date et d'heure sans fuseau horaire. La classe java.util.Date implémente une interface sérialisable, clonable et comparable. Il est hérité parjava.sql.Date
,java.sql.Time
etjava.sql.Timestamp
interfaces.java.sql.Date
étend la classe java.util.Date qui représente les informations de date sans heure et ne doit être utilisée que pour les bases de données. Pour se conformer à la définition de SQL DATE, les valeurs en millisecondes encapsulées par unejava.sql.Date
instance doivent être `` normalisées '' en définissant les heures, minutes, secondes et millisecondes sur zéro dans le fuseau horaire particulier auquel l'instance est associée.Il hérite de toutes les méthodes publiques de
java.util.Date
telles quegetHours()
,getMinutes()
,getSeconds()
,setHours()
,setMinutes()
,setSeconds()
. Commejava.sql.Date
il ne stocke pas les informations de temps, il remplace toutes les opérations de tempsjava.util.Date
et toutes ces méthodes sont lancéesjava.lang.IllegalArgumentException
si elles sont invoquées comme le montrent leurs détails d'implémentation.la source