2010-11-07 5 views
16

Cuando Hibernate escribe un objeto Java Calendar a una columna de SQL TIMESTAMP, a qué zona de tiempo se ajusta la fecha, la del ordenador o la especificada en el objeto de calendario (o algún otro)?¿Qué zona horaria utiliza Hibernate cuando lee y escribe un objeto de calendario Java en un SQL TIMESTAMP?

Cuando Hibernate lee el TIMESTAMP en el objeto de calendario, ¿a qué zona horaria le asigna la fecha?

+1

Pregunta relacionada: http://stackoverflow.com/questions/508019/jpa-hibernate-store-date-in-utc-time-zone –

+0

http://community.jboss.org/wiki/UserTypefornon-defaultTimeZone aparece para ofrecer una solución. –

Respuesta

13

Cuando Hibernate escribe un objeto de calendario Java en una columna SQL TIMESTAMP, ¿a qué zona horaria ajusta la fecha, la de la computadora o la especificada en el objeto de calendario (u otro)?

Hiberante 3.x utiliza el siguiente en el CalendarType (ver HB-1006):

public void set(PreparedStatement st, Object value, int index) throws HibernateException, SQLException { 
    final Calendar cal = (Calendar) value; 
    //st.setTimestamp(index, new Timestamp(cal.getTimeInMillis()), cal); //JDK 1.5 only 
    st.setTimestamp(index, new Timestamp(cal.getTime().getTime()), cal); 
} 

Así Hibernate utiliza PreparedStatement#setTimestamp(int, Timestamp, Calendar) que utiliza la zona horaria del calendario.

Cuando Hibernate lee el TIMESTAMP en el objeto del calendario, ¿a qué zona horaria lo traslada?

Bueno, de nuevo, vamos a ver la clase CalendarType:

public Object get(ResultSet rs, String name) throws HibernateException, SQLException { 

    Timestamp ts = rs.getTimestamp(name); 
    if (ts!=null) { 
     Calendar cal = new GregorianCalendar(); 
     if (Environment.jvmHasTimestampBug()) { 
      cal.setTime(new Date(ts.getTime() + ts.getNanos()/1000000)); 
     } 
     else { 
      cal.setTime(ts); 
     } 
     return cal; 
    } 
    else { 
     return null; 
    } 

} 

Así Hibernate construye un defecto GregorianCalendar utilizando la hora actual en la zona horaria predeterminada con la configuración regional predeterminada.


Como nota al margen, le recomiendo que lea la siguiente pregunta: ¿

+0

¡Buena respuesta! Directamente de la "fuente"! Por curiosidad, ¿qué es el error de marca de tiempo de JVM al que se refiere el código? –

+0

@Derek El javadoc dice * ¿Esta JVM tiene IBM JDK 1.3.1. El error es 'new Timestamp (x) .getTime()! = X' *. –

+0

¡Un poco interesante de trivia histórica de Java! –

6

Acabo de pasar 6 horas en un problema similar y pensé que iba a documentar aquí . Hibernate ciertamente no utilizar la zona horaria JVM pero se puede cambiar mediante la extensión de la CalendarType así:

public class UTCCalendarType extends CalendarType { 

    private static final TimeZone UTC = TimeZone.getTimeZone("UTC"); 

    /** 
    * This is the original code from the class, with two changes. First we pull 
    * it out of the result set with an example Calendar. Second, we set the new 
    * calendar up in UTC. 
    */ 
    @Override 
    public Object get(ResultSet rs, String name) throws SQLException { 
     Timestamp ts = rs.getTimestamp(name, new GregorianCalendar(UTC)); 
     if (ts != null) { 
      Calendar cal = new GregorianCalendar(UTC); 
      cal.setTime(ts); 
      return cal; 
     } else { 
      return null; 
     } 
    } 

    @Override 
    public void set(PreparedStatement st, Object value, int index) throws SQLException { 
     final Calendar cal = (Calendar) value; 
     cal.setTimeZone(UTC); 
     st.setTimestamp(index, new Timestamp(cal.getTime().getTime()), cal); 
    } 
} 

el ingrediente secreto aquí es:

rs.getTimestamp(name, new GregorianCalendar(UTC)); 

Esto convierte la zona horaria del conjunto de resultados a cualquier zona horaria usted quiere. Entonces, lo que hice fue utilizar este tipo con cualquier calendario UTC y el tipo Hibernate estándar para la hora local. Funciona como un silbido ...

+0

Gracias por su respuesta, Mark! –

+0

Hola @markthegrea, ¿hay algún cambio de configuración requerido para hibernar para permitir que hibernate tome UTCCalendarType personalizado y no la clase base CalendarType? Muchas gracias ... ¡¡¡Yash ... !!! –

+1

¡Sip! markthegrea

0

Si no desea escribir el código usted mismo, puede usar la biblioteca de código abierto DbAssist. Después de aplicar este arreglo, las fechas en la base de datos serán tratadas por JDBC y luego Hibernate como UTC, por lo que ni siquiera tendrá que cambiar sus clases.

Por ejemplo, si está utilizando Anotaciones JPA con Hibernate 4.3.11, agregue la siguiente dependencia Maven:

<dependency> 
    <groupId>com.montrosesoftware</groupId> 
    <artifactId>DbAssist-4.3.11</artifactId> 
    <version>1.0-RELEASE</version> 
</dependency> 

A continuación, sólo aplicar la revisión:

Para la configuración de Hibernate + resorte de arranque, añadir la anotación @EnableAutoConfiguration antes de la clase de aplicación.

Para los archivos de HBM, usted tiene que cambiar los archivos de mapeo de entidad que se Date tipos a la costumbre uno:

<property name="createdAt" type="com.montrosesoftware.dbassist.types.UtcDateType" column="created_at"/> 

Si desea obtener más información sobre cómo aplicar la solución para diferentes versiones de Hibernate (o Archivos HBM), consulte the project's github. También puede leer más sobre el problema del cambio de zona horaria en este article.

1

De forma predeterminada, depende del controlador JDBC decidir qué zona horaria usar. Normalmente, la zona horaria JVM se utiliza a menos que configure el controlador JDBC para usar una zona horaria personalizada.

Si desea controlar qué zona horaria se utiliza, puede establecer la zona horaria en el nivel JVM. Si desea que la zona horaria JVM a difiere de la utilizada por la base de datos, entonces es necesario utilizar la siguiente Hibernate propiedad de configuración 5.2:

<property name="hibernate.jdbc.time_zone" value="US/Eastern"/> 

Para más detalles, echa un vistazo a this article.

Cuestiones relacionadas