From 4fc6b0ffa4f771991a5ebd982b5133d2e364fdae Mon Sep 17 00:00:00 2001 From: Eamonn McManus Date: Sat, 23 Dec 2023 22:53:23 +0000 Subject: [PATCH] 8068958: Timestamp.from(Instant) should throw when conversion is not possible Reviewed-by: rgiulietti, rriggs --- .../share/classes/java/sql/Timestamp.java | 4 +-- .../sql/testng/test/sql/TimestampTests.java | 27 ++++++++++++++++++- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/java.sql/share/classes/java/sql/Timestamp.java b/src/java.sql/share/classes/java/sql/Timestamp.java index dc347ab02ff..8fb85f73c7e 100644 --- a/src/java.sql/share/classes/java/sql/Timestamp.java +++ b/src/java.sql/share/classes/java/sql/Timestamp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -542,7 +542,7 @@ public class Timestamp extends java.util.Date { */ public static Timestamp from(Instant instant) { try { - Timestamp stamp = new Timestamp(instant.getEpochSecond() * MILLIS_PER_SECOND); + Timestamp stamp = new Timestamp(Math.multiplyExact(instant.getEpochSecond(), MILLIS_PER_SECOND)); stamp.nanos = instant.getNano(); return stamp; } catch (ArithmeticException ex) { diff --git a/test/jdk/java/sql/testng/test/sql/TimestampTests.java b/test/jdk/java/sql/testng/test/sql/TimestampTests.java index 7766b5a2b4c..fefe3276d47 100644 --- a/test/jdk/java/sql/testng/test/sql/TimestampTests.java +++ b/test/jdk/java/sql/testng/test/sql/TimestampTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -642,6 +642,31 @@ public class TimestampTests extends BaseTest { assertEquals(ts1.toString(), ts, "ts1.toString() != ts"); } + @Test + public void test53() { + // The latest Instant that can be converted to a Timestamp. + Instant instant1 = Instant.ofEpochSecond(Long.MAX_VALUE / 1000, 999_999_999); + assertEquals(Timestamp.from(instant1).toInstant(), instant1); + + // One nanosecond more, and converting it gets an overflow. + Instant instant2 = instant1.plusNanos(1); + expectThrows(IllegalArgumentException.class, () -> Timestamp.from(instant2)); + + // The earliest Instant that can be converted to a Timestamp. + Instant instant3 = Instant.ofEpochSecond(Long.MIN_VALUE / 1000, 0); + assertEquals(Timestamp.from(instant3).toInstant(), instant3); + + // One nanosecond less, and converting it gets an overflow. + Instant instant4 = instant3.minusNanos(1); + expectThrows(IllegalArgumentException.class, () -> Timestamp.from(instant4)); + + // The latest possible Instant will certainly overflow. + expectThrows(IllegalArgumentException.class, () -> Timestamp.from(Instant.MAX)); + + // The earliest possible Instant will certainly overflow. + expectThrows(IllegalArgumentException.class, () -> Timestamp.from(Instant.MIN)); + } + /* * DataProvider used to provide Timestamps which are not valid and are used * to validate that an IllegalArgumentException will be thrown from the