diff --git a/jdk/src/share/classes/java/time/Duration.java b/jdk/src/share/classes/java/time/Duration.java index ce2ba7781b0..896a2990eaa 100644 --- a/jdk/src/share/classes/java/time/Duration.java +++ b/jdk/src/share/classes/java/time/Duration.java @@ -441,9 +441,13 @@ public final class Duration //----------------------------------------------------------------------- /** - * Obtains a {@code Duration} representing the duration between two instants. + * Obtains a {@code Duration} representing the duration between two temporal objects. + *

+ * This calculates the duration between two temporal objects. If the objects + * are of different types, then the duration is calculated based on the type + * of the first object. For example, if the first argument is a {@code LocalTime} + * then the second argument is converted to a {@code LocalTime}. *

- * This calculates the duration between two temporal objects of the same type. * The specified temporal objects must support the {@link ChronoUnit#SECONDS SECONDS} unit. * For full accuracy, either the {@link ChronoUnit#NANOS NANOS} unit or the * {@link ChronoField#NANO_OF_SECOND NANO_OF_SECOND} field should be supported. diff --git a/jdk/src/share/classes/java/time/Instant.java b/jdk/src/share/classes/java/time/Instant.java index 9d74e29f91a..a7bd6f92004 100644 --- a/jdk/src/share/classes/java/time/Instant.java +++ b/jdk/src/share/classes/java/time/Instant.java @@ -362,6 +362,10 @@ public final class Instant * @throws DateTimeException if unable to convert to an {@code Instant} */ public static Instant from(TemporalAccessor temporal) { + if (temporal instanceof Instant) { + return (Instant) temporal; + } + Objects.requireNonNull(temporal, "temporal"); long instantSecs = temporal.getLong(INSTANT_SECONDS); int nanoOfSecond = temporal.get(NANO_OF_SECOND); return Instant.ofEpochSecond(instantSecs, nanoOfSecond); @@ -1091,7 +1095,8 @@ public final class Instant * The result will be negative if the end is before the start. * The calculation returns a whole number, representing the number of * complete units between the two instants. - * The {@code Temporal} passed to this method must be an {@code Instant}. + * The {@code Temporal} passed to this method is converted to a + * {@code Instant} using {@link #from(TemporalAccessor)}. * For example, the amount in days between two dates can be calculated * using {@code startInstant.until(endInstant, SECONDS)}. *

@@ -1112,25 +1117,22 @@ public final class Instant *

* If the unit is not a {@code ChronoUnit}, then the result of this method * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} - * passing {@code this} as the first argument and the input temporal as - * the second argument. + * passing {@code this} as the first argument and the converted input temporal + * as the second argument. *

* This instance is immutable and unaffected by this method call. * - * @param endInstant the end date, which must be an {@code Instant}, not null + * @param endExclusive the end date, exclusive, which is converted to an {@code Instant}, not null * @param unit the unit to measure the amount in, not null * @return the amount of time between this instant and the end instant - * @throws DateTimeException if the amount cannot be calculated + * @throws DateTimeException if the amount cannot be calculated, or the end + * temporal cannot be converted to an {@code Instant} * @throws UnsupportedTemporalTypeException if the unit is not supported * @throws ArithmeticException if numeric overflow occurs */ @Override - public long until(Temporal endInstant, TemporalUnit unit) { - if (endInstant instanceof Instant == false) { - Objects.requireNonNull(endInstant, "endInstant"); - throw new DateTimeException("Unable to calculate amount as objects are of two different types"); - } - Instant end = (Instant) endInstant; + public long until(Temporal endExclusive, TemporalUnit unit) { + Instant end = Instant.from(endExclusive); if (unit instanceof ChronoUnit) { ChronoUnit f = (ChronoUnit) unit; switch (f) { @@ -1145,7 +1147,7 @@ public final class Instant } throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } - return unit.between(this, endInstant); + return unit.between(this, end); } private long nanosUntil(Instant end) { diff --git a/jdk/src/share/classes/java/time/LocalDate.java b/jdk/src/share/classes/java/time/LocalDate.java index 110a80fc9c0..f388959aa63 100644 --- a/jdk/src/share/classes/java/time/LocalDate.java +++ b/jdk/src/share/classes/java/time/LocalDate.java @@ -353,6 +353,7 @@ public final class LocalDate * @throws DateTimeException if unable to convert to a {@code LocalDate} */ public static LocalDate from(TemporalAccessor temporal) { + Objects.requireNonNull(temporal, "temporal"); LocalDate date = temporal.query(TemporalQuery.localDate()); if (date == null) { throw new DateTimeException("Unable to obtain LocalDate from TemporalAccessor: " + temporal.getClass()); @@ -1125,11 +1126,11 @@ public final class LocalDate */ @Override public LocalDate plus(TemporalAmount amountToAdd) { - Objects.requireNonNull(amountToAdd, "amountToAdd"); if (amountToAdd instanceof Period) { Period periodToAdd = (Period) amountToAdd; return plusMonths(periodToAdd.toTotalMonths()).plusDays(periodToAdd.getDays()); } + Objects.requireNonNull(amountToAdd, "amountToAdd"); return (LocalDate) amountToAdd.addTo(this); } @@ -1358,11 +1359,11 @@ public final class LocalDate */ @Override public LocalDate minus(TemporalAmount amountToSubtract) { - Objects.requireNonNull(amountToSubtract, "amountToSubtract"); if (amountToSubtract instanceof Period) { Period periodToSubtract = (Period) amountToSubtract; return minusMonths(periodToSubtract.toTotalMonths()).minusDays(periodToSubtract.getDays()); } + Objects.requireNonNull(amountToSubtract, "amountToSubtract"); return (LocalDate) amountToSubtract.subtractFrom(this); } @@ -1541,7 +1542,8 @@ public final class LocalDate * objects in terms of a single {@code TemporalUnit}. * The start and end points are {@code this} and the specified date. * The result will be negative if the end is before the start. - * The {@code Temporal} passed to this method must be a {@code LocalDate}. + * The {@code Temporal} passed to this method is converted to a + * {@code LocalDate} using {@link #from(TemporalAccessor)}. * For example, the amount in days between two dates can be calculated * using {@code startDate.until(endDate, DAYS)}. *

@@ -1567,26 +1569,22 @@ public final class LocalDate *

* If the unit is not a {@code ChronoUnit}, then the result of this method * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} - * passing {@code this} as the first argument and the input temporal as - * the second argument. + * passing {@code this} as the first argument and the converted input temporal + * as the second argument. *

* This instance is immutable and unaffected by this method call. * - * @param endDate the end date, which must be a {@code LocalDate}, not null + * @param endExclusive the end date, exclusive, which is converted to a {@code LocalDate}, not null * @param unit the unit to measure the amount in, not null * @return the amount of time between this date and the end date - * @throws DateTimeException if the amount cannot be calculated + * @throws DateTimeException if the amount cannot be calculated, or the end + * temporal cannot be converted to a {@code LocalDate} * @throws UnsupportedTemporalTypeException if the unit is not supported * @throws ArithmeticException if numeric overflow occurs */ @Override - public long until(Temporal endDate, TemporalUnit unit) { - Objects.requireNonNull(unit, "unit"); - if (endDate instanceof LocalDate == false) { - Objects.requireNonNull(endDate, "endDate"); - throw new DateTimeException("Unable to calculate amount as objects are of two different types"); - } - LocalDate end = (LocalDate) endDate; + public long until(Temporal endExclusive, TemporalUnit unit) { + LocalDate end = LocalDate.from(endExclusive); if (unit instanceof ChronoUnit) { switch ((ChronoUnit) unit) { case DAYS: return daysUntil(end); @@ -1600,7 +1598,7 @@ public final class LocalDate } throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } - return unit.between(this, endDate); + return unit.between(this, end); } long daysUntil(LocalDate end) { diff --git a/jdk/src/share/classes/java/time/LocalDateTime.java b/jdk/src/share/classes/java/time/LocalDateTime.java index d0b72b90f82..aed44dd4bfe 100644 --- a/jdk/src/share/classes/java/time/LocalDateTime.java +++ b/jdk/src/share/classes/java/time/LocalDateTime.java @@ -1129,11 +1129,11 @@ public final class LocalDateTime */ @Override public LocalDateTime plus(TemporalAmount amountToAdd) { - Objects.requireNonNull(amountToAdd, "amountToAdd"); if (amountToAdd instanceof Period) { Period periodToAdd = (Period) amountToAdd; return with(date.plus(periodToAdd), time); } + Objects.requireNonNull(amountToAdd, "amountToAdd"); return (LocalDateTime) amountToAdd.addTo(this); } @@ -1348,11 +1348,11 @@ public final class LocalDateTime */ @Override public LocalDateTime minus(TemporalAmount amountToSubtract) { - Objects.requireNonNull(amountToSubtract, "amountToSubtract"); if (amountToSubtract instanceof Period) { Period periodToSubtract = (Period) amountToSubtract; return with(date.minus(periodToSubtract), time); } + Objects.requireNonNull(amountToSubtract, "amountToSubtract"); return (LocalDateTime) amountToSubtract.subtractFrom(this); } @@ -1621,7 +1621,8 @@ public final class LocalDateTime * objects in terms of a single {@code TemporalUnit}. * The start and end points are {@code this} and the specified date-time. * The result will be negative if the end is before the start. - * The {@code Temporal} passed to this method must be a {@code LocalDateTime}. + * The {@code Temporal} passed to this method is converted to a + * {@code LocalDateTime} using {@link #from(TemporalAccessor)}. * For example, the amount in days between two date-times can be calculated * using {@code startDateTime.until(endDateTime, DAYS)}. *

@@ -1649,25 +1650,22 @@ public final class LocalDateTime *

* If the unit is not a {@code ChronoUnit}, then the result of this method * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} - * passing {@code this} as the first argument and the input temporal as - * the second argument. + * passing {@code this} as the first argument and the converted input temporal + * as the second argument. *

* This instance is immutable and unaffected by this method call. * - * @param endDateTime the end date-time, which must be a {@code LocalDateTime}, not null + * @param endExclusive the end date, exclusive, which is converted to a {@code LocalDateTime}, not null * @param unit the unit to measure the amount in, not null * @return the amount of time between this date-time and the end date-time - * @throws DateTimeException if the amount cannot be calculated + * @throws DateTimeException if the amount cannot be calculated, or the end + * temporal cannot be converted to a {@code LocalDateTime} * @throws UnsupportedTemporalTypeException if the unit is not supported * @throws ArithmeticException if numeric overflow occurs */ @Override - public long until(Temporal endDateTime, TemporalUnit unit) { - if (endDateTime instanceof LocalDateTime == false) { - Objects.requireNonNull(endDateTime, "endDateTime"); - throw new DateTimeException("Unable to calculate amount as objects are of two different types"); - } - LocalDateTime end = (LocalDateTime) endDateTime; + public long until(Temporal endExclusive, TemporalUnit unit) { + LocalDateTime end = LocalDateTime.from(endExclusive); if (unit instanceof ChronoUnit) { if (unit.isTimeBased()) { long amount = date.daysUntil(end.date); @@ -1721,7 +1719,7 @@ public final class LocalDateTime } return date.until(endDate, unit); } - return unit.between(this, endDateTime); + return unit.between(this, end); } /** diff --git a/jdk/src/share/classes/java/time/LocalTime.java b/jdk/src/share/classes/java/time/LocalTime.java index a6270db19cf..77ab2c7f286 100644 --- a/jdk/src/share/classes/java/time/LocalTime.java +++ b/jdk/src/share/classes/java/time/LocalTime.java @@ -394,6 +394,7 @@ public final class LocalTime * @throws DateTimeException if unable to convert to a {@code LocalTime} */ public static LocalTime from(TemporalAccessor temporal) { + Objects.requireNonNull(temporal, "temporal"); LocalTime time = temporal.query(TemporalQuery.localTime()); if (time == null) { throw new DateTimeException("Unable to obtain LocalTime from TemporalAccessor: " + temporal.getClass()); @@ -1330,7 +1331,8 @@ public final class LocalTime * objects in terms of a single {@code TemporalUnit}. * The start and end points are {@code this} and the specified time. * The result will be negative if the end is before the start. - * The {@code Temporal} passed to this method must be a {@code LocalTime}. + * The {@code Temporal} passed to this method is converted to a + * {@code LocalTime} using {@link #from(TemporalAccessor)}. * For example, the amount in hours between two times can be calculated * using {@code startTime.until(endTime, HOURS)}. *

@@ -1356,25 +1358,22 @@ public final class LocalTime *

* If the unit is not a {@code ChronoUnit}, then the result of this method * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} - * passing {@code this} as the first argument and the input temporal as - * the second argument. + * passing {@code this} as the first argument and the converted input temporal + * as the second argument. *

* This instance is immutable and unaffected by this method call. * - * @param endTime the end time, which must be a {@code LocalTime}, not null + * @param endExclusive the end time, exclusive, which is converted to a {@code LocalTime}, not null * @param unit the unit to measure the amount in, not null * @return the amount of time between this time and the end time - * @throws DateTimeException if the amount cannot be calculated + * @throws DateTimeException if the amount cannot be calculated, or the end + * temporal cannot be converted to a {@code LocalTime} * @throws UnsupportedTemporalTypeException if the unit is not supported * @throws ArithmeticException if numeric overflow occurs */ @Override - public long until(Temporal endTime, TemporalUnit unit) { - if (endTime instanceof LocalTime == false) { - Objects.requireNonNull(endTime, "endTime"); - throw new DateTimeException("Unable to calculate amount as objects are of two different types"); - } - LocalTime end = (LocalTime) endTime; + public long until(Temporal endExclusive, TemporalUnit unit) { + LocalTime end = LocalTime.from(endExclusive); if (unit instanceof ChronoUnit) { long nanosUntil = end.toNanoOfDay() - toNanoOfDay(); // no overflow switch ((ChronoUnit) unit) { @@ -1388,7 +1387,7 @@ public final class LocalTime } throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } - return unit.between(this, endTime); + return unit.between(this, end); } /** diff --git a/jdk/src/share/classes/java/time/MonthDay.java b/jdk/src/share/classes/java/time/MonthDay.java index 22807822f2b..67f5d4fa87f 100644 --- a/jdk/src/share/classes/java/time/MonthDay.java +++ b/jdk/src/share/classes/java/time/MonthDay.java @@ -246,7 +246,8 @@ public final class MonthDay *

* The conversion extracts the {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} and * {@link ChronoField#DAY_OF_MONTH DAY_OF_MONTH} fields. - * The extraction is only permitted if the date-time has an ISO chronology. + * The extraction is only permitted if the temporal object has an ISO + * chronology, or can be converted to a {@code LocalDate}. *

* This method matches the signature of the functional interface {@link TemporalQuery} * allowing it to be used in queries via method reference, {@code MonthDay::from}. diff --git a/jdk/src/share/classes/java/time/OffsetDateTime.java b/jdk/src/share/classes/java/time/OffsetDateTime.java index f894e53e46f..410c7f3a747 100644 --- a/jdk/src/share/classes/java/time/OffsetDateTime.java +++ b/jdk/src/share/classes/java/time/OffsetDateTime.java @@ -1592,7 +1592,8 @@ public final class OffsetDateTime * For example, the period in days between two date-times can be calculated * using {@code startDateTime.until(endDateTime, DAYS)}. *

- * The {@code Temporal} passed to this method must be an {@code OffsetDateTime}. + * The {@code Temporal} passed to this method is converted to a + * {@code OffsetDateTime} using {@link #from(TemporalAccessor)}. * If the offset differs between the two date-times, the specified * end date-time is normalized to have the same offset as this date-time. *

@@ -1620,30 +1621,27 @@ public final class OffsetDateTime *

* If the unit is not a {@code ChronoUnit}, then the result of this method * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} - * passing {@code this} as the first argument and the input temporal as - * the second argument. + * passing {@code this} as the first argument and the converted input temporal + * as the second argument. *

* This instance is immutable and unaffected by this method call. * - * @param endDateTime the end date-time, which must be an {@code OffsetDateTime}, not null + * @param endExclusive the end date, exclusive, which is converted to an {@code OffsetDateTime}, not null * @param unit the unit to measure the amount in, not null * @return the amount of time between this date-time and the end date-time - * @throws DateTimeException if the amount cannot be calculated + * @throws DateTimeException if the amount cannot be calculated, or the end + * temporal cannot be converted to an {@code OffsetDateTime} * @throws UnsupportedTemporalTypeException if the unit is not supported * @throws ArithmeticException if numeric overflow occurs */ @Override - public long until(Temporal endDateTime, TemporalUnit unit) { - if (endDateTime instanceof OffsetDateTime == false) { - Objects.requireNonNull(endDateTime, "endDateTime"); - throw new DateTimeException("Unable to calculate amount as objects are of two different types"); - } + public long until(Temporal endExclusive, TemporalUnit unit) { + OffsetDateTime end = OffsetDateTime.from(endExclusive); if (unit instanceof ChronoUnit) { - OffsetDateTime end = (OffsetDateTime) endDateTime; end = end.withOffsetSameInstant(offset); return dateTime.until(end.dateTime, unit); } - return unit.between(this, endDateTime); + return unit.between(this, end); } /** diff --git a/jdk/src/share/classes/java/time/OffsetTime.java b/jdk/src/share/classes/java/time/OffsetTime.java index 6c67ef82bb1..a8dbf8a7a56 100644 --- a/jdk/src/share/classes/java/time/OffsetTime.java +++ b/jdk/src/share/classes/java/time/OffsetTime.java @@ -1124,7 +1124,8 @@ public final class OffsetTime * For example, the period in hours between two times can be calculated * using {@code startTime.until(endTime, HOURS)}. *

- * The {@code Temporal} passed to this method must be an {@code OffsetTime}. + * The {@code Temporal} passed to this method is converted to a + * {@code OffsetTime} using {@link #from(TemporalAccessor)}. * If the offset differs between the two times, then the specified * end time is normalized to have the same offset as this time. *

@@ -1150,26 +1151,23 @@ public final class OffsetTime *

* If the unit is not a {@code ChronoUnit}, then the result of this method * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} - * passing {@code this} as the first argument and the input temporal as - * the second argument. + * passing {@code this} as the first argument and the converted input temporal + * as the second argument. *

* This instance is immutable and unaffected by this method call. * - * @param endTime the end time, which must be an {@code OffsetTime}, not null + * @param endExclusive the end date, exclusive, which is converted to an {@code OffsetTime}, not null * @param unit the unit to measure the amount in, not null * @return the amount of time between this time and the end time - * @throws DateTimeException if the amount cannot be calculated + * @throws DateTimeException if the amount cannot be calculated, or the end + * temporal cannot be converted to an {@code OffsetTime} * @throws UnsupportedTemporalTypeException if the unit is not supported * @throws ArithmeticException if numeric overflow occurs */ @Override - public long until(Temporal endTime, TemporalUnit unit) { - if (endTime instanceof OffsetTime == false) { - Objects.requireNonNull(endTime, "endTime"); - throw new DateTimeException("Unable to calculate amount as objects are of two different types"); - } + public long until(Temporal endExclusive, TemporalUnit unit) { + OffsetTime end = OffsetTime.from(endExclusive); if (unit instanceof ChronoUnit) { - OffsetTime end = (OffsetTime) endTime; long nanosUntil = end.toEpochNano() - toEpochNano(); // no overflow switch ((ChronoUnit) unit) { case NANOS: return nanosUntil; @@ -1182,7 +1180,7 @@ public final class OffsetTime } throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } - return unit.between(this, endTime); + return unit.between(this, end); } /** diff --git a/jdk/src/share/classes/java/time/Year.java b/jdk/src/share/classes/java/time/Year.java index f51bda69664..377dfd5185a 100644 --- a/jdk/src/share/classes/java/time/Year.java +++ b/jdk/src/share/classes/java/time/Year.java @@ -242,6 +242,7 @@ public final class Year if (temporal instanceof Year) { return (Year) temporal; } + Objects.requireNonNull(temporal, "temporal"); try { if (IsoChronology.INSTANCE.equals(Chronology.from(temporal)) == false) { temporal = LocalDate.from(temporal); @@ -859,7 +860,8 @@ public final class Year * objects in terms of a single {@code TemporalUnit}. * The start and end points are {@code this} and the specified year. * The result will be negative if the end is before the start. - * The {@code Temporal} passed to this method must be a {@code Year}. + * The {@code Temporal} passed to this method is converted to a + * {@code Year} using {@link #from(TemporalAccessor)}. * For example, the period in decades between two year can be calculated * using {@code startYear.until(endYear, DECADES)}. *

@@ -885,25 +887,22 @@ public final class Year *

* If the unit is not a {@code ChronoUnit}, then the result of this method * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} - * passing {@code this} as the first argument and the input temporal as - * the second argument. + * passing {@code this} as the first argument and the converted input temporal + * as the second argument. *

* This instance is immutable and unaffected by this method call. * - * @param endYear the end year, which must be a {@code Year}, not null + * @param endExclusive the end date, exclusive, which is converted to a {@code Year}, not null * @param unit the unit to measure the amount in, not null * @return the amount of time between this year and the end year - * @throws DateTimeException if the amount cannot be calculated + * @throws DateTimeException if the amount cannot be calculated, or the end + * temporal cannot be converted to a {@code Year} * @throws UnsupportedTemporalTypeException if the unit is not supported * @throws ArithmeticException if numeric overflow occurs */ @Override - public long until(Temporal endYear, TemporalUnit unit) { - if (endYear instanceof Year == false) { - Objects.requireNonNull(endYear, "endYear"); - throw new DateTimeException("Unable to calculate amount as objects are of two different types"); - } - Year end = (Year) endYear; + public long until(Temporal endExclusive, TemporalUnit unit) { + Year end = Year.from(endExclusive); if (unit instanceof ChronoUnit) { long yearsUntil = ((long) end.year) - year; // no overflow switch ((ChronoUnit) unit) { @@ -915,7 +914,7 @@ public final class Year } throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } - return unit.between(this, endYear); + return unit.between(this, end); } /** diff --git a/jdk/src/share/classes/java/time/YearMonth.java b/jdk/src/share/classes/java/time/YearMonth.java index 541676117eb..223c90ab0f0 100644 --- a/jdk/src/share/classes/java/time/YearMonth.java +++ b/jdk/src/share/classes/java/time/YearMonth.java @@ -245,6 +245,7 @@ public final class YearMonth if (temporal instanceof YearMonth) { return (YearMonth) temporal; } + Objects.requireNonNull(temporal, "temporal"); try { if (IsoChronology.INSTANCE.equals(Chronology.from(temporal)) == false) { temporal = LocalDate.from(temporal); @@ -992,7 +993,8 @@ public final class YearMonth * objects in terms of a single {@code TemporalUnit}. * The start and end points are {@code this} and the specified year-month. * The result will be negative if the end is before the start. - * The {@code Temporal} passed to this method must be a {@code YearMonth}. + * The {@code Temporal} passed to this method is converted to a + * {@code YearMonth} using {@link #from(TemporalAccessor)}. * For example, the period in years between two year-months can be calculated * using {@code startYearMonth.until(endYearMonth, YEARS)}. *

@@ -1018,25 +1020,22 @@ public final class YearMonth *

* If the unit is not a {@code ChronoUnit}, then the result of this method * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} - * passing {@code this} as the first argument and the input temporal as - * the second argument. + * passing {@code this} as the first argument and the converted input temporal + * as the second argument. *

* This instance is immutable and unaffected by this method call. * - * @param endYearMonth the end year-month, which must be a {@code YearMonth}, not null + * @param endExclusive the end date, exclusive, which is converted to a {@code YearMonth}, not null * @param unit the unit to measure the amount in, not null * @return the amount of time between this year-month and the end year-month - * @throws DateTimeException if the amount cannot be calculated + * @throws DateTimeException if the amount cannot be calculated, or the end + * temporal cannot be converted to a {@code YearMonth} * @throws UnsupportedTemporalTypeException if the unit is not supported * @throws ArithmeticException if numeric overflow occurs */ @Override - public long until(Temporal endYearMonth, TemporalUnit unit) { - if (endYearMonth instanceof YearMonth == false) { - Objects.requireNonNull(endYearMonth, "endYearMonth"); - throw new DateTimeException("Unable to calculate amount as objects are of two different types"); - } - YearMonth end = (YearMonth) endYearMonth; + public long until(Temporal endExclusive, TemporalUnit unit) { + YearMonth end = YearMonth.from(endExclusive); if (unit instanceof ChronoUnit) { long monthsUntil = end.getProlepticMonth() - getProlepticMonth(); // no overflow switch ((ChronoUnit) unit) { @@ -1049,7 +1048,7 @@ public final class YearMonth } throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } - return unit.between(this, endYearMonth); + return unit.between(this, end); } /** diff --git a/jdk/src/share/classes/java/time/ZoneOffset.java b/jdk/src/share/classes/java/time/ZoneOffset.java index 2d63a978d8c..3475e5f4db3 100644 --- a/jdk/src/share/classes/java/time/ZoneOffset.java +++ b/jdk/src/share/classes/java/time/ZoneOffset.java @@ -333,6 +333,7 @@ public final class ZoneOffset * @throws DateTimeException if unable to convert to an {@code ZoneOffset} */ public static ZoneOffset from(TemporalAccessor temporal) { + Objects.requireNonNull(temporal, "temporal"); ZoneOffset offset = temporal.query(TemporalQuery.offset()); if (offset == null) { throw new DateTimeException("Unable to obtain ZoneOffset from TemporalAccessor: " + temporal.getClass()); diff --git a/jdk/src/share/classes/java/time/ZonedDateTime.java b/jdk/src/share/classes/java/time/ZonedDateTime.java index 971ba6daf5b..1114ab4edd3 100644 --- a/jdk/src/share/classes/java/time/ZonedDateTime.java +++ b/jdk/src/share/classes/java/time/ZonedDateTime.java @@ -1540,11 +1540,11 @@ public final class ZonedDateTime */ @Override public ZonedDateTime plus(TemporalAmount amountToAdd) { - Objects.requireNonNull(amountToAdd, "amountToAdd"); if (amountToAdd instanceof Period) { Period periodToAdd = (Period) amountToAdd; return resolveLocal(dateTime.plus(periodToAdd)); } + Objects.requireNonNull(amountToAdd, "amountToAdd"); return (ZonedDateTime) amountToAdd.addTo(this); } @@ -1792,11 +1792,11 @@ public final class ZonedDateTime */ @Override public ZonedDateTime minus(TemporalAmount amountToSubtract) { - Objects.requireNonNull(amountToSubtract, "amountToSubtract"); if (amountToSubtract instanceof Period) { Period periodToSubtract = (Period) amountToSubtract; return resolveLocal(dateTime.minus(periodToSubtract)); } + Objects.requireNonNull(amountToSubtract, "amountToSubtract"); return (ZonedDateTime) amountToSubtract.subtractFrom(this); } @@ -2044,7 +2044,8 @@ public final class ZonedDateTime * For example, the period in days between two date-times can be calculated * using {@code startDateTime.until(endDateTime, DAYS)}. *

- * The {@code Temporal} passed to this method must be a {@code ZonedDateTime}. + * The {@code Temporal} passed to this method is converted to a + * {@code ZonedDateTime} using {@link #from(TemporalAccessor)}. * If the time-zone differs between the two zoned date-times, the specified * end date-time is normalized to have the same zone as this date-time. *

@@ -2086,26 +2087,23 @@ public final class ZonedDateTime *

* If the unit is not a {@code ChronoUnit}, then the result of this method * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} - * passing {@code this} as the first argument and the input temporal as - * the second argument. + * passing {@code this} as the first argument and the converted input temporal + * as the second argument. *

* This instance is immutable and unaffected by this method call. * - * @param endDateTime the end date-time, which must be a {@code ZonedDateTime}, not null + * @param endExclusive the end date, exclusive, which is converted to a {@code ZonedDateTime}, not null * @param unit the unit to measure the amount in, not null * @return the amount of time between this date-time and the end date-time - * @throws DateTimeException if the amount cannot be calculated + * @throws DateTimeException if the amount cannot be calculated, or the end + * temporal cannot be converted to a {@code ZonedDateTime} * @throws UnsupportedTemporalTypeException if the unit is not supported * @throws ArithmeticException if numeric overflow occurs */ @Override - public long until(Temporal endDateTime, TemporalUnit unit) { - if (endDateTime instanceof ZonedDateTime == false) { - Objects.requireNonNull(endDateTime, "endDateTime"); - throw new DateTimeException("Unable to calculate amount as objects are of two different types"); - } + public long until(Temporal endExclusive, TemporalUnit unit) { + ZonedDateTime end = ZonedDateTime.from(endExclusive); if (unit instanceof ChronoUnit) { - ZonedDateTime end = (ZonedDateTime) endDateTime; end = end.withZoneSameInstant(zone); if (unit.isDateBased()) { return dateTime.until(end.dateTime, unit); @@ -2113,7 +2111,7 @@ public final class ZonedDateTime return toOffsetDateTime().until(end.toOffsetDateTime(), unit); } } - return unit.between(this, endDateTime); + return unit.between(this, end); } /** diff --git a/jdk/src/share/classes/java/time/chrono/ChronoLocalDate.java b/jdk/src/share/classes/java/time/chrono/ChronoLocalDate.java index 58ae3b8c1c5..58e4f5d5250 100644 --- a/jdk/src/share/classes/java/time/chrono/ChronoLocalDate.java +++ b/jdk/src/share/classes/java/time/chrono/ChronoLocalDate.java @@ -291,6 +291,7 @@ public interface ChronoLocalDate if (temporal instanceof ChronoLocalDate) { return (ChronoLocalDate) temporal; } + Objects.requireNonNull(temporal, "temporal"); Chronology chrono = temporal.query(TemporalQuery.chronology()); if (chrono == null) { throw new DateTimeException("Unable to obtain ChronoLocalDate from TemporalAccessor: " + temporal.getClass()); @@ -560,8 +561,8 @@ public interface ChronoLocalDate * objects in terms of a single {@code TemporalUnit}. * The start and end points are {@code this} and the specified date. * The result will be negative if the end is before the start. - * The {@code Temporal} passed to this method must be a - * {@code ChronoLocalDate} in the same chronology. + * The {@code Temporal} passed to this method is converted to a + * {@code ChronoLocalDate} using {@link Chronology#date(TemporalAccessor)}. * The calculation returns a whole number, representing the number of * complete units between the two dates. * For example, the amount in days between two dates can be calculated @@ -585,20 +586,22 @@ public interface ChronoLocalDate *

* If the unit is not a {@code ChronoUnit}, then the result of this method * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} - * passing {@code this} as the first argument and the input temporal as + * passing {@code this} as the first argument and the converted input temporal as * the second argument. *

* This instance is immutable and unaffected by this method call. * - * @param endDate the end date, which must be a {@code ChronoLocalDate} - * in the same chronology, not null + * @param endExclusive the end date, exclusive, which is converted to a + * {@code ChronoLocalDate} in the same chronology, not null * @param unit the unit to measure the amount in, not null * @return the amount of time between this date and the end date - * @throws DateTimeException if the amount cannot be calculated + * @throws DateTimeException if the amount cannot be calculated, or the end + * temporal cannot be converted to a {@code ChronoLocalDate} + * @throws UnsupportedTemporalTypeException if the unit is not supported * @throws ArithmeticException if numeric overflow occurs */ @Override // override for Javadoc - long until(Temporal endDate, TemporalUnit unit); + long until(Temporal endExclusive, TemporalUnit unit); /** * Calculates the period between this date and another date as a {@code ChronoPeriod}. diff --git a/jdk/src/share/classes/java/time/chrono/ChronoLocalDateImpl.java b/jdk/src/share/classes/java/time/chrono/ChronoLocalDateImpl.java index fd8c8f88662..6cb115d393e 100644 --- a/jdk/src/share/classes/java/time/chrono/ChronoLocalDateImpl.java +++ b/jdk/src/share/classes/java/time/chrono/ChronoLocalDateImpl.java @@ -372,22 +372,10 @@ abstract class ChronoLocalDateImpl } //----------------------------------------------------------------------- - /** - * {@inheritDoc} - * @throws DateTimeException {@inheritDoc} - * @throws ArithmeticException {@inheritDoc} - */ @Override - public long until(Temporal endDateTime, TemporalUnit unit) { - Objects.requireNonNull(endDateTime, "endDateTime"); - Objects.requireNonNull(unit, "unit"); - if (endDateTime instanceof ChronoLocalDate == false) { - throw new DateTimeException("Unable to calculate amount as objects are of two different types"); - } - ChronoLocalDate end = (ChronoLocalDate) endDateTime; - if (getChronology().equals(end.getChronology()) == false) { - throw new DateTimeException("Unable to calculate amount as objects have different chronologies"); - } + public long until(Temporal endExclusive, TemporalUnit unit) { + Objects.requireNonNull(endExclusive, "endExclusive"); + ChronoLocalDate end = getChronology().date(endExclusive); if (unit instanceof ChronoUnit) { switch ((ChronoUnit) unit) { case DAYS: return daysUntil(end); @@ -401,7 +389,8 @@ abstract class ChronoLocalDateImpl } throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } - return unit.between(this, endDateTime); + Objects.requireNonNull(unit, "unit"); + return unit.between(this, end); } private long daysUntil(ChronoLocalDate end) { diff --git a/jdk/src/share/classes/java/time/chrono/ChronoLocalDateTime.java b/jdk/src/share/classes/java/time/chrono/ChronoLocalDateTime.java index be93f0e036a..cde8a982fbc 100644 --- a/jdk/src/share/classes/java/time/chrono/ChronoLocalDateTime.java +++ b/jdk/src/share/classes/java/time/chrono/ChronoLocalDateTime.java @@ -165,6 +165,7 @@ public interface ChronoLocalDateTime if (temporal instanceof ChronoLocalDateTime) { return (ChronoLocalDateTime) temporal; } + Objects.requireNonNull(temporal, "temporal"); Chronology chrono = temporal.query(TemporalQuery.chronology()); if (chrono == null) { throw new DateTimeException("Unable to obtain ChronoLocalDateTime from TemporalAccessor: " + temporal.getClass()); diff --git a/jdk/src/share/classes/java/time/chrono/ChronoLocalDateTimeImpl.java b/jdk/src/share/classes/java/time/chrono/ChronoLocalDateTimeImpl.java index 13b3a0e8817..817ae85411a 100644 --- a/jdk/src/share/classes/java/time/chrono/ChronoLocalDateTimeImpl.java +++ b/jdk/src/share/classes/java/time/chrono/ChronoLocalDateTimeImpl.java @@ -69,7 +69,6 @@ import java.io.ObjectInput; import java.io.ObjectOutput; import java.io.ObjectStreamException; import java.io.Serializable; -import java.time.DateTimeException; import java.time.LocalTime; import java.time.ZoneId; import java.time.temporal.ChronoField; @@ -369,15 +368,10 @@ final class ChronoLocalDateTimeImpl //----------------------------------------------------------------------- @Override - public long until(Temporal endDateTime, TemporalUnit unit) { - if (endDateTime instanceof ChronoLocalDateTime == false) { - throw new DateTimeException("Unable to calculate amount as objects are of two different types"); - } + public long until(Temporal endExclusive, TemporalUnit unit) { + Objects.requireNonNull(endExclusive, "endExclusive"); @SuppressWarnings("unchecked") - ChronoLocalDateTime end = (ChronoLocalDateTime) endDateTime; - if (toLocalDate().getChronology().equals(end.toLocalDate().getChronology()) == false) { - throw new DateTimeException("Unable to calculate amount as objects have different chronologies"); - } + ChronoLocalDateTime end = (ChronoLocalDateTime) toLocalDate().getChronology().localDateTime(endExclusive); if (unit instanceof ChronoUnit) { if (unit.isTimeBased()) { long amount = end.getLong(EPOCH_DAY) - date.getLong(EPOCH_DAY); @@ -398,7 +392,8 @@ final class ChronoLocalDateTimeImpl } return date.until(endDate, unit); } - return unit.between(this, endDateTime); + Objects.requireNonNull(unit, "unit"); + return unit.between(this, end); } //----------------------------------------------------------------------- diff --git a/jdk/src/share/classes/java/time/chrono/ChronoZonedDateTime.java b/jdk/src/share/classes/java/time/chrono/ChronoZonedDateTime.java index dd911fcd789..abe84799716 100644 --- a/jdk/src/share/classes/java/time/chrono/ChronoZonedDateTime.java +++ b/jdk/src/share/classes/java/time/chrono/ChronoZonedDateTime.java @@ -166,6 +166,7 @@ public interface ChronoZonedDateTime if (temporal instanceof ChronoZonedDateTime) { return (ChronoZonedDateTime) temporal; } + Objects.requireNonNull(temporal, "temporal"); Chronology chrono = temporal.query(TemporalQuery.chronology()); if (chrono == null) { throw new DateTimeException("Unable to obtain ChronoZonedDateTime from TemporalAccessor: " + temporal.getClass()); diff --git a/jdk/src/share/classes/java/time/chrono/ChronoZonedDateTimeImpl.java b/jdk/src/share/classes/java/time/chrono/ChronoZonedDateTimeImpl.java index 1cc7b5b5786..1fe8ccf0192 100644 --- a/jdk/src/share/classes/java/time/chrono/ChronoZonedDateTimeImpl.java +++ b/jdk/src/share/classes/java/time/chrono/ChronoZonedDateTimeImpl.java @@ -69,7 +69,6 @@ import java.io.ObjectInput; import java.io.ObjectOutput; import java.io.ObjectStreamException; import java.io.Serializable; -import java.time.DateTimeException; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; @@ -234,7 +233,7 @@ final class ChronoZonedDateTimeImpl if (trans != null && trans.isOverlap()) { ZoneOffset earlierOffset = trans.getOffsetBefore(); if (earlierOffset.equals(offset) == false) { - return new ChronoZonedDateTimeImpl(dateTime, earlierOffset, zone); + return new ChronoZonedDateTimeImpl<>(dateTime, earlierOffset, zone); } } return this; @@ -246,7 +245,7 @@ final class ChronoZonedDateTimeImpl if (trans != null) { ZoneOffset offset = trans.getOffsetAfter(); if (offset.equals(getOffset()) == false) { - return new ChronoZonedDateTimeImpl(dateTime, offset, zone); + return new ChronoZonedDateTimeImpl<>(dateTime, offset, zone); } } return this; @@ -308,20 +307,16 @@ final class ChronoZonedDateTimeImpl //----------------------------------------------------------------------- @Override - public long until(Temporal endDateTime, TemporalUnit unit) { - if (endDateTime instanceof ChronoZonedDateTime == false) { - throw new DateTimeException("Unable to calculate amount as objects are of two different types"); - } + public long until(Temporal endExclusive, TemporalUnit unit) { + Objects.requireNonNull(endExclusive, "endExclusive"); @SuppressWarnings("unchecked") - ChronoZonedDateTime end = (ChronoZonedDateTime) endDateTime; - if (toLocalDate().getChronology().equals(end.toLocalDate().getChronology()) == false) { - throw new DateTimeException("Unable to calculate amount as objects have different chronologies"); - } + ChronoZonedDateTime end = (ChronoZonedDateTime) toLocalDate().getChronology().zonedDateTime(endExclusive); if (unit instanceof ChronoUnit) { end = end.withZoneSameInstant(offset); return dateTime.until(end.toLocalDateTime(), unit); } - return unit.between(this, endDateTime); + Objects.requireNonNull(unit, "unit"); + return unit.between(this, end); } //----------------------------------------------------------------------- diff --git a/jdk/src/share/classes/java/time/temporal/ChronoUnit.java b/jdk/src/share/classes/java/time/temporal/ChronoUnit.java index 19a37e46f4c..c7043272398 100644 --- a/jdk/src/share/classes/java/time/temporal/ChronoUnit.java +++ b/jdk/src/share/classes/java/time/temporal/ChronoUnit.java @@ -268,8 +268,8 @@ public enum ChronoUnit implements TemporalUnit { //----------------------------------------------------------------------- @Override - public long between(Temporal temporal1, Temporal temporal2) { - return temporal1.until(temporal2, this); + public long between(Temporal temporal1Inclusive, Temporal temporal2Exclusive) { + return temporal1Inclusive.until(temporal2Exclusive, this); } //----------------------------------------------------------------------- diff --git a/jdk/src/share/classes/java/time/temporal/IsoFields.java b/jdk/src/share/classes/java/time/temporal/IsoFields.java index eae057afb2a..bb19c299875 100644 --- a/jdk/src/share/classes/java/time/temporal/IsoFields.java +++ b/jdk/src/share/classes/java/time/temporal/IsoFields.java @@ -684,13 +684,16 @@ public final class IsoFields { } @Override - public long between(Temporal temporal1, Temporal temporal2) { + public long between(Temporal temporal1Inclusive, Temporal temporal2Exclusive) { + if (temporal1Inclusive.getClass() != temporal2Exclusive.getClass()) { + return temporal1Inclusive.until(temporal2Exclusive, this); + } switch(this) { case WEEK_BASED_YEARS: - return Math.subtractExact(temporal2.getLong(WEEK_BASED_YEAR), - temporal1.getLong(WEEK_BASED_YEAR)); + return Math.subtractExact(temporal2Exclusive.getLong(WEEK_BASED_YEAR), + temporal1Inclusive.getLong(WEEK_BASED_YEAR)); case QUARTER_YEARS: - return temporal1.until(temporal2, MONTHS) / 3; + return temporal1Inclusive.until(temporal2Exclusive, MONTHS) / 3; default: throw new IllegalStateException("Unreachable"); } diff --git a/jdk/src/share/classes/java/time/temporal/Temporal.java b/jdk/src/share/classes/java/time/temporal/Temporal.java index 54110bed771..9931c46f4f1 100644 --- a/jdk/src/share/classes/java/time/temporal/Temporal.java +++ b/jdk/src/share/classes/java/time/temporal/Temporal.java @@ -374,8 +374,9 @@ public interface Temporal extends TemporalAccessor { * Calculates the amount of time until another temporal in terms of the specified unit. *

* This calculates the amount of time between two temporal objects - * of the same type in terms of a single {@code TemporalUnit}. + * in terms of a single {@code TemporalUnit}. * The start and end points are {@code this} and the specified temporal. + * The end point is converted to be of the same type as the start point if different. * The result will be negative if the end is before the start. * For example, the period in hours between two temporal objects can be * calculated using {@code startTime.until(endTime, HOURS)}. @@ -412,31 +413,36 @@ public interface Temporal extends TemporalAccessor { *

* If the unit is not a {@code ChronoUnit}, then the result of this method * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} - * passing {@code this} as the first argument and the input temporal as + * passing {@code this} as the first argument and the converted input temporal as * the second argument. *

- * In summary, implementations must behave in a manner equivalent to this code: + * In summary, implementations must behave in a manner equivalent to this pseudo-code: *

-     *  // check input temporal is the same type as this class
+     *  // convert the end temporal to the same type as this class
      *  if (unit instanceof ChronoUnit) {
      *    // if unit is supported, then calculate and return result
      *    // else throw UnsupportedTemporalTypeException for unsupported units
      *  }
-     *  return unit.between(this, endTemporal);
+     *  return unit.between(this, convertedEndTemporal);
      * 
*

+ * Note that the unit's {@code between} method must only be invoked if the + * two temporal objects have exactly the same type evaluated by {@code getClass()}. + *

* Implementations must ensure that no observable state is altered when this * read-only method is invoked. * - * @param endTemporal the end temporal, of the same type as this object, not null + * @param endExclusive the end temporal, exclusive, converted to be of the + * same type as this object, not null * @param unit the unit to measure the amount in, not null * @return the amount of time between this temporal object and the specified one * in terms of the unit; positive if the specified object is later than this one, * negative if it is earlier than this one - * @throws DateTimeException if the amount cannot be calculated + * @throws DateTimeException if the amount cannot be calculated, or the end + * temporal cannot be converted to the same type as this temporal * @throws UnsupportedTemporalTypeException if the unit is not supported * @throws ArithmeticException if numeric overflow occurs */ - long until(Temporal endTemporal, TemporalUnit unit); + long until(Temporal endExclusive, TemporalUnit unit); } diff --git a/jdk/src/share/classes/java/time/temporal/TemporalUnit.java b/jdk/src/share/classes/java/time/temporal/TemporalUnit.java index 05577d713f8..1c41afa0593 100644 --- a/jdk/src/share/classes/java/time/temporal/TemporalUnit.java +++ b/jdk/src/share/classes/java/time/temporal/TemporalUnit.java @@ -231,7 +231,9 @@ public interface TemporalUnit { * Calculates the amount of time between two temporal objects. *

* This calculates the amount in terms of this unit. The start and end - * points are supplied as temporal objects and must be of the same type. + * points are supplied as temporal objects and must be of compatible types. + * The implementation will convert the second type to be an instance of the + * first type before the calculating the amount. * The result will be negative if the end is before the start. * For example, the amount in hours between two temporal objects can be * calculated using {@code HOURS.between(startTime, endTime)}. @@ -264,15 +266,22 @@ public interface TemporalUnit { * If the unit is not supported an {@code UnsupportedTemporalTypeException} must be thrown. * Implementations must not alter the specified temporal objects. * - * @param temporal1 the base temporal object, not null - * @param temporal2 the other temporal object, not null - * @return the amount of time between temporal1 and temporal2 in terms of this unit; - * positive if temporal2 is later than temporal1, negative if earlier - * @throws DateTimeException if the amount cannot be calculated + * @implSpec + * Implementations must begin by checking to if the two temporals have the + * same type using {@code getClass()}. If they do not, then the result must be + * obtained by calling {@code temporal1Inclusive.until(temporal2Exclusive, this)}. + * + * @param temporal1Inclusive the base temporal object, not null + * @param temporal2Exclusive the other temporal object, exclusive, not null + * @return the amount of time between temporal1Inclusive and temporal2Exclusive + * in terms of this unit; positive if temporal2Exclusive is later than + * temporal1Inclusive, negative if earlier + * @throws DateTimeException if the amount cannot be calculated, or the end + * temporal cannot be converted to the same type as the start temporal * @throws UnsupportedTemporalTypeException if the unit is not supported by the temporal * @throws ArithmeticException if numeric overflow occurs */ - long between(Temporal temporal1, Temporal temporal2); + long between(Temporal temporal1Inclusive, Temporal temporal2Exclusive); //----------------------------------------------------------------------- /** diff --git a/jdk/test/java/time/tck/java/time/TCKDuration.java b/jdk/test/java/time/tck/java/time/TCKDuration.java index c3bb0c9c906..c12e914b91f 100644 --- a/jdk/test/java/time/tck/java/time/TCKDuration.java +++ b/jdk/test/java/time/tck/java/time/TCKDuration.java @@ -77,6 +77,7 @@ import java.io.DataOutputStream; import java.time.DateTimeException; import java.time.Duration; import java.time.Instant; +import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.Period; @@ -843,10 +844,17 @@ public class TCKDuration extends AbstractTCKTest { assertEquals(Duration.between(end, start), Duration.between(start, end).negated()); } - @Test(expectedExceptions=DateTimeException.class) + @Test public void factory_between_TemporalTemporal_mixedTypes() { Instant start = Instant.ofEpochSecond(1); ZonedDateTime end = Instant.ofEpochSecond(4).atZone(ZoneOffset.UTC); + assertEquals(Duration.between(start, end), Duration.ofSeconds(3)); + } + + @Test(expectedExceptions=DateTimeException.class) + public void factory_between_TemporalTemporal_invalidMixedTypes() { + Instant start = Instant.ofEpochSecond(1); + LocalDate end = LocalDate.of(2010, 6, 20); Duration.between(start, end); } diff --git a/jdk/test/java/time/tck/java/time/TCKInstant.java b/jdk/test/java/time/tck/java/time/TCKInstant.java index bb3a765de42..bf6ac9e7026 100644 --- a/jdk/test/java/time/tck/java/time/TCKInstant.java +++ b/jdk/test/java/time/tck/java/time/TCKInstant.java @@ -84,6 +84,7 @@ import java.time.DateTimeException; import java.time.Duration; import java.time.Instant; import java.time.LocalDateTime; +import java.time.LocalTime; import java.time.OffsetDateTime; import java.time.ZoneId; import java.time.ZoneOffset; @@ -1800,7 +1801,7 @@ public class TCKInstant extends AbstractDateTimeTest { } @Test(dataProvider="periodUntilUnit") - public void test_periodUntil_TemporalUnit(long seconds1, int nanos1, long seconds2, long nanos2, TemporalUnit unit, long expected) { + public void test_until_TemporalUnit(long seconds1, int nanos1, long seconds2, long nanos2, TemporalUnit unit, long expected) { Instant i1 = Instant.ofEpochSecond(seconds1, nanos1); Instant i2 = Instant.ofEpochSecond(seconds2, nanos2); long amount = i1.until(i2, unit); @@ -1808,25 +1809,46 @@ public class TCKInstant extends AbstractDateTimeTest { } @Test(dataProvider="periodUntilUnit") - public void test_periodUntil_TemporalUnit_negated(long seconds1, int nanos1, long seconds2, long nanos2, TemporalUnit unit, long expected) { + public void test_until_TemporalUnit_negated(long seconds1, int nanos1, long seconds2, long nanos2, TemporalUnit unit, long expected) { Instant i1 = Instant.ofEpochSecond(seconds1, nanos1); Instant i2 = Instant.ofEpochSecond(seconds2, nanos2); long amount = i2.until(i1, unit); assertEquals(amount, -expected); } + @Test(dataProvider="periodUntilUnit") + public void test_until_TemporalUnit_between(long seconds1, int nanos1, long seconds2, long nanos2, TemporalUnit unit, long expected) { + Instant i1 = Instant.ofEpochSecond(seconds1, nanos1); + Instant i2 = Instant.ofEpochSecond(seconds2, nanos2); + long amount = unit.between(i1, i2); + assertEquals(amount, expected); + } + + @Test + public void test_until_convertedType() { + Instant start = Instant.ofEpochSecond(12, 3000); + OffsetDateTime end = start.plusSeconds(2).atOffset(ZoneOffset.ofHours(2)); + assertEquals(start.until(end, SECONDS), 2); + } + + @Test(expectedExceptions=DateTimeException.class) + public void test_until_invalidType() { + Instant start = Instant.ofEpochSecond(12, 3000); + start.until(LocalTime.of(11, 30), SECONDS); + } + @Test(expectedExceptions = UnsupportedTemporalTypeException.class) - public void test_periodUntil_TemporalUnit_unsupportedUnit() { + public void test_until_TemporalUnit_unsupportedUnit() { TEST_12345_123456789.until(TEST_12345_123456789, MONTHS); } @Test(expectedExceptions = NullPointerException.class) - public void test_periodUntil_TemporalUnit_nullEnd() { + public void test_until_TemporalUnit_nullEnd() { TEST_12345_123456789.until(null, HOURS); } @Test(expectedExceptions = NullPointerException.class) - public void test_periodUntil_TemporalUnit_nullUnit() { + public void test_until_TemporalUnit_nullUnit() { TEST_12345_123456789.until(TEST_12345_123456789, null); } diff --git a/jdk/test/java/time/tck/java/time/TCKLocalDate.java b/jdk/test/java/time/tck/java/time/TCKLocalDate.java index 3d4cbbbc884..cb41a707945 100644 --- a/jdk/test/java/time/tck/java/time/TCKLocalDate.java +++ b/jdk/test/java/time/tck/java/time/TCKLocalDate.java @@ -1723,29 +1723,48 @@ public class TCKLocalDate extends AbstractDateTimeTest { } @Test(dataProvider="periodUntilUnit") - public void test_periodUntil_TemporalUnit(LocalDate date1, LocalDate date2, TemporalUnit unit, long expected) { + public void test_until_TemporalUnit(LocalDate date1, LocalDate date2, TemporalUnit unit, long expected) { long amount = date1.until(date2, unit); assertEquals(amount, expected); } @Test(dataProvider="periodUntilUnit") - public void test_periodUntil_TemporalUnit_negated(LocalDate date1, LocalDate date2, TemporalUnit unit, long expected) { + public void test_until_TemporalUnit_negated(LocalDate date1, LocalDate date2, TemporalUnit unit, long expected) { long amount = date2.until(date1, unit); assertEquals(amount, -expected); } + @Test(dataProvider="periodUntilUnit") + public void test_until_TemporalUnit_between(LocalDate date1, LocalDate date2, TemporalUnit unit, long expected) { + long amount = unit.between(date1, date2); + assertEquals(amount, expected); + } + + @Test + public void test_until_convertedType() { + LocalDate start = LocalDate.of(2010, 6, 30); + OffsetDateTime end = start.plusDays(2).atStartOfDay().atOffset(OFFSET_PONE); + assertEquals(start.until(end, DAYS), 2); + } + + @Test(expectedExceptions=DateTimeException.class) + public void test_until_invalidType() { + LocalDate start = LocalDate.of(2010, 6, 30); + start.until(LocalTime.of(11, 30), DAYS); + } + @Test(expectedExceptions = UnsupportedTemporalTypeException.class) - public void test_periodUntil_TemporalUnit_unsupportedUnit() { + public void test_until_TemporalUnit_unsupportedUnit() { TEST_2007_07_15.until(TEST_2007_07_15, HOURS); } @Test(expectedExceptions = NullPointerException.class) - public void test_periodUntil_TemporalUnit_nullEnd() { + public void test_until_TemporalUnit_nullEnd() { TEST_2007_07_15.until(null, DAYS); } @Test(expectedExceptions = NullPointerException.class) - public void test_periodUntil_TemporalUnit_nullUnit() { + public void test_until_TemporalUnit_nullUnit() { TEST_2007_07_15.until(TEST_2007_07_15, null); } diff --git a/jdk/test/java/time/tck/java/time/TCKLocalDateTime.java b/jdk/test/java/time/tck/java/time/TCKLocalDateTime.java index 040704cd9bc..62b53b3b8a3 100644 --- a/jdk/test/java/time/tck/java/time/TCKLocalDateTime.java +++ b/jdk/test/java/time/tck/java/time/TCKLocalDateTime.java @@ -2895,24 +2895,43 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { } @Test(dataProvider="periodUntilUnit") - public void test_periodUntil_TemporalUnit(LocalDateTime dt1, LocalDateTime dt2, TemporalUnit unit, long expected) { + public void test_until_TemporalUnit(LocalDateTime dt1, LocalDateTime dt2, TemporalUnit unit, long expected) { long amount = dt1.until(dt2, unit); assertEquals(amount, expected); } @Test(dataProvider="periodUntilUnit") - public void test_periodUntil_TemporalUnit_negated(LocalDateTime dt1, LocalDateTime dt2, TemporalUnit unit, long expected) { + public void test_until_TemporalUnit_negated(LocalDateTime dt1, LocalDateTime dt2, TemporalUnit unit, long expected) { long amount = dt2.until(dt1, unit); assertEquals(amount, -expected); } + @Test(dataProvider="periodUntilUnit") + public void test_until_TemporalUnit_between(LocalDateTime dt1, LocalDateTime dt2, TemporalUnit unit, long expected) { + long amount = unit.between(dt1, dt2); + assertEquals(amount, expected); + } + + @Test + public void test_until_convertedType() { + LocalDateTime start = LocalDateTime.of(2010, 6, 30, 2, 30); + OffsetDateTime end = start.plusDays(2).atOffset(OFFSET_PONE); + assertEquals(start.until(end, DAYS), 2); + } + + @Test(expectedExceptions=DateTimeException.class) + public void test_until_invalidType() { + LocalDateTime start = LocalDateTime.of(2010, 6, 30, 2, 30); + start.until(LocalTime.of(11, 30), DAYS); + } + @Test(expectedExceptions = NullPointerException.class) - public void test_periodUntil_TemporalUnit_nullEnd() { + public void test_until_TemporalUnit_nullEnd() { TEST_2007_07_15_12_30_40_987654321.until(null, HOURS); } @Test(expectedExceptions = NullPointerException.class) - public void test_periodUntil_TemporalUnit_nullUnit() { + public void test_until_TemporalUnit_nullUnit() { TEST_2007_07_15_12_30_40_987654321.until(TEST_2007_07_15_12_30_40_987654321, null); } diff --git a/jdk/test/java/time/tck/java/time/TCKLocalTime.java b/jdk/test/java/time/tck/java/time/TCKLocalTime.java index 2291b5ca16b..bac3f8587d1 100644 --- a/jdk/test/java/time/tck/java/time/TCKLocalTime.java +++ b/jdk/test/java/time/tck/java/time/TCKLocalTime.java @@ -1971,29 +1971,48 @@ public class TCKLocalTime extends AbstractDateTimeTest { } @Test(dataProvider="periodUntilUnit") - public void test_periodUntil_TemporalUnit(LocalTime time1, LocalTime time2, TemporalUnit unit, long expected) { + public void test_until_TemporalUnit(LocalTime time1, LocalTime time2, TemporalUnit unit, long expected) { long amount = time1.until(time2, unit); assertEquals(amount, expected); } @Test(dataProvider="periodUntilUnit") - public void test_periodUntil_TemporalUnit_negated(LocalTime time1, LocalTime time2, TemporalUnit unit, long expected) { + public void test_until_TemporalUnit_negated(LocalTime time1, LocalTime time2, TemporalUnit unit, long expected) { long amount = time2.until(time1, unit); assertEquals(amount, -expected); } + @Test(dataProvider="periodUntilUnit") + public void test_until_TemporalUnit_between(LocalTime time1, LocalTime time2, TemporalUnit unit, long expected) { + long amount = unit.between(time1, time2); + assertEquals(amount, expected); + } + + @Test + public void test_until_convertedType() { + LocalTime start = LocalTime.of(11, 30); + LocalDateTime end = start.plusSeconds(2).atDate(LocalDate.of(2010, 6, 30)); + assertEquals(start.until(end, SECONDS), 2); + } + + @Test(expectedExceptions=DateTimeException.class) + public void test_until_invalidType() { + LocalTime start = LocalTime.of(11, 30); + start.until(LocalDate.of(2010, 6, 30), SECONDS); + } + @Test(expectedExceptions = UnsupportedTemporalTypeException.class) - public void test_periodUntil_TemporalUnit_unsupportedUnit() { + public void test_until_TemporalUnit_unsupportedUnit() { TEST_12_30_40_987654321.until(TEST_12_30_40_987654321, DAYS); } @Test(expectedExceptions = NullPointerException.class) - public void test_periodUntil_TemporalUnit_nullEnd() { + public void test_until_TemporalUnit_nullEnd() { TEST_12_30_40_987654321.until(null, HOURS); } @Test(expectedExceptions = NullPointerException.class) - public void test_periodUntil_TemporalUnit_nullUnit() { + public void test_until_TemporalUnit_nullUnit() { TEST_12_30_40_987654321.until(TEST_12_30_40_987654321, null); } diff --git a/jdk/test/java/time/tck/java/time/TCKOffsetDateTime.java b/jdk/test/java/time/tck/java/time/TCKOffsetDateTime.java index 0cf024fdde1..0ced814d06b 100644 --- a/jdk/test/java/time/tck/java/time/TCKOffsetDateTime.java +++ b/jdk/test/java/time/tck/java/time/TCKOffsetDateTime.java @@ -91,6 +91,13 @@ import static java.time.temporal.ChronoField.SECOND_OF_MINUTE; import static java.time.temporal.ChronoField.YEAR; import static java.time.temporal.ChronoField.YEAR_OF_ERA; import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.FOREVER; +import static java.time.temporal.ChronoUnit.HALF_DAYS; +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 org.testng.Assert.assertEquals; @@ -1128,6 +1135,74 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { assertEquals(test, OffsetDateTime.of(2008, 6, 30, 11, 30, 58, 999999999, OFFSET_PONE)); } + //----------------------------------------------------------------------- + // until(Temporal, TemporalUnit) + //----------------------------------------------------------------------- + @DataProvider(name="periodUntilUnit") + Object[][] data_untilUnit() { + return new Object[][] { + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 6, 30, 13, 1, 1, 0, OFFSET_PONE), HALF_DAYS, 1}, + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 6, 30, 2, 1, 1, 0, OFFSET_PONE), HOURS, 1}, + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 6, 30, 2, 1, 1, 0, OFFSET_PONE), MINUTES, 60}, + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 6, 30, 2, 1, 1, 0, OFFSET_PONE), SECONDS, 3600}, + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 6, 30, 2, 1, 1, 0, OFFSET_PONE), MILLIS, 3600*1000}, + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 6, 30, 2, 1, 1, 0, OFFSET_PONE), MICROS, 3600*1000*1000L}, + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 6, 30, 2, 1, 1, 0, OFFSET_PONE), NANOS, 3600*1000*1000L*1000}, + + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 6, 30, 14, 1, 1, 0, OFFSET_PTWO), HALF_DAYS, 1}, + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 6, 30, 3, 1, 1, 0, OFFSET_PTWO), HOURS, 1}, + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 6, 30, 3, 1, 1, 0, OFFSET_PTWO), MINUTES, 60}, + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 6, 30, 3, 1, 1, 0, OFFSET_PTWO), SECONDS, 3600}, + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 6, 30, 3, 1, 1, 0, OFFSET_PTWO), MILLIS, 3600*1000}, + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 6, 30, 3, 1, 1, 0, OFFSET_PTWO), MICROS, 3600*1000*1000L}, + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 6, 30, 3, 1, 1, 0, OFFSET_PTWO), NANOS, 3600*1000*1000L*1000}, + + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 7, 1, 1, 1, 0, 999999999, OFFSET_PONE), DAYS, 0}, + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 7, 1, 1, 1, 1, 0, OFFSET_PONE), DAYS, 1}, + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 8, 29, 1, 1, 1, 0, OFFSET_PONE), MONTHS, 1}, + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 8, 30, 1, 1, 1, 0, OFFSET_PONE), MONTHS, 2}, + {OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE), OffsetDateTime.of(2010, 8, 31, 1, 1, 1, 0, OFFSET_PONE), MONTHS, 2}, + }; + } + + @Test(dataProvider="periodUntilUnit") + public void test_until_TemporalUnit(OffsetDateTime odt1, OffsetDateTime odt2, TemporalUnit unit, long expected) { + long amount = odt1.until(odt2, unit); + assertEquals(amount, expected); + } + + @Test(dataProvider="periodUntilUnit") + public void test_until_TemporalUnit_negated(OffsetDateTime odt1, OffsetDateTime odt2, TemporalUnit unit, long expected) { + long amount = odt2.until(odt1, unit); + assertEquals(amount, -expected); + } + + @Test(dataProvider="periodUntilUnit") + public void test_until_TemporalUnit_between(OffsetDateTime odt1, OffsetDateTime odt2, TemporalUnit unit, long expected) { + long amount = unit.between(odt1, odt2); + assertEquals(amount, expected); + } + + @Test + public void test_until_convertedType() { + OffsetDateTime odt = OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE); + ZonedDateTime zdt = odt.plusSeconds(3).toZonedDateTime(); + assertEquals(odt.until(zdt, SECONDS), 3); + } + + @Test(expectedExceptions=DateTimeException.class) + public void test_until_invalidType() { + OffsetDateTime odt = OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE); + odt.until(Instant.ofEpochSecond(12), SECONDS); + } + + @Test(expectedExceptions=DateTimeException.class) + public void test_until_invalidTemporalUnit() { + OffsetDateTime odt1 = OffsetDateTime.of(2010, 6, 30, 1, 1, 1, 0, OFFSET_PONE); + OffsetDateTime odt2 = OffsetDateTime.of(2010, 6, 30, 2, 1, 1, 0, OFFSET_PONE); + odt1.until(odt2, FOREVER); + } + //----------------------------------------------------------------------- // format(DateTimeFormatter) //----------------------------------------------------------------------- diff --git a/jdk/test/java/time/tck/java/time/TCKOffsetTime.java b/jdk/test/java/time/tck/java/time/TCKOffsetTime.java index ee5b2d3f69f..5bc2312ea0f 100644 --- a/jdk/test/java/time/tck/java/time/TCKOffsetTime.java +++ b/jdk/test/java/time/tck/java/time/TCKOffsetTime.java @@ -1069,49 +1069,61 @@ public class TCKOffsetTime extends AbstractDateTimeTest { // until(Temporal, TemporalUnit) //----------------------------------------------------------------------- @DataProvider(name="periodUntilUnit") - Object[][] data_periodUntilUnit() { + Object[][] data_untilUnit() { return new Object[][] { - {OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(13, 1, 1), ZoneOffset.ofHours(1)), HALF_DAYS, 1}, - {OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(2, 1, 1), ZoneOffset.ofHours(1)), HOURS, 1}, - {OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(2, 1, 1), ZoneOffset.ofHours(1)), MINUTES, 60}, - {OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(2, 1, 1), ZoneOffset.ofHours(1)), SECONDS, 3600}, - {OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(2, 1, 1), ZoneOffset.ofHours(1)), MILLIS, 3600*1000}, - {OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(2, 1, 1), ZoneOffset.ofHours(1)), MICROS, 3600*1000*1000L}, - {OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(2, 1, 1), ZoneOffset.ofHours(1)), NANOS, 3600*1000*1000L*1000}, + {OffsetTime.of(1, 1, 1, 0, OFFSET_PONE), OffsetTime.of(13, 1, 1, 0, OFFSET_PONE), HALF_DAYS, 1}, + {OffsetTime.of(1, 1, 1, 0, OFFSET_PONE), OffsetTime.of(2, 1, 1, 0, OFFSET_PONE), HOURS, 1}, + {OffsetTime.of(1, 1, 1, 0, OFFSET_PONE), OffsetTime.of(2, 1, 1, 0, OFFSET_PONE), MINUTES, 60}, + {OffsetTime.of(1, 1, 1, 0, OFFSET_PONE), OffsetTime.of(2, 1, 1, 0, OFFSET_PONE), SECONDS, 3600}, + {OffsetTime.of(1, 1, 1, 0, OFFSET_PONE), OffsetTime.of(2, 1, 1, 0, OFFSET_PONE), MILLIS, 3600*1000}, + {OffsetTime.of(1, 1, 1, 0, OFFSET_PONE), OffsetTime.of(2, 1, 1, 0, OFFSET_PONE), MICROS, 3600*1000*1000L}, + {OffsetTime.of(1, 1, 1, 0, OFFSET_PONE), OffsetTime.of(2, 1, 1, 0, OFFSET_PONE), NANOS, 3600*1000*1000L*1000}, - {OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(14, 1, 1), ZoneOffset.ofHours(2)), HALF_DAYS, 1}, - {OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(3, 1, 1), ZoneOffset.ofHours(2)), HOURS, 1}, - {OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(3, 1, 1), ZoneOffset.ofHours(2)), MINUTES, 60}, - {OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(3, 1, 1), ZoneOffset.ofHours(2)), SECONDS, 3600}, - {OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(3, 1, 1), ZoneOffset.ofHours(2)), MILLIS, 3600*1000}, - {OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(3, 1, 1), ZoneOffset.ofHours(2)), MICROS, 3600*1000*1000L}, - {OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(3, 1, 1), ZoneOffset.ofHours(2)), NANOS, 3600*1000*1000L*1000}, + {OffsetTime.of(1, 1, 1, 0, OFFSET_PONE), OffsetTime.of(14, 1, 1, 0, OFFSET_PTWO), HALF_DAYS, 1}, + {OffsetTime.of(1, 1, 1, 0, OFFSET_PONE), OffsetTime.of(3, 1, 1, 0, OFFSET_PTWO), HOURS, 1}, + {OffsetTime.of(1, 1, 1, 0, OFFSET_PONE), OffsetTime.of(3, 1, 1, 0, OFFSET_PTWO), MINUTES, 60}, + {OffsetTime.of(1, 1, 1, 0, OFFSET_PONE), OffsetTime.of(3, 1, 1, 0, OFFSET_PTWO), SECONDS, 3600}, + {OffsetTime.of(1, 1, 1, 0, OFFSET_PONE), OffsetTime.of(3, 1, 1, 0, OFFSET_PTWO), MILLIS, 3600*1000}, + {OffsetTime.of(1, 1, 1, 0, OFFSET_PONE), OffsetTime.of(3, 1, 1, 0, OFFSET_PTWO), MICROS, 3600*1000*1000L}, + {OffsetTime.of(1, 1, 1, 0, OFFSET_PONE), OffsetTime.of(3, 1, 1, 0, OFFSET_PTWO), NANOS, 3600*1000*1000L*1000}, }; } @Test(dataProvider="periodUntilUnit") - public void test_periodUntil_TemporalUnit(OffsetTime offsetTime1, OffsetTime offsetTime2, TemporalUnit unit, long expected) { + public void test_until_TemporalUnit(OffsetTime offsetTime1, OffsetTime offsetTime2, TemporalUnit unit, long expected) { long amount = offsetTime1.until(offsetTime2, unit); assertEquals(amount, expected); } @Test(dataProvider="periodUntilUnit") - public void test_periodUntil_TemporalUnit_negated(OffsetTime offsetTime1, OffsetTime offsetTime2, TemporalUnit unit, long expected) { + public void test_until_TemporalUnit_negated(OffsetTime offsetTime1, OffsetTime offsetTime2, TemporalUnit unit, long expected) { long amount = offsetTime2.until(offsetTime1, unit); assertEquals(amount, -expected); } - @Test(expectedExceptions=DateTimeException.class) - public void test_periodUntil_InvalidType() { - OffsetTime offsetTime = OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)); - OffsetDateTime offsetDateTime = offsetTime.atDate(LocalDate.of(1980, 2, 10)); - offsetTime.until(offsetDateTime, SECONDS); + @Test(dataProvider="periodUntilUnit") + public void test_until_TemporalUnit_between(OffsetTime offsetTime1, OffsetTime offsetTime2, TemporalUnit unit, long expected) { + long amount = unit.between(offsetTime1, offsetTime2); + assertEquals(amount, expected); + } + + @Test + public void test_until_convertedType() { + OffsetTime offsetTime = OffsetTime.of(1, 1, 1, 0, OFFSET_PONE); + OffsetDateTime offsetDateTime = offsetTime.plusSeconds(3).atDate(LocalDate.of(1980, 2, 10)); + assertEquals(offsetTime.until(offsetDateTime, SECONDS), 3); } @Test(expectedExceptions=DateTimeException.class) - public void test_periodUntil_InvalidTemporalUnit() { - OffsetTime offsetTime1 = OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)); - OffsetTime offsetTime2 = OffsetTime.of(LocalTime.of(2, 1, 1), ZoneOffset.ofHours(1)); + public void test_until_invalidType() { + OffsetTime offsetTime = OffsetTime.of(1, 1, 1, 0, OFFSET_PONE); + offsetTime.until(LocalDate.of(1980, 2, 10), SECONDS); + } + + @Test(expectedExceptions=DateTimeException.class) + public void test_until_invalidTemporalUnit() { + OffsetTime offsetTime1 = OffsetTime.of(1, 1, 1, 0, OFFSET_PONE); + OffsetTime offsetTime2 = OffsetTime.of(2, 1, 1, 0, OFFSET_PONE); offsetTime1.until(offsetTime2, MONTHS); } diff --git a/jdk/test/java/time/tck/java/time/TCKYear.java b/jdk/test/java/time/tck/java/time/TCKYear.java index c0a35967a7b..59d464a5373 100644 --- a/jdk/test/java/time/tck/java/time/TCKYear.java +++ b/jdk/test/java/time/tck/java/time/TCKYear.java @@ -65,10 +65,8 @@ import static java.time.temporal.ChronoField.YEAR_OF_ERA; import static java.time.temporal.ChronoUnit.CENTURIES; import static java.time.temporal.ChronoUnit.DAYS; import static java.time.temporal.ChronoUnit.DECADES; -import static java.time.temporal.ChronoUnit.HOURS; import static java.time.temporal.ChronoUnit.MILLENNIA; import static java.time.temporal.ChronoUnit.MONTHS; -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; @@ -90,8 +88,8 @@ import java.time.Year; import java.time.YearMonth; import java.time.ZoneId; import java.time.ZoneOffset; -import java.time.chrono.IsoEra; import java.time.chrono.IsoChronology; +import java.time.chrono.IsoEra; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; import java.time.temporal.ChronoField; @@ -229,17 +227,17 @@ public class TCKYear extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test - public void test_factory_CalendricalObject() { + public void test_from_TemporalAccessor() { assertEquals(Year.from(LocalDate.of(2007, 7, 15)), Year.of(2007)); } @Test(expectedExceptions=DateTimeException.class) - public void test_factory_CalendricalObject_invalid_noDerive() { + public void test_from_TemporalAccessor_invalid_noDerive() { Year.from(LocalTime.of(12, 30)); } @Test(expectedExceptions=NullPointerException.class) - public void test_factory_CalendricalObject_null() { + public void test_from_TemporalAccessor_null() { Year.from((TemporalAccessor) null); } @@ -597,13 +595,13 @@ public class TCKYear extends AbstractDateTimeTest { }; } - @Test(groups={"tck"}, dataProvider="plus_long_TemporalUnit") + @Test(dataProvider="plus_long_TemporalUnit") public void test_plus_long_TemporalUnit(Year base, long amount, TemporalUnit unit, Year expectedYear, Class expectedEx) { if (expectedEx == null) { assertEquals(base.plus(amount, unit), expectedYear); } else { try { - Year result = base.plus(amount, unit); + base.plus(amount, unit); fail(); } catch (Exception ex) { assertTrue(expectedEx.isInstance(ex)); @@ -729,7 +727,7 @@ public class TCKYear extends AbstractDateTimeTest { }; } - @Test(groups={"tck"}, dataProvider="minus_long_TemporalUnit") + @Test(dataProvider="minus_long_TemporalUnit") public void test_minus_long_TemporalUnit(Year base, long amount, TemporalUnit unit, Year expectedYear, Class expectedEx) { if (expectedEx == null) { assertEquals(base.minus(amount, unit), expectedYear); @@ -788,7 +786,7 @@ public class TCKYear extends AbstractDateTimeTest { //----------------------------------------------------------------------- // with(TemporalField, long) //----------------------------------------------------------------------- - @Test(groups={"tck"}) + @Test public void test_with() { Year base = Year.of(5); Year result = base.with(ChronoField.ERA, 0); @@ -923,29 +921,48 @@ public class TCKYear extends AbstractDateTimeTest { } @Test(dataProvider="periodUntilUnit") - public void test_periodUntil_TemporalUnit(Year year1, Year year2, TemporalUnit unit, long expected) { + public void test_until_TemporalUnit(Year year1, Year year2, TemporalUnit unit, long expected) { long amount = year1.until(year2, unit); assertEquals(amount, expected); } @Test(dataProvider="periodUntilUnit") - public void test_periodUntil_TemporalUnit_negated(Year year1, Year year2, TemporalUnit unit, long expected) { + public void test_until_TemporalUnit_negated(Year year1, Year year2, TemporalUnit unit, long expected) { long amount = year2.until(year1, unit); assertEquals(amount, -expected); } + @Test(dataProvider="periodUntilUnit") + public void test_until_TemporalUnit_between(Year year1, Year year2, TemporalUnit unit, long expected) { + long amount = unit.between(year1, year2); + assertEquals(amount, expected); + } + + @Test + public void test_until_convertedType() { + Year start = Year.of(2010); + YearMonth end = start.plusYears(2).atMonth(Month.APRIL); + assertEquals(start.until(end, YEARS), 2); + } + + @Test(expectedExceptions=DateTimeException.class) + public void test_until_invalidType() { + Year start = Year.of(2010); + start.until(LocalTime.of(11, 30), YEARS); + } + @Test(expectedExceptions = UnsupportedTemporalTypeException.class) - public void test_periodUntil_TemporalUnit_unsupportedUnit() { + public void test_until_TemporalUnit_unsupportedUnit() { TEST_2008.until(TEST_2008, MONTHS); } @Test(expectedExceptions = NullPointerException.class) - public void test_periodUntil_TemporalUnit_nullEnd() { + public void test_until_TemporalUnit_nullEnd() { TEST_2008.until(null, DAYS); } @Test(expectedExceptions = NullPointerException.class) - public void test_periodUntil_TemporalUnit_nullUnit() { + public void test_until_TemporalUnit_nullUnit() { TEST_2008.until(TEST_2008, null); } diff --git a/jdk/test/java/time/tck/java/time/TCKYearMonth.java b/jdk/test/java/time/tck/java/time/TCKYearMonth.java index e1f1a466574..bb16839bda1 100644 --- a/jdk/test/java/time/tck/java/time/TCKYearMonth.java +++ b/jdk/test/java/time/tck/java/time/TCKYearMonth.java @@ -70,7 +70,6 @@ import static java.time.temporal.ChronoUnit.DECADES; import static java.time.temporal.ChronoUnit.HOURS; import static java.time.temporal.ChronoUnit.MILLENNIA; import static java.time.temporal.ChronoUnit.MONTHS; -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; @@ -270,17 +269,17 @@ public class TCKYearMonth extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test - public void test_factory_CalendricalObject() { + public void test_from_TemporalAccessor() { assertEquals(YearMonth.from(LocalDate.of(2007, 7, 15)), YearMonth.of(2007, 7)); } @Test(expectedExceptions=DateTimeException.class) - public void test_factory_CalendricalObject_invalid_noDerive() { + public void test_from_TemporalAccessor_invalid_noDerive() { YearMonth.from(LocalTime.of(12, 30)); } @Test(expectedExceptions=NullPointerException.class) - public void test_factory_CalendricalObject_null() { + public void test_from_TemporalAccessor_null() { YearMonth.from((TemporalAccessor) null); } @@ -768,7 +767,7 @@ public class TCKYearMonth extends AbstractDateTimeTest { }; } - @Test(groups={"tck"}, dataProvider="plus_long_TemporalUnit") + @Test(dataProvider="plus_long_TemporalUnit") public void test_plus_long_TemporalUnit(YearMonth base, long amount, TemporalUnit unit, YearMonth expectedYearMonth, Class expectedEx) { if (expectedEx == null) { assertEquals(base.plus(amount, unit), expectedYearMonth); @@ -820,7 +819,7 @@ public class TCKYearMonth extends AbstractDateTimeTest { }; } - @Test(groups={"tck"}, dataProvider="plus_TemporalAmount") + @Test(dataProvider="plus_TemporalAmount") public void test_plus_TemporalAmount(YearMonth base, TemporalAmount temporalAmount, YearMonth expectedYearMonth, Class expectedEx) { if (expectedEx == null) { assertEquals(base.plus(temporalAmount), expectedYearMonth); @@ -983,7 +982,7 @@ public class TCKYearMonth extends AbstractDateTimeTest { }; } - @Test(groups={"tck"}, dataProvider="minus_long_TemporalUnit") + @Test(dataProvider="minus_long_TemporalUnit") public void test_minus_long_TemporalUnit(YearMonth base, long amount, TemporalUnit unit, YearMonth expectedYearMonth, Class expectedEx) { if (expectedEx == null) { assertEquals(base.minus(amount, unit), expectedYearMonth); @@ -1035,7 +1034,7 @@ public class TCKYearMonth extends AbstractDateTimeTest { }; } - @Test(groups={"tck"}, dataProvider="minus_TemporalAmount") + @Test(dataProvider="minus_TemporalAmount") public void test_minus_TemporalAmount(YearMonth base, TemporalAmount temporalAmount, YearMonth expectedYearMonth, Class expectedEx) { if (expectedEx == null) { assertEquals(base.minus(temporalAmount), expectedYearMonth); @@ -1243,29 +1242,48 @@ public class TCKYearMonth extends AbstractDateTimeTest { } @Test(dataProvider="periodUntilUnit") - public void test_periodUntil_TemporalUnit(YearMonth ym1, YearMonth ym2, TemporalUnit unit, long expected) { + public void test_until_TemporalUnit(YearMonth ym1, YearMonth ym2, TemporalUnit unit, long expected) { long amount = ym1.until(ym2, unit); assertEquals(amount, expected); } @Test(dataProvider="periodUntilUnit") - public void test_periodUntil_TemporalUnit_negated(YearMonth ym1, YearMonth ym2, TemporalUnit unit, long expected) { + public void test_until_TemporalUnit_negated(YearMonth ym1, YearMonth ym2, TemporalUnit unit, long expected) { long amount = ym2.until(ym1, unit); assertEquals(amount, -expected); } + @Test(dataProvider="periodUntilUnit") + public void test_until_TemporalUnit_between(YearMonth ym1, YearMonth ym2, TemporalUnit unit, long expected) { + long amount = unit.between(ym1, ym2); + assertEquals(amount, expected); + } + + @Test + public void test_until_convertedType() { + YearMonth start = YearMonth.of(2010, 6); + LocalDate end = start.plusMonths(2).atDay(12); + assertEquals(start.until(end, MONTHS), 2); + } + + @Test(expectedExceptions=DateTimeException.class) + public void test_until_invalidType() { + YearMonth start = YearMonth.of(2010, 6); + start.until(LocalTime.of(11, 30), MONTHS); + } + @Test(expectedExceptions = UnsupportedTemporalTypeException.class) - public void test_periodUntil_TemporalUnit_unsupportedUnit() { + public void test_until_TemporalUnit_unsupportedUnit() { TEST_2008_06.until(TEST_2008_06, HOURS); } @Test(expectedExceptions = NullPointerException.class) - public void test_periodUntil_TemporalUnit_nullEnd() { + public void test_until_TemporalUnit_nullEnd() { TEST_2008_06.until(null, DAYS); } @Test(expectedExceptions = NullPointerException.class) - public void test_periodUntil_TemporalUnit_nullUnit() { + public void test_until_TemporalUnit_nullUnit() { TEST_2008_06.until(TEST_2008_06, null); } diff --git a/jdk/test/java/time/tck/java/time/TCKZonedDateTime.java b/jdk/test/java/time/tck/java/time/TCKZonedDateTime.java index 1f5bee32283..4c5319d483a 100644 --- a/jdk/test/java/time/tck/java/time/TCKZonedDateTime.java +++ b/jdk/test/java/time/tck/java/time/TCKZonedDateTime.java @@ -2001,7 +2001,7 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { // compare results to OffsetDateTime.until, especially wrt dates @Test(dataProvider="plusDays") - public void test_periodUntil_days(ZonedDateTime base, long expected, ZonedDateTime end) { + public void test_until_days(ZonedDateTime base, long expected, ZonedDateTime end) { if (base.toLocalTime().equals(end.toLocalTime()) == false) { return; // avoid DST gap input values } @@ -2009,27 +2009,27 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { } @Test(dataProvider="plusTime") - public void test_periodUntil_hours(ZonedDateTime base, long expected, ZonedDateTime end) { + public void test_until_hours(ZonedDateTime base, long expected, ZonedDateTime end) { assertEquals(base.until(end, HOURS), expected); } @Test(dataProvider="plusTime") - public void test_periodUntil_minutes(ZonedDateTime base, long expected, ZonedDateTime end) { + public void test_until_minutes(ZonedDateTime base, long expected, ZonedDateTime end) { assertEquals(base.until(end, MINUTES), expected * 60); } @Test(dataProvider="plusTime") - public void test_periodUntil_seconds(ZonedDateTime base, long expected, ZonedDateTime end) { + public void test_until_seconds(ZonedDateTime base, long expected, ZonedDateTime end) { assertEquals(base.until(end, SECONDS), expected * 3600); } @Test(dataProvider="plusTime") - public void test_periodUntil_nanos(ZonedDateTime base, long expected, ZonedDateTime end) { + public void test_until_nanos(ZonedDateTime base, long expected, ZonedDateTime end) { assertEquals(base.until(end, NANOS), expected * 3600_000_000_000L); } @Test - public void test_periodUntil_parisLondon() { + public void test_until_parisLondon() { ZonedDateTime midnightLondon = LocalDate.of(2012, 6, 28).atStartOfDay(ZONE_LONDON); ZonedDateTime midnightParis1 = LocalDate.of(2012, 6, 29).atStartOfDay(ZONE_PARIS); ZonedDateTime oneAm1 = LocalDateTime.of(2012, 6, 29, 1, 0).atZone(ZONE_PARIS); @@ -2045,7 +2045,7 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { } @Test - public void test_periodUntil_gap() { + public void test_until_gap() { ZonedDateTime before = TEST_PARIS_GAP_2008_03_30_02_30.withHour(0).withMinute(0).atZone(ZONE_PARIS); ZonedDateTime after = TEST_PARIS_GAP_2008_03_30_02_30.withHour(0).withMinute(0).plusDays(1).atZone(ZONE_PARIS); @@ -2054,7 +2054,7 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { } @Test - public void test_periodUntil_overlap() { + public void test_until_overlap() { ZonedDateTime before = TEST_PARIS_OVERLAP_2008_10_26_02_30.withHour(0).withMinute(0).atZone(ZONE_PARIS); ZonedDateTime after = TEST_PARIS_OVERLAP_2008_10_26_02_30.withHour(0).withMinute(0).plusDays(1).atZone(ZONE_PARIS); @@ -2063,17 +2063,17 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { } @Test(expectedExceptions=DateTimeException.class) - public void test_periodUntil_differentType() { + public void test_until_differentType() { TEST_DATE_TIME_PARIS.until(TEST_LOCAL_2008_06_30_11_30_59_500, DAYS); } @Test(expectedExceptions=NullPointerException.class) - public void test_periodUntil_nullTemporal() { + public void test_until_nullTemporal() { TEST_DATE_TIME_PARIS.until(null, DAYS); } @Test(expectedExceptions=NullPointerException.class) - public void test_periodUntil_nullUnit() { + public void test_until_nullUnit() { TEST_DATE_TIME_PARIS.until(TEST_DATE_TIME_PARIS, null); } diff --git a/jdk/test/java/time/tck/java/time/chrono/CopticDate.java b/jdk/test/java/time/tck/java/time/chrono/CopticDate.java index 6377c1fc421..c0da6975623 100644 --- a/jdk/test/java/time/tck/java/time/chrono/CopticDate.java +++ b/jdk/test/java/time/tck/java/time/chrono/CopticDate.java @@ -297,18 +297,12 @@ public final class CopticDate } @Override - public long until(Temporal endDateTime, TemporalUnit unit) { - if (endDateTime instanceof ChronoLocalDate == false) { - throw new DateTimeException("Unable to calculate period between objects of two different types"); - } - ChronoLocalDate end = (ChronoLocalDate) endDateTime; - if (getChronology().equals(end.getChronology()) == false) { - throw new DateTimeException("Unable to calculate period between two different chronologies"); - } + public long until(Temporal endExclusive, TemporalUnit unit) { + CopticDate end = getChronology().date(endExclusive); if (unit instanceof ChronoUnit) { return LocalDate.from(this).until(end, unit); // TODO: this is wrong } - return unit.between(this, endDateTime); + return unit.between(this, end); } @Override diff --git a/jdk/test/java/time/tck/java/time/temporal/TCKIsoFields.java b/jdk/test/java/time/tck/java/time/temporal/TCKIsoFields.java index 7159b312866..d607571aba1 100644 --- a/jdk/test/java/time/tck/java/time/temporal/TCKIsoFields.java +++ b/jdk/test/java/time/tck/java/time/temporal/TCKIsoFields.java @@ -70,11 +70,13 @@ import static org.testng.Assert.fail; import java.time.DayOfWeek; import java.time.LocalDate; +import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.format.DateTimeParseException; import java.time.format.ResolverStyle; import java.time.temporal.IsoFields; +import java.time.temporal.Temporal; import java.time.temporal.ValueRange; import org.testng.annotations.DataProvider; @@ -276,14 +278,21 @@ public class TCKIsoFields { {LocalDate.of(2000, 1, 1), LocalDate.of(1998, 12, 31), -4}, {LocalDate.of(2000, 1, 1), LocalDate.of(1998, 10, 2), -4}, {LocalDate.of(2000, 1, 1), LocalDate.of(1998, 10, 1), -5}, + + {LocalDate.of(2000, 1, 1), LocalDateTime.of(2001, 4, 5, 0, 0), 5}, }; } @Test(dataProvider="quartersBetween") - public void test_quarters_between(LocalDate start, LocalDate end, long expected) { + public void test_quarters_between(LocalDate start, Temporal end, long expected) { assertEquals(IsoFields.QUARTER_YEARS.between(start, end), expected); } + @Test(dataProvider="quartersBetween") + public void test_quarters_between_until(LocalDate start, Temporal end, long expected) { + assertEquals(start.until(end, IsoFields.QUARTER_YEARS), expected); + } + //----------------------------------------------------------------------- //----------------------------------------------------------------------- //-----------------------------------------------------------------------