8146747: java.time.Duration.toNanos() and toMillis() exception on negative durations
Reviewed-by: rriggs, scolebourne
--- a/jdk/src/java.base/share/classes/java/time/Duration.java Mon Feb 08 15:33:53 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/time/Duration.java Mon Feb 08 09:56:26 2016 -0500
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016, 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
@@ -62,6 +62,7 @@
package java.time;
import static java.time.LocalTime.MINUTES_PER_HOUR;
+import static java.time.LocalTime.NANOS_PER_MILLI;
import static java.time.LocalTime.NANOS_PER_SECOND;
import static java.time.LocalTime.SECONDS_PER_DAY;
import static java.time.LocalTime.SECONDS_PER_HOUR;
@@ -1214,8 +1215,16 @@
* @throws ArithmeticException if numeric overflow occurs
*/
public long toMillis() {
- long millis = Math.multiplyExact(seconds, 1000);
- millis = Math.addExact(millis, nanos / 1000_000);
+ long tempSeconds = seconds;
+ long tempNanos = nanos;
+ if (tempSeconds < 0) {
+ // change the seconds and nano value to
+ // handle Long.MIN_VALUE case
+ tempSeconds = tempSeconds + 1;
+ tempNanos = tempNanos - NANOS_PER_SECOND;
+ }
+ long millis = Math.multiplyExact(tempSeconds, 1000);
+ millis = Math.addExact(millis, tempNanos / NANOS_PER_MILLI);
return millis;
}
@@ -1229,8 +1238,16 @@
* @throws ArithmeticException if numeric overflow occurs
*/
public long toNanos() {
- long totalNanos = Math.multiplyExact(seconds, NANOS_PER_SECOND);
- totalNanos = Math.addExact(totalNanos, nanos);
+ long tempSeconds = seconds;
+ long tempNanos = nanos;
+ if (tempSeconds < 0) {
+ // change the seconds and nano value to
+ // handle Long.MIN_VALUE case
+ tempSeconds = tempSeconds + 1;
+ tempNanos = tempNanos - NANOS_PER_SECOND;
+ }
+ long totalNanos = Math.multiplyExact(tempSeconds, NANOS_PER_SECOND);
+ totalNanos = Math.addExact(totalNanos, tempNanos);
return totalNanos;
}
--- a/jdk/test/java/time/tck/java/time/TCKDuration.java Mon Feb 08 15:33:53 2016 +0100
+++ b/jdk/test/java/time/tck/java/time/TCKDuration.java Mon Feb 08 09:56:26 2016 -0500
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016, 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
@@ -2496,8 +2496,9 @@
//-----------------------------------------------------------------------
@Test
public void test_toNanos() {
- Duration test = Duration.ofSeconds(321, 123456789);
- assertEquals(test.toNanos(), 321123456789L);
+ assertEquals(Duration.ofSeconds(321, 123456789).toNanos(), 321123456789L);
+ assertEquals(Duration.ofNanos(Long.MAX_VALUE).toNanos(), 9223372036854775807L);
+ assertEquals(Duration.ofNanos(Long.MIN_VALUE).toNanos(), -9223372036854775808L);
}
@Test
@@ -2512,13 +2513,26 @@
test.toNanos();
}
+ @Test
+ public void test_toNanos_min() {
+ Duration test = Duration.ofSeconds(0, Long.MIN_VALUE);
+ assertEquals(test.toNanos(), Long.MIN_VALUE);
+ }
+
+ @Test(expectedExceptions=ArithmeticException.class)
+ public void test_toNanos_tooSmall() {
+ Duration test = Duration.ofSeconds(0, Long.MIN_VALUE).minusNanos(1);
+ test.toNanos();
+ }
+
//-----------------------------------------------------------------------
// toMillis()
//-----------------------------------------------------------------------
@Test
public void test_toMillis() {
- Duration test = Duration.ofSeconds(321, 123456789);
- assertEquals(test.toMillis(), 321000 + 123);
+ assertEquals(Duration.ofSeconds(321, 123456789).toMillis(), 321000 + 123);
+ assertEquals(Duration.ofMillis(Long.MAX_VALUE).toMillis(), 9223372036854775807L);
+ assertEquals(Duration.ofMillis(Long.MIN_VALUE).toMillis(), -9223372036854775808L);
}
@Test
@@ -2533,6 +2547,18 @@
test.toMillis();
}
+ @Test
+ public void test_toMillis_min() {
+ Duration test = Duration.ofSeconds(Long.MIN_VALUE / 1000, (Long.MIN_VALUE % 1000) * 1000000);
+ assertEquals(test.toMillis(), Long.MIN_VALUE);
+ }
+
+ @Test(expectedExceptions=ArithmeticException.class)
+ public void test_toMillis_tooSmall() {
+ Duration test = Duration.ofSeconds(Long.MIN_VALUE / 1000, ((Long.MIN_VALUE % 1000) - 1) * 1000000);
+ test.toMillis();
+ }
+
//-----------------------------------------------------------------------
// toSeconds()
//-----------------------------------------------------------------------