Comment puis-je configurer JPA / Hibernate pour stocker une date / heure dans la base de données en tant que fuseau horaire UTC (GMT)? Considérez cette entité JPA annotée:
public class Event {
@Id
public int id;
@Temporal(TemporalType.TIMESTAMP)
public java.util.Date date;
}
Si la date est le 03 février 2008 à 9 h 30, heure normale du Pacifique (PST), je souhaite que l'heure UTC du 03 février 2008 à 17 h 30 soit stockée dans la base de données. De même, lorsque la date est extraite de la base de données, je veux qu'elle soit interprétée comme UTC. Donc, dans ce cas, 17h30 est 17h30 UTC. Lorsqu'il est affiché, il sera formaté à 9h30 PST.
Réponses:
Avec Hibernate 5.2, vous pouvez désormais forcer le fuseau horaire UTC à l'aide de la propriété de configuration suivante:
Pour plus de détails, consultez cet article .
la source
useTimezone=true
dans la chaîne de connexion. Ensuite, seule la définition de la propriétéhibernate.jdbc.time_zone
fonctionnerauseLegacyDatetimeCode
sur falseÀ ma connaissance, vous devez mettre toute votre application Java dans le fuseau horaire UTC (afin qu'Hibernate stocke les dates en UTC), et vous devrez convertir le fuseau horaire souhaité lorsque vous affichez des éléments (au moins nous le faisons par ici).
Au démarrage, nous faisons:
Et définissez le fuseau horaire souhaité sur DateFormat:
la source
Hibernate ignore les éléments de fuseau horaire dans Dates (car il n'y en a pas), mais c'est en fait la couche JDBC qui pose des problèmes.
ResultSet.getTimestamp
et lesPreparedStatement.setTimestamp
deux disent dans leur documentation qu'ils transforment les dates vers / depuis le fuseau horaire JVM actuel par défaut lors de la lecture et de l'écriture depuis / vers la base de données.J'ai trouvé une solution à cela dans Hibernate 3.5 en sous
org.hibernate.type.TimestampType
- classant qui oblige ces méthodes JDBC à utiliser UTC au lieu du fuseau horaire local:La même chose doit être faite pour corriger TimeType et DateType si vous utilisez ces types. L'inconvénient est que vous devrez spécifier manuellement que ces types doivent être utilisés à la place des valeurs par défaut sur chaque champ Date de vos POJO (et interrompent également la compatibilité JPA pure), à moins que quelqu'un ne connaisse une méthode de remplacement plus générale.
MISE À JOUR: Hibernate 3.6 a changé l'API des types. En 3.6, j'ai écrit une classe UtcTimestampTypeDescriptor pour l'implémenter.
Désormais, lorsque l'application démarre, si vous définissez TimestampTypeDescriptor.INSTANCE sur une instance de UtcTimestampTypeDescriptor, tous les horodatages seront stockés et traités comme étant en UTC sans avoir à modifier les annotations sur les POJO. [Je n'ai pas encore testé cela]
la source
UtcTimestampType
?UtcTimestampType
compatible?Date
ouTimestamp
dépendent du pilote JDBC.Avec Spring Boot JPA, utilisez le code ci-dessous dans votre fichier application.properties et vous pouvez évidemment modifier le fuseau horaire à votre choix
Puis dans votre fichier de classe Entity,
la source
Ajout d'une réponse qui est entièrement basée sur et doit se désengager avec un indice de Shaun Stone. Je voulais juste l'expliquer en détail car c'est un problème courant et la solution est un peu déroutante.
Ceci utilise Hibernate 4.1.4.Final, bien que je soupçonne que tout ce qui sera après 3.6 fonctionnera.
Commencez par créer UtcTimestampTypeDescriptor de divestoclimb
Ensuite, créez UtcTimestampType, qui utilise UtcTimestampTypeDescriptor au lieu de TimestampTypeDescriptor comme SqlTypeDescriptor dans l'appel du super constructeur mais délègue sinon tout à TimestampType:
Enfin, lorsque vous initialisez votre configuration Hibernate, enregistrez UtcTimestampType comme remplacement de type:
Désormais, les horodatages ne devraient pas être concernés par le fuseau horaire de la JVM sur le chemin de et vers la base de données. HTH.
la source
On pourrait penser que ce problème commun serait pris en charge par Hibernate. Mais ce n'est pas! Il y a quelques "hacks" pour bien faire les choses.
Celui que j'utilise est de stocker la date sous forme de long dans la base de données. Donc je travaille toujours avec des millisecondes après le 1/1/70. J'ai alors des getters et des setters sur ma classe qui retournent / n'acceptent que des dates. Ainsi, l'API reste la même. L'inconvénient est que j'ai longtemps dans la base de données. SO avec SQL, je ne peux pratiquement faire que des comparaisons <,>, = - pas des opérateurs de date sophistiqués.
Une autre approche consiste à utiliser un type de mappage personnalisé comme décrit ici: http://www.hibernate.org/100.html
Je pense que la bonne façon de gérer cela est d'utiliser un calendrier au lieu d'une date. Avec le calendrier, vous pouvez définir le fuseau horaire avant de persister.
REMARQUE: Stackoverflow stupide ne me laisse pas commenter, voici donc une réponse à david a.
Si vous créez cet objet à Chicago:
Hibernate le persiste sous le nom "31/12/1969 18:00:00". Les dates doivent être dépourvues de fuseau horaire, je ne sais donc pas pourquoi l'ajustement serait effectué.
la source
Calendar
problème de lecture, je pense qu'Hibernate ou JPA devrait fournir un moyen de spécifier, pour chaque mappage, le fuseau horaire vers lequel Hibernate doit traduire la date à laquelle il lit et écrit dans uneTIMESTAMP
colonne.Timestamp
car nous ne pouvons pas nécessairement faire confiance au pilote JDBC pour stocker les dates comme nous nous attendrions.Il y a plusieurs fuseaux horaires en fonctionnement ici:
Tout cela peut être différent. Hibernate / JPA présente un grave défaut de conception en ce qu'un utilisateur ne peut pas facilement garantir que les informations de fuseau horaire sont conservées dans le serveur de base de données (ce qui permet la reconstruction des heures et des dates correctes dans la JVM).
Sans la possibilité de stocker (facilement) le fuseau horaire à l'aide de JPA / Hibernate, les informations sont perdues et une fois les informations perdues, leur construction devient coûteuse (si possible).
Je dirais qu'il est préférable de toujours stocker les informations de fuseau horaire (devrait être la valeur par défaut) et que les utilisateurs devraient alors avoir la possibilité facultative d'optimiser le fuseau horaire (bien que cela n'affecte vraiment que l'affichage, il y a toujours un fuseau horaire implicite dans n'importe quelle date).
Désolé, cet article ne fournit pas de solution de contournement (cela a été répondu ailleurs), mais il explique pourquoi il est important de toujours stocker les informations de fuseau horaire. Malheureusement, il semble que de nombreux informaticiens et spécialistes de la programmation s'opposent au besoin de fuseaux horaires simplement parce qu'ils n'apprécient pas la perspective de la «perte d'informations» et comment cela rend des choses comme l'internationalisation très difficiles - ce qui est très important de nos jours avec des sites Web accessibles par les clients et les membres de votre organisation lorsqu'ils se déplacent à travers le monde.
la source
Veuillez jeter un œil à mon projet sur Sourceforge qui contient des types d'utilisateurs pour les types de date et d'heure SQL standard ainsi que JSR 310 et Joda Time. Tous les types tentent de résoudre le problème de la compensation. Voir http://sourceforge.net/projects/usertype/
EDIT: En réponse à la question de Derek Mahar jointe à ce commentaire:
"Chris, est-ce que vos types d'utilisateurs fonctionnent avec Hibernate 3 ou une version supérieure? - Derek Mahar 7 novembre 2010 à 12h30"
Oui, ces types prennent en charge les versions Hibernate 3.x, y compris Hibernate 3.6.
la source
La date ne se trouve dans aucun fuseau horaire (il s'agit d'un bureau de la milliseconde à partir d'un moment défini dans le temps, identique pour tout le monde), mais les bases de données (R) sous-jacentes stockent généralement les horodatages au format politique (année, mois, jour, heure, minute, seconde,. ..) qui est sensible au fuseau horaire.
Pour être sérieux, Hibernate DOIT être autorisé à se faire dire dans une forme de mappage que la date de la base de données est dans tel ou tel fuseau horaire de sorte que lorsqu'il la charge ou la stocke, elle n'assume pas la sienne ...
la source
J'ai rencontré le même problème lorsque je voulais stocker les dates dans la base de données au format UTC et éviter d'utiliser
varchar
desString <-> java.util.Date
conversions explicites , ou de définir toute mon application Java dans le fuseau horaire UTC (car cela pourrait entraîner d'autres problèmes inattendus, si la JVM est partagé entre de nombreuses applications).Il existe donc un projet open source
DbAssist
, qui vous permet de corriger facilement la lecture / écriture en date UTC à partir de la base de données. Puisque vous utilisez des annotations JPA pour mapper les champs de l'entité, il vous suffit d'inclure la dépendance suivante dans votrepom
fichier Maven :Ensuite, vous appliquez le correctif (pour l'exemple Hibernate + Spring Boot) en ajoutant une
@EnableAutoConfiguration
annotation avant la classe d'application Spring. Pour obtenir d'autres instructions d'installation et d'autres exemples d'utilisation, reportez-vous simplement au github du projet .La bonne chose est que vous n'avez pas du tout à modifier les entités; vous pouvez laisser leurs
java.util.Date
champs tels quels.5.2.2
doit correspondre à la version Hibernate que vous utilisez. Je ne sais pas quelle version vous utilisez dans votre projet, mais la liste complète des correctifs fournis est disponible sur la page wiki du github du projet . La raison pour laquelle le correctif est différent pour les différentes versions d'Hibernate est que les créateurs d'Hibernate ont changé l'API plusieurs fois entre les versions.En interne, le correctif utilise des indices de divestoclimb, Shane et quelques autres sources afin de créer une personnalisation
UtcDateType
. Ensuite, il mappe la normejava.util.Date
avec la coutumeUtcDateType
qui gère toute la gestion du fuseau horaire nécessaire. Le mappage des types est réalisé en utilisant l'@Typedef
annotation dans lepackage-info.java
fichier fourni .Vous pouvez trouver un article ici qui explique pourquoi un tel décalage temporel se produit et quelles sont les approches pour le résoudre.
la source
Hibernate ne permet pas de spécifier des fuseaux horaires par annotation ou par tout autre moyen. Si vous utilisez Calendar au lieu de date, vous pouvez implémenter une solution de contournement à l'aide de la propriété HIbernate AccessType et implémenter vous-même le mappage. La solution la plus avancée consiste à implémenter un UserType personnalisé pour mapper votre date ou votre calendrier. Les deux solutions sont expliquées dans mon article de blog ici: http://www.joobik.com/2010/11/mapping-dates-and-time-zones-with.html
la source