8146747: java.time.Duration.toNanos() and toMillis() exception on negative durations
authorntv
Mon, 08 Feb 2016 09:56:26 -0500
changeset 35715 006017186296
parent 35714 05eadb5e7022
child 35716 07ecc6d51751
8146747: java.time.Duration.toNanos() and toMillis() exception on negative durations Reviewed-by: rriggs, scolebourne
jdk/src/java.base/share/classes/java/time/Duration.java
jdk/test/java/time/tck/java/time/TCKDuration.java
--- 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()
     //-----------------------------------------------------------------------