代码之家  ›  专栏  ›  技术社区  ›  Derek Mahar

Hibernate在将Java日历对象读写到SQL时间戳时使用哪个时区?

  •  18
  • Derek Mahar  · 技术社区  · 15 年前

    Hibernate 写入 Calendar 对象到SQL TIMESTAMP 列,它将日期、计算机日期或日历对象中指定的日期(或其他日期)调整到哪个时区?

    冬眠时 这个 时间戳

    4 回复  |  直到 15 年前
        1
  •  17
  •   Community Mohan Dere    8 年前

    当Hibernate将Java日历对象写入SQL TIMESTAMP列时,它会将日期、计算机的日期或日历对象中指定的日期(或其他日期)调整到哪个时区?

    Hibernate 3.x在 CalendarType (见 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 );
    }
    

    所以Hibernate使用 PreparedStatement#setTimestamp(int, Timestamp, Calendar) 它使用日历的时区。

    好吧,再说一遍,让我们看看 日历类型

    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;
        }
    
    }
    

    所以冬眠 构造默认值 GregorianCalendar 默认时区 使用默认区域设置 .


        2
  •  6
  •   markthegrea    13 年前

    我刚刚花了6个小时研究了一个类似的问题,我想我会在这里记录下来。Hibernate确实使用了JVM时区,但是可以通过如下扩展日历类型来更改它:

    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);
        }
    }
    

    这里的秘方是:

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

    这将时区从结果集转换为所需的任何时区。因此,我所做的是将此类型与任何UTC日历和本地时间的标准Hibernate类型一起使用。像哨子一样圆滑。。。

        3
  •  1
  •   Vlad Mihalcea    8 年前

    如果要控制使用的时区,可以在JVM级别设置时区。如果希望JVM时区与数据库使用的时区不同,则需要使用以下Hibernate 5.2配置属性:

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

    有关详细信息,请查看 this article .

        4
  •  0
  •   orim    9 年前

    DbAssist . 应用此修复程序后,数据库中的日期将被JDBC处理,然后作为UTC休眠,因此您甚至不必更改实体类。

    例如,如果在Hibernate4.3.11中使用JPA注释,请添加以下Maven依赖项:

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

    然后你只需应用修复:

    @EnableAutoConfiguration

    对于HBM文件,必须将实体映射文件更改为映射 Date

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

    如果要了解有关如何为不同的Hibernate版本(或HBM文件)应用修补程序的详细信息,请参阅 the project's github article .