在SQLServer中使用ZonedDateTime和datetimeoffset

Tyl*_*rry 4 java sql-server jpa

我有一个使用带有datetimeoffset列的SQLServer数据库的应用程序。最好是,我想使用ZonedDateTime作为我的JPA实体对象类型,如下所示:

@Column(name = "CreateTimestamp", nullable = false)
ZonedDateTime createTimestamp;
Run Code Online (Sandbox Code Playgroud)

但是,时区未正确保存。无论我在ZonedDateTime中将ZoneId设置为什么,该值将始终位于数据库的GMT中。

查看Microsoft的JDBC映射图,推荐使用的类是microsoft.sql.DateTimeOffset,这不是我想要的。

我已经探索过使用@Converter在两者之间进行映射,但是必须提供这样的特殊知识似乎是对我做错了事的一个危险信号-尤其是因为我需要使用它在H2集成测试中进行工作。

以供应商不可知的方式使用datetimeoffset和ZonedDateTime的最佳方法是什么?

Tyl*_*rry 6

我不想回答我自己的问题,但我想确保解决方案已记录在案。

解决方案是使用@Converter将ZonedDateTime转换为字符串。Hibernate会将其作为VARCHAR传递给SQLServer,数据库本身会将值隐式转换为datetimeoffset,与执行独立查询时转换硬编码日期的方式相同。

以下转换器适用于我的情况:

@Converter(autoApply = true)
public class ZonedDateTimeConverter implements AttributeConverter<ZonedDateTime, String>
{
    private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss.SSSSSSS xxx";

    @Override
    public String convertToDatabaseColumn(ZonedDateTime zonedDateTime)
    {
        return DateTimeFormatter.ofPattern(DATE_FORMAT).format(zonedDateTime);
    }

    @Override
    public ZonedDateTime convertToEntityAttribute(String dateAsString)
    {
        return ZonedDateTime.parse(dateAsString, DateTimeFormatter.ofPattern(DATE_FORMAT));
    }
}
Run Code Online (Sandbox Code Playgroud)

此外,这也适用于H2,因此可以在集成测试中使用,而无需执行任何特定于供应商的逻辑。


小智 6

这里有点棘手。数据时间 ZoneDateTime 包含比 OffsetDateTime 更多的信息。该区。请注意,区域与偏移量不同。更多的是。在给定时刻,两个区域可能具有相同的偏移量,但几个月后,一个区域会“向前推进”,而另一个区域则不会。或者,他们在不同的日子里向前迈进。在将字符串从 OffsetDateTime 转换为 ZoneDateTime 时,您将引入一个以前不存在的区域。