text: /*
   * @copyright (c) 2016, Philipp Thürwächter & Pattrick Hüper
   * @copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos
   * @license BSD-3-Clause (see LICENSE in the root directory of this source tree)
   */
  
  import {UnsupportedTemporalTypeException, IllegalStateException} from '../errors';
  
  import {DayOfWeek} from '../DayOfWeek';
  import {Duration} from '../Duration';
  import {MathUtil} from '../MathUtil';
  import {LocalDate} from '../LocalDate';
  
  import {ChronoField} from './ChronoField';
  import {ChronoUnit} from './ChronoUnit';
  import {TemporalField} from './TemporalField';
  import {TemporalUnit} from './TemporalUnit';
  import {ValueRange} from './ValueRange';
  
  import {IsoChronology} from '../chrono/IsoChronology';
  
  import {ResolverStyle} from '../format/ResolverStyle';
  
  /**
   * Fields and units specific to the ISO-8601 calendar system,
   * including quarter-of-year and week-based-year.
   *
   * This class defines fields and units that are specific to the ISO calendar system.
   *
   * ### Quarter of year
   *
   * The ISO-8601 standard is based on the standard civic 12 month year.
   * This is commonly divided into four quarters, often abbreviated as Q1, Q2, Q3 and Q4.
   *
   * January, February and March are in Q1.
   * April, May and June are in Q2.
   * July, August and September are in Q3.
   * October, November and December are in Q4.
   *
   * The complete date is expressed using three fields:
   *
   * * {@link DAY_OF_QUARTER} - the day within the quarter, from 1 to 90, 91 or 92
   * * {@link QUARTER_OF_YEAR} - the week within the week-based-year
   * * {@link ChronoField#YEAR} - the standard ISO year
   *
   * ### Week based years
   *
   * The ISO-8601 standard was originally intended as a data interchange format,
   * defining a string format for dates and times. However, it also defines an
   * alternate way of expressing the date, based on the concept of week-based-year.
   *
   * The date is expressed using three fields:
   *
   * * {@link ChronoField#DAY_OF_WEEK} - the standard field defining the
   *   day-of-week from Monday (1) to Sunday (7)
   * * {@link WEEK_OF_WEEK_BASED_YEAR} - the week within the week-based-year
   * * {@link WEEK_BASED_YEAR} - the week-based-year
   *
   * The week-based-year itself is defined relative to the standard ISO proleptic year.
   * It differs from the standard year in that it always starts on a Monday.
   *
   * The first week of a week-based-year is the first Monday-based week of the standard
   * ISO year that has at least 4 days in the new year.
   *
   * * If January 1st is Monday then week 1 starts on January 1st
   * * If January 1st is Tuesday then week 1 starts on December 31st of the previous standard year
   * * If January 1st is Wednesday then week 1 starts on December 30th of the previous standard year
   * * If January 1st is Thursday then week 1 starts on December 29th of the previous standard year
   * * If January 1st is Friday then week 1 starts on January 4th
   * * If January 1st is Saturday then week 1 starts on January 3rd
   * * If January 1st is Sunday then week 1 starts on January 2nd
   *
   * There are 52 weeks in most week-based years, however on occasion there are 53 weeks.
   *
   * For example:
   *
   * * Sunday, 2008-12-28: Week 52 of week-based-year 2008
   * * Monday, 2008-12-29: Week 1 of week-based-year 2009
   * * Wednesday, 2008-12-31: Week 1 of week-based-year 2009
   * * Thursday, 2009-01-01: Week 1 of week-based-year 2009
   * * Sunday, 2009-01-04: Week 1 of week-based-year 2009
   * * Monday, 2009-01-05: Week 2 of week-based-year 2009
   *
   * ### Static properties of Class {@link IsoFields}
   *
   * IsoFields.DAY_OF_QUARTER
   *
   * The field that represents the day-of-quarter.
   *
   * This field allows the day-of-quarter value to be queried and set.
   * The day-of-quarter has values from 1 to 90 in Q1 of a standard year, from 1 to 91
   * in Q1 of a leap year, from 1 to 91 in Q2 and from 1 to 92 in Q3 and Q4.
   *
   * The day-of-quarter can only be calculated if the day-of-year, month-of-year and year
   * are available.
   *
   * When setting this field, the value is allowed to be partially lenient, taking any
   * value from 1 to 92. If the quarter has less than 92 days, then day 92, and
   * potentially day 91, is in the following quarter.
   *
   * IsoFields.QUARTER_OF_YEAR
   *
   * The field that represents the quarter-of-year.
   *
   * This field allows the quarter-of-year value to be queried and set.
   * The quarter-of-year has values from 1 to 4.
   *
   * The day-of-quarter can only be calculated if the month-of-year is available.
   *
   * IsoFields.WEEK_OF_WEEK_BASED_YEAR
   *
   * The field that represents the week-of-week-based-year.
   *
   * This field allows the week of the week-based-year value to be queried and set.
   *
   * IsoFields.WEEK_BASED_YEAR
   *
   * The field that represents the week-based-year.
   *
   * This field allows the week-based-year value to be queried and set.
   *
   * IsoFields.WEEK_BASED_YEARS
   *
   * The unit that represents week-based-years for the purpose of addition and subtraction.
   *
   * This allows a number of week-based-years to be added to, or subtracted from, a date.
   * The unit is equal to either 52 or 53 weeks.
   * The estimated duration of a week-based-year is the same as that of a standard ISO
   * year at 365.2425 days.
   *
   * The rules for addition add the number of week-based-years to the existing value
   * for the week-based-year field. If the resulting week-based-year only has 52 weeks,
   * then the date will be in week 1 of the following week-based-year.
   *
   * IsoFields.QUARTER_YEARS
   *
   * Unit that represents the concept of a quarter-year.
   * For the ISO calendar system, it is equal to 3 months.
   * The estimated duration of a quarter-year is one quarter of 365.2425 days.
   */
  export class IsoFields {
  }
  
  //-----------------------------------------------------------------------
  
  const QUARTER_DAYS = [0, 90, 181, 273, 0, 91, 182, 274];
  
  /**
   * Implementation of the field.
   */
  class Field extends TemporalField{
  
      /**
       *
       * @returns {boolean}
       */
      isDateBased() {
          return true;
      }
  
      /**
       *
       * @returns {boolean}
       */
      isTimeBased() {
          return false;
      }
  
      /**
       *
       * @returns {boolean}
       */
      _isIso() {
          return true;
      }
  
      /**
       *
       * @param {LocalDate} date
       * @returns {ValueRange}
       */
      static _getWeekRangeByLocalDate(date) {
          const wby = Field._getWeekBasedYear(date);
          return ValueRange.of(1, Field._getWeekRangeByYear(wby));
      }
  
      /**
       *
       * @param {number} wby
       * @returns {number}
       */
      static _getWeekRangeByYear(wby) {
          const date = LocalDate.of(wby, 1, 1);
          // 53 weeks if standard year starts on Thursday, or Wed in a leap year
          if (date.dayOfWeek() === DayOfWeek.THURSDAY || (date.dayOfWeek() === DayOfWeek.WEDNESDAY && date.isLeapYear())) {
              return 53;
          }
          return 52;
      }
  
      /**
       *
       * @param {LocalDate} date
       * @returns {number}
       */
      static _getWeek(date) {
          const dow0 = date.dayOfWeek().ordinal();
          const doy0 = date.dayOfYear() - 1;
          const doyThu0 = doy0 + (3 - dow0);  // adjust to mid-week Thursday (which is 3 indexed from zero)
          const alignedWeek = MathUtil.intDiv(doyThu0, 7);
          const firstThuDoy0 = doyThu0 - (alignedWeek * 7);
          let firstMonDoy0 = firstThuDoy0 - 3;
          if (firstMonDoy0 < -3) {
              firstMonDoy0 += 7;
          }
          if (doy0 < firstMonDoy0) {
              return Field._getWeekRangeByLocalDate(date.withDayOfYear(180).minusYears(1)).maximum();
          }
          let week = MathUtil.intDiv((doy0 - firstMonDoy0), 7) + 1;
          if (week === 53) {
              if ((firstMonDoy0 === -3 || (firstMonDoy0 === -2 && date.isLeapYear())) === false) {
                  week = 1;
              }
          }
          return week;
      }
  
      /**
       *
       * @param {LocalDate} date
       * @returns {number}
       */
      static _getWeekBasedYear(date) {
          let year = date.year();
          let doy = date.dayOfYear();
          if (doy <= 3) {
              const dow = date.dayOfWeek().ordinal();
              if (doy - dow < -2) {
                  year--;
              }
          } else if (doy >= 363) {
              const dow = date.dayOfWeek().ordinal();
              doy = doy - 363 - (date.isLeapYear() ? 1 : 0);
              if (doy - dow >= 0) {
                  year++;
              }
          }
          return year;
      }
  
      /**
       *
       * @returns {string}
       */
      getDisplayName(/*locale*/) {
          return this.toString();
      }
  
      /**
       *
       * @returns {null}
       */
      resolve() {
          return null;
      }
  
      name(){
          return this.toString();
      }
  
  }
  
  
  class DAY_OF_QUARTER_FIELD extends Field {
  
      /**
       *
       * @returns {string}
       */
      toString() {
          return 'DayOfQuarter';
      }
  
      /**
       *
       * @returns {TemporalUnit}
       */
      baseUnit() {
          return ChronoUnit.DAYS;
      }
  
      /**
       *
       * @returns {TemporalUnit}
       */
      rangeUnit() {
          return QUARTER_YEARS;
      }
  
      /**
       *
       * @returns {ValueRange}
       */
      range() {
          return ValueRange.of(1, 90, 92);
      }
  
      /**
       *
       * @param {TemporalAccessor} temporal
       * @returns {boolean}
       */
      isSupportedBy(temporal) {
          return temporal.isSupported(ChronoField.DAY_OF_YEAR) && temporal.isSupported(ChronoField.MONTH_OF_YEAR) &&
              temporal.isSupported(ChronoField.YEAR) && this._isIso(temporal);
      }
  
  
      /**
       *
       * @param {TemporalAccessor} temporal
       * @returns {ValueRange}
       */
      rangeRefinedBy(temporal) {
          if (temporal.isSupported(this) === false) {
              throw new UnsupportedTemporalTypeException('Unsupported field: DayOfQuarter');
          }
          const qoy = temporal.getLong(QUARTER_OF_YEAR);
          if (qoy === 1) {
              const year = temporal.getLong(ChronoField.YEAR);
              return (IsoChronology.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 this.range();
      }
  
      /**
       *
       * @param {TemporalAccessor} temporal
       * @returns {number}
       */
      getFrom(temporal) {
          if (temporal.isSupported(this) === false) {
              throw new UnsupportedTemporalTypeException('Unsupported field: DayOfQuarter');
          }
          const doy = temporal.get(ChronoField.DAY_OF_YEAR);
          const moy = temporal.get(ChronoField.MONTH_OF_YEAR);
          const year = temporal.getLong(ChronoField.YEAR);
          return doy - QUARTER_DAYS[MathUtil.intDiv((moy - 1), 3) + (IsoChronology.isLeapYear(year) ? 4 : 0)];
      }
  
      /**
       *
       * @param {Temporal} temporal
       * @param {number} newValue
       * @returns {temporal}
       */
      adjustInto(temporal, newValue) {
          const curValue = this.getFrom(temporal);
          this.range().checkValidValue(newValue, this);
          return temporal.with(ChronoField.DAY_OF_YEAR, temporal.getLong(ChronoField.DAY_OF_YEAR) + (newValue - curValue));
      }
  
      /**
       *
       * @param {Map<TemporalField, number>} fieldValues
       * @param {TemporalAccessor} partialTemporal
       * @param {ResolverStyle} resolverStyle
       * @returns {ValueRange}
       */
      resolve(fieldValues, partialTemporal, resolverStyle) {
          const yearLong = fieldValues.get(ChronoField.YEAR);
          const qoyLong = fieldValues.get(QUARTER_OF_YEAR);
          if (yearLong == null || qoyLong == null) {
              return null;
          }
          const y = ChronoField.YEAR.checkValidIntValue(yearLong);
          const doq = fieldValues.get(DAY_OF_QUARTER);
          let date;
          if (resolverStyle === ResolverStyle.LENIENT) {
              const qoy = qoyLong;
              date = LocalDate.of(y, 1, 1);
              date = date.plusMonths(MathUtil.safeMultiply(MathUtil.safeSubtract(qoy, 1), 3));
              date = date.plusDays(MathUtil.safeSubtract(doq, 1));
          } else {
              const qoy = QUARTER_OF_YEAR.range().checkValidIntValue(qoyLong, QUARTER_OF_YEAR);
              if (resolverStyle === ResolverStyle.STRICT) {
                  let max = 92;
                  if (qoy === 1) {
                      max = (IsoChronology.isLeapYear(y) ? 91 : 90);
                  } else if (qoy === 2) {
                      max = 91;
                  }
                  ValueRange.of(1, max).checkValidValue(doq, this);
              } else {
                  this.range().checkValidValue(doq, this);  // leniently check from 1 to 92
              }
              date = LocalDate.of(y, ((qoy - 1) * 3) + 1, 1).plusDays(doq - 1);
          }
          fieldValues.remove(this);
          fieldValues.remove(ChronoField.YEAR);
          fieldValues.remove(QUARTER_OF_YEAR);
          return date;
      }
  }
  
  class QUARTER_OF_YEAR_FIELD extends Field {
  
      /**
       *
       * @returns {string}
       */
      toString() {
          return 'QuarterOfYear';
      }
  
      /**
       *
       * @returns {TemporalUnit}
       */
      baseUnit() {
          return QUARTER_YEARS;
      }
  
      /**
       *
       * @returns {TemporalUnit}
       */
      rangeUnit() {
          return ChronoUnit.YEARS;
      }
  
      /**
       *
       * @returns {ValueRange}
       */
      range() {
          return ValueRange.of(1, 4);
      }
  
      /**
       *
       * @param {TemporalAccessor} temporal
       * @returns {boolean}
       */
      isSupportedBy(temporal) {
          return temporal.isSupported(ChronoField.MONTH_OF_YEAR) && this._isIso(temporal);
      }
  
  
      /**
       *
       * @param {TemporalAccessor} temporal
       * @returns {ValueRange}
       */
      //eslint-disable-next-line no-unused-vars
      rangeRefinedBy(temporal) {
          return this.range();
      }
  
      /**
       *
       * @param {TemporalAccessor} temporal
       * @returns {number}
       */
      getFrom(temporal) {
          if (temporal.isSupported(this) === false) {
              throw new UnsupportedTemporalTypeException('Unsupported field: QuarterOfYear');
          }
          const moy = temporal.getLong(ChronoField.MONTH_OF_YEAR);
          return MathUtil.intDiv((moy + 2), 3);
      }
  
      /**
       *
       * @param {Temporal} temporal
       * @param {number} newValue
       * @returns {temporal}
       */
      adjustInto(temporal, newValue) {
          const curValue = this.getFrom(temporal);
          this.range().checkValidValue(newValue, this);
          return temporal.with(ChronoField.MONTH_OF_YEAR, temporal.getLong(ChronoField.MONTH_OF_YEAR) + (newValue - curValue) * 3);
      }
  
  }
  
  class WEEK_OF_WEEK_BASED_YEAR_FIELD extends Field {
  
      /**
       *
       * @returns {string}
       */
      toString() {
          return 'WeekOfWeekBasedYear';
      }
  
      /**
       *
       * @returns {TemporalUnit}
       */
      baseUnit() {
          return ChronoUnit.WEEKS;
      }
  
      /**
       *
       * @returns {TemporalUnit}
       */
      rangeUnit() {
          return WEEK_BASED_YEARS;
      }
  
      /**
       *
       * @returns {ValueRange}
       */
      range() {
          return ValueRange.of(1, 52, 53);
      }
  
      /**
       *
       * @param {TemporalAccessor} temporal
       * @returns {boolean}
       */
      isSupportedBy(temporal) {
          return temporal.isSupported(ChronoField.EPOCH_DAY) && this._isIso(temporal);
      }
  
  
      /**
       *
       * @param {TemporalAccessor} temporal
       * @returns {ValueRange}
       */
      rangeRefinedBy(temporal) {
          if (temporal.isSupported(this) === false) {
              throw new UnsupportedTemporalTypeException('Unsupported field: WeekOfWeekBasedYear');
          }
          return Field._getWeekRangeByLocalDate(LocalDate.from(temporal));
      }
  
      /**
       *
       * @param {TemporalAccessor} temporal
       * @returns {number}
       */
      getFrom(temporal) {
          if (temporal.isSupported(this) === false) {
              throw new UnsupportedTemporalTypeException('Unsupported field: WeekOfWeekBasedYear');
          }
          return Field._getWeek(LocalDate.from(temporal));
      }
  
      /**
       *
       * @param {Temporal} temporal
       * @param {number} newValue
       * @returns {temporal}
       */
      adjustInto(temporal, newValue) {
          this.range().checkValidValue(newValue, this);
          return temporal.plus(MathUtil.safeSubtract(newValue, this.getFrom(temporal)), ChronoUnit.WEEKS);
      }
  
      /**
       *
       * @param {Map<TemporalField, number>} fieldValues
       * @param {TemporalAccessor} partialTemporal
       * @param {ResolverStyle} resolverStyle
       * @returns {ValueRange}
       */
      resolve(fieldValues, partialTemporal, resolverStyle) {
          const wbyLong = fieldValues.get(WEEK_BASED_YEAR);
          const dowLong = fieldValues.get(ChronoField.DAY_OF_WEEK);
          if (wbyLong == null || dowLong == null) {
              return null;
          }
          const wby = WEEK_BASED_YEAR.range().checkValidIntValue(wbyLong, WEEK_BASED_YEAR);
          const wowby = fieldValues.get(WEEK_OF_WEEK_BASED_YEAR);
          let date;
          if (resolverStyle === ResolverStyle.LENIENT) {
              let dow = dowLong;
              let weeks = 0;
              if (dow > 7) {
                  weeks = MathUtil.intDiv((dow - 1), 7);
                  dow = (MathUtil.intMod((dow - 1), 7) + 1);
              } else if (dow < 1) {
                  weeks = MathUtil.intDiv(dow, 7) - 1;
                  dow = MathUtil.intMod(dow, 7) + 7;
              }
              date = LocalDate.of(wby, 1, 4).plusWeeks(wowby - 1).plusWeeks(weeks).with(ChronoField.DAY_OF_WEEK, dow);
          } else {
              const dow = ChronoField.DAY_OF_WEEK.checkValidIntValue(dowLong);
              if (resolverStyle === ResolverStyle.STRICT) {
                  const temp = LocalDate.of(wby, 1, 4);
                  const range = Field._getWeekRangeByLocalDate(temp);
                  range.checkValidValue(wowby, this);
              } else {
                  this.range().checkValidValue(wowby, this);  // leniently check from 1 to 53
              }
              date = LocalDate.of(wby, 1, 4).plusWeeks(wowby - 1).with(ChronoField.DAY_OF_WEEK, dow);
          }
          fieldValues.remove(this);
          fieldValues.remove(WEEK_BASED_YEAR);
          fieldValues.remove(ChronoField.DAY_OF_WEEK);
          return date;
      }
  
      /**
       *
       * @returns {string}
       */
      getDisplayName() {
          return 'Week';
      }
  
  }
  
  class WEEK_BASED_YEAR_FIELD extends Field {
  
      /**
       *
       * @returns {string}
       */
      toString() {
          return 'WeekBasedYear';
      }
  
      /**
       *
       * @returns {TemporalUnit}
       */
      baseUnit() {
          return WEEK_BASED_YEARS;
      }
  
      /**
       *
       * @returns {TemporalUnit}
       */
      rangeUnit() {
          return ChronoUnit.FOREVER;
      }
  
      /**
       *
       * @returns {ValueRange}
       */
      range() {
          return ChronoField.YEAR.range();
      }
  
      /**
       *
       * @param {TemporalAccessor} temporal
       * @returns {boolean}
       */
      isSupportedBy(temporal) {
          return temporal.isSupported(ChronoField.EPOCH_DAY) && this._isIso(temporal);
      }
  
  
      /**
       *
       * @param {TemporalAccessor} temporal
       * @returns {ValueRange}
       */
      //eslint-disable-next-line no-unused-vars
      rangeRefinedBy(temporal) {
          return ChronoField.YEAR.range();
      }
  
      /**
       *
       * @param {TemporalAccessor} temporal
       * @returns {number}
       */
      getFrom(temporal) {
          if (temporal.isSupported(this) === false) {
              throw new UnsupportedTemporalTypeException('Unsupported field: WeekBasedYear');
          }
          return Field._getWeekBasedYear(LocalDate.from(temporal));
      }
  
      /**
       *
       * @param {Temporal} temporal
       * @param {number} newValue
       * @returns {temporal}
       */
      adjustInto(temporal, newValue) {
          if (this.isSupportedBy(temporal) === false) {
              throw new UnsupportedTemporalTypeException('Unsupported field: WeekBasedYear');
          }
          const newWby = this.range().checkValidIntValue(newValue, WEEK_BASED_YEAR);  // strict check
          const date = LocalDate.from(temporal);
          const dow = date.get(ChronoField.DAY_OF_WEEK);
          let week = Field._getWeek(date);
          if (week === 53 && Field._getWeekRangeByYear(newWby) === 52) {
              week = 52;
          }
          let resolved = LocalDate.of(newWby, 1, 4);  // 4th is guaranteed to be in week one
          const days = (dow - resolved.get(ChronoField.DAY_OF_WEEK)) + ((week - 1) * 7);
          resolved = resolved.plusDays(days);
          return temporal.with(resolved);
      }
  
  }
  
  //-----------------------------------------------------------------------
  /**
   * Implementation of the period unit.
   */
  class Unit extends TemporalUnit {
  
      /**
       *
       * @param {string} name
       * @param {Duration} estimatedDuration
       * @private
       */
      constructor(name, estimatedDuration) {
          super();
          this._name = name;
          this._duration = estimatedDuration;
      }
  
      /**
       *
       * @returns {Duration}
       */
      duration() {
          return this._duration;
      }
  
      /**
       *
       * @returns {boolean}
       */
      isDurationEstimated() {
          return true;
      }
  
      /**
       *
       * @returns {boolean}
       */
      isDateBased() {
          return true;
      }
  
      /**
       *
       * @returns {boolean}
       */
      isTimeBased() {
          return false;
      }
  
      /**
       *
       * @param {Temporal} temporal
       * @returns {boolean}
       */
      isSupportedBy(temporal) {
          return temporal.isSupported(ChronoField.EPOCH_DAY);
      }
  
      /**
       *
       * @param {Temporal} temporal
       * @param {number} periodToAdd
       * @returns {number}
       */
      addTo(temporal, periodToAdd) {
          switch(this) {
              case WEEK_BASED_YEARS: {
                  const added = MathUtil.safeAdd(temporal.get(WEEK_BASED_YEAR), periodToAdd);
                  return temporal.with(WEEK_BASED_YEAR, added);
              }
              case QUARTER_YEARS:
                  // no overflow (256 is multiple of 4)
                  return temporal.plus(MathUtil.intDiv(periodToAdd, 256), ChronoUnit.YEARS).plus(MathUtil.intMod(periodToAdd, 256) * 3, ChronoUnit.MONTHS);
              default:
                  throw new IllegalStateException('Unreachable');
          }
      }
  
      /**
       *
       * @param {Temporal} temporal1
       * @param {Temporal} temporal2
       * @returns {number}
       */
      between(temporal1, temporal2) {
          switch(this) {
              case WEEK_BASED_YEARS:
                  return MathUtil.safeSubtract(temporal2.getLong(WEEK_BASED_YEAR), temporal1.getLong(WEEK_BASED_YEAR));
              case QUARTER_YEARS:
                  return MathUtil.intDiv(temporal1.until(temporal2, ChronoUnit.MONTHS), 3);
              default:
                  throw new IllegalStateException('Unreachable');
          }
      }
  
      toString() {
          return name;
      }
  }
  
  let DAY_OF_QUARTER = null;
  let QUARTER_OF_YEAR = null;
  let WEEK_OF_WEEK_BASED_YEAR = null;
  let WEEK_BASED_YEAR = null;
  let WEEK_BASED_YEARS = null;
  let QUARTER_YEARS = null;
  
  export function _init() {
      DAY_OF_QUARTER = new DAY_OF_QUARTER_FIELD();
      QUARTER_OF_YEAR = new QUARTER_OF_YEAR_FIELD();
      WEEK_OF_WEEK_BASED_YEAR = new WEEK_OF_WEEK_BASED_YEAR_FIELD();
      WEEK_BASED_YEAR = new WEEK_BASED_YEAR_FIELD();
  
      WEEK_BASED_YEARS = new Unit('WeekBasedYears', Duration.ofSeconds(31556952));
      QUARTER_YEARS = new Unit('QuarterYears', Duration.ofSeconds(31556952 / 4));
  
      IsoFields.DAY_OF_QUARTER = DAY_OF_QUARTER;
      IsoFields.QUARTER_OF_YEAR = QUARTER_OF_YEAR;
      IsoFields.WEEK_OF_WEEK_BASED_YEAR = WEEK_OF_WEEK_BASED_YEAR;
      IsoFields.WEEK_BASED_YEAR = WEEK_BASED_YEAR;
      IsoFields.WEEK_BASED_YEARS = WEEK_BASED_YEARS;
      IsoFields.QUARTER_YEARS = QUARTER_YEARS;
  
      // this differs from threeten, but for ease of use we bring back good old joda time functionality
      /**
       * the week of the week based year as defined by the ISO8601 Standard with a Monday-based week
       *
       * @returns {number} the week a the week based year
       */
      LocalDate.prototype.isoWeekOfWeekyear = function () {
          return this.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR);
      };
      /**
       * the year of the week based year as defined by the ISO8601 Standard with a Monday-based week
       *
       * @returns {number} the year a the week based year
       */
      LocalDate.prototype.isoWeekyear = function () {
          return this.get(IsoFields.WEEK_BASED_YEAR);
      };
  }
  