/**
  * Resolves parsed {@code ChronoField} values into a date during parsing.
  * <p>
  * Most {@code TemporalField} implementations are resolved using the
  * resolve method on the field. By contrast, the {@code ChronoField} class
  * defines fields that only have meaning relative to the chronology.
  * As such, {@code ChronoField} date fields are resolved here in the
  * context of a specific chronology.
  * <p>
  * {@code ChronoField} instances are resolved by this method, which may
  * be overridden in subclasses.
  * <ul>
  * <li>{@code EPOCH_DAY} - If present, this is converted to a date and
  *  all other date fields are then cross-checked against the date.
  * <li>{@code PROLEPTIC_MONTH} - If present, then it is split into the
  *  {@code YEAR} and {@code MONTH_OF_YEAR}. If the mode is strict or smart
  *  then the field is validated.
  * <li>{@code YEAR_OF_ERA} and {@code ERA} - If both are present, then they
  *  are combined to form a {@code YEAR}. In lenient mode, the {@code YEAR_OF_ERA}
  *  range is not validated, in smart and strict mode it is. The {@code ERA} is
  *  validated for range in all three modes. If only the {@code YEAR_OF_ERA} is
  *  present, and the mode is smart or lenient, then the last available era
  *  is assumed. In strict mode, no era is assumed and the {@code YEAR_OF_ERA} is
  *  left untouched. If only the {@code ERA} is present, then it is left untouched.
  * <li>{@code YEAR}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} -
  *  If all three are present, then they are combined to form a date.
  *  In all three modes, the {@code YEAR} is validated.
  *  If the mode is smart or strict, then the month and day are validated.
  *  If the mode is lenient, then the date is combined in a manner equivalent to
  *  creating a date on the first day of the first month in the requested year,
  *  then adding the difference in months, then the difference in days.
  *  If the mode is smart, and the day-of-month is greater than the maximum for
  *  the year-month, then the day-of-month is adjusted to the last day-of-month.
  *  If the mode is strict, then the three fields must form a valid date.
  * <li>{@code YEAR} and {@code DAY_OF_YEAR} -
  *  If both are present, then they are combined to form a date.
  *  In all three modes, the {@code YEAR} is validated.
  *  If the mode is lenient, then the date is combined in a manner equivalent to
  *  creating a date on the first day of the requested year, then adding
  *  the difference in days.
  *  If the mode is smart or strict, then the two fields must form a valid date.
  * <li>{@code YEAR}, {@code MONTH_OF_YEAR}, {@code ALIGNED_WEEK_OF_MONTH} and
  *  {@code ALIGNED_DAY_OF_WEEK_IN_MONTH} -
  *  If all four are present, then they are combined to form a date.
  *  In all three modes, the {@code YEAR} is validated.
  *  If the mode is lenient, then the date is combined in a manner equivalent to
  *  creating a date on the first day of the first month in the requested year, then adding
  *  the difference in months, then the difference in weeks, then in days.
  *  If the mode is smart or strict, then the all four fields are validated to
  *  their outer ranges. The date is then combined in a manner equivalent to
  *  creating a date on the first day of the requested year and month, then adding
  *  the amount in weeks and days to reach their values. If the mode is strict,
  *  the date is additionally validated to check that the day and week adjustment
  *  did not change the month.
  * <li>{@code YEAR}, {@code MONTH_OF_YEAR}, {@code ALIGNED_WEEK_OF_MONTH} and
  *  {@code DAY_OF_WEEK} - If all four are present, then they are combined to
  *  form a date. The approach is the same as described above for
  *  years, months and weeks in {@code ALIGNED_DAY_OF_WEEK_IN_MONTH}.
  *  The day-of-week is adjusted as the next or same matching day-of-week once
  *  the years, months and weeks have been handled.
  * <li>{@code YEAR}, {@code ALIGNED_WEEK_OF_YEAR} and {@code ALIGNED_DAY_OF_WEEK_IN_YEAR} -
  *  If all three are present, then they are combined to form a date.
  *  In all three modes, the {@code YEAR} is validated.
  *  If the mode is lenient, then the date is combined in a manner equivalent to
  *  creating a date on the first day of the requested year, then adding
  *  the difference in weeks, then in days.
  *  If the mode is smart or strict, then the all three fields are validated to
  *  their outer ranges. The date is then combined in a manner equivalent to
  *  creating a date on the first day of the requested year, then adding
  *  the amount in weeks and days to reach their values. If the mode is strict,
  *  the date is additionally validated to check that the day and week adjustment
  *  did not change the year.
  * <li>{@code YEAR}, {@code ALIGNED_WEEK_OF_YEAR} and {@code DAY_OF_WEEK} -
  *  If all three are present, then they are combined to form a date.
  *  The approach is the same as described above for years and weeks in
  *  {@code ALIGNED_DAY_OF_WEEK_IN_YEAR}. The day-of-week is adjusted as the
  *  next or same matching day-of-week once the years and weeks have been handled.
  * </ul>
  * <p>
  * The default implementation is suitable for most calendar systems.
  * If {@link java.time.temporal.ChronoField#YEAR_OF_ERA} is found without an {@link java.time.temporal.ChronoField#ERA}
  * then the last era in {@link #eras()} is used.
  * The implementation assumes a 7 day week, that the first day-of-month
  * has the value 1, that first day-of-year has the value 1, and that the
  * first of the month and year always exists.
  *
  * @param FieldValues $fieldValues the map of fields to values, which can be updated, not null
  * @param ResolverStyle $resolverStyle the requested type of resolve, not null
  * @return ChronoLocalDate the resolved date, null if insufficient information to create a date
  * @throws DateTimeException if the date cannot be resolved, typically
  *  because of a conflict in the input data
  */
 public function resolveDate(FieldValues $fieldValues, ResolverStyle $resolverStyle)
 {
     // check epoch-day before inventing era
     if ($fieldValues->has(ChronoField::EPOCH_DAY())) {
         return $this->dateEpochDay($fieldValues->remove(ChronoField::EPOCH_DAY()));
     }
     // fix proleptic month before inventing era
     $this->resolveProlepticMonth($fieldValues, $resolverStyle);
     // invent era if necessary to resolve year-of-era
     $resolved = $this->resolveYearOfEra($fieldValues, $resolverStyle);
     if ($resolved !== null) {
         return $resolved;
     }
     // build date
     if ($fieldValues->has(ChronoField::YEAR())) {
         if ($fieldValues->has(ChronoField::MONTH_OF_YEAR())) {
             if ($fieldValues->has(ChronoField::DAY_OF_MONTH())) {
                 return $this->resolveYMD($fieldValues, $resolverStyle);
             }
             if ($fieldValues->has(ChronoField::ALIGNED_WEEK_OF_MONTH())) {
                 if ($fieldValues->has(ChronoField::ALIGNED_DAY_OF_WEEK_IN_MONTH())) {
                     return $this->resolveYMAA($fieldValues, $resolverStyle);
                 }
                 if ($fieldValues->has(ChronoField::DAY_OF_WEEK())) {
                     return $this->resolveYMAD($fieldValues, $resolverStyle);
                 }
             }
         }
         if ($fieldValues->has(ChronoField::DAY_OF_YEAR())) {
             return $this->resolveYD($fieldValues, $resolverStyle);
         }
         if ($fieldValues->has(ChronoField::ALIGNED_WEEK_OF_YEAR())) {
             if ($fieldValues->has(ChronoField::ALIGNED_DAY_OF_WEEK_IN_YEAR())) {
                 return $this->resolveYAA($fieldValues, $resolverStyle);
             }
             if ($fieldValues->has(ChronoField::DAY_OF_WEEK())) {
                 return $this->resolveYAD($fieldValues, $resolverStyle);
             }
         }
     }
     return null;
 }
 public function resolve(FieldValues $fieldValues, TemporalAccessor $partialTemporal, ResolverStyle $resolverStyle)
 {
     $value = $fieldValues->get($this);
     $newValue = Math::toIntExact($value);
     // broad limit makes overflow checking lighter
     // first convert localized day-of-week to ISO day-of-week
     // doing this first handles case where both ISO and localized were parsed and might mismatch
     // day-of-week is always strict as two different day-of-week values makes lenient complex
     if ($this->rangeUnit == ChronoUnit::WEEKS()) {
         // day-of-week
         $checkedValue = $this->range->checkValidIntValue($value, $this);
         // no leniency as too complex
         $startDow = $this->weekDef->getFirstDayOfWeek()->getValue();
         $isoDow = Math::floorMod($startDow - 1 + ($checkedValue - 1), 7) + 1;
         $fieldValues->remove($this);
         $fieldValues->put(CF::DAY_OF_WEEK(), $isoDow);
         return null;
     }
     // can only build date if ISO day-of-week is present
     if (!$fieldValues->has(CF::DAY_OF_WEEK())) {
         return null;
     }
     $isoDow = CF::DAY_OF_WEEK()->checkValidIntValue($fieldValues->get(CF::DAY_OF_WEEK()));
     $dow = $this->localizedDayOfWeekNumerical($isoDow);
     // build date
     $chrono = AbstractChronology::from($partialTemporal);
     if ($fieldValues->has(CF::YEAR())) {
         $year = CF::YEAR()->checkValidIntValue($fieldValues->get(CF::YEAR()));
         // validate
         if ($this->rangeUnit == ChronoUnit::MONTHS() && $fieldValues->has(CF::MONTH_OF_YEAR())) {
             // week-of-month
             $month = $fieldValues->get(CF::MONTH_OF_YEAR());
             // not validated yet
             return $this->resolveWoM($fieldValues, $chrono, $year, $month, $newValue, $dow, $resolverStyle);
         }
         if ($this->rangeUnit == ChronoUnit::YEARS()) {
             // week-of-year
             return $this->resolveWoY($fieldValues, $chrono, $year, $newValue, $dow, $resolverStyle);
         }
     } else {
         if (($this->rangeUnit == IsoFields::WEEK_BASED_YEARS() || $this->rangeUnit == ChronoUnit::FOREVER()) && $fieldValues->has($this->weekDef->weekBasedYear) && $fieldValues->has($this->weekDef->weekOfWeekBasedYear)) {
             // week-of-week-based-year and year-of-week-based-year
             return $this->resolveWBY($fieldValues, $chrono, $dow, $resolverStyle);
         }
     }
     return null;
 }
示例#3
0
 private function resolveFractional()
 {
     // ensure fractional seconds available as CF requires
     // resolveTimeLenient() will have merged CF::MICRO_OF_SECOND()/MILLI_OF_SECOND to NANO_OF_SECOND
     if ($this->time == null && ($this->fieldValues->has(CF::INSTANT_SECONDS()) || $this->fieldValues->has(CF::SECOND_OF_DAY()) || $this->fieldValues->has(CF::SECOND_OF_MINUTE()))) {
         if ($this->fieldValues->has(CF::NANO_OF_SECOND())) {
             $nos = $this->fieldValues->get(CF::NANO_OF_SECOND());
             $this->fieldValues->put(CF::MICRO_OF_SECOND(), Math::div($nos, 1000));
             $this->fieldValues->put(CF::MILLI_OF_SECOND(), Math::div($nos, 1000000));
         } else {
             $this->fieldValues->put(CF::NANO_OF_SECOND(), 0);
             $this->fieldValues->put(CF::MICRO_OF_SECOND(), 0);
             $this->fieldValues->put(CF::MILLI_OF_SECOND(), 0);
         }
     }
 }
 public function isSupported(TemporalField $field)
 {
     return $this->fields->has($field);
 }