8025720: Separate temporal interface layer
authorrriggs
Thu, 26 Sep 2013 23:05:29 -0700
changeset 20793 5acd4b8d70a1
parent 20792 8d5c16e4f64c
child 20794 ec823009c5f7
8025720: Separate temporal interface layer Summary: Remove ZoneId and Chronology from TemporalField interface Reviewed-by: sherman Contributed-by: scolebourne@joda.org
jdk/src/share/classes/java/time/format/Parsed.java
jdk/src/share/classes/java/time/temporal/IsoFields.java
jdk/src/share/classes/java/time/temporal/JulianFields.java
jdk/src/share/classes/java/time/temporal/TemporalField.java
jdk/src/share/classes/java/time/temporal/WeekFields.java
jdk/test/java/time/tck/java/time/format/TCKDateTimeParseResolver.java
--- a/jdk/src/share/classes/java/time/format/Parsed.java	Tue Oct 15 13:01:28 2013 +0200
+++ b/jdk/src/share/classes/java/time/format/Parsed.java	Thu Sep 26 23:05:29 2013 -0700
@@ -262,7 +262,7 @@
             while (changedCount < 50) {
                 for (Map.Entry<TemporalField, Long> entry : fieldValues.entrySet()) {
                     TemporalField targetField = entry.getKey();
-                    TemporalAccessor resolvedObject = targetField.resolve(fieldValues, chrono, zone, resolverStyle);
+                    TemporalAccessor resolvedObject = targetField.resolve(fieldValues, this, resolverStyle);
                     if (resolvedObject != null) {
                         if (resolvedObject instanceof ChronoZonedDateTime) {
                             ChronoZonedDateTime czdt = (ChronoZonedDateTime) resolvedObject;
--- a/jdk/src/share/classes/java/time/temporal/IsoFields.java	Tue Oct 15 13:01:28 2013 +0200
+++ b/jdk/src/share/classes/java/time/temporal/IsoFields.java	Thu Sep 26 23:05:29 2013 -0700
@@ -69,6 +69,7 @@
 import static java.time.temporal.ChronoUnit.WEEKS;
 import static java.time.temporal.ChronoUnit.YEARS;
 
+import java.time.DateTimeException;
 import java.time.Duration;
 import java.time.LocalDate;
 import java.time.ZoneId;
@@ -343,7 +344,7 @@
             }
             @Override
             public ChronoLocalDate resolve(
-                    Map<TemporalField, Long> fieldValues, Chronology chronology, ZoneId zone, ResolverStyle resolverStyle) {
+                    Map<TemporalField, Long> fieldValues, TemporalAccessor partialTemporal, ResolverStyle resolverStyle) {
                 Long yearLong = fieldValues.get(YEAR);
                 Long qoyLong = fieldValues.get(QUARTER_OF_YEAR);
                 if (yearLong == null || qoyLong == null) {
@@ -351,6 +352,7 @@
                 }
                 int y = YEAR.checkValidIntValue(yearLong);  // always validate
                 long doq = fieldValues.get(DAY_OF_QUARTER);
+                ensureIso(partialTemporal);
                 LocalDate date;
                 if (resolverStyle == ResolverStyle.LENIENT) {
                     date = LocalDate.of(y, 1, 1).plusMonths(Math.multiplyExact(Math.subtractExact(qoyLong, 1), 3));
@@ -464,7 +466,7 @@
             }
             @Override
             public ChronoLocalDate resolve(
-                    Map<TemporalField, Long> fieldValues, Chronology chronology, ZoneId zone, ResolverStyle resolverStyle) {
+                    Map<TemporalField, Long> fieldValues, TemporalAccessor partialTemporal, ResolverStyle resolverStyle) {
                 Long wbyLong = fieldValues.get(WEEK_BASED_YEAR);
                 Long dowLong = fieldValues.get(DAY_OF_WEEK);
                 if (wbyLong == null || dowLong == null) {
@@ -472,6 +474,7 @@
                 }
                 int wby = WEEK_BASED_YEAR.range().checkValidIntValue(wbyLong, WEEK_BASED_YEAR);  // always validate
                 long wowby = fieldValues.get(WEEK_OF_WEEK_BASED_YEAR);
+                ensureIso(partialTemporal);
                 LocalDate date = LocalDate.of(wby, 1, 4);
                 if (resolverStyle == ResolverStyle.LENIENT) {
                     long dow = dowLong;  // unvalidated
@@ -568,6 +571,12 @@
             return Chronology.from(temporal).equals(IsoChronology.INSTANCE);
         }
 
+        private static void ensureIso(TemporalAccessor temporal) {
+            if (isIso(temporal) == false) {
+                throw new DateTimeException("Resolve requires IsoChronology");
+            }
+        }
+
         private static ValueRange getWeekRange(LocalDate date) {
             int wby = getWeekBasedYear(date);
             date = date.withDayOfYear(1).withYear(wby);
--- a/jdk/src/share/classes/java/time/temporal/JulianFields.java	Tue Oct 15 13:01:28 2013 +0200
+++ b/jdk/src/share/classes/java/time/temporal/JulianFields.java	Thu Sep 26 23:05:29 2013 -0700
@@ -291,13 +291,14 @@
         //-----------------------------------------------------------------------
         @Override
         public ChronoLocalDate resolve(
-                Map<TemporalField, Long> fieldValues, Chronology chronology, ZoneId zone, ResolverStyle resolverStyle) {
+                Map<TemporalField, Long> fieldValues, TemporalAccessor partialTemporal, ResolverStyle resolverStyle) {
             long value = fieldValues.remove(this);
+            Chronology chrono = Chronology.from(partialTemporal);
             if (resolverStyle == ResolverStyle.LENIENT) {
-                return chronology.dateEpochDay(Math.subtractExact(value, offset));
+                return chrono.dateEpochDay(Math.subtractExact(value, offset));
             }
             range().checkValidValue(value, this);
-            return chronology.dateEpochDay(value - offset);
+            return chrono.dateEpochDay(value - offset);
         }
 
         //-----------------------------------------------------------------------
--- a/jdk/src/share/classes/java/time/temporal/TemporalField.java	Tue Oct 15 13:01:28 2013 +0200
+++ b/jdk/src/share/classes/java/time/temporal/TemporalField.java	Thu Sep 26 23:05:29 2013 -0700
@@ -62,7 +62,6 @@
 package java.time.temporal;
 
 import java.time.DateTimeException;
-import java.time.ZoneId;
 import java.time.chrono.Chronology;
 import java.time.format.ResolverStyle;
 import java.util.Locale;
@@ -338,6 +337,13 @@
      * complete {@code LocalDate}. The resolve method will remove all three
      * fields from the map before returning the {@code LocalDate}.
      * <p>
+     * A partially complete temporal is used to allow the chronology and zone
+     * to be queried. In general, only the chronology will be needed.
+     * Querying items other than the zone or chronology is undefined and
+     * must not be relied on.
+     * The behavior of other methods such as {@code get}, {@code getLong},
+     * {@code range} and {@code isSupported} is unpredictable and the results undefined.
+     * <p>
      * If resolution should be possible, but the data is invalid, the resolver
      * style should be used to determine an appropriate level of leniency, which
      * may require throwing a {@code DateTimeException} or {@code ArithmeticException}.
@@ -350,16 +356,14 @@
      * instances that can produce a date, such as {@code EPOCH_DAY}.
      * <p>
      * Not all {@code TemporalAccessor} implementations are accepted as return values.
-     * Implementations must accept {@code ChronoLocalDate}, {@code ChronoLocalDateTime},
-     * {@code ChronoZonedDateTime} and {@code LocalTime}.
-     * <p>
-     * The zone is not normally required for resolution, but is provided for completeness.
+     * Implementations that call this method must accept {@code ChronoLocalDate},
+     * {@code ChronoLocalDateTime}, {@code ChronoZonedDateTime} and {@code LocalTime}.
      * <p>
      * The default implementation must return null.
      *
      * @param fieldValues  the map of fields to values, which can be updated, not null
-     * @param chronology  the effective chronology, not null
-     * @param zone  the effective zone, not null
+     * @param partialTemporal  the partially complete temporal to query for zone and
+     *  chronology; querying for other things is undefined and not recommended, not null
      * @param resolverStyle  the requested type of resolve, not null
      * @return the resolved temporal object; null if resolving only
      *  changed the map, or no resolve occurred
@@ -368,8 +372,9 @@
      *  by querying a field on the temporal without first checking if it is supported
      */
     default TemporalAccessor resolve(
-            Map<TemporalField, Long> fieldValues, Chronology chronology,
-            ZoneId zone, ResolverStyle resolverStyle) {
+            Map<TemporalField, Long> fieldValues,
+            TemporalAccessor partialTemporal,
+            ResolverStyle resolverStyle) {
         return null;
     }
 
--- a/jdk/src/share/classes/java/time/temporal/WeekFields.java	Tue Oct 15 13:01:28 2013 +0200
+++ b/jdk/src/share/classes/java/time/temporal/WeekFields.java	Thu Sep 26 23:05:29 2013 -0700
@@ -892,7 +892,7 @@
 
         @Override
         public ChronoLocalDate resolve(
-                Map<TemporalField, Long> fieldValues, Chronology chronology, ZoneId zone, ResolverStyle resolverStyle) {
+                Map<TemporalField, Long> fieldValues, TemporalAccessor partialTemporal, ResolverStyle resolverStyle) {
             final long value = fieldValues.get(this);
             final int newValue = Math.toIntExact(value);  // broad limit makes overflow checking lighter
             // first convert localized day-of-week to ISO day-of-week
@@ -915,19 +915,20 @@
             int dow = localizedDayOfWeek(isoDow);
 
             // build date
+            Chronology chrono = Chronology.from(partialTemporal);
             if (fieldValues.containsKey(YEAR)) {
                 int year = YEAR.checkValidIntValue(fieldValues.get(YEAR));  // validate
                 if (rangeUnit == MONTHS && fieldValues.containsKey(MONTH_OF_YEAR)) {  // week-of-month
                     long month = fieldValues.get(MONTH_OF_YEAR);  // not validated yet
-                    return resolveWoM(fieldValues, chronology, year, month, newValue, dow, resolverStyle);
+                    return resolveWoM(fieldValues, chrono, year, month, newValue, dow, resolverStyle);
                 }
                 if (rangeUnit == YEARS) {  // week-of-year
-                    return resolveWoY(fieldValues, chronology, year, newValue, dow, resolverStyle);
+                    return resolveWoY(fieldValues, chrono, year, newValue, dow, resolverStyle);
                 }
             } else if ((rangeUnit == WEEK_BASED_YEARS || rangeUnit == FOREVER) &&
                     fieldValues.containsKey(weekDef.weekBasedYear) &&
                     fieldValues.containsKey(weekDef.weekOfWeekBasedYear)) { // week-of-week-based-year and year-of-week-based-year
-                return resolveWBY(fieldValues, chronology, dow, resolverStyle);
+                return resolveWBY(fieldValues, chrono, dow, resolverStyle);
             }
             return null;
         }
--- a/jdk/test/java/time/tck/java/time/format/TCKDateTimeParseResolver.java	Tue Oct 15 13:01:28 2013 +0200
+++ b/jdk/test/java/time/tck/java/time/format/TCKDateTimeParseResolver.java	Thu Sep 26 23:05:29 2013 -0700
@@ -927,8 +927,7 @@
             }
             @Override
             public TemporalAccessor resolve(
-                    Map<TemporalField, Long> fieldValues, Chronology chronology,
-                    ZoneId zone, ResolverStyle resolverStyle) {
+                    Map<TemporalField, Long> fieldValues, TemporalAccessor partialTemporal, ResolverStyle resolverStyle) {
                 return LocalTime.MIDNIGHT.plusNanos(fieldValues.remove(this));
             }
         };
@@ -979,8 +978,7 @@
             }
             @Override
             public TemporalAccessor resolve(
-                    Map<TemporalField, Long> fieldValues, Chronology chronology,
-                    ZoneId zone, ResolverStyle resolverStyle) {
+                    Map<TemporalField, Long> fieldValues, TemporalAccessor partialTemporal, ResolverStyle resolverStyle) {
                 fieldValues.remove(this);
                 return LocalDateTime.of(2010, 6, 30, 12, 30);
             }
@@ -1032,8 +1030,7 @@
             }
             @Override
             public TemporalAccessor resolve(
-                    Map<TemporalField, Long> fieldValues, Chronology chronology,
-                    ZoneId zone, ResolverStyle resolverStyle) {
+                    Map<TemporalField, Long> fieldValues, TemporalAccessor partialTemporal, ResolverStyle resolverStyle) {
                 return ThaiBuddhistChronology.INSTANCE.dateNow();
             }
         };
@@ -1082,8 +1079,7 @@
             }
             @Override
             public TemporalAccessor resolve(
-                    Map<TemporalField, Long> fieldValues, Chronology chronology,
-                    ZoneId zone, ResolverStyle resolverStyle) {
+                    Map<TemporalField, Long> fieldValues, TemporalAccessor partialTemporal, ResolverStyle resolverStyle) {
                 return ZonedDateTime.of(2010, 6, 30, 12, 30, 0, 0, ZoneId.of("Europe/Paris"));
             }
         };