【问题标题】:java.sql.Timestamp wrong time parsingjava.sql.Timestamp 错误时间解析
【发布时间】:2018-05-29 02:48:41
【问题描述】:

有人可以解释为什么会这样吗?为什么该时间有 24 分钟的偏移量以及如何处理?

Scala 2.12 和 Java 8。

scala> java.sql.Timestamp.valueOf("1900-01-01 00:59:00")
res22: java.sql.Timestamp = 1900-01-01 00:59:00.0

scala> java.sql.Timestamp.valueOf("1900-01-01 01:00:00")
res23: java.sql.Timestamp = 1900-01-01 01:24:00.0

scala> java.sql.Timestamp.valueOf("1900-01-01 01:14:00")
res24: java.sql.Timestamp = 1900-01-01 01:38:00.0

scala> java.sql.Timestamp.valueOf("1900-01-01 01:20:00")
res25: java.sql.Timestamp = 1900-01-01 01:44:00.0

scala> java.sql.Timestamp.valueOf("1900-01-01 01:23:00")
res26: java.sql.Timestamp = 1900-01-01 01:47:00.0

scala> java.sql.Timestamp.valueOf("1900-01-01 01:24:00")
res27: java.sql.Timestamp = 1900-01-01 01:24:00.0

scala> java.sql.Timestamp.valueOf("1900-01-01 01:30:00")
res28: java.sql.Timestamp = 1900-01-01 01:30:00.0

【问题讨论】:

  • 您的语言环境是什么?仅通过 Java 8,没有 Scala,我无法在我的语言环境(en_US)中重现它。
  • @rgettman ZoneId.systemDefault 返回Europe/Warsaw
  • 我用System.setProperty("user.timezone", "Europe/Warsaw"); 重现了这个问题...对我来说看起来像是一个错误,过去也有过时区错误。单步浏览库代码,似乎在该期间 zoneinfo 数据库中可能存在虚假转换。这需要一些工作来验证,很遗憾,我现在没有时间。
  • 这里有一个非常相似的问题,只是时区不同:Why is subtracting these two times (in 1927) giving a strange result?
  • 我可以用纯 Java 8 重现你的输出。所以这不是 Scala 的错。

标签: java sql postgresql scala timestamp


【解决方案1】:

查看 IANA 时区数据库中的时区定义:

# Zone  NAME            GMTOFF  RULES   FORMAT  [UNTIL]
Zone    Europe/Warsaw   1:24:00 -       LMT     1880
                        1:24:00 -       WMT     1915 Aug  5 # Warsaw Mean Time
                        1:00    C-Eur   CE%sT   1918 Sep 16  3:00
                        2:00    Poland  EE%sT   1922 Jun
                        1:00    Poland  CE%sT   1940 Jun 23  2:00
                        1:00    C-Eur   CE%sT   1944 Oct
                        1:00    Poland  CE%sT   1977
                        1:00    W-Eur   CE%sT   1988
                        1:00    EU  CE%sT

在 1900 年,波兰与 UTC 有 1 小时 24 分钟的时区偏移,也就是说,他们使用的是当地平均太阳时。那是在 1915 年 8 月 5 日引入标准时区之前。

您必须为 PostgreSQL 提供 timestamp without time zone,它在您的本地时区解释(偏移量为 1:24)。

然后有人(scala?)将此时间戳转换回您当地时区的时间戳,但错误地使用了一小时的偏移量。

我不知道该如何解决这个问题,但要么始终使用timestamp without time zone,要么修复认为波兰时间与 1900 年 UTC 偏移 1 小时的组件。

【讨论】:

  • 正确:我的 Java 8 不知道 1900 年有任何过渡。它知道的最早是在 1915 年:Transition[重叠在 1915-08-05T00:00+01:24 到 + 01:00]。
  • 谢谢。看起来Java是问题所在。所以剩下的唯一选择是避免timestamp with time zone
  • 我想你可以在你的数据库中使用 timestamp-with-timezone 如果你只能使用java.time.Instant 来保存和检索(或者String 如果一切都失败了,但你更喜欢@987654327 @)。
【解决方案2】:

据我所知,这里涉及两个错误。两者都(如果我是正确的)在java.util.Date 类中,java.sql.Timestamp 的超类。

首先,华沙在 1900 年没有时间偏移转换。我的 Java 8 所知道的最早转换是在 1915 年。因此,在我们关注的所有时间里,华沙的时间偏移都与 GMT 相差 1:24 .

我试过了:

    TimeZone.setDefault(TimeZone.getTimeZone("Europe/Warsaw"));
    ZoneOffset offset0124 = ZoneOffset.ofHoursMinutes(1, 24);

    System.out.println("" + new Date(0, 0, 1, 0, 59) 
            + " -> " + new Date(0, 0, 1, 0, 59).toInstant().atOffset(offset0124));
    System.out.println("" + new Date(0, 0, 1, 1, 14) 
            + " -> " + new Date(0, 0, 1, 1, 14).toInstant().atOffset(offset0124));
    System.out.println("" + new Date(0, 0, 1, 1, 24) 
            + " -> " + new Date(0, 0, 1, 1, 24).toInstant().atOffset(offset0124));

打印出来:

Mon Jan 01 00:59:00 CET 1900 -> 1900-01-01T01:23+01:24
Mon Jan 01 01:38:00 CET 1900 -> 1900-01-01T01:38+01:24
Mon Jan 01 01:24:00 CET 1900 -> 1900-01-01T01:24+01:24

您间接使用的方法Timestamp.valueOf 方法使用了已弃用的Date 构造函数,我也是(不是完全相同的构造函数,我使用的是没有秒数的构造函数,相信它没有区别)。我将评论以上三种情况向后

  • 1:24 处理正确,我们从Date.toString()OffsetDateTime 都获得了预期时间。
  • 1:14 被认为是 24 分钟后的 1:38。这对我来说似乎是一个错误。
  • 0:59 被视为 1:23,也是 24 分钟后。我们可以从OffsetDateTime 看到这一点。同样的错误。但是,Date.toString() 按预期生成 00:59。在我看来,这似乎是第二个错误,它以某种方式弥补了第一个错误。我没有检查,但我怀疑这个 bug 的来源也会导致 Timestamp.toString() 行为不正确。

作为检查,我计算了您的 Timestamp 对象在 0:59 和 1:24 之间的差异。期望的结果是 25 分钟或 1 500 000 毫秒。代码是:

    System.out.println(java.sql.Timestamp.valueOf("1900-01-01 01:24:00").getTime() 
            - java.sql.Timestamp.valueOf("1900-01-01 00:59:00").getTime());

打印出来

60000

60 秒,相当于 1 分钟。因此,即使这两个时间戳都按照我们预期的方式打印,但仍然存在一个错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-27
    • 2018-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-26
    相关资源
    最近更新 更多