从java.time.Instant生成的java.sql.Timestamp的最小值/最大值与从Long.MIN\u值/Long.MAX\u值构造时的行为不同

从java.time.Instant生成的java.sql.Timestamp的最小值/最大值与从Long.MIN\u值/Long.MAX\u值构造时的行为不同,java,java-8,java-time,java.time.instant,Java,Java 8,Java Time,Java.time.instant,我在编写一个测试用例时遇到了这个问题,在这个测试用例中,我必须获得一系列时间戳之间的一系列记录——使用H2嵌入式数据库和spring数据jpa 原始版本位于: 我的时间戳是java.time.Instant实例 如果用户没有给出开始-结束时间戳,我将继续并分别插入Instant.MIN和Instant.MAX 让我困惑的是,以下测试用例通过了: @Test public void test_date_min_max_instants_timestamps() { Timestam

我在编写一个测试用例时遇到了这个问题,在这个测试用例中,我必须获得一系列时间戳之间的一系列记录——使用H2嵌入式数据库和spring数据jpa

原始版本位于:

我的时间戳是java.time.Instant实例

如果用户没有给出开始-结束时间戳,我将继续并分别插入Instant.MIN和Instant.MAX

让我困惑的是,以下测试用例通过了:

  @Test
  public void test_date_min_max_instants_timestamps() {
    Timestamp past = new Timestamp(Long.MIN_VALUE); 
    Timestamp future = new Timestamp(Long.MAX_VALUE); 
    Timestamp present = Timestamp.from(Instant.now()); 

    assertTrue(present.after(past));
    assertTrue(future.after(past));
    assertTrue(future.after(present));

    assertTrue(present.before(future));
    assertTrue(past.before(present));
    assertTrue(past.before(future));
  }
但是,以下测试用例失败:

 @Test
  public void test_instant_ranges() throws InterruptedException {
    Timestamp past = Timestamp.from(Instant.MIN);
    Timestamp future = Timestamp.from(Instant.MAX);
    Timestamp present = Timestamp.from(Instant.now());

    assertTrue(present.after(past));
    assertTrue(future.after(past));
    assertTrue(future.after(present));

    assertTrue(present.before(future));
    assertTrue(past.before(present));
    assertTrue(past.before(future));
  }
此外,如果过去和未来不是最小/最大值,而是正常值,则结果与预期一致

知道java.sql.Timestamp为什么会这样吗

此外,如果Instant表示的时间对于时间戳来说太大,那么它不应该失败吗

另外,如果这个问题已经被问过了,有没有人可以链接一下原文,因为我一直找不到

编辑:添加了我在评论部分提到的调试信息,这样我们就可以把所有东西都放在一个地方


对于从Instant.MIN和Instant.MAX生成的时间戳实例,我有以下值:

past = 169108098-07-03 21:51:43.0 
future = 169104627-12-11 11:08:15.999999999 
present = 2018-07-23 10:46:50.842 
对于由Long.MIN_值和Long.MAX_值生成的时间戳实例,我得到:


为了澄清我的问题,时间戳应该显式失败,而不是静默失败或在内部使用不同的值。目前没有。

这是Timestamp类及其从Instant转换中的已知错误。三年半前,它于2015年1月在Java bug数据库中注册,目前仍然开放,没有确定的修复版本。请参阅底部的官方bug报告链接

预期的行为是明确的 Timestamp.fromInstant的文档对此非常清楚:

Instant可以在将来和将来进一步存储时间线上的点 在过去比现在更远。在此场景中,此方法将 抛出异常

所以是的,应该抛出一个异常

复制错误很简单 在我的Java10上,我复制了两个示例,其中转换默默地给出了错误的结果,而不是抛出异常。一个例子是:

        Instant i = LocalDate.of(-400_000_000, Month.JUNE, 14)
                .atStartOfDay(ZoneId.of("Africa/Cairo"))
                .toInstant();
        Timestamp ts = Timestamp.from(i);
        System.out.println("" + i + " -> " + ts + " -> " + ts.toInstant());
这张照片是:

-400000000-06-13T21:54:51Z->184554049-09-1414:20:42.0->+184554049-09-14T12:20:42Z

前一种转换显然是错误的:一个遥远过去的时间被转换成了一个遥远的时间,尽管不是那么遥远的未来。回到瞬间的转换似乎是正确的

附录:JDK源代码 出于好奇,以下是转换方法的实现:

public static Timestamp from(Instant instant) {
    try {
        Timestamp stamp = new Timestamp(instant.getEpochSecond() * MILLIS_PER_SECOND);
        stamp.nanos = instant.getNano();
        return stamp;
    } catch (ArithmeticException ex) {
        throw new IllegalArgumentException(ex);
    }
}
似乎作者预期乘法运算中的算术溢出会导致算术异常。事实并非如此

链接
此外,如果Instant表示的时间对于时间戳来说太大,那么它不应该失败吗?而不是什么?。使用step调试器可以非常快速轻松地回答您的问题。在使用StackOverflow之前,您应该始终尝试使用step调试器解决问题。对于由Instant.MIN和Instant.MAX生成的时间戳实例-过去=169108098-07-03 21:51:43.0未来=169104627-12-11 11:08:15.99999999当前=2018-07-23 10:46:50.842以及由Long.MIN_值和Long.MAX_VALUE,我得到:pass=292278994-08-16 23:12:55.192 future=292278994-08-16 23:12:55.807 present=2018-07-23 10:49:54.281 P.S.我发布这个问题的原因是因为我自己无法解决它。@shmosel没有默默失败或在内部使用不同的值。基本上,我想说的是:如果不可能的话,转换应该会显式失败。感谢@sidmishraw添加更多信息。请在问题中这样做,而不是在评论中这样做,这样我们就把一切都放在一个地方了。谢谢。
public static Timestamp from(Instant instant) {
    try {
        Timestamp stamp = new Timestamp(instant.getEpochSecond() * MILLIS_PER_SECOND);
        stamp.nanos = instant.getNano();
        return stamp;
    } catch (ArithmeticException ex) {
        throw new IllegalArgumentException(ex);
    }
}