8024835: Change until() to accept any compatible temporal
authorrriggs
Sat, 14 Sep 2013 22:46:49 +0100
changeset 20520 0952771e3e25
parent 20519 eee7a92074fd
child 20521 0a672997e442
8024835: Change until() to accept any compatible temporal Summary: Method until(Temporal,TemporalUnit) now uses from() to convert; Enhance from() methods where necessary Reviewed-by: sherman Contributed-by: scolebourne@joda.org
jdk/src/share/classes/java/time/Duration.java
jdk/src/share/classes/java/time/Instant.java
jdk/src/share/classes/java/time/LocalDate.java
jdk/src/share/classes/java/time/LocalDateTime.java
jdk/src/share/classes/java/time/LocalTime.java
jdk/src/share/classes/java/time/MonthDay.java
jdk/src/share/classes/java/time/OffsetDateTime.java
jdk/src/share/classes/java/time/OffsetTime.java
jdk/src/share/classes/java/time/Year.java
jdk/src/share/classes/java/time/YearMonth.java
jdk/src/share/classes/java/time/ZoneOffset.java
jdk/src/share/classes/java/time/ZonedDateTime.java
jdk/src/share/classes/java/time/chrono/ChronoLocalDate.java
jdk/src/share/classes/java/time/chrono/ChronoLocalDateImpl.java
jdk/src/share/classes/java/time/chrono/ChronoLocalDateTime.java
jdk/src/share/classes/java/time/chrono/ChronoLocalDateTimeImpl.java
jdk/src/share/classes/java/time/chrono/ChronoZonedDateTime.java
jdk/src/share/classes/java/time/chrono/ChronoZonedDateTimeImpl.java
jdk/src/share/classes/java/time/temporal/ChronoUnit.java
jdk/src/share/classes/java/time/temporal/IsoFields.java
jdk/src/share/classes/java/time/temporal/Temporal.java
jdk/src/share/classes/java/time/temporal/TemporalUnit.java
jdk/test/java/time/tck/java/time/TCKDuration.java
jdk/test/java/time/tck/java/time/TCKInstant.java
jdk/test/java/time/tck/java/time/TCKLocalDate.java
jdk/test/java/time/tck/java/time/TCKLocalDateTime.java
jdk/test/java/time/tck/java/time/TCKLocalTime.java
jdk/test/java/time/tck/java/time/TCKOffsetDateTime.java
jdk/test/java/time/tck/java/time/TCKOffsetTime.java
jdk/test/java/time/tck/java/time/TCKYear.java
jdk/test/java/time/tck/java/time/TCKYearMonth.java
jdk/test/java/time/tck/java/time/TCKZonedDateTime.java
jdk/test/java/time/tck/java/time/chrono/CopticDate.java
jdk/test/java/time/tck/java/time/temporal/TCKIsoFields.java
--- a/jdk/src/share/classes/java/time/Duration.java	Wed Sep 04 15:18:54 2013 +0100
+++ b/jdk/src/share/classes/java/time/Duration.java	Sat Sep 14 22:46:49 2013 +0100
@@ -441,9 +441,13 @@
 
     //-----------------------------------------------------------------------
     /**
-     * Obtains a {@code Duration} representing the duration between two instants.
+     * Obtains a {@code Duration} representing the duration between two temporal objects.
      * <p>
-     * This calculates the duration between two temporal objects of the same type.
+     * 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}.
+     * <p>
      * 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.
--- a/jdk/src/share/classes/java/time/Instant.java	Wed Sep 04 15:18:54 2013 +0100
+++ b/jdk/src/share/classes/java/time/Instant.java	Sat Sep 14 22:46:49 2013 +0100
@@ -362,6 +362,10 @@
      * @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 @@
      * 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)}.
      * <p>
@@ -1112,25 +1117,22 @@
      * <p>
      * 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.
      * <p>
      * 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 @@
             }
             throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
         }
-        return unit.between(this, endInstant);
+        return unit.between(this, end);
     }
 
     private long nanosUntil(Instant end) {
--- a/jdk/src/share/classes/java/time/LocalDate.java	Wed Sep 04 15:18:54 2013 +0100
+++ b/jdk/src/share/classes/java/time/LocalDate.java	Sat Sep 14 22:46:49 2013 +0100
@@ -353,6 +353,7 @@
      * @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 @@
      */
     @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 @@
      */
     @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 @@
      * 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)}.
      * <p>
@@ -1567,26 +1569,22 @@
      * <p>
      * 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.
      * <p>
      * 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 @@
             }
             throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
         }
-        return unit.between(this, endDate);
+        return unit.between(this, end);
     }
 
     long daysUntil(LocalDate end) {
--- a/jdk/src/share/classes/java/time/LocalDateTime.java	Wed Sep 04 15:18:54 2013 +0100
+++ b/jdk/src/share/classes/java/time/LocalDateTime.java	Sat Sep 14 22:46:49 2013 +0100
@@ -1129,11 +1129,11 @@
      */
     @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 @@
      */
     @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 @@
      * 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)}.
      * <p>
@@ -1649,25 +1650,22 @@
      * <p>
      * 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.
      * <p>
      * 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 @@
             }
             return date.until(endDate, unit);
         }
-        return unit.between(this, endDateTime);
+        return unit.between(this, end);
     }
 
     /**
--- a/jdk/src/share/classes/java/time/LocalTime.java	Wed Sep 04 15:18:54 2013 +0100
+++ b/jdk/src/share/classes/java/time/LocalTime.java	Sat Sep 14 22:46:49 2013 +0100
@@ -394,6 +394,7 @@
      * @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 @@
      * 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)}.
      * <p>
@@ -1356,25 +1358,22 @@
      * <p>
      * 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.
      * <p>
      * 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 @@
             }
             throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
         }
-        return unit.between(this, endTime);
+        return unit.between(this, end);
     }
 
     /**
--- a/jdk/src/share/classes/java/time/MonthDay.java	Wed Sep 04 15:18:54 2013 +0100
+++ b/jdk/src/share/classes/java/time/MonthDay.java	Sat Sep 14 22:46:49 2013 +0100
@@ -246,7 +246,8 @@
      * <p>
      * 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}.
      * <p>
      * This method matches the signature of the functional interface {@link TemporalQuery}
      * allowing it to be used in queries via method reference, {@code MonthDay::from}.
--- a/jdk/src/share/classes/java/time/OffsetDateTime.java	Wed Sep 04 15:18:54 2013 +0100
+++ b/jdk/src/share/classes/java/time/OffsetDateTime.java	Sat Sep 14 22:46:49 2013 +0100
@@ -1592,7 +1592,8 @@
      * For example, the period in days between two date-times can be calculated
      * using {@code startDateTime.until(endDateTime, DAYS)}.
      * <p>
-     * 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.
      * <p>
@@ -1620,30 +1621,27 @@
      * <p>
      * 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.
      * <p>
      * 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);
     }
 
     /**
--- a/jdk/src/share/classes/java/time/OffsetTime.java	Wed Sep 04 15:18:54 2013 +0100
+++ b/jdk/src/share/classes/java/time/OffsetTime.java	Sat Sep 14 22:46:49 2013 +0100
@@ -1124,7 +1124,8 @@
      * For example, the period in hours between two times can be calculated
      * using {@code startTime.until(endTime, HOURS)}.
      * <p>
-     * 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.
      * <p>
@@ -1150,26 +1151,23 @@
      * <p>
      * 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.
      * <p>
      * 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 @@
             }
             throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
         }
-        return unit.between(this, endTime);
+        return unit.between(this, end);
     }
 
     /**
--- a/jdk/src/share/classes/java/time/Year.java	Wed Sep 04 15:18:54 2013 +0100
+++ b/jdk/src/share/classes/java/time/Year.java	Sat Sep 14 22:46:49 2013 +0100
@@ -242,6 +242,7 @@
         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 @@
      * 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)}.
      * <p>
@@ -885,25 +887,22 @@
      * <p>
      * 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.
      * <p>
      * 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 @@
             }
             throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
         }
-        return unit.between(this, endYear);
+        return unit.between(this, end);
     }
 
     /**
--- a/jdk/src/share/classes/java/time/YearMonth.java	Wed Sep 04 15:18:54 2013 +0100
+++ b/jdk/src/share/classes/java/time/YearMonth.java	Sat Sep 14 22:46:49 2013 +0100
@@ -245,6 +245,7 @@
         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 @@
      * 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)}.
      * <p>
@@ -1018,25 +1020,22 @@
      * <p>
      * 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.
      * <p>
      * 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 @@
             }
             throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
         }
-        return unit.between(this, endYearMonth);
+        return unit.between(this, end);
     }
 
     /**
--- a/jdk/src/share/classes/java/time/ZoneOffset.java	Wed Sep 04 15:18:54 2013 +0100
+++ b/jdk/src/share/classes/java/time/ZoneOffset.java	Sat Sep 14 22:46:49 2013 +0100
@@ -333,6 +333,7 @@
      * @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());
--- a/jdk/src/share/classes/java/time/ZonedDateTime.java	Wed Sep 04 15:18:54 2013 +0100
+++ b/jdk/src/share/classes/java/time/ZonedDateTime.java	Sat Sep 14 22:46:49 2013 +0100
@@ -1540,11 +1540,11 @@
      */
     @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 @@
      */
     @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 @@
      * For example, the period in days between two date-times can be calculated
      * using {@code startDateTime.until(endDateTime, DAYS)}.
      * <p>
-     * 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.
      * <p>
@@ -2086,26 +2087,23 @@
      * <p>
      * 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.
      * <p>
      * 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 @@
                 return toOffsetDateTime().until(end.toOffsetDateTime(), unit);
             }
         }
-        return unit.between(this, endDateTime);
+        return unit.between(this, end);
     }
 
     /**
--- a/jdk/src/share/classes/java/time/chrono/ChronoLocalDate.java	Wed Sep 04 15:18:54 2013 +0100
+++ b/jdk/src/share/classes/java/time/chrono/ChronoLocalDate.java	Sat Sep 14 22:46:49 2013 +0100
@@ -291,6 +291,7 @@
         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 @@
      * 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 @@
      * <p>
      * 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.
      * <p>
      * 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}.
--- a/jdk/src/share/classes/java/time/chrono/ChronoLocalDateImpl.java	Wed Sep 04 15:18:54 2013 +0100
+++ b/jdk/src/share/classes/java/time/chrono/ChronoLocalDateImpl.java	Sat Sep 14 22:46:49 2013 +0100
@@ -372,22 +372,10 @@
     }
 
     //-----------------------------------------------------------------------
-    /**
-     * {@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 @@
             }
             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) {
--- a/jdk/src/share/classes/java/time/chrono/ChronoLocalDateTime.java	Wed Sep 04 15:18:54 2013 +0100
+++ b/jdk/src/share/classes/java/time/chrono/ChronoLocalDateTime.java	Sat Sep 14 22:46:49 2013 +0100
@@ -165,6 +165,7 @@
         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());
--- a/jdk/src/share/classes/java/time/chrono/ChronoLocalDateTimeImpl.java	Wed Sep 04 15:18:54 2013 +0100
+++ b/jdk/src/share/classes/java/time/chrono/ChronoLocalDateTimeImpl.java	Sat Sep 14 22:46:49 2013 +0100
@@ -69,7 +69,6 @@
 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 @@
 
     //-----------------------------------------------------------------------
     @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<D> end = (ChronoLocalDateTime<D>) endDateTime;
-        if (toLocalDate().getChronology().equals(end.toLocalDate().getChronology()) == false) {
-            throw new DateTimeException("Unable to calculate amount as objects have different chronologies");
-        }
+        ChronoLocalDateTime<D> end = (ChronoLocalDateTime<D>) 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 @@
             }
             return date.until(endDate, unit);
         }
-        return unit.between(this, endDateTime);
+        Objects.requireNonNull(unit, "unit");
+        return unit.between(this, end);
     }
 
     //-----------------------------------------------------------------------
--- a/jdk/src/share/classes/java/time/chrono/ChronoZonedDateTime.java	Wed Sep 04 15:18:54 2013 +0100
+++ b/jdk/src/share/classes/java/time/chrono/ChronoZonedDateTime.java	Sat Sep 14 22:46:49 2013 +0100
@@ -166,6 +166,7 @@
         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());
--- a/jdk/src/share/classes/java/time/chrono/ChronoZonedDateTimeImpl.java	Wed Sep 04 15:18:54 2013 +0100
+++ b/jdk/src/share/classes/java/time/chrono/ChronoZonedDateTimeImpl.java	Sat Sep 14 22:46:49 2013 +0100
@@ -69,7 +69,6 @@
 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 @@
         if (trans != null && trans.isOverlap()) {
             ZoneOffset earlierOffset = trans.getOffsetBefore();
             if (earlierOffset.equals(offset) == false) {
-                return new ChronoZonedDateTimeImpl<D>(dateTime, earlierOffset, zone);
+                return new ChronoZonedDateTimeImpl<>(dateTime, earlierOffset, zone);
             }
         }
         return this;
@@ -246,7 +245,7 @@
         if (trans != null) {
             ZoneOffset offset = trans.getOffsetAfter();
             if (offset.equals(getOffset()) == false) {
-                return new ChronoZonedDateTimeImpl<D>(dateTime, offset, zone);
+                return new ChronoZonedDateTimeImpl<>(dateTime, offset, zone);
             }
         }
         return this;
@@ -308,20 +307,16 @@
 
     //-----------------------------------------------------------------------
     @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<D> end = (ChronoZonedDateTime<D>) endDateTime;
-        if (toLocalDate().getChronology().equals(end.toLocalDate().getChronology()) == false) {
-            throw new DateTimeException("Unable to calculate amount as objects have different chronologies");
-        }
+        ChronoZonedDateTime<D> end = (ChronoZonedDateTime<D>) 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);
     }
 
     //-----------------------------------------------------------------------
--- a/jdk/src/share/classes/java/time/temporal/ChronoUnit.java	Wed Sep 04 15:18:54 2013 +0100
+++ b/jdk/src/share/classes/java/time/temporal/ChronoUnit.java	Sat Sep 14 22:46:49 2013 +0100
@@ -268,8 +268,8 @@
 
     //-----------------------------------------------------------------------
     @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);
     }
 
     //-----------------------------------------------------------------------
--- a/jdk/src/share/classes/java/time/temporal/IsoFields.java	Wed Sep 04 15:18:54 2013 +0100
+++ b/jdk/src/share/classes/java/time/temporal/IsoFields.java	Sat Sep 14 22:46:49 2013 +0100
@@ -684,13 +684,16 @@
         }
 
         @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");
             }
--- a/jdk/src/share/classes/java/time/temporal/Temporal.java	Wed Sep 04 15:18:54 2013 +0100
+++ b/jdk/src/share/classes/java/time/temporal/Temporal.java	Sat Sep 14 22:46:49 2013 +0100
@@ -374,8 +374,9 @@
      * Calculates the amount of time until another temporal in terms of the specified unit.
      * <p>
      * 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 @@
      * <p>
      * 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.
      * <p>
-     * 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:
      * <pre>
-     *  // 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);
      * </pre>
      * <p>
+     * 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()}.
+     * <p>
      * 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);
 
 }
--- a/jdk/src/share/classes/java/time/temporal/TemporalUnit.java	Wed Sep 04 15:18:54 2013 +0100
+++ b/jdk/src/share/classes/java/time/temporal/TemporalUnit.java	Sat Sep 14 22:46:49 2013 +0100
@@ -231,7 +231,9 @@
      * Calculates the amount of time between two temporal objects.
      * <p>
      * 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 @@
      * 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);
 
     //-----------------------------------------------------------------------
     /**
--- a/jdk/test/java/time/tck/java/time/TCKDuration.java	Wed Sep 04 15:18:54 2013 +0100
+++ b/jdk/test/java/time/tck/java/time/TCKDuration.java	Sat Sep 14 22:46:49 2013 +0100
@@ -77,6 +77,7 @@
 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 @@
         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);
     }
 
--- a/jdk/test/java/time/tck/java/time/TCKInstant.java	Wed Sep 04 15:18:54 2013 +0100
+++ b/jdk/test/java/time/tck/java/time/TCKInstant.java	Sat Sep 14 22:46:49 2013 +0100
@@ -84,6 +84,7 @@
 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 @@
     }
 
     @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 @@
     }
 
     @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);
     }
 
--- a/jdk/test/java/time/tck/java/time/TCKLocalDate.java	Wed Sep 04 15:18:54 2013 +0100
+++ b/jdk/test/java/time/tck/java/time/TCKLocalDate.java	Sat Sep 14 22:46:49 2013 +0100
@@ -1723,29 +1723,48 @@
     }
 
     @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);
     }
 
--- a/jdk/test/java/time/tck/java/time/TCKLocalDateTime.java	Wed Sep 04 15:18:54 2013 +0100
+++ b/jdk/test/java/time/tck/java/time/TCKLocalDateTime.java	Sat Sep 14 22:46:49 2013 +0100
@@ -2895,24 +2895,43 @@
     }
 
     @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);
     }
 
--- a/jdk/test/java/time/tck/java/time/TCKLocalTime.java	Wed Sep 04 15:18:54 2013 +0100
+++ b/jdk/test/java/time/tck/java/time/TCKLocalTime.java	Sat Sep 14 22:46:49 2013 +0100
@@ -1971,29 +1971,48 @@
     }
 
     @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);
     }
 
--- a/jdk/test/java/time/tck/java/time/TCKOffsetDateTime.java	Wed Sep 04 15:18:54 2013 +0100
+++ b/jdk/test/java/time/tck/java/time/TCKOffsetDateTime.java	Sat Sep 14 22:46:49 2013 +0100
@@ -91,6 +91,13 @@
 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;
@@ -1129,6 +1136,74 @@
     }
 
     //-----------------------------------------------------------------------
+    // 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)
     //-----------------------------------------------------------------------
     @Test
--- a/jdk/test/java/time/tck/java/time/TCKOffsetTime.java	Wed Sep 04 15:18:54 2013 +0100
+++ b/jdk/test/java/time/tck/java/time/TCKOffsetTime.java	Sat Sep 14 22:46:49 2013 +0100
@@ -1069,49 +1069,61 @@
     // 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);
     }
 
--- a/jdk/test/java/time/tck/java/time/TCKYear.java	Wed Sep 04 15:18:54 2013 +0100
+++ b/jdk/test/java/time/tck/java/time/TCKYear.java	Sat Sep 14 22:46:49 2013 +0100
@@ -65,10 +65,8 @@
 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.YearMonth;
 import java.time.ZoneId;
 import java.time.ZoneOffset;
+import java.time.chrono.IsoChronology;
 import java.time.chrono.IsoEra;
-import java.time.chrono.IsoChronology;
 import java.time.format.DateTimeFormatter;
 import java.time.format.DateTimeParseException;
 import java.time.temporal.ChronoField;
@@ -229,17 +227,17 @@
 
     //-----------------------------------------------------------------------
     @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 @@
         };
     }
 
-    @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 @@
         };
     }
 
-    @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 @@
     //-----------------------------------------------------------------------
     // 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 @@
     }
 
     @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);
     }
 
--- a/jdk/test/java/time/tck/java/time/TCKYearMonth.java	Wed Sep 04 15:18:54 2013 +0100
+++ b/jdk/test/java/time/tck/java/time/TCKYearMonth.java	Sat Sep 14 22:46:49 2013 +0100
@@ -70,7 +70,6 @@
 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 @@
 
     //-----------------------------------------------------------------------
     @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 @@
         };
     }
 
-    @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 @@
         };
     }
 
-    @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 @@
         };
     }
 
-    @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 @@
         };
     }
 
-    @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 @@
     }
 
     @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);
     }
 
--- a/jdk/test/java/time/tck/java/time/TCKZonedDateTime.java	Wed Sep 04 15:18:54 2013 +0100
+++ b/jdk/test/java/time/tck/java/time/TCKZonedDateTime.java	Sat Sep 14 22:46:49 2013 +0100
@@ -2001,7 +2001,7 @@
     // 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 @@
     }
 
     @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 @@
     }
 
     @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 @@
     }
 
     @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 @@
     }
 
     @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);
     }
 
--- a/jdk/test/java/time/tck/java/time/chrono/CopticDate.java	Wed Sep 04 15:18:54 2013 +0100
+++ b/jdk/test/java/time/tck/java/time/chrono/CopticDate.java	Sat Sep 14 22:46:49 2013 +0100
@@ -297,18 +297,12 @@
     }
 
     @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
--- a/jdk/test/java/time/tck/java/time/temporal/TCKIsoFields.java	Wed Sep 04 15:18:54 2013 +0100
+++ b/jdk/test/java/time/tck/java/time/temporal/TCKIsoFields.java	Sat Sep 14 22:46:49 2013 +0100
@@ -70,11 +70,13 @@
 
 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 @@
                 {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);
+    }
+
     //-----------------------------------------------------------------------
     //-----------------------------------------------------------------------
     //-----------------------------------------------------------------------