¿Cómo puedo configurar JPA / Hibernate para almacenar una fecha / hora en la base de datos como zona horaria UTC (GMT)? Considere esta entidad JPA anotada:
public class Event {
@Id
public int id;
@Temporal(TemporalType.TIMESTAMP)
public java.util.Date date;
}
Si la fecha es 2008-Feb-03 9:30 am hora estándar del Pacífico (PST), entonces quiero que la hora UTC del 2008-Feb-03 5:30 pm se almacene en la base de datos. Del mismo modo, cuando se recupera la fecha de la base de datos, quiero que se interprete como UTC. Entonces, en este caso, las 530 pm son las 530 pm UTC. Cuando se muestre, tendrá el formato de las 9:30 am PST.
Respuestas:
Con Hibernate 5.2, ahora puede forzar la zona horaria UTC usando la siguiente propiedad de configuración:
Para obtener más detalles, consulte este artículo .
fuente
useTimezone=true
en la cadena de conexión. Entonces única propiedad establecerhibernate.jdbc.time_zone
trabajaráuseLegacyDatetimeCode
en falsoHasta donde yo sé, debe poner toda su aplicación Java en la zona horaria UTC (para que Hibernate almacene las fechas en UTC), y deberá convertir a la zona horaria que desee cuando muestre cosas (al menos lo hacemos de esta manera).
Al inicio, hacemos:
Y establezca la zona horaria deseada en DateFormat:
fuente
Hibernate ignora las cosas de la zona horaria en Dates (porque no hay ninguna), pero en realidad es la capa JDBC la que está causando problemas.
ResultSet.getTimestamp
yPreparedStatement.setTimestamp
ambos dicen en sus documentos que transforman fechas a / desde la zona horaria actual de JVM de forma predeterminada al leer y escribir desde / a la base de datos.Se me ocurrió una solución a esto en Hibernate 3.5 mediante la subclasificación
org.hibernate.type.TimestampType
que obliga a estos métodos JDBC a usar UTC en lugar de la zona horaria local:Se debe hacer lo mismo para corregir TimeType y DateType si usa esos tipos. La desventaja es que tendrá que especificar manualmente que estos tipos se usarán en lugar de los valores predeterminados en cada campo de fecha en sus POJO (y también rompe la compatibilidad pura con JPA), a menos que alguien sepa de un método de anulación más general.
ACTUALIZACIÓN: Hibernate 3.6 ha cambiado los tipos de API. En 3.6, escribí una clase UtcTimestampTypeDescriptor para implementar esto.
Ahora, cuando se inicia la aplicación, si configura TimestampTypeDescriptor.INSTANCE en una instancia de UtcTimestampTypeDescriptor, todas las marcas de tiempo se almacenarán y se tratarán como si estuvieran en UTC sin tener que cambiar las anotaciones en los POJO. [No lo he probado todavía]
fuente
UtcTimestampType
?UtcTimestampType
compatible?Date
oTimestamp
depende del controlador JDBC.Con Spring Boot JPA, use el siguiente código en su archivo application.properties y obviamente puede modificar la zona horaria a su elección
Luego, en su archivo de clase de entidad,
fuente
Agregando una respuesta que está completamente basada y en deuda con divestoclimb con una pista de Shaun Stone. Solo quería explicarlo en detalle, ya que es un problema común y la solución es un poco confusa.
Esto está usando Hibernate 4.1.4.Final, aunque sospecho que cualquier cosa después de 3.6 funcionará.
Primero, cree el UtcTimestampTypeDescriptor de divestoclimb
Luego, cree UtcTimestampType, que usa UtcTimestampTypeDescriptor en lugar de TimestampTypeDescriptor como SqlTypeDescriptor en la llamada del superconstructor pero, de lo contrario, delega todo a TimestampType:
Finalmente, cuando inicialice su configuración de Hibernate, registre UtcTimestampType como una anulación de tipo:
Ahora, las marcas de tiempo no deben preocuparse por la zona horaria de la JVM en su camino hacia y desde la base de datos. HTH.
fuente
Usted pensaría que Hibernate se ocuparía de este problema común. ¡Pero no lo es! Hay algunos "trucos" para hacerlo bien.
El que yo uso es para almacenar la fecha como Long en la base de datos. Entonces siempre estoy trabajando con milisegundos después del 1/1/70. Luego tengo getters y setters en mi Clase que devuelven / aceptan solo Fechas. Entonces la API sigue siendo la misma. El lado negativo es que tengo largos en la base de datos. Entonces, con SQL prácticamente solo puedo hacer <,>, = comparaciones, no operadores de fecha sofisticados.
Otro enfoque es utilizar un tipo de mapeo personalizado como se describe aquí: http://www.hibernate.org/100.html
Sin embargo, creo que la forma correcta de lidiar con esto es usar un calendario en lugar de una fecha. Con el calendario puede configurar la zona horaria antes de continuar.
NOTA: Stackoverflow tonto no me deja comentar, así que aquí hay una respuesta a david a.
Si crea este objeto en Chicago:
Hibernate lo persiste como "31/12/1969 18:00:00". Las fechas deben estar desprovistas de zona horaria, por lo que no estoy seguro de por qué se haría el ajuste.
fuente
Calendar
problema de lectura, creo que Hibernate o JPA deberían proporcionar alguna forma de especificar, para cada asignación, la zona horaria a la que Hibernate debería traducir la fecha en la que lee y escribe en unaTIMESTAMP
columna.Timestamp
ya que no necesariamente podemos confiar en el controlador JDBC para almacenar fechas como esperaríamos.Hay varias zonas horarias en funcionamiento aquí:
Todos estos pueden ser diferentes. Hibernate / JPA tiene una deficiencia de diseño severa en el sentido de que un usuario no puede garantizar fácilmente que la información de la zona horaria se conserve en el servidor de la base de datos (lo que permite la reconstrucción de las horas y fechas correctas en la JVM).
Sin la capacidad de almacenar (fácilmente) la zona horaria usando JPA / Hibernate, la información se pierde y una vez que se pierde la información se vuelve costoso construirla (si es posible).
Yo diría que es mejor almacenar siempre la información de la zona horaria (debería ser la predeterminada) y los usuarios deberían tener la capacidad opcional de optimizar la zona horaria (aunque solo afecta la visualización, todavía hay una zona horaria implícita en cualquier fecha).
Lo sentimos, esta publicación no proporciona una solución alternativa (que se ha respondido en otro lugar), pero es una racionalización de por qué siempre es importante almacenar información de zona horaria. Desafortunadamente, parece que muchos informáticos y profesionales de la programación argumentan en contra de la necesidad de zonas horarias simplemente porque no aprecian la perspectiva de la "pérdida de información" y cómo eso hace que cosas como la internacionalización sean muy difíciles, lo cual es muy importante en estos días con sitios web accesibles por clientes y personas de su organización a medida que se mueven por el mundo.
fuente
Por favor, eche un vistazo a mi proyecto en Sourceforge, que tiene tipos de usuario para los tipos estándar de fecha y hora de SQL, así como JSR 310 y Joda Time. Todos los tipos intentan abordar el problema de la compensación. Ver http://sourceforge.net/projects/usertype/
EDITAR: En respuesta a la pregunta de Derek Mahar adjunta a este comentario:
"Chris, ¿tus tipos de usuario funcionan con Hibernate 3 o superior? - Derek Mahar 7 de noviembre de 2010 a las 12:30"
Sí, estos tipos son compatibles con las versiones de Hibernate 3.x, incluido Hibernate 3.6.
fuente
La fecha no está en ninguna zona horaria (es una oficina de milisegundos desde un momento definido en el tiempo, lo mismo para todos), pero las bases de datos (R) subyacentes generalmente almacenan marcas de tiempo en formato político (año, mes, día, hora, minuto, segundo,. ..) que es sensible a la zona horaria.
Para ser serio, Hibernate DEBE permitir que se le diga dentro de alguna forma de mapeo que la fecha de la base de datos está en tal o cual zona horaria para que cuando la cargue o la almacene no asuma la suya propia ...
fuente
Encontré el mismo problema cuando quería almacenar las fechas en la base de datos como UTC y evitar el uso
varchar
yString <-> java.util.Date
conversiones explícitas , o configurar toda mi aplicación Java en la zona horaria UTC (porque esto podría conducir a otros problemas inesperados, si la JVM es compartido en muchas aplicaciones).Por lo tanto, existe un proyecto de código abierto
DbAssist
, que le permite corregir fácilmente la lectura / escritura como fecha UTC de la base de datos. Dado que está utilizando JPA Annotations para mapear los campos en la entidad, todo lo que tiene que hacer es incluir la siguiente dependencia en supom
archivo Maven :Luego aplica la corrección (para el ejemplo de Hibernate + Spring Boot) agregando una
@EnableAutoConfiguration
anotación antes de la clase de aplicación Spring. Para obtener instrucciones de instalación de otras configuraciones y más ejemplos de uso, solo consulte el github del proyecto .Lo bueno es que no tienes que modificar las entidades en absoluto; puede dejar sus
java.util.Date
campos como están.5.2.2
tiene que corresponder a la versión de Hibernate que está utilizando. No estoy seguro de qué versión está utilizando en su proyecto, pero la lista completa de correcciones proporcionadas está disponible en la página wiki del github del proyecto . La razón por la que la solución es diferente para varias versiones de Hibernate es porque los creadores de Hibernate cambiaron la API un par de veces entre las versiones.Internamente, la solución utiliza sugerencias de divestoclimb, Shane y algunas otras fuentes para crear un archivo personalizado
UtcDateType
. Luego mapea el estándarjava.util.Date
con el personalizadoUtcDateType
que maneja todo el manejo necesario de la zona horaria. El mapeo de los tipos se logra mediante la@Typedef
anotación en elpackage-info.java
archivo proporcionado .Puede encontrar un artículo aquí que explica por qué ocurre tal cambio de tiempo y cuáles son los enfoques para resolverlo.
fuente
Hibernate no permite especificar zonas horarias mediante anotaciones o cualquier otro medio. Si usa Calendar en lugar de date, puede implementar una solución alternativa usando la propiedad AccessType de HIbernate e implementando el mapeo usted mismo. La solución más avanzada es implementar un UserType personalizado para mapear su fecha o calendario. Ambas soluciones se explican en la publicación de mi blog aquí: http://www.joobik.com/2010/11/mapping-dates-and-time-zones-with.html
fuente