【问题标题】:ZonedDateTime value incorrect after loading via Spring Boot JPA, PostgreSQL通过 Spring Boot JPA、PostgreSQL 加载后 ZonedDateTime 值不正确
【发布时间】:2020-06-04 14:07:31
【问题描述】:

我有一个带有特定时刻的 ZonedDateTime,Zone 设置为 America/Los_Angeles。

如果我使用 "d-MMM-uuuu HH:mm VV" 模式显示它,它会按我的预期显示(例如 ... 8:00 am America/Los_Angeles)。

但是,如果我通过删除“VV”来极少地改变模式,那么它不会显示西海岸时间的时间,而是显示我的当地时间(东海岸)或上午 11:00 - 所以它基本上忽略了 ZonedDateTime 上设置的区域,而是使用其他东西(我假设系统本地区域)。

在某些情况下,我宁愿不显示时区 ID,以节省空间(例如在表格中),但仍希望它以当地时间显示。

有没有办法做到这一点?

更新:

我注意到,令人惊讶的是,使用模式 "d-MMM-uuuu HH:mm O" 给出了我认为错误的答案:

2020 年 6 月 2 日 11:09 GMT-7

这是正确的时间,使用 VV 显示:

2-Jun-2020 08:09 America/Los_Angeles

“GMT-7”的 11am 值看起来显然是一个错误 - 当然我仍在使用 Java 8。

更新:

我认为问题可能出在数据层,尽管我仍在努力解决这个问题......(我使用的是 Spring Boot JPA 和 PostgreSQL)。

如果我只是纯粹使用 Java,那么:

        ZoneId pdt = ZoneId.of("America/Los_Angeles");
        ZonedDateTime now = ZonedDateTime.now().withZoneSameInstant(pdt);
        logger.debug("now with VV: "+now.format(DateTimeFormatter.ofPattern("d-MMM-uuuu HH:mm VV")));
        logger.debug("now with O: "+now.format(DateTimeFormatter.ofPattern("d-MMM-uuuu HH:mm O")));
        logger.debug("now with nothing: "+now.format(DateTimeFormatter.ofPattern("d-MMM-uuuu HH:mm")));
        logger.debug("now with VV+withZ: "+now.format(DateTimeFormatter.ofPattern("d-MMM-uuuu HH:mm VV").withZone(pdt)));
        logger.debug("now with O+withZ: "+now.format(DateTimeFormatter.ofPattern("d-MMM-uuuu HH:mm O").withZone(pdt)));
        logger.debug("now with nothing+withZ: "+now.format(DateTimeFormatter.ofPattern("d-MMM-uuuu HH:mm").withZone(pdt)));
        logger.debug("using static formatter: "+now.format(TIMESTAMP_FORMATTER_SHORT));
        logger.debug("using static formatter w/zone: "+now.format(TIMESTAMP_FORMATTER_SHORT.withZone(pdt)));

然后在每种情况下,它都会显示洛杉矶的预期正确时间。

所以,在调试查看差异时,我看到了这个异常:

在纯 java 中,如果我查看 now 的值(在上面的代码中),它看起来是正确的 - LocalDateTime 显示洛杉矶的当前时间,偏移量是 7 小时。

但是,如果我查看在 JPA 加载后设置的 ZonedDateTime 值,它看起来很不寻常:

  • 存储在数据库中的值的小时为 15(如预期的那样,UTC 时间)
  • ZonedDateTime 中 LocalDateTime 中的值关闭 - 它显示小时为 11,这是本地系统时间,而不是洛杉矶的时间
  • 但是 ZonedDateTime 偏移量仍然是 -7

真正奇怪的是,DateTimeFormatter 以某种方式纠正了问题,但只有当我在格式中使用 VV 时

【问题讨论】:

  • 你能提供一个你的代码示例吗?
  • 我无法在 Java 8 或 Java 14 中重现您的问题。对我来说,无论模式是否有时区,都会显示一天中的同一时间。您的 ZonedDateTime 值是否可能不是您认为的那样?
  • 是的,我已经用 ZonedDateTime 似乎有什么问题的最新信息更新了帖子 - 尽管我不知道它是如何被破坏的。

标签: java-time


【解决方案1】:

我已经确定了问题(不出所料,不是 JPA 或 PostgreSQL)。

这是一个很久以前引入的错误,但在我切换到尝试显示更短的时间戳之前从未暴露。

实际导致问题的代码是对本机查询进行后处理,将 java.sql.Timestamp 错误地转换为 ZonedDateTime。这是问题代码:

java.sql.Timestamp timestamp = (Timestamp) objects[0];
String tzId = (String) objects[1];
ZonedDateTime dt = ZonedDateTime.of(timestamp.toLocalDateTime(), ZoneId.of(tzId));

我错误地假设 ZonedDateTime.of 将使用提供的 ZoneId 来修改时间,但我相信它不是这样工作的。相反,toLocalDateTime() 是根据系统默认创建 LocalDateTime,因此与传入的 ZoneId 值不一致,该值是存储在 DB 中的值,与系统默认值不同。

以下是我更正代码的方法:

java.sql.Timestamp timestamp = (Timestamp) objects[0];
String tzId = (String) objects[1];
ZonedDateTime dt = ZonedDateTime.of(timestamp.toLocalDateTime(), ZoneId.systemDefault())
                                        .withZoneSameInstant(ZoneId.of(tzId));

【讨论】:

    猜你喜欢
    • 2020-04-27
    • 2020-10-18
    • 1970-01-01
    • 2021-02-26
    • 2021-03-01
    • 1970-01-01
    • 2020-05-12
    • 2017-06-05
    • 1970-01-01
    相关资源
    最近更新 更多