8148849: Truncating Duration
Introduce a new method to truncatedTo() Reviewed-by: rriggs, scolebourne
This commit is contained in:
parent
c304110149
commit
f1634255f5
@ -1350,6 +1350,48 @@ public final class Duration
|
||||
return nanos;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Returns a copy of this {@code Duration} truncated to the specified unit.
|
||||
* <p>
|
||||
* Truncating the duration returns a copy of the original with conceptual fields
|
||||
* smaller than the specified unit set to zero.
|
||||
* For example, truncating with the {@link ChronoUnit#MINUTES MINUTES} unit will
|
||||
* round down to the nearest minute, setting the seconds and nanoseconds to zero.
|
||||
* <p>
|
||||
* The unit must have a {@linkplain TemporalUnit#getDuration() duration}
|
||||
* that divides into the length of a standard day without remainder.
|
||||
* This includes all supplied time units on {@link ChronoUnit} and
|
||||
* {@link ChronoUnit#DAYS DAYS}. Other ChronoUnits throw an exception.
|
||||
* <p>
|
||||
* This instance is immutable and unaffected by this method call.
|
||||
*
|
||||
* @param unit the unit to truncate to, not null
|
||||
* @return a {@code Duration} based on this duration with the time truncated, not null
|
||||
* @throws DateTimeException if the unit is invalid for truncation
|
||||
* @throws UnsupportedTemporalTypeException if the unit is not supported
|
||||
*/
|
||||
public Duration truncatedTo(TemporalUnit unit) {
|
||||
Objects.requireNonNull(unit, "unit");
|
||||
if (unit == ChronoUnit.SECONDS && (seconds >= 0 || nanos == 0)) {
|
||||
return new Duration(seconds, 0);
|
||||
} else if (unit == ChronoUnit.NANOS) {
|
||||
return this;
|
||||
}
|
||||
Duration unitDur = unit.getDuration();
|
||||
if (unitDur.getSeconds() > LocalTime.SECONDS_PER_DAY) {
|
||||
throw new UnsupportedTemporalTypeException("Unit is too large to be used for truncation");
|
||||
}
|
||||
long dur = unitDur.toNanos();
|
||||
if ((LocalTime.NANOS_PER_DAY % dur) != 0) {
|
||||
throw new UnsupportedTemporalTypeException("Unit must divide into a standard day without remainder");
|
||||
}
|
||||
long nod = (seconds % LocalTime.SECONDS_PER_DAY) * LocalTime.NANOS_PER_SECOND + nanos;
|
||||
long result = (nod / dur) * dur ;
|
||||
return plusNanos(result - nod);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Compares this duration to the specified {@code Duration}.
|
||||
|
@ -65,9 +65,11 @@ import static java.time.temporal.ChronoUnit.HOURS;
|
||||
import static java.time.temporal.ChronoUnit.MICROS;
|
||||
import static java.time.temporal.ChronoUnit.MILLIS;
|
||||
import static java.time.temporal.ChronoUnit.MINUTES;
|
||||
import static java.time.temporal.ChronoUnit.MONTHS;
|
||||
import static java.time.temporal.ChronoUnit.NANOS;
|
||||
import static java.time.temporal.ChronoUnit.SECONDS;
|
||||
import static java.time.temporal.ChronoUnit.WEEKS;
|
||||
import static java.time.temporal.ChronoUnit.YEARS;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
import static org.testng.Assert.fail;
|
||||
@ -2286,6 +2288,133 @@ public class TCKDuration extends AbstractTCKTest {
|
||||
test.multipliedBy(Long.MIN_VALUE);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// truncated(TemporalUnit)
|
||||
//-----------------------------------------------------------------------
|
||||
TemporalUnit NINETY_MINS = new TemporalUnit() {
|
||||
@Override
|
||||
public Duration getDuration() {
|
||||
return Duration.ofMinutes(90);
|
||||
}
|
||||
@Override
|
||||
public boolean isDurationEstimated() {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean isDateBased() {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean isTimeBased() {
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean isSupportedBy(Temporal temporal) {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public <R extends Temporal> R addTo(R temporal, long amount) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
@Override
|
||||
public long between(Temporal temporal1, Temporal temporal2) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NinetyMins";
|
||||
}
|
||||
};
|
||||
|
||||
TemporalUnit NINETY_FIVE_MINS = new TemporalUnit() {
|
||||
@Override
|
||||
public Duration getDuration() {
|
||||
return Duration.ofMinutes(95);
|
||||
}
|
||||
@Override
|
||||
public boolean isDurationEstimated() {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean isDateBased() {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean isTimeBased() {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean isSupportedBy(Temporal temporal) {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public <R extends Temporal> R addTo(R temporal, long amount) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
@Override
|
||||
public long between(Temporal temporal1, Temporal temporal2) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NinetyFiveMins";
|
||||
}
|
||||
};
|
||||
|
||||
@DataProvider(name="truncatedToValid")
|
||||
Object[][] data_truncatedToValid() {
|
||||
return new Object[][] {
|
||||
{Duration.ofSeconds(86400 + 3600 + 60 + 1, 123_456_789), NANOS, Duration.ofSeconds(86400 + 3600 + 60 + 1, 123_456_789)},
|
||||
{Duration.ofSeconds(86400 + 3600 + 60 + 1, 123_456_789), MICROS, Duration.ofSeconds(86400 + 3600 + 60 + 1, 123_456_000)},
|
||||
{Duration.ofSeconds(86400 + 3600 + 60 + 1, 123_456_789), MILLIS, Duration.ofSeconds(86400 + 3600 + 60 + 1, 1230_00_000)},
|
||||
{Duration.ofSeconds(86400 + 3600 + 60 + 1, 123_456_789), SECONDS, Duration.ofSeconds(86400 + 3600 + 60 + 1, 0)},
|
||||
{Duration.ofSeconds(86400 + 3600 + 60 + 1, 123_456_789), MINUTES, Duration.ofSeconds(86400 + 3600 + 60, 0)},
|
||||
{Duration.ofSeconds(86400 + 3600 + 60 + 1, 123_456_789), HOURS, Duration.ofSeconds(86400 + 3600, 0)},
|
||||
{Duration.ofSeconds(86400 + 3600 + 60 + 1, 123_456_789), DAYS, Duration.ofSeconds(86400, 0)},
|
||||
|
||||
{Duration.ofSeconds(86400 + 3600 + 60 + 1, 123_456_789), NINETY_MINS, Duration.ofSeconds(86400 + 0, 0)},
|
||||
{Duration.ofSeconds(86400 + 7200 + 60 + 1, 123_456_789), NINETY_MINS, Duration.ofSeconds(86400 + 5400, 0)},
|
||||
{Duration.ofSeconds(86400 + 10800 + 60 + 1, 123_456_789), NINETY_MINS, Duration.ofSeconds(86400 + 10800, 0)},
|
||||
|
||||
{Duration.ofSeconds(-86400 - 3600 - 60 - 1, 123_456_789), MINUTES, Duration.ofSeconds(-86400 - 3600 - 60, 0 )},
|
||||
{Duration.ofSeconds(-86400 - 3600 - 60 - 1, 123_456_789), MICROS, Duration.ofSeconds(-86400 - 3600 - 60 - 1, 123_457_000)},
|
||||
|
||||
{Duration.ofSeconds(86400 + 3600 + 60 + 1, 0), SECONDS, Duration.ofSeconds(86400 + 3600 + 60 + 1, 0)},
|
||||
{Duration.ofSeconds(-86400 - 3600 - 120, 0), MINUTES, Duration.ofSeconds(-86400 - 3600 - 120, 0)},
|
||||
|
||||
{Duration.ofSeconds(-1, 0), SECONDS, Duration.ofSeconds(-1, 0)},
|
||||
{Duration.ofSeconds(-1, 123_456_789), SECONDS, Duration.ofSeconds(0, 0)},
|
||||
{Duration.ofSeconds(-1, 123_456_789), NANOS, Duration.ofSeconds(0, -876_543_211)},
|
||||
{Duration.ofSeconds(0, 123_456_789), SECONDS, Duration.ofSeconds(0, 0)},
|
||||
{Duration.ofSeconds(0, 123_456_789), NANOS, Duration.ofSeconds(0, 123_456_789)},
|
||||
};
|
||||
}
|
||||
|
||||
@Test(dataProvider="truncatedToValid")
|
||||
public void test_truncatedTo_valid(Duration input, TemporalUnit unit, Duration expected) {
|
||||
assertEquals(input.truncatedTo(unit), expected);
|
||||
}
|
||||
|
||||
@DataProvider(name="truncatedToInvalid")
|
||||
Object[][] data_truncatedToInvalid() {
|
||||
return new Object[][] {
|
||||
{Duration.ofSeconds(1, 123_456_789), NINETY_FIVE_MINS},
|
||||
{Duration.ofSeconds(1, 123_456_789), WEEKS},
|
||||
{Duration.ofSeconds(1, 123_456_789), MONTHS},
|
||||
{Duration.ofSeconds(1, 123_456_789), YEARS},
|
||||
};
|
||||
}
|
||||
|
||||
@Test(dataProvider="truncatedToInvalid", expectedExceptions=DateTimeException.class)
|
||||
public void test_truncatedTo_invalid(Duration input, TemporalUnit unit) {
|
||||
input.truncatedTo(unit);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions=NullPointerException.class)
|
||||
public void test_truncatedTo_null() {
|
||||
Duration.ofSeconds(1234).truncatedTo(null);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// dividedBy()
|
||||
//-----------------------------------------------------------------------
|
||||
|
Loading…
x
Reference in New Issue
Block a user