我有一个使用带有datetimeoffset列的SQLServer数据库的应用程序。最好,我想使用ZonedDateTime作为我的JPA实体对象类型,如下所示:
@Column(name = "CreateTimestamp", nullable = false)
ZonedDateTime createTimestamp;
但是,时区未正确保存。无论我在ZonedDateTime中将ZoneId设置为什么,该值始终都是数据库中的GMT。
查看Microsoft's JDBC mapping diagram,推荐使用的类是microsoft.sql.DateTimeOffset,这不是我想要的。
我已经探索过使用@Converter在两者之间进行映射,但是必须提供这样的特殊知识似乎是一个红旗,我做错了 - 特别是因为我需要在集成测试中工作使用H2。
以供应商不可知的方式使用datetimeoffset和ZonedDateTime的最佳方法是什么?
答案 0 :(得分:5)
我讨厌回答我自己的问题,但我想确保解决方案已记录在案。
解决方案是使用@Converter将ZonedDateTime转换为String。 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));
}
}
此外,这也适用于H2,因此可以在集成测试中使用,而无需执行任何特定于供应商的逻辑。
答案 1 :(得分:0)
这里有点傻瓜。 数据时间ZoneDateTime比OffsetDateTime包含更多信息。 区域。 请注意,区域与偏移量不同。更多。 在给定的时刻,两个区域可能具有相同的偏移量,但是几个月后,一个区域“向后弹”,另一区域则没有。 或者,它们在不同的日子向前发展。 在将字符串从OffsetDateTime转换为ZoneDateTime时,您要引入一个以前不存在的区域。