2016-03-05 58 views
1

我想在SQL Server 2008中使用一个datetimeoffset列,该列存储日期&时间加上时区。休眠没有正确地将ZonedDateTime存储为SQL Server中的datetimeoffset

在数据库中列的DDL定义:

LastUpdatedDateTime datetimeoffset DEFAULT SysDateTimeOffset() 

我的实体领域中的java定义使用Hibernate映射:

private ZonedDateTime lastUpdatedDateTime = ZonedDateTime.now(); 

我使用Hibernate 5.1.0。最后(通过Spring引导1.3.2.RELEASE)和包括org.hibernate:hibernate-java8。

观察到的行为(通过查询使用WinSQL的数据库):经由SQL插入语句的结果在存储所述正确的日期时间&和正确时区 插入数据:2016年3月3日13:41:17.5358944 -07:00

通过保存Java实体(根据上面的Java代码片段初始化字段)插入数据。 Java将日期/时间值(保存之前)报告为:2016-03-04T14:18:17.076-07:00 [America/Denver]

保存之后,WinSQL将存储在数据库中的值报告为: 2016-03-04 14:18:17.0760000 +00:00

这与&的日期相同,但错误的时区(UTC而不是-07:00)。

当我使用Timestamp而不是ZonedDateTime在Java中声明该字段时,我得到了相同的行为。

如何获得正确存储的时区?只要时间基于时区正确,我不在乎它是否存储为UTC或-07:00时区。我认为Hibernate会为此提供支持(在hibernate-java8库中),并且我不必编写自定义转换器或自定义用户数据类型。

+0

我“米朝着与时间戳坚持,因为我有与Hibernate 5的其他问题,可能会阻止我使用它的休眠靠在-java8库。 –

回答

6

我终于找到了一个解决方案:

  1. 使用java.time.OffsetDateTime而不是ZonedDateTime为实体领域。根据Javadoc类,OffsetDateTime旨在用于数据库持久性。

  2. 恢复到休眠4(由于我遇到的其他问题)。所以我不知道如果你使用Hibernate 5和hibernate-java8库,下一步是否必要。

  3. 将Hibernate转换器从OffsetDateTime添加到字符串。显然,datetimeoffset列默认由JDBC作为String(而不是Microsoft JDBC驱动程序文档建议的microsoft.sql.DateTimeOffset类)处理。此转换器中的逻辑必须处理SQL Server仅在7秒内存储7位数字(而OffsetDateTime提供9)的复杂性。

  4. 确保Converter包含在Hibernate EntityManager中。是

在这些步骤的细节如下:

DDL列定义不变。

实体字段定义:

private OffsetDateTime lastUpdatedDateTime; 

Converter类:

@Converter(autoApply = true) 
public class OffsetDateTimeConverter implements AttributeConverter<OffsetDateTime, String> { 

    private static DateTimeFormatter FORMATTER_FROM_DB = DateTimeFormatter.ofPattern(
     "yyyy-MM-dd HH:mm:ss.nnnnnnn xxx"); 
    private static DateTimeFormatter FORMATTER_TO_DB = DateTimeFormatter.ofPattern(
     "yyyy-MM-dd HH:mm:ss.nnnnnnnnn xxx"); 

    @Override 
    public String convertToDatabaseColumn(OffsetDateTime attribute) { 
     if (attribute == null) { 
      return null; 
     } 
     return attribute.format(FORMATTER_TO_DB); 
    } 

    @Override 
    public OffsetDateTime convertToEntityAttribute(String dbData) { 
     if (dbData == null) { 
      return null; 
     } 
     return OffsetDateTime.parse(dbData, FORMATTER_FROM_DB); 
    } 
}