首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何为Spring时间戳指定UTC时区

如何为Spring时间戳指定UTC时区
EN

Stack Overflow用户
提问于 2017-01-12 16:22:26
回答 3查看 24.2K关注 0票数 11

环境

  • Spring Boot启动器数据JPA 1.4.2
  • Eclipselink 2.5.0
  • Postgresql 9.4.1211.jre7

问题

我正在构建一个Spring微服务,它与一个不同的服务共享一个Postgresql数据库。数据库从外部初始化(超出我们的控制范围),其他服务使用的日期时间列类型是时间戳,没有时区。因此,由于我希望db上的所有日期都具有相同的类型,因此对我的JPA实体日期来说,拥有该类型是必需的。

我在JPA实体对象上映射它们的方式如下:

代码语言:javascript
复制
@Column(name = "some_date", nullable = false)
private Timestamp someDate;

问题是,当我创建时间戳时,如下所示:

代码语言:javascript
复制
new java.sql.Timestamp(System.currentTimeMillis())

我查看数据库,时间戳包含我的本地时区日期时间,但是我想将它存储在UTC中。这是因为我的默认时区设置为“Europe/布鲁塞尔”,JPA/JDBC在将java.sql.Timestamp对象放入数据库之前将其转换为时区。

找到了不理想的解决方案

  • TimeZone.setDefault(TimeZone.getTimeZone("Etc/UTC"));具有我想要实现的效果,但是它并不适合我的服务,因为它并不是特定于我的服务。也就是说,它将影响整个JVM或当前线程加上子线程。
  • 使用-Duser.timezone=GMT启动应用程序似乎也为运行中的JVM的单个实例做了工作。因此,一个比以前更好的解决方案。

但是,是否有一种方法可以在JPA/数据源/spring引导配置中指定时区?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-01-16 12:33:10

我能找到的最合适的解决方法是使用AttributeConverter将Java8 ZonedDateTime对象转换为java.sql.Timestamp对象,这样就可以将它们映射到PostgreSQL timestamp without time zone类型。

需要AttributeConverter的原因是Java8/Joda时间时间类型为尚未与JPA兼容。

AttributeConverter看起来如下所示:

代码语言:javascript
复制
@Converter(autoApply = true)
public class ZonedDateTimeAttributeConverter implements AttributeConverter<ZonedDateTime, Timestamp> {

    @Override
    public Timestamp convertToDatabaseColumn(ZonedDateTime zonedDateTime) {
        return (zonedDateTime == null ? null : Timestamp.valueOf(zonedDateTime.toLocalDateTime()));
    }

    @Override
    public ZonedDateTime convertToEntityAttribute(Timestamp sqlTimestamp) {
        return (sqlTimestamp == null ? null : sqlTimestamp.toLocalDateTime().atZone(ZoneId.of("UTC")));
    }

}

这使我可以读取具有时区信息的数据库时间戳作为具有UTC时区的ZonedDateTime对象。这样,无论我的应用程序在中运行的时区是什么,我都可以在db 上看到确切的日期时间。

由于toLocalDateTime()还应用了系统的默认时区转换,因此这个AttributeConverter基本上取消了JDBC驱动程序应用的转换。

你真的需要使用timestamp without timezone吗?

现实情况是,如果您将日期时间信息存储在时区(即使是UTC),则timestamp without timezone PostgreSQL类型是错误的选择。正确的数据类型是timestamp with timezone,它确实包含时区信息。有关此主题的更多信息,这里

但是,如果出于任何原因,必须使用timestamp without timezone,我认为上面的ZonedDateTime方法是一个健壮和一致的解决方案。

您是否也将ZonedDateTime序列化为JSON?

然后,您可能感兴趣的是,至少需要2.6.0版本的jackson-datatype-jsr310依赖才能使序列化工作。更多关于在这个答案中的报道。

票数 6
EN

Stack Overflow用户

发布于 2017-01-14 05:42:02

Eclipselink使用setTimestamp的单个arg版本,将时区处理的责任委托给驱动程序,postgresql驱动程序不允许覆盖默认时区。postgres驱动程序甚至将客户端时区传播到会话,因此服务器端默认设置对您也没有任何用处。

您可以尝试解决一些棘手的问题,例如编写JPA2.1 AttributeConverter将时间戳转换到目标区域,但最终它们注定会失败,因为客户端时区进行了夏时制调整,使某些时候变得模棱两可或无法表示。

您必须在客户端上设置默认时区,或者进入本机SQL,将时间戳设置为具有强制转换的字符串。

票数 1
EN

Stack Overflow用户

发布于 2022-06-20 11:35:05

如何使用即时,而不是LocalDateTime?我认为它可以将实体值转换为时间戳,以UTC为单位。

代码语言:javascript
复制
@Converter(autoApply = true)
public class ZonedDateTimeAttributeConverter implements         AttributeConverter<ZonedDateTime, Timestamp> {

    @Override
    public Timestamp convertToDatabaseColumn(ZonedDateTime zonedDateTime) {
            return (zonedDateTime == null ? null : Timestamp.from(zonedDateTime.toInstant()));
    }

    @Override
    public ZonedDateTime convertToEntityAttribute(Timestamp sqlTimestamp) {
        return (sqlTimestamp == null ? null : sqlTimestamp.toInstant().atZone(ZoneId.of("UTC")));
    }

}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41618165

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档