src/share/classes/java/time/temporal/IsoFields.java

Print this page

        

@@ -70,11 +70,14 @@
 import static java.time.temporal.ChronoUnit.YEARS;
 
 import java.time.DateTimeException;
 import java.time.Duration;
 import java.time.LocalDate;
-import java.time.format.DateTimeBuilder;
+import java.time.chrono.Chronology;
+import java.time.chrono.IsoChronology;
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  * Fields and units specific to the ISO-8601 calendar system,
  * including quarter-of-year and week-based-year.
  * <p>

@@ -141,11 +144,11 @@
  * <p>
  * This class is immutable and thread-safe.
  *
  * @since 1.8
  */
-public final class ISOFields {
+public final class IsoFields {
 
     /**
      * The field that represents the day-of-quarter.
      * <p>
      * This field allows the day-of-quarter value to be queried and set.

@@ -214,11 +217,11 @@
     public static final TemporalUnit QUARTER_YEARS = Unit.QUARTER_YEARS;
 
     /**
      * Restricted constructor.
      */
-    private ISOFields() {
+    private IsoFields() {
         throw new AssertionError("Not instantiable");
     }
 
     //-----------------------------------------------------------------------
     /**

@@ -241,46 +244,63 @@
             @Override
             public ValueRange range() {
                 return ValueRange.of(1, 90, 92);
             }
             @Override
-            public boolean doIsSupported(TemporalAccessor temporal) {
+            public boolean isSupportedBy(TemporalAccessor temporal) {
                 return temporal.isSupported(DAY_OF_YEAR) && temporal.isSupported(MONTH_OF_YEAR) &&
-                        temporal.isSupported(YEAR) && Chrono.from(temporal).equals(ISOChrono.INSTANCE);
+                        temporal.isSupported(YEAR) && isIso(temporal);
             }
             @Override
-            public ValueRange doRange(TemporalAccessor temporal) {
-                if (doIsSupported(temporal) == false) {
+            public ValueRange rangeRefinedBy(TemporalAccessor temporal) {
+                if (isSupportedBy(temporal) == false) {
                     throw new DateTimeException("Unsupported field: DayOfQuarter");
                 }
                 long qoy = temporal.getLong(QUARTER_OF_YEAR);
                 if (qoy == 1) {
                     long year = temporal.getLong(YEAR);
-                    return (ISOChrono.INSTANCE.isLeapYear(year) ? ValueRange.of(1, 91) : ValueRange.of(1, 90));
+                    return (IsoChronology.INSTANCE.isLeapYear(year) ? ValueRange.of(1, 91) : ValueRange.of(1, 90));
                 } else if (qoy == 2) {
                     return ValueRange.of(1, 91);
                 } else if (qoy == 3 || qoy == 4) {
                     return ValueRange.of(1, 92);
                 } // else value not from 1 to 4, so drop through
                 return range();
             }
             @Override
-            public long doGet(TemporalAccessor temporal) {
-                if (doIsSupported(temporal) == false) {
+            public long getFrom(TemporalAccessor temporal) {
+                if (isSupportedBy(temporal) == false) {
                     throw new DateTimeException("Unsupported field: DayOfQuarter");
                 }
                 int doy = temporal.get(DAY_OF_YEAR);
                 int moy = temporal.get(MONTH_OF_YEAR);
                 long year = temporal.getLong(YEAR);
-                return doy - QUARTER_DAYS[((moy - 1) / 3) + (ISOChrono.INSTANCE.isLeapYear(year) ? 4 : 0)];
+                return doy - QUARTER_DAYS[((moy - 1) / 3) + (IsoChronology.INSTANCE.isLeapYear(year) ? 4 : 0)];
             }
+            @SuppressWarnings("unchecked")
             @Override
-            public <R extends Temporal> R doWith(R temporal, long newValue) {
-                long curValue = doGet(temporal);
-                range().checkValidValue(newValue, this);
+            public <R extends Temporal> R adjustInto(R temporal, long newValue) {
+                // calls getFrom() to check if supported
+                long curValue = getFrom(temporal);
+                range().checkValidValue(newValue, this);  // leniently check from 1 to 92 TODO: check
                 return (R) temporal.with(DAY_OF_YEAR, temporal.getLong(DAY_OF_YEAR) + (newValue - curValue));
             }
+            @Override
+            public Map<TemporalField, Long> resolve(TemporalAccessor temporal, long value) {
+                if ((temporal.isSupported(YEAR) && temporal.isSupported(DAY_OF_QUARTER)) == false) {
+                    return null;
+                }
+                int y = temporal.get(YEAR);
+                int qoy = temporal.get(QUARTER_OF_YEAR);
+                range().checkValidValue(value, this);  // leniently check from 1 to 92 TODO: check
+                LocalDate date = LocalDate.of(y, ((qoy - 1) * 3) + 1, 1).plusDays(value - 1);
+                Map<TemporalField, Long> result = new HashMap<>(4, 1.0f);
+                result.put(EPOCH_DAY, date.toEpochDay());
+                result.put(YEAR, null);
+                result.put(QUARTER_OF_YEAR, null);
+                return result;
+            }
         },
         QUARTER_OF_YEAR {
             @Override
             public String getName() {
                 return "QuarterOfYear";

@@ -296,40 +316,29 @@
             @Override
             public ValueRange range() {
                 return ValueRange.of(1, 4);
             }
             @Override
-            public boolean doIsSupported(TemporalAccessor temporal) {
-                return temporal.isSupported(MONTH_OF_YEAR) && Chrono.from(temporal).equals(ISOChrono.INSTANCE);
+            public boolean isSupportedBy(TemporalAccessor temporal) {
+                return temporal.isSupported(MONTH_OF_YEAR) && isIso(temporal);
             }
             @Override
-            public long doGet(TemporalAccessor temporal) {
-                if (doIsSupported(temporal) == false) {
-                    throw new DateTimeException("Unsupported field: DayOfQuarter");
+            public long getFrom(TemporalAccessor temporal) {
+                if (isSupportedBy(temporal) == false) {
+                    throw new DateTimeException("Unsupported field: QuarterOfYear");
                 }
                 long moy = temporal.getLong(MONTH_OF_YEAR);
                 return ((moy + 2) / 3);
             }
+            @SuppressWarnings("unchecked")
             @Override
-            public <R extends Temporal> R doWith(R temporal, long newValue) {
-                long curValue = doGet(temporal);
-                range().checkValidValue(newValue, this);
+            public <R extends Temporal> R adjustInto(R temporal, long newValue) {
+                // calls getFrom() to check if supported
+                long curValue = getFrom(temporal);
+                range().checkValidValue(newValue, this);  // strictly check from 1 to 4
                 return (R) temporal.with(MONTH_OF_YEAR, temporal.getLong(MONTH_OF_YEAR) + (newValue - curValue) * 3);
             }
-            @Override
-            public boolean resolve(DateTimeBuilder builder, long value) {
-                Long[] values = builder.queryFieldValues(YEAR, QUARTER_OF_YEAR, DAY_OF_QUARTER);
-                if (values[0] != null && values[1] != null && values[2] != null) {
-                    int y = YEAR.range().checkValidIntValue(values[0], YEAR);
-                    int qoy = QUARTER_OF_YEAR.range().checkValidIntValue(values[1], QUARTER_OF_YEAR);
-                    int doq = DAY_OF_QUARTER.range().checkValidIntValue(values[2], DAY_OF_QUARTER);
-                    LocalDate date = LocalDate.of(y, ((qoy - 1) * 3) + 1, 1).plusDays(doq - 1);
-                    builder.addFieldValue(EPOCH_DAY, date.toEpochDay());
-                    builder.removeFieldValues(QUARTER_OF_YEAR, DAY_OF_QUARTER);
-                }
-                return false;
-            }
         },
         WEEK_OF_WEEK_BASED_YEAR {
             @Override
             public String getName() {
                 return "WeekOfWeekBasedYear";

@@ -345,25 +354,48 @@
             @Override
             public ValueRange range() {
                 return ValueRange.of(1, 52, 53);
             }
             @Override
-            public boolean doIsSupported(TemporalAccessor temporal) {
-                return temporal.isSupported(EPOCH_DAY);
+            public boolean isSupportedBy(TemporalAccessor temporal) {
+                return temporal.isSupported(EPOCH_DAY) && isIso(temporal);
             }
             @Override
-            public ValueRange doRange(TemporalAccessor temporal) {
+            public ValueRange rangeRefinedBy(TemporalAccessor temporal) {
+                if (isSupportedBy(temporal) == false) {
+                    throw new DateTimeException("Unsupported field: WeekOfWeekBasedYear");
+                }
                 return getWeekRange(LocalDate.from(temporal));
             }
             @Override
-            public long doGet(TemporalAccessor temporal) {
+            public long getFrom(TemporalAccessor temporal) {
+                if (isSupportedBy(temporal) == false) {
+                    throw new DateTimeException("Unsupported field: WeekOfWeekBasedYear");
+                }
                 return getWeek(LocalDate.from(temporal));
             }
+            @SuppressWarnings("unchecked")
             @Override
-            public <R extends Temporal> R doWith(R temporal, long newValue) {
-                ValueRange.of(1, 53).checkValidValue(newValue, this);
-                return (R) temporal.plus(Math.subtractExact(newValue, doGet(temporal)), WEEKS);
+            public <R extends Temporal> R adjustInto(R temporal, long newValue) {
+                // calls getFrom() to check if supported
+                range().checkValidValue(newValue, this);  // lenient range
+                return (R) temporal.plus(Math.subtractExact(newValue, getFrom(temporal)), WEEKS);
+            }
+            @Override
+            public Map<TemporalField, Long> resolve(TemporalAccessor temporal, long value) {
+                if ((temporal.isSupported(WEEK_BASED_YEAR) && temporal.isSupported(DAY_OF_WEEK)) == false) {
+                    return null;
+                }
+                int wby = temporal.get(WEEK_BASED_YEAR);
+                int dow = temporal.get(DAY_OF_WEEK);
+                range().checkValidValue(value, this);  // lenient range
+                LocalDate date = LocalDate.of(wby, 1, 4).plusWeeks(value - 1).with(DAY_OF_WEEK, dow);
+                Map<TemporalField, Long> result = new HashMap<>(2, 1.0f);
+                result.put(EPOCH_DAY, date.toEpochDay());
+                result.put(WEEK_BASED_YEAR, null);
+                result.put(DAY_OF_WEEK, null);
+                return result;
             }
         },
         WEEK_BASED_YEAR {
             @Override
             public String getName() {

@@ -380,58 +412,51 @@
             @Override
             public ValueRange range() {
                 return YEAR.range();
             }
             @Override
-            public boolean doIsSupported(TemporalAccessor temporal) {
-                return temporal.isSupported(EPOCH_DAY);
+            public boolean isSupportedBy(TemporalAccessor temporal) {
+                return temporal.isSupported(EPOCH_DAY) && isIso(temporal);
             }
             @Override
-            public long doGet(TemporalAccessor temporal) {
+            public long getFrom(TemporalAccessor temporal) {
+                if (isSupportedBy(temporal) == false) {
+                    throw new DateTimeException("Unsupported field: WeekBasedYear");
+                }
                 return getWeekBasedYear(LocalDate.from(temporal));
             }
+            @SuppressWarnings("unchecked")
             @Override
-            public <R extends Temporal> R doWith(R temporal, long newValue) {
-                int newVal = range().checkValidIntValue(newValue, WEEK_BASED_YEAR);
+            public <R extends Temporal> R adjustInto(R temporal, long newValue) {
+                if (isSupportedBy(temporal) == false) {
+                    throw new DateTimeException("Unsupported field: WeekBasedYear");
+                }
+                int newVal = range().checkValidIntValue(newValue, WEEK_BASED_YEAR);  // strict check
                 LocalDate date = LocalDate.from(temporal);
                 int week = getWeek(date);
                 date = date.withDayOfYear(180).withYear(newVal).with(WEEK_OF_WEEK_BASED_YEAR, week);
                 return (R) date.with(date);
             }
-            @Override
-            public boolean resolve(DateTimeBuilder builder, long value) {
-                Long[] values = builder.queryFieldValues(WEEK_BASED_YEAR, WEEK_OF_WEEK_BASED_YEAR, DAY_OF_WEEK);
-                if (values[0] != null && values[1] != null && values[2] != null) {
-                    int wby = WEEK_BASED_YEAR.range().checkValidIntValue(values[0], WEEK_BASED_YEAR);
-                    int week = WEEK_OF_WEEK_BASED_YEAR.range().checkValidIntValue(values[1], WEEK_OF_WEEK_BASED_YEAR);
-                    int dow = DAY_OF_WEEK.range().checkValidIntValue(values[2], DAY_OF_WEEK);
-                    LocalDate date = LocalDate.of(wby, 2, 1).with(WEEK_OF_WEEK_BASED_YEAR, week).with(DAY_OF_WEEK, dow);
-                    builder.addFieldValue(EPOCH_DAY, date.toEpochDay());
-                    builder.removeFieldValues(WEEK_BASED_YEAR, WEEK_OF_WEEK_BASED_YEAR, DAY_OF_WEEK);
-                }
-                return false;
-            }
         };
 
         @Override
-        public ValueRange doRange(TemporalAccessor temporal) {
+        public ValueRange rangeRefinedBy(TemporalAccessor temporal) {
             return range();
         }
 
         @Override
-        public boolean resolve(DateTimeBuilder builder, long value) {
-            return false;
-        }
-
-        @Override
         public String toString() {
             return getName();
         }
 
         //-------------------------------------------------------------------------
         private static final int[] QUARTER_DAYS = {0, 90, 181, 273, 0, 91, 182, 274};
 
+        private static boolean isIso(TemporalAccessor temporal) {
+            return Chronology.from(temporal).equals(IsoChronology.INSTANCE);
+        }
+
         private static ValueRange getWeekRange(LocalDate date) {
             int wby = getWeekBasedYear(date);
             date = date.withDayOfYear(1).withYear(wby);
             // 53 weeks if standard year starts on Thursday, or Wed in a leap year
             if (date.getDayOfWeek() == THURSDAY || (date.getDayOfWeek() == WEDNESDAY && date.isLeapYear())) {

@@ -518,40 +543,38 @@
         public boolean isDurationEstimated() {
             return true;
         }
 
         @Override
-        public boolean isSupported(Temporal temporal) {
+        public boolean isSupportedBy(Temporal temporal) {
             return temporal.isSupported(EPOCH_DAY);
         }
 
+        @SuppressWarnings("unchecked")
         @Override
-        public <R extends Temporal> R doPlus(R dateTime, long periodToAdd) {
+        public <R extends Temporal> R addTo(R temporal, long amount) {
             switch(this) {
                 case WEEK_BASED_YEARS:
-                    return (R) dateTime.with(WEEK_BASED_YEAR,
-                            Math.addExact(dateTime.get(WEEK_BASED_YEAR), periodToAdd));
+                    return (R) temporal.with(WEEK_BASED_YEAR,
+                            Math.addExact(temporal.get(WEEK_BASED_YEAR), amount));
                 case QUARTER_YEARS:
                     // no overflow (256 is multiple of 4)
-                    return (R) dateTime.plus(periodToAdd / 256, YEARS)
-                            .plus((periodToAdd % 256) * 3, MONTHS);
+                    return (R) temporal.plus(amount / 256, YEARS)
+                            .plus((amount % 256) * 3, MONTHS);
                 default:
                     throw new IllegalStateException("Unreachable");
             }
         }
 
         @Override
-        public <R extends Temporal> SimplePeriod between(R dateTime1, R dateTime2) {
+        public long between(Temporal temporal1, Temporal temporal2) {
             switch(this) {
                 case WEEK_BASED_YEARS:
-                    long period = Math.subtractExact(dateTime2.getLong(WEEK_BASED_YEAR),
-                            dateTime1.getLong(WEEK_BASED_YEAR));
-                    return new SimplePeriod(period, WEEK_BASED_YEARS);
+                    return Math.subtractExact(temporal2.getLong(WEEK_BASED_YEAR),
+                            temporal1.getLong(WEEK_BASED_YEAR));
                 case QUARTER_YEARS:
-                    long period2 = Math.subtractExact(dateTime2.getLong(QUARTER_OF_YEAR),
-                            dateTime1.getLong(QUARTER_OF_YEAR));
-                    return new SimplePeriod(period2, QUARTER_YEARS);
+                    return temporal1.periodUntil(temporal2, MONTHS) / 3;
                 default:
                     throw new IllegalStateException("Unreachable");
             }
         }