java.util.Date
vs java.sql.Date
: quand utiliser quoi et pourquoi?
java.util.Date
vs java.sql.Date
: quand utiliser quoi et pourquoi?
Réponses:
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
ni java.sql.Date
si vous pouvez l'éviter, et préférez plutôt utiliser le java.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.
java.sql.Date
avec PreparedStatement
etc! Mais lorsque vous le faites circuler, utilisez un fichier que LocalDate
vous convertissez en utilisant java.sql.Date.valueOf
et java.sql.Date.valueOf
en le définissant, et reconvertissez-le le plus tôt possible en utilisant java.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 un PreparedStatement.setDate
. Sinon, utilisez java.util.Date
. C'est révélateur qui ResultSet.getDate
renvoie un java.sql.Date
mais il peut être affecté directement à un java.util.Date
.
java.sql.Date
puisse être attribué à un java.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:
preparedStatement.setDate(1, new java.sql.Date(new java.util.Date().getTime()));
N'utilisez ni l'un ni l'autre.
java.time.Instant
remplace java.util.Date
java.time.LocalDate
remplace java.sql.Date
java.util.Date vs java.sql.Date: quand utiliser quoi et pourquoi?
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
.
Instant instant = Instant.now() ; // Capture the current moment as seen in UTC.
java.time.OffsetDateTime
Instant
est la classe de base de java.time . Pour plus de flexibilité, utilisez OffsetDateTime
set to ZoneOffset.UTC
dans le même but: représenter un moment en UTC.
OffsetDateTime odt = OffsetDateTime.now( ZoneOffset.UTC ) ;
Vous pouvez envoyer cet objet à une base de données à l'aide PreparedStatement::setObject
de JDBC 4.2 ou version ultérieure.
myPreparedStatement.setObject( … , odt ) ;
Récupérer.
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
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.
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
LocalDate ld = LocalDate.now( z ) ; // Capture the current date as seen in the wall-clock time used by the people of a particular region (a time zone).
Envoyer à la base de données.
myPreparedStatement.setObject( … , ld ) ;
Récupérer.
LocalDate ld = myResultSet.getObject( … , LocalDate.class ) ;
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
, et SimpleDateFormat
.
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 dejava.sql.*
cours.
Où obtenir les classes java.time?
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:
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 DB). Cela se 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 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:
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());
}
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
et java.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 une java.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 que getHours()
, getMinutes()
, getSeconds()
, setHours()
, setMinutes()
, setSeconds()
. Comme java.sql.Date
il ne stocke pas les informations de temps, il remplace toutes les opérations de temps java.util.Date
et toutes ces méthodes sont lancées java.lang.IllegalArgumentException
si elles sont invoquées comme le montrent leurs détails d'implémentation.