8273369: Computing micros between two instants unexpectedly overflows for some cases
Reviewed-by: lancea, rriggs, joehw
This commit is contained in:
parent
efe3ed1e70
commit
81d2acee57
src/java.base/share/classes/java/time
test/jdk/java/time/test/java/time
@ -61,6 +61,8 @@
|
||||
*/
|
||||
package java.time;
|
||||
|
||||
import static java.time.LocalTime.MICROS_PER_SECOND;
|
||||
import static java.time.LocalTime.MILLIS_PER_SECOND;
|
||||
import static java.time.LocalTime.NANOS_PER_SECOND;
|
||||
import static java.time.LocalTime.SECONDS_PER_DAY;
|
||||
import static java.time.LocalTime.SECONDS_PER_HOUR;
|
||||
@ -1145,8 +1147,8 @@ public final class Instant
|
||||
if (unit instanceof ChronoUnit chronoUnit) {
|
||||
return switch (chronoUnit) {
|
||||
case NANOS -> nanosUntil(end);
|
||||
case MICROS -> nanosUntil(end) / 1000;
|
||||
case MILLIS -> Math.subtractExact(end.toEpochMilli(), toEpochMilli());
|
||||
case MICROS -> microsUntil(end);
|
||||
case MILLIS -> millisUntil(end);
|
||||
case SECONDS -> secondsUntil(end);
|
||||
case MINUTES -> secondsUntil(end) / SECONDS_PER_MINUTE;
|
||||
case HOURS -> secondsUntil(end) / SECONDS_PER_HOUR;
|
||||
@ -1164,6 +1166,18 @@ public final class Instant
|
||||
return Math.addExact(totalNanos, end.nanos - nanos);
|
||||
}
|
||||
|
||||
private long microsUntil(Instant end) {
|
||||
long secsDiff = Math.subtractExact(end.seconds, seconds);
|
||||
long totalMicros = Math.multiplyExact(secsDiff, MICROS_PER_SECOND);
|
||||
return Math.addExact(totalMicros, (end.nanos - nanos) / 1000);
|
||||
}
|
||||
|
||||
private long millisUntil(Instant end) {
|
||||
long secsDiff = Math.subtractExact(end.seconds, seconds);
|
||||
long totalMillis = Math.multiplyExact(secsDiff, MILLIS_PER_SECOND);
|
||||
return Math.addExact(totalMillis, (end.nanos - nanos) / 1000_000);
|
||||
}
|
||||
|
||||
private long secondsUntil(Instant end) {
|
||||
long secsDiff = Math.subtractExact(end.seconds, seconds);
|
||||
long nanosDiff = end.nanos - nanos;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2021, 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
|
||||
@ -182,14 +182,22 @@ public final class LocalTime
|
||||
* Seconds per day.
|
||||
*/
|
||||
static final int SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY;
|
||||
/**
|
||||
* Milliseconds per second.
|
||||
*/
|
||||
static final long MILLIS_PER_SECOND = 1000L;
|
||||
/**
|
||||
* Milliseconds per day.
|
||||
*/
|
||||
static final long MILLIS_PER_DAY = SECONDS_PER_DAY * 1000L;
|
||||
static final long MILLIS_PER_DAY = MILLIS_PER_SECOND * SECONDS_PER_DAY;
|
||||
/**
|
||||
* Microseconds per second.
|
||||
*/
|
||||
static final long MICROS_PER_SECOND = 1000_000L;
|
||||
/**
|
||||
* Microseconds per day.
|
||||
*/
|
||||
static final long MICROS_PER_DAY = SECONDS_PER_DAY * 1000_000L;
|
||||
static final long MICROS_PER_DAY = MICROS_PER_SECOND * SECONDS_PER_DAY;
|
||||
/**
|
||||
* Nanos per millisecond.
|
||||
*/
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2021, 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
|
||||
@ -60,6 +60,7 @@
|
||||
package test.java.time;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
import org.testng.annotations.DataProvider;
|
||||
@ -67,6 +68,7 @@ import static org.testng.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* Test Instant.
|
||||
* @bug 8273369
|
||||
*/
|
||||
@Test
|
||||
public class TestInstant extends AbstractTest {
|
||||
@ -96,4 +98,26 @@ public class TestInstant extends AbstractTest {
|
||||
assertEquals(millis, m, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether Instant.until() returning microseconds does not throw
|
||||
* an ArithmeticException for Instants apart for more than Long.MAX_VALUE
|
||||
* nanoseconds.
|
||||
*/
|
||||
@Test
|
||||
public void test_microsUntil() {
|
||||
var nanoMax = Instant.EPOCH.plusNanos(Long.MAX_VALUE);
|
||||
var totalMicros = Instant.EPOCH.until(nanoMax, ChronoUnit.MICROS);
|
||||
var plusOneMicro = Instant.EPOCH.until(nanoMax.plusNanos(1000), ChronoUnit.MICROS);
|
||||
assertEquals(plusOneMicro - totalMicros, 1L);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether Instant.until() returning milliseconds does not throw
|
||||
* an ArithmeticException for very large/small Instants
|
||||
*/
|
||||
@Test
|
||||
public void test_millisUntil() {
|
||||
assertEquals(Instant.MIN.until(Instant.MIN.plusSeconds(1), ChronoUnit.MILLIS), 1000L);
|
||||
assertEquals(Instant.MAX.plusSeconds(-1).until(Instant.MAX, ChronoUnit.MILLIS), 1000L);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user