src/share/classes/java/time/chrono/Chronology.java

Print this page




  57  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  58  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  59  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  60  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  61  */
  62 package java.time.chrono;
  63 
  64 import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH;
  65 import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR;
  66 import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH;
  67 import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR;
  68 import static java.time.temporal.ChronoField.DAY_OF_MONTH;
  69 import static java.time.temporal.ChronoField.DAY_OF_WEEK;
  70 import static java.time.temporal.ChronoField.DAY_OF_YEAR;
  71 import static java.time.temporal.ChronoField.EPOCH_DAY;
  72 import static java.time.temporal.ChronoField.ERA;
  73 import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
  74 import static java.time.temporal.ChronoField.PROLEPTIC_MONTH;
  75 import static java.time.temporal.ChronoField.YEAR;
  76 import static java.time.temporal.ChronoField.YEAR_OF_ERA;



  77 import static java.time.temporal.TemporalAdjuster.nextOrSame;
  78 
  79 import java.io.DataInput;
  80 import java.io.DataOutput;
  81 import java.io.IOException;
  82 import java.io.InvalidObjectException;
  83 import java.io.ObjectStreamException;
  84 import java.io.Serializable;
  85 import java.time.Clock;
  86 import java.time.DateTimeException;
  87 import java.time.DayOfWeek;
  88 import java.time.Instant;
  89 import java.time.LocalDate;
  90 import java.time.LocalTime;


  91 import java.time.ZoneId;
  92 import java.time.format.DateTimeFormatterBuilder;
  93 import java.time.format.ResolverStyle;
  94 import java.time.format.TextStyle;
  95 import java.time.temporal.ChronoField;
  96 import java.time.temporal.ChronoUnit;
  97 import java.time.temporal.Temporal;
  98 import java.time.temporal.TemporalAccessor;

  99 import java.time.temporal.TemporalField;
 100 import java.time.temporal.TemporalQuery;
 101 import java.time.temporal.UnsupportedTemporalTypeException;
 102 import java.time.temporal.ValueRange;
 103 import java.util.Comparator;
 104 import java.util.HashSet;
 105 import java.util.List;
 106 import java.util.Locale;
 107 import java.util.Map;
 108 import java.util.Objects;
 109 import java.util.ServiceLoader;
 110 import java.util.Set;
 111 import java.util.concurrent.ConcurrentHashMap;
 112 
 113 import sun.util.logging.PlatformLogger;
 114 
 115 /**
 116  * A calendar system, used to organize and identify dates.
 117  * <p>
 118  * The main date and time API is built on the ISO calendar system.


 171  * For lookup by id or calendarType, the system provided calendars are found
 172  * first followed by application provided calendars.
 173  * <p>
 174  * Each chronology must define a chronology ID that is unique within the system.
 175  * If the chronology represents a calendar system defined by the
 176  * CLDR specification then the calendar type is the concatenation of the
 177  * CLDR type and, if applicable, the CLDR variant,
 178  *
 179  * @implSpec
 180  * This class must be implemented with care to ensure other classes operate correctly.
 181  * All implementations that can be instantiated must be final, immutable and thread-safe.
 182  * Subclasses should be Serializable wherever possible.
 183  *
 184  * @since 1.8
 185  */
 186 public abstract class Chronology implements Comparable<Chronology> {
 187 
 188     /**
 189      * ChronoLocalDate order constant.
 190      */
 191     static final Comparator<ChronoLocalDate<?>> DATE_ORDER =
 192         (Comparator<ChronoLocalDate<?>> & Serializable) (date1, date2) -> {
 193             return Long.compare(date1.toEpochDay(), date2.toEpochDay());
 194         };
 195     /**
 196      * ChronoLocalDateTime order constant.
 197      */
 198     static final Comparator<ChronoLocalDateTime<?>> DATE_TIME_ORDER =
 199         (Comparator<ChronoLocalDateTime<?>> & Serializable) (dateTime1, dateTime2) -> {
 200             int cmp = Long.compare(dateTime1.toLocalDate().toEpochDay(), dateTime2.toLocalDate().toEpochDay());
 201             if (cmp == 0) {
 202                 cmp = Long.compare(dateTime1.toLocalTime().toNanoOfDay(), dateTime2.toLocalTime().toNanoOfDay());
 203             }
 204             return cmp;
 205         };
 206     /**
 207      * ChronoZonedDateTime order constant.
 208      */
 209     static final Comparator<ChronoZonedDateTime<?>> INSTANT_ORDER =
 210             (Comparator<ChronoZonedDateTime<?>> & Serializable) (dateTime1, dateTime2) -> {
 211                 int cmp = Long.compare(dateTime1.toEpochSecond(), dateTime2.toEpochSecond());
 212                 if (cmp == 0) {


 465         HashSet<Chronology> chronos = new HashSet<>(CHRONOS_BY_ID.values());
 466 
 467         /// Add in Chronologies from the ServiceLoader configuration
 468         @SuppressWarnings("rawtypes")
 469         ServiceLoader<Chronology> loader = ServiceLoader.load(Chronology.class);
 470         for (Chronology chrono : loader) {
 471             chronos.add(chrono);
 472         }
 473         return chronos;
 474     }
 475 
 476     //-----------------------------------------------------------------------
 477     /**
 478      * Creates an instance.
 479      */
 480     protected Chronology() {
 481     }
 482 
 483     //-----------------------------------------------------------------------
 484     /**
 485      * Casts the {@code Temporal} to {@code ChronoLocalDate} with the same chronology.
 486      *
 487      * @param temporal  a date-time to cast, not null
 488      * @return the date-time checked and cast to {@code ChronoLocalDate}, not null
 489      * @throws ClassCastException if the date-time cannot be cast to ChronoLocalDate
 490      *  or the chronology is not equal this Chronology
 491      */
 492     ChronoLocalDate<?> ensureChronoLocalDate(Temporal temporal) {
 493         @SuppressWarnings("unchecked")
 494         ChronoLocalDate<?> other = (ChronoLocalDate<?>) temporal;
 495         if (this.equals(other.getChronology()) == false) {
 496             throw new ClassCastException("Chronology mismatch, expected: " + getId() + ", actual: " + other.getChronology().getId());
 497         }
 498         return other;
 499     }
 500 
 501     /**
 502      * Casts the {@code Temporal} to {@code ChronoLocalDateTime} with the same chronology.
 503      *
 504      * @param temporal   a date-time to cast, not null
 505      * @return the date-time checked and cast to {@code ChronoLocalDateTime}, not null
 506      * @throws ClassCastException if the date-time cannot be cast to ChronoLocalDateTimeImpl
 507      *  or the chronology is not equal this Chronology
 508      */
 509     ChronoLocalDateTimeImpl<?> ensureChronoLocalDateTime(Temporal temporal) {
 510         @SuppressWarnings("unchecked")
 511         ChronoLocalDateTimeImpl<?> other = (ChronoLocalDateTimeImpl<?>) temporal;
 512         if (this.equals(other.toLocalDate().getChronology()) == false) {
 513             throw new ClassCastException("Chronology mismatch, required: " + getId()
 514                     + ", supplied: " + other.toLocalDate().getChronology().getId());
 515         }
 516         return other;
 517     }
 518 
 519     /**
 520      * Casts the {@code Temporal} to {@code ChronoZonedDateTimeImpl} with the same chronology.
 521      *
 522      * @param temporal  a date-time to cast, not null
 523      * @return the date-time checked and cast to {@code ChronoZonedDateTimeImpl}, not null
 524      * @throws ClassCastException if the date-time cannot be cast to ChronoZonedDateTimeImpl
 525      *  or the chronology is not equal this Chronology
 526      */
 527     ChronoZonedDateTimeImpl<?> ensureChronoZonedDateTime(Temporal temporal) {
 528         @SuppressWarnings("unchecked")
 529         ChronoZonedDateTimeImpl<?> other = (ChronoZonedDateTimeImpl<?>) temporal;
 530         if (this.equals(other.toLocalDate().getChronology()) == false) {
 531             throw new ClassCastException("Chronology mismatch, required: " + getId()
 532                     + ", supplied: " + other.toLocalDate().getChronology().getId());
 533         }
 534         return other;
 535     }
 536 
 537     //-----------------------------------------------------------------------
 538     /**
 539      * Gets the ID of the chronology.
 540      * <p>
 541      * The ID uniquely identifies the {@code Chronology}.
 542      * It can be used to lookup the {@code Chronology} using {@link #of(String)}.
 543      *
 544      * @return the chronology ID, not null
 545      * @see #getCalendarType()
 546      */
 547     public abstract String getId();
 548 
 549     /**
 550      * Gets the calendar type of the calendar system.
 551      * <p>
 552      * The calendar type is an identifier defined by the CLDR and
 553      * <em>Unicode Locale Data Markup Language (LDML)</em> specifications
 554      * to uniquely identification a calendar.
 555      * The {@code getCalendarType} is the concatenation of the CLDR calendar type
 556      * and the variant, if applicable, is appended separated by "-".
 557      * The calendar type is used to lookup the {@code Chronology} using {@link #of(String)}.
 558      *
 559      * @return the calendar system type, null if the calendar is not defined by CLDR/LDML
 560      * @see #getId()
 561      */
 562     public abstract String getCalendarType();
 563 
 564     //-----------------------------------------------------------------------
 565     /**
 566      * Obtains a local date in this chronology from the era, year-of-era,
 567      * month-of-year and day-of-month fields.
 568      *
 569      * @param era  the era of the correct type for the chronology, not null
 570      * @param yearOfEra  the chronology year-of-era
 571      * @param month  the chronology month-of-year
 572      * @param dayOfMonth  the chronology day-of-month
 573      * @return the local date in this chronology, not null
 574      * @throws DateTimeException if unable to create the date
 575      * @throws ClassCastException if the {@code era} is not of the correct type for the chronology
 576      */
 577     public ChronoLocalDate<?> date(Era era, int yearOfEra, int month, int dayOfMonth) {
 578         return date(prolepticYear(era, yearOfEra), month, dayOfMonth);
 579     }
 580 
 581     /**
 582      * Obtains a local date in this chronology from the proleptic-year,
 583      * month-of-year and day-of-month fields.
 584      *
 585      * @param prolepticYear  the chronology proleptic-year
 586      * @param month  the chronology month-of-year
 587      * @param dayOfMonth  the chronology day-of-month
 588      * @return the local date in this chronology, not null
 589      * @throws DateTimeException if unable to create the date
 590      */
 591     public abstract ChronoLocalDate<?> date(int prolepticYear, int month, int dayOfMonth);
 592 
 593     /**
 594      * Obtains a local date in this chronology from the era, year-of-era and
 595      * day-of-year fields.
 596      *
 597      * @param era  the era of the correct type for the chronology, not null
 598      * @param yearOfEra  the chronology year-of-era
 599      * @param dayOfYear  the chronology day-of-year
 600      * @return the local date in this chronology, not null
 601      * @throws DateTimeException if unable to create the date
 602      * @throws ClassCastException if the {@code era} is not of the correct type for the chronology
 603      */
 604     public ChronoLocalDate<?> dateYearDay(Era era, int yearOfEra, int dayOfYear) {
 605         return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear);
 606     }
 607 
 608     /**
 609      * Obtains a local date in this chronology from the proleptic-year and
 610      * day-of-year fields.
 611      *
 612      * @param prolepticYear  the chronology proleptic-year
 613      * @param dayOfYear  the chronology day-of-year
 614      * @return the local date in this chronology, not null
 615      * @throws DateTimeException if unable to create the date
 616      */
 617     public abstract ChronoLocalDate<?> dateYearDay(int prolepticYear, int dayOfYear);
 618 
 619     /**
 620      * Obtains a local date in this chronology from the epoch-day.
 621      * <p>
 622      * The definition of {@link ChronoField#EPOCH_DAY EPOCH_DAY} is the same
 623      * for all calendar systems, thus it can be used for conversion.
 624      *
 625      * @param epochDay  the epoch day
 626      * @return the local date in this chronology, not null
 627      * @throws DateTimeException if unable to create the date
 628      */
 629     public abstract ChronoLocalDate<?> dateEpochDay(long epochDay);
 630 
 631     //-----------------------------------------------------------------------
 632     /**
 633      * Obtains the current local date in this chronology from the system clock in the default time-zone.
 634      * <p>
 635      * This will query the {@link Clock#systemDefaultZone() system clock} in the default
 636      * time-zone to obtain the current date.
 637      * <p>
 638      * Using this method will prevent the ability to use an alternate clock for testing
 639      * because the clock is hard-coded.
 640      * <p>
 641      * This implementation uses {@link #dateNow(Clock)}.
 642      *
 643      * @return the current local date using the system clock and default time-zone, not null
 644      * @throws DateTimeException if unable to create the date
 645      */
 646     public ChronoLocalDate<?> dateNow() {
 647         return dateNow(Clock.systemDefaultZone());
 648     }
 649 
 650     /**
 651      * Obtains the current local date in this chronology from the system clock in the specified time-zone.
 652      * <p>
 653      * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date.
 654      * Specifying the time-zone avoids dependence on the default time-zone.
 655      * <p>
 656      * Using this method will prevent the ability to use an alternate clock for testing
 657      * because the clock is hard-coded.
 658      *
 659      * @param zone  the zone ID to use, not null
 660      * @return the current local date using the system clock, not null
 661      * @throws DateTimeException if unable to create the date
 662      */
 663     public ChronoLocalDate<?> dateNow(ZoneId zone) {
 664         return dateNow(Clock.system(zone));
 665     }
 666 
 667     /**
 668      * Obtains the current local date in this chronology from the specified clock.
 669      * <p>
 670      * This will query the specified clock to obtain the current date - today.
 671      * Using this method allows the use of an alternate clock for testing.
 672      * The alternate clock may be introduced using {@link Clock dependency injection}.
 673      *
 674      * @param clock  the clock to use, not null
 675      * @return the current local date, not null
 676      * @throws DateTimeException if unable to create the date
 677      */
 678     public ChronoLocalDate<?> dateNow(Clock clock) {
 679         Objects.requireNonNull(clock, "clock");
 680         return date(LocalDate.now(clock));
 681     }
 682 
 683     //-----------------------------------------------------------------------
 684     /**
 685      * Obtains a local date in this chronology from another temporal object.
 686      * <p>
 687      * This obtains a date in this chronology based on the specified temporal.
 688      * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
 689      * which this factory converts to an instance of {@code ChronoLocalDate}.
 690      * <p>
 691      * The conversion typically uses the {@link ChronoField#EPOCH_DAY EPOCH_DAY}
 692      * field, which is standardized across calendar systems.
 693      * <p>
 694      * This method matches the signature of the functional interface {@link TemporalQuery}
 695      * allowing it to be used as a query via method reference, {@code aChronology::date}.
 696      *
 697      * @param temporal  the temporal object to convert, not null
 698      * @return the local date in this chronology, not null
 699      * @throws DateTimeException if unable to create the date
 700      * @see ChronoLocalDate#from(TemporalAccessor)
 701      */
 702     public abstract ChronoLocalDate<?> date(TemporalAccessor temporal);
 703 
 704     /**
 705      * Obtains a local date-time in this chronology from another temporal object.
 706      * <p>
 707      * This obtains a date-time in this chronology based on the specified temporal.
 708      * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
 709      * which this factory converts to an instance of {@code ChronoLocalDateTime}.
 710      * <p>
 711      * The conversion extracts and combines the {@code ChronoLocalDate} and the
 712      * {@code LocalTime} from the temporal object.
 713      * Implementations are permitted to perform optimizations such as accessing
 714      * those fields that are equivalent to the relevant objects.
 715      * The result uses this chronology.
 716      * <p>
 717      * This method matches the signature of the functional interface {@link TemporalQuery}
 718      * allowing it to be used as a query via method reference, {@code aChronology::localDateTime}.
 719      *
 720      * @param temporal  the temporal object to convert, not null
 721      * @return the local date-time in this chronology, not null
 722      * @throws DateTimeException if unable to create the date-time
 723      * @see ChronoLocalDateTime#from(TemporalAccessor)
 724      */
 725     public ChronoLocalDateTime<?> localDateTime(TemporalAccessor temporal) {
 726         try {
 727             return date(temporal).atTime(LocalTime.from(temporal));
 728         } catch (DateTimeException ex) {
 729             throw new DateTimeException("Unable to obtain ChronoLocalDateTime from TemporalAccessor: " + temporal.getClass(), ex);
 730         }
 731     }
 732 
 733     /**
 734      * Obtains a {@code ChronoZonedDateTime} in this chronology from another temporal object.
 735      * <p>
 736      * This obtains a zoned date-time in this chronology based on the specified temporal.
 737      * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
 738      * which this factory converts to an instance of {@code ChronoZonedDateTime}.
 739      * <p>
 740      * The conversion will first obtain a {@code ZoneId} from the temporal object,
 741      * falling back to a {@code ZoneOffset} if necessary. It will then try to obtain
 742      * an {@code Instant}, falling back to a {@code ChronoLocalDateTime} if necessary.
 743      * The result will be either the combination of {@code ZoneId} or {@code ZoneOffset}
 744      * with {@code Instant} or {@code ChronoLocalDateTime}.
 745      * Implementations are permitted to perform optimizations such as accessing
 746      * those fields that are equivalent to the relevant objects.
 747      * The result uses this chronology.
 748      * <p>
 749      * This method matches the signature of the functional interface {@link TemporalQuery}
 750      * allowing it to be used as a query via method reference, {@code aChronology::zonedDateTime}.
 751      *
 752      * @param temporal  the temporal object to convert, not null
 753      * @return the zoned date-time in this chronology, not null
 754      * @throws DateTimeException if unable to create the date-time
 755      * @see ChronoZonedDateTime#from(TemporalAccessor)
 756      */
 757     public ChronoZonedDateTime<?> zonedDateTime(TemporalAccessor temporal) {
 758         try {
 759             ZoneId zone = ZoneId.from(temporal);
 760             try {
 761                 Instant instant = Instant.from(temporal);
 762                 return zonedDateTime(instant, zone);
 763 
 764             } catch (DateTimeException ex1) {
 765                 @SuppressWarnings("rawtypes")
 766                 ChronoLocalDateTimeImpl cldt = ensureChronoLocalDateTime(localDateTime(temporal));
 767                 return ChronoZonedDateTimeImpl.ofBest(cldt, zone, null);
 768             }
 769         } catch (DateTimeException ex) {
 770             throw new DateTimeException("Unable to obtain ChronoZonedDateTime from TemporalAccessor: " + temporal.getClass(), ex);
 771         }
 772     }
 773 
 774     /**
 775      * Obtains a {@code ChronoZonedDateTime} in this chronology from an {@code Instant}.
 776      * <p>
 777      * This obtains a zoned date-time with the same instant as that specified.
 778      *
 779      * @param instant  the instant to create the date-time from, not null
 780      * @param zone  the time-zone, not null
 781      * @return the zoned date-time, not null
 782      * @throws DateTimeException if the result exceeds the supported range
 783      */
 784     public ChronoZonedDateTime<?> zonedDateTime(Instant instant, ZoneId zone) {
 785         return ChronoZonedDateTimeImpl.ofInstant(this, instant, zone);
 786     }
 787 
 788     //-----------------------------------------------------------------------
 789     /**
 790      * Checks if the specified year is a leap year.
 791      * <p>
 792      * A leap-year is a year of a longer length than normal.
 793      * The exact meaning is determined by the chronology according to the following constraints.
 794      * <p><ul>
 795      * <li>a leap-year must imply a year-length longer than a non leap-year.
 796      * <li>a chronology that does not support the concept of a year must return false.
 797      * </ul><p>
 798      *
 799      * @param prolepticYear  the proleptic-year to check, not validated for range
 800      * @return true if the year is a leap year
 801      */
 802     public abstract boolean isLeapYear(long prolepticYear);
 803 
 804     /**


 912             @Override
 913             public <R> R query(TemporalQuery<R> query) {
 914                 if (query == TemporalQuery.chronology()) {
 915                     return (R) Chronology.this;
 916                 }
 917                 return TemporalAccessor.super.query(query);
 918             }
 919         };
 920     }
 921 
 922     //-----------------------------------------------------------------------
 923     /**
 924      * Resolves parsed {@code ChronoField} values into a date during parsing.
 925      * <p>
 926      * Most {@code TemporalField} implementations are resolved using the
 927      * resolve method on the field. By contrast, the {@code ChronoField} class
 928      * defines fields that only have meaning relative to the chronology.
 929      * As such, {@code ChronoField} date fields are resolved here in the
 930      * context of a specific chronology.
 931      * <p>






































































 932      * The default implementation is suitable for most calendar systems.
 933      * If {@link ChronoField#YEAR_OF_ERA} is found without an {@link ChronoField#ERA}
 934      * then the last era in {@link #eras()} is used.
 935      * The implementation assumes a 7 day week, that the first day-of-month
 936      * has the value 1, and that first day-of-year has the value 1.

 937      *
 938      * @param fieldValues  the map of fields to values, which can be updated, not null
 939      * @param resolverStyle  the requested type of resolve, not null
 940      * @return the resolved date, null if insufficient information to create a date
 941      * @throws DateTimeException if the date cannot be resolved, typically
 942      *  because of a conflict in the input data
 943      */
 944     public ChronoLocalDate<?> resolveDate(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
 945         // check epoch-day before inventing era
 946         if (fieldValues.containsKey(EPOCH_DAY)) {
 947             return dateEpochDay(fieldValues.remove(EPOCH_DAY));
 948         }
 949 
 950         // fix proleptic month before inventing era







































 951         Long pMonth = fieldValues.remove(PROLEPTIC_MONTH);
 952         if (pMonth != null) {



 953             // first day-of-month is likely to be safest for setting proleptic-month
 954             // cannot add to year zero, as not all chronologies have a year zero
 955             ChronoLocalDate<?> chronoDate = dateNow()
 956                     .with(DAY_OF_MONTH, 1).with(PROLEPTIC_MONTH, pMonth);
 957             addFieldValue(fieldValues, MONTH_OF_YEAR, chronoDate.get(MONTH_OF_YEAR));
 958             addFieldValue(fieldValues, YEAR, chronoDate.get(YEAR));
 959         }

 960 
 961         // invent era if necessary to resolve year-of-era
 962         Long yoeLong = fieldValues.remove(YEAR_OF_ERA);
 963         if (yoeLong != null) {
 964             Long eraLong = fieldValues.remove(ERA);
 965             int yoe = range(YEAR_OF_ERA).checkValidIntValue(yoeLong, YEAR_OF_ERA);





 966             if (eraLong != null) {
 967                 Era eraObj = eraOf(Math.toIntExact(eraLong));
 968                 addFieldValue(fieldValues, YEAR, prolepticYear(eraObj, yoe));
 969             } else if (fieldValues.containsKey(YEAR)) {

 970                 int year = range(YEAR).checkValidIntValue(fieldValues.get(YEAR), YEAR);
 971                 ChronoLocalDate<?> chronoDate = dateYearDay(year, 1);
 972                 addFieldValue(fieldValues, YEAR, prolepticYear(chronoDate.getEra(), yoe));




 973             } else {
 974                 List<Era> eras = eras();
 975                 if (eras.isEmpty()) {
 976                     addFieldValue(fieldValues, YEAR, yoe);
 977                 } else {
 978                     Era eraObj = eras.get(eras.size() - 1);
 979                     addFieldValue(fieldValues, YEAR, prolepticYear(eraObj, yoe));
 980                 }
 981             }
 982         }





 983 
 984         // build date
 985         if (fieldValues.containsKey(YEAR)) {
 986             if (fieldValues.containsKey(MONTH_OF_YEAR)) {
 987                 if (fieldValues.containsKey(DAY_OF_MONTH)) {
 988                     int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR);





 989                     int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR);
 990                     int dom = range(DAY_OF_MONTH).checkValidIntValue(fieldValues.remove(DAY_OF_MONTH), DAY_OF_MONTH);








 991                     return date(y, moy, dom);
 992                 }
 993                 if (fieldValues.containsKey(ALIGNED_WEEK_OF_MONTH)) {
 994                     if (fieldValues.containsKey(ALIGNED_DAY_OF_WEEK_IN_MONTH)) {
 995                         int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR);
















 996                         int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR);
 997                         int aw = range(ALIGNED_WEEK_OF_MONTH).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), ALIGNED_WEEK_OF_MONTH);
 998                         int ad = range(ALIGNED_DAY_OF_WEEK_IN_MONTH).checkValidIntValue(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_MONTH), ALIGNED_DAY_OF_WEEK_IN_MONTH);
 999                         ChronoLocalDate<?> chronoDate = date(y, moy, 1);
1000                         return chronoDate.plus((aw - 1) * 7 + (ad - 1), ChronoUnit.DAYS);

1001                     }
1002                     if (fieldValues.containsKey(DAY_OF_WEEK)) {



1003                         int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR);






1004                         int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR);
1005                         int aw = range(ALIGNED_WEEK_OF_MONTH).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), ALIGNED_WEEK_OF_MONTH);
1006                         int dow = range(DAY_OF_WEEK).checkValidIntValue(fieldValues.remove(DAY_OF_WEEK), DAY_OF_WEEK);
1007                         ChronoLocalDate<?> chronoDate = date(y, moy, 1);
1008                         return chronoDate.plus((aw - 1) * 7, ChronoUnit.DAYS).with(nextOrSame(DayOfWeek.of(dow)));
1009                     }
1010                 }

1011             }
1012             if (fieldValues.containsKey(DAY_OF_YEAR)) {

1013                 int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR);
1014                 int doy = range(DAY_OF_YEAR).checkValidIntValue(fieldValues.remove(DAY_OF_YEAR), DAY_OF_YEAR);
1015                 return dateYearDay(y, doy);


1016             }
1017             if (fieldValues.containsKey(ALIGNED_WEEK_OF_YEAR)) {
1018                 if (fieldValues.containsKey(ALIGNED_DAY_OF_WEEK_IN_YEAR)) {
1019                     int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR);
1020                     int aw = range(ALIGNED_WEEK_OF_YEAR).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), ALIGNED_WEEK_OF_YEAR);
1021                     int ad = range(ALIGNED_DAY_OF_WEEK_IN_YEAR).checkValidIntValue(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_YEAR), ALIGNED_DAY_OF_WEEK_IN_YEAR);
1022                     ChronoLocalDate<?> chronoDate = dateYearDay(y, 1);
1023                     return chronoDate.plus((aw - 1) * 7 + (ad - 1), ChronoUnit.DAYS);

1024                 }
1025                 if (fieldValues.containsKey(DAY_OF_WEEK)) {



1026                     int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR);





1027                     int aw = range(ALIGNED_WEEK_OF_YEAR).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), ALIGNED_WEEK_OF_YEAR);
1028                     int dow = range(DAY_OF_WEEK).checkValidIntValue(fieldValues.remove(DAY_OF_WEEK), DAY_OF_WEEK);
1029                     ChronoLocalDate<?> chronoDate = dateYearDay(y, 1);
1030                     return chronoDate.plus((aw - 1) * 7, ChronoUnit.DAYS).with(nextOrSame(DayOfWeek.of(dow)));













1031                 }
1032             }
1033         }
1034         return null;
1035     }
1036 
1037     /**
1038      * Adds a field-value pair to the map, checking for conflicts.
1039      * <p>
1040      * If the field is not already present, then the field-value pair is added to the map.
1041      * If the field is already present and it has the same value as that specified, no action occurs.
1042      * If the field is already present and it has a different value to that specified, then
1043      * an exception is thrown.
1044      *
1045      * @param field  the field to add, not null
1046      * @param value  the value to add, not null
1047      * @throws DateTimeException if the field is already present with a different value
1048      */
1049     void addFieldValue(Map<TemporalField, Long> fieldValues, ChronoField field, long value) {
1050         Long old = fieldValues.get(field);  // check first for better error message
1051         if (old != null && old.longValue() != value) {
1052             throw new DateTimeException("Conflict found: " + field + " " + old + " differs from " + field + " " + value);
1053         }
1054         fieldValues.put(field, value);




  57  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  58  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  59  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  60  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  61  */
  62 package java.time.chrono;
  63 
  64 import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH;
  65 import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR;
  66 import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH;
  67 import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR;
  68 import static java.time.temporal.ChronoField.DAY_OF_MONTH;
  69 import static java.time.temporal.ChronoField.DAY_OF_WEEK;
  70 import static java.time.temporal.ChronoField.DAY_OF_YEAR;
  71 import static java.time.temporal.ChronoField.EPOCH_DAY;
  72 import static java.time.temporal.ChronoField.ERA;
  73 import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
  74 import static java.time.temporal.ChronoField.PROLEPTIC_MONTH;
  75 import static java.time.temporal.ChronoField.YEAR;
  76 import static java.time.temporal.ChronoField.YEAR_OF_ERA;
  77 import static java.time.temporal.ChronoUnit.DAYS;
  78 import static java.time.temporal.ChronoUnit.MONTHS;
  79 import static java.time.temporal.ChronoUnit.WEEKS;
  80 import static java.time.temporal.TemporalAdjuster.nextOrSame;
  81 
  82 import java.io.DataInput;
  83 import java.io.DataOutput;
  84 import java.io.IOException;
  85 import java.io.InvalidObjectException;
  86 import java.io.ObjectStreamException;
  87 import java.io.Serializable;
  88 import java.time.Clock;
  89 import java.time.DateTimeException;
  90 import java.time.DayOfWeek;
  91 import java.time.Instant;
  92 import java.time.LocalDate;
  93 import java.time.LocalTime;
  94 import java.time.Month;
  95 import java.time.Year;
  96 import java.time.ZoneId;
  97 import java.time.format.DateTimeFormatterBuilder;
  98 import java.time.format.ResolverStyle;
  99 import java.time.format.TextStyle;
 100 import java.time.temporal.ChronoField;

 101 import java.time.temporal.Temporal;
 102 import java.time.temporal.TemporalAccessor;
 103 import java.time.temporal.TemporalAdjuster;
 104 import java.time.temporal.TemporalField;
 105 import java.time.temporal.TemporalQuery;
 106 import java.time.temporal.UnsupportedTemporalTypeException;
 107 import java.time.temporal.ValueRange;
 108 import java.util.Comparator;
 109 import java.util.HashSet;
 110 import java.util.List;
 111 import java.util.Locale;
 112 import java.util.Map;
 113 import java.util.Objects;
 114 import java.util.ServiceLoader;
 115 import java.util.Set;
 116 import java.util.concurrent.ConcurrentHashMap;
 117 
 118 import sun.util.logging.PlatformLogger;
 119 
 120 /**
 121  * A calendar system, used to organize and identify dates.
 122  * <p>
 123  * The main date and time API is built on the ISO calendar system.


 176  * For lookup by id or calendarType, the system provided calendars are found
 177  * first followed by application provided calendars.
 178  * <p>
 179  * Each chronology must define a chronology ID that is unique within the system.
 180  * If the chronology represents a calendar system defined by the
 181  * CLDR specification then the calendar type is the concatenation of the
 182  * CLDR type and, if applicable, the CLDR variant,
 183  *
 184  * @implSpec
 185  * This class must be implemented with care to ensure other classes operate correctly.
 186  * All implementations that can be instantiated must be final, immutable and thread-safe.
 187  * Subclasses should be Serializable wherever possible.
 188  *
 189  * @since 1.8
 190  */
 191 public abstract class Chronology implements Comparable<Chronology> {
 192 
 193     /**
 194      * ChronoLocalDate order constant.
 195      */
 196     static final Comparator<ChronoLocalDate> DATE_ORDER =
 197         (Comparator<ChronoLocalDate> & Serializable) (date1, date2) -> {
 198             return Long.compare(date1.toEpochDay(), date2.toEpochDay());
 199         };
 200     /**
 201      * ChronoLocalDateTime order constant.
 202      */
 203     static final Comparator<ChronoLocalDateTime<?>> DATE_TIME_ORDER =
 204         (Comparator<ChronoLocalDateTime<?>> & Serializable) (dateTime1, dateTime2) -> {
 205             int cmp = Long.compare(dateTime1.toLocalDate().toEpochDay(), dateTime2.toLocalDate().toEpochDay());
 206             if (cmp == 0) {
 207                 cmp = Long.compare(dateTime1.toLocalTime().toNanoOfDay(), dateTime2.toLocalTime().toNanoOfDay());
 208             }
 209             return cmp;
 210         };
 211     /**
 212      * ChronoZonedDateTime order constant.
 213      */
 214     static final Comparator<ChronoZonedDateTime<?>> INSTANT_ORDER =
 215             (Comparator<ChronoZonedDateTime<?>> & Serializable) (dateTime1, dateTime2) -> {
 216                 int cmp = Long.compare(dateTime1.toEpochSecond(), dateTime2.toEpochSecond());
 217                 if (cmp == 0) {


 470         HashSet<Chronology> chronos = new HashSet<>(CHRONOS_BY_ID.values());
 471 
 472         /// Add in Chronologies from the ServiceLoader configuration
 473         @SuppressWarnings("rawtypes")
 474         ServiceLoader<Chronology> loader = ServiceLoader.load(Chronology.class);
 475         for (Chronology chrono : loader) {
 476             chronos.add(chrono);
 477         }
 478         return chronos;
 479     }
 480 
 481     //-----------------------------------------------------------------------
 482     /**
 483      * Creates an instance.
 484      */
 485     protected Chronology() {
 486     }
 487 
 488     //-----------------------------------------------------------------------
 489     /**






















































 490      * Gets the ID of the chronology.
 491      * <p>
 492      * The ID uniquely identifies the {@code Chronology}.
 493      * It can be used to lookup the {@code Chronology} using {@link #of(String)}.
 494      *
 495      * @return the chronology ID, not null
 496      * @see #getCalendarType()
 497      */
 498     public abstract String getId();
 499 
 500     /**
 501      * Gets the calendar type of the calendar system.
 502      * <p>
 503      * The calendar type is an identifier defined by the CLDR and
 504      * <em>Unicode Locale Data Markup Language (LDML)</em> specifications
 505      * to uniquely identification a calendar.
 506      * The {@code getCalendarType} is the concatenation of the CLDR calendar type
 507      * and the variant, if applicable, is appended separated by "-".
 508      * The calendar type is used to lookup the {@code Chronology} using {@link #of(String)}.
 509      *
 510      * @return the calendar system type, null if the calendar is not defined by CLDR/LDML
 511      * @see #getId()
 512      */
 513     public abstract String getCalendarType();
 514 
 515     //-----------------------------------------------------------------------
 516     /**
 517      * Obtains a local date in this chronology from the era, year-of-era,
 518      * month-of-year and day-of-month fields.
 519      *
 520      * @param era  the era of the correct type for the chronology, not null
 521      * @param yearOfEra  the chronology year-of-era
 522      * @param month  the chronology month-of-year
 523      * @param dayOfMonth  the chronology day-of-month
 524      * @return the local date in this chronology, not null
 525      * @throws DateTimeException if unable to create the date
 526      * @throws ClassCastException if the {@code era} is not of the correct type for the chronology
 527      */
 528     public ChronoLocalDate date(Era era, int yearOfEra, int month, int dayOfMonth) {
 529         return date(prolepticYear(era, yearOfEra), month, dayOfMonth);
 530     }
 531 
 532     /**
 533      * Obtains a local date in this chronology from the proleptic-year,
 534      * month-of-year and day-of-month fields.
 535      *
 536      * @param prolepticYear  the chronology proleptic-year
 537      * @param month  the chronology month-of-year
 538      * @param dayOfMonth  the chronology day-of-month
 539      * @return the local date in this chronology, not null
 540      * @throws DateTimeException if unable to create the date
 541      */
 542     public abstract ChronoLocalDate date(int prolepticYear, int month, int dayOfMonth);
 543 
 544     /**
 545      * Obtains a local date in this chronology from the era, year-of-era and
 546      * day-of-year fields.
 547      *
 548      * @param era  the era of the correct type for the chronology, not null
 549      * @param yearOfEra  the chronology year-of-era
 550      * @param dayOfYear  the chronology day-of-year
 551      * @return the local date in this chronology, not null
 552      * @throws DateTimeException if unable to create the date
 553      * @throws ClassCastException if the {@code era} is not of the correct type for the chronology
 554      */
 555     public ChronoLocalDate dateYearDay(Era era, int yearOfEra, int dayOfYear) {
 556         return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear);
 557     }
 558 
 559     /**
 560      * Obtains a local date in this chronology from the proleptic-year and
 561      * day-of-year fields.
 562      *
 563      * @param prolepticYear  the chronology proleptic-year
 564      * @param dayOfYear  the chronology day-of-year
 565      * @return the local date in this chronology, not null
 566      * @throws DateTimeException if unable to create the date
 567      */
 568     public abstract ChronoLocalDate dateYearDay(int prolepticYear, int dayOfYear);
 569 
 570     /**
 571      * Obtains a local date in this chronology from the epoch-day.
 572      * <p>
 573      * The definition of {@link ChronoField#EPOCH_DAY EPOCH_DAY} is the same
 574      * for all calendar systems, thus it can be used for conversion.
 575      *
 576      * @param epochDay  the epoch day
 577      * @return the local date in this chronology, not null
 578      * @throws DateTimeException if unable to create the date
 579      */
 580     public abstract ChronoLocalDate dateEpochDay(long epochDay);
 581 
 582     //-----------------------------------------------------------------------
 583     /**
 584      * Obtains the current local date in this chronology from the system clock in the default time-zone.
 585      * <p>
 586      * This will query the {@link Clock#systemDefaultZone() system clock} in the default
 587      * time-zone to obtain the current date.
 588      * <p>
 589      * Using this method will prevent the ability to use an alternate clock for testing
 590      * because the clock is hard-coded.
 591      * <p>
 592      * This implementation uses {@link #dateNow(Clock)}.
 593      *
 594      * @return the current local date using the system clock and default time-zone, not null
 595      * @throws DateTimeException if unable to create the date
 596      */
 597     public ChronoLocalDate dateNow() {
 598         return dateNow(Clock.systemDefaultZone());
 599     }
 600 
 601     /**
 602      * Obtains the current local date in this chronology from the system clock in the specified time-zone.
 603      * <p>
 604      * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date.
 605      * Specifying the time-zone avoids dependence on the default time-zone.
 606      * <p>
 607      * Using this method will prevent the ability to use an alternate clock for testing
 608      * because the clock is hard-coded.
 609      *
 610      * @param zone  the zone ID to use, not null
 611      * @return the current local date using the system clock, not null
 612      * @throws DateTimeException if unable to create the date
 613      */
 614     public ChronoLocalDate dateNow(ZoneId zone) {
 615         return dateNow(Clock.system(zone));
 616     }
 617 
 618     /**
 619      * Obtains the current local date in this chronology from the specified clock.
 620      * <p>
 621      * This will query the specified clock to obtain the current date - today.
 622      * Using this method allows the use of an alternate clock for testing.
 623      * The alternate clock may be introduced using {@link Clock dependency injection}.
 624      *
 625      * @param clock  the clock to use, not null
 626      * @return the current local date, not null
 627      * @throws DateTimeException if unable to create the date
 628      */
 629     public ChronoLocalDate dateNow(Clock clock) {
 630         Objects.requireNonNull(clock, "clock");
 631         return date(LocalDate.now(clock));
 632     }
 633 
 634     //-----------------------------------------------------------------------
 635     /**
 636      * Obtains a local date in this chronology from another temporal object.
 637      * <p>
 638      * This obtains a date in this chronology based on the specified temporal.
 639      * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
 640      * which this factory converts to an instance of {@code ChronoLocalDate}.
 641      * <p>
 642      * The conversion typically uses the {@link ChronoField#EPOCH_DAY EPOCH_DAY}
 643      * field, which is standardized across calendar systems.
 644      * <p>
 645      * This method matches the signature of the functional interface {@link TemporalQuery}
 646      * allowing it to be used as a query via method reference, {@code aChronology::date}.
 647      *
 648      * @param temporal  the temporal object to convert, not null
 649      * @return the local date in this chronology, not null
 650      * @throws DateTimeException if unable to create the date
 651      * @see ChronoLocalDate#from(TemporalAccessor)
 652      */
 653     public abstract ChronoLocalDate date(TemporalAccessor temporal);
 654 
 655     /**
 656      * Obtains a local date-time in this chronology from another temporal object.
 657      * <p>
 658      * This obtains a date-time in this chronology based on the specified temporal.
 659      * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
 660      * which this factory converts to an instance of {@code ChronoLocalDateTime}.
 661      * <p>
 662      * The conversion extracts and combines the {@code ChronoLocalDate} and the
 663      * {@code LocalTime} from the temporal object.
 664      * Implementations are permitted to perform optimizations such as accessing
 665      * those fields that are equivalent to the relevant objects.
 666      * The result uses this chronology.
 667      * <p>
 668      * This method matches the signature of the functional interface {@link TemporalQuery}
 669      * allowing it to be used as a query via method reference, {@code aChronology::localDateTime}.
 670      *
 671      * @param temporal  the temporal object to convert, not null
 672      * @return the local date-time in this chronology, not null
 673      * @throws DateTimeException if unable to create the date-time
 674      * @see ChronoLocalDateTime#from(TemporalAccessor)
 675      */
 676     public ChronoLocalDateTime<? extends ChronoLocalDate> localDateTime(TemporalAccessor temporal) {
 677         try {
 678             return date(temporal).atTime(LocalTime.from(temporal));
 679         } catch (DateTimeException ex) {
 680             throw new DateTimeException("Unable to obtain ChronoLocalDateTime from TemporalAccessor: " + temporal.getClass(), ex);
 681         }
 682     }
 683 
 684     /**
 685      * Obtains a {@code ChronoZonedDateTime} in this chronology from another temporal object.
 686      * <p>
 687      * This obtains a zoned date-time in this chronology based on the specified temporal.
 688      * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
 689      * which this factory converts to an instance of {@code ChronoZonedDateTime}.
 690      * <p>
 691      * The conversion will first obtain a {@code ZoneId} from the temporal object,
 692      * falling back to a {@code ZoneOffset} if necessary. It will then try to obtain
 693      * an {@code Instant}, falling back to a {@code ChronoLocalDateTime} if necessary.
 694      * The result will be either the combination of {@code ZoneId} or {@code ZoneOffset}
 695      * with {@code Instant} or {@code ChronoLocalDateTime}.
 696      * Implementations are permitted to perform optimizations such as accessing
 697      * those fields that are equivalent to the relevant objects.
 698      * The result uses this chronology.
 699      * <p>
 700      * This method matches the signature of the functional interface {@link TemporalQuery}
 701      * allowing it to be used as a query via method reference, {@code aChronology::zonedDateTime}.
 702      *
 703      * @param temporal  the temporal object to convert, not null
 704      * @return the zoned date-time in this chronology, not null
 705      * @throws DateTimeException if unable to create the date-time
 706      * @see ChronoZonedDateTime#from(TemporalAccessor)
 707      */
 708     public ChronoZonedDateTime<? extends ChronoLocalDate> zonedDateTime(TemporalAccessor temporal) {
 709         try {
 710             ZoneId zone = ZoneId.from(temporal);
 711             try {
 712                 Instant instant = Instant.from(temporal);
 713                 return zonedDateTime(instant, zone);
 714 
 715             } catch (DateTimeException ex1) {
 716                 ChronoLocalDateTimeImpl<?> cldt = ChronoLocalDateTimeImpl.ensureValid(this, localDateTime(temporal));

 717                 return ChronoZonedDateTimeImpl.ofBest(cldt, zone, null);
 718             }
 719         } catch (DateTimeException ex) {
 720             throw new DateTimeException("Unable to obtain ChronoZonedDateTime from TemporalAccessor: " + temporal.getClass(), ex);
 721         }
 722     }
 723 
 724     /**
 725      * Obtains a {@code ChronoZonedDateTime} in this chronology from an {@code Instant}.
 726      * <p>
 727      * This obtains a zoned date-time with the same instant as that specified.
 728      *
 729      * @param instant  the instant to create the date-time from, not null
 730      * @param zone  the time-zone, not null
 731      * @return the zoned date-time, not null
 732      * @throws DateTimeException if the result exceeds the supported range
 733      */
 734     public ChronoZonedDateTime<? extends ChronoLocalDate> zonedDateTime(Instant instant, ZoneId zone) {
 735         return ChronoZonedDateTimeImpl.ofInstant(this, instant, zone);
 736     }
 737 
 738     //-----------------------------------------------------------------------
 739     /**
 740      * Checks if the specified year is a leap year.
 741      * <p>
 742      * A leap-year is a year of a longer length than normal.
 743      * The exact meaning is determined by the chronology according to the following constraints.
 744      * <p><ul>
 745      * <li>a leap-year must imply a year-length longer than a non leap-year.
 746      * <li>a chronology that does not support the concept of a year must return false.
 747      * </ul><p>
 748      *
 749      * @param prolepticYear  the proleptic-year to check, not validated for range
 750      * @return true if the year is a leap year
 751      */
 752     public abstract boolean isLeapYear(long prolepticYear);
 753 
 754     /**


 862             @Override
 863             public <R> R query(TemporalQuery<R> query) {
 864                 if (query == TemporalQuery.chronology()) {
 865                     return (R) Chronology.this;
 866                 }
 867                 return TemporalAccessor.super.query(query);
 868             }
 869         };
 870     }
 871 
 872     //-----------------------------------------------------------------------
 873     /**
 874      * Resolves parsed {@code ChronoField} values into a date during parsing.
 875      * <p>
 876      * Most {@code TemporalField} implementations are resolved using the
 877      * resolve method on the field. By contrast, the {@code ChronoField} class
 878      * defines fields that only have meaning relative to the chronology.
 879      * As such, {@code ChronoField} date fields are resolved here in the
 880      * context of a specific chronology.
 881      * <p>
 882      * {@code ChronoField} instances are resolved by this method, which may
 883      * be overridden in subclasses.
 884      * <ul>
 885      * <li>{@code EPOCH_DAY} - If present, this is converted to a date and
 886      *  all other date fields are then cross-checked against the date.
 887      * <li>{@code PROLEPTIC_MONTH} - If present, then it is split into the
 888      *  {@code YEAR} and {@code MONTH_OF_YEAR}. If the mode is strict or smart
 889      *  then the field is validated.
 890      * <li>{@code YEAR_OF_ERA} and {@code ERA} - If both are present, then they
 891      *  are combined to form a {@code YEAR}. In lenient mode, the {@code YEAR_OF_ERA}
 892      *  range is not validated, in smart and strict mode it is. The {@code ERA} is
 893      *  validated for range in all three modes. If only the {@code YEAR_OF_ERA} is
 894      *  present, and the mode is smart or lenient, then the last available era
 895      *  is assumed. In strict mode, no era is assumed and the {@code YEAR_OF_ERA} is
 896      *  left untouched. If only the {@code ERA} is present, then it is left untouched.
 897      * <li>{@code YEAR}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} -
 898      *  If all three are present, then they are combined to form a date.
 899      *  In all three modes, the {@code YEAR} is validated.
 900      *  If the mode is smart or strict, then the month and day are validated.
 901      *  If the mode is lenient, then the date is combined in a manner equivalent to
 902      *  creating a date on the first day of the first month in the requested year,
 903      *  then adding the difference in months, then the difference in days.
 904      *  If the mode is smart, and the day-of-month is greater than the maximum for
 905      *  the year-month, then the day-of-month is adjusted to the last day-of-month.
 906      *  If the mode is strict, then the three fields must form a valid date.
 907      * <li>{@code YEAR} and {@code DAY_OF_YEAR} -
 908      *  If both are present, then they are combined to form a date.
 909      *  In all three modes, the {@code YEAR} is validated.
 910      *  If the mode is lenient, then the date is combined in a manner equivalent to
 911      *  creating a date on the first day of the requested year, then adding
 912      *  the difference in days.
 913      *  If the mode is smart or strict, then the two fields must form a valid date.
 914      * <li>{@code YEAR}, {@code MONTH_OF_YEAR}, {@code ALIGNED_WEEK_OF_MONTH} and
 915      *  {@code ALIGNED_DAY_OF_WEEK_IN_MONTH} -
 916      *  If all four are present, then they are combined to form a date.
 917      *  In all three modes, the {@code YEAR} is validated.
 918      *  If the mode is lenient, then the date is combined in a manner equivalent to
 919      *  creating a date on the first day of the first month in the requested year, then adding
 920      *  the difference in months, then the difference in weeks, then in days.
 921      *  If the mode is smart or strict, then the all four fields are validated to
 922      *  their outer ranges. The date is then combined in a manner equivalent to
 923      *  creating a date on the first day of the requested year and month, then adding
 924      *  the amount in weeks and days to reach their values. If the mode is strict,
 925      *  the date is additionally validated to check that the day and week adjustment
 926      *  did not change the month.
 927      * <li>{@code YEAR}, {@code MONTH_OF_YEAR}, {@code ALIGNED_WEEK_OF_MONTH} and
 928      *  {@code DAY_OF_WEEK} - If all four are present, then they are combined to
 929      *  form a date. The approach is the same as described above for
 930      *  years, months and weeks in {@code ALIGNED_DAY_OF_WEEK_IN_MONTH}.
 931      *  The day-of-week is adjusted as the next or same matching day-of-week once
 932      *  the years, months and weeks have been handled.
 933      * <li>{@code YEAR}, {@code ALIGNED_WEEK_OF_YEAR} and {@code ALIGNED_DAY_OF_WEEK_IN_YEAR} -
 934      *  If all three are present, then they are combined to form a date.
 935      *  In all three modes, the {@code YEAR} is validated.
 936      *  If the mode is lenient, then the date is combined in a manner equivalent to
 937      *  creating a date on the first day of the requested year, then adding
 938      *  the difference in weeks, then in days.
 939      *  If the mode is smart or strict, then the all three fields are validated to
 940      *  their outer ranges. The date is then combined in a manner equivalent to
 941      *  creating a date on the first day of the requested year, then adding
 942      *  the amount in weeks and days to reach their values. If the mode is strict,
 943      *  the date is additionally validated to check that the day and week adjustment
 944      *  did not change the year.
 945      * <li>{@code YEAR}, {@code ALIGNED_WEEK_OF_YEAR} and {@code DAY_OF_WEEK} -
 946      *  If all three are present, then they are combined to form a date.
 947      *  The approach is the same as described above for years and weeks in
 948      *  {@code ALIGNED_DAY_OF_WEEK_IN_YEAR}. The day-of-week is adjusted as the
 949      *  next or same matching day-of-week once the years and weeks have been handled.
 950      * </ul>
 951      * <p>
 952      * The default implementation is suitable for most calendar systems.
 953      * If {@link ChronoField#YEAR_OF_ERA} is found without an {@link ChronoField#ERA}
 954      * then the last era in {@link #eras()} is used.
 955      * The implementation assumes a 7 day week, that the first day-of-month
 956      * has the value 1, that first day-of-year has the value 1, and that the
 957      * first of the month and year always exists.
 958      *
 959      * @param fieldValues  the map of fields to values, which can be updated, not null
 960      * @param resolverStyle  the requested type of resolve, not null
 961      * @return the resolved date, null if insufficient information to create a date
 962      * @throws DateTimeException if the date cannot be resolved, typically
 963      *  because of a conflict in the input data
 964      */
 965     public ChronoLocalDate resolveDate(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
 966         // check epoch-day before inventing era
 967         if (fieldValues.containsKey(EPOCH_DAY)) {
 968             return dateEpochDay(fieldValues.remove(EPOCH_DAY));
 969         }
 970 
 971         // fix proleptic month before inventing era
 972         resolveProlepticMonth(fieldValues, resolverStyle);
 973 
 974         // invent era if necessary to resolve year-of-era
 975         ChronoLocalDate resolved = resolveYearOfEra(fieldValues, resolverStyle);
 976         if (resolved != null) {
 977             return resolved;
 978         }
 979 
 980         // build date
 981         if (fieldValues.containsKey(YEAR)) {
 982             if (fieldValues.containsKey(MONTH_OF_YEAR)) {
 983                 if (fieldValues.containsKey(DAY_OF_MONTH)) {
 984                     return resolveYMD(fieldValues, resolverStyle);
 985                 }
 986                 if (fieldValues.containsKey(ALIGNED_WEEK_OF_MONTH)) {
 987                     if (fieldValues.containsKey(ALIGNED_DAY_OF_WEEK_IN_MONTH)) {
 988                         return resolveYMAA(fieldValues, resolverStyle);
 989                     }
 990                     if (fieldValues.containsKey(DAY_OF_WEEK)) {
 991                         return resolveYMAD(fieldValues, resolverStyle);
 992                     }
 993                 }
 994             }
 995             if (fieldValues.containsKey(DAY_OF_YEAR)) {
 996                 return resolveYD(fieldValues, resolverStyle);
 997             }
 998             if (fieldValues.containsKey(ALIGNED_WEEK_OF_YEAR)) {
 999                 if (fieldValues.containsKey(ALIGNED_DAY_OF_WEEK_IN_YEAR)) {
1000                     return resolveYAA(fieldValues, resolverStyle);
1001                 }
1002                 if (fieldValues.containsKey(DAY_OF_WEEK)) {
1003                     return resolveYAD(fieldValues, resolverStyle);
1004                 }
1005             }
1006         }
1007         return null;
1008     }
1009 
1010     void resolveProlepticMonth(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
1011         Long pMonth = fieldValues.remove(PROLEPTIC_MONTH);
1012         if (pMonth != null) {
1013             if (resolverStyle != ResolverStyle.LENIENT) {
1014                 PROLEPTIC_MONTH.checkValidValue(pMonth);
1015             }
1016             // first day-of-month is likely to be safest for setting proleptic-month
1017             // cannot add to year zero, as not all chronologies have a year zero
1018             ChronoLocalDate chronoDate = dateNow()
1019                     .with(DAY_OF_MONTH, 1).with(PROLEPTIC_MONTH, pMonth);
1020             addFieldValue(fieldValues, MONTH_OF_YEAR, chronoDate.get(MONTH_OF_YEAR));
1021             addFieldValue(fieldValues, YEAR, chronoDate.get(YEAR));
1022         }
1023     }
1024 
1025     ChronoLocalDate resolveYearOfEra(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
1026         Long yoeLong = fieldValues.remove(YEAR_OF_ERA);
1027         if (yoeLong != null) {
1028             Long eraLong = fieldValues.remove(ERA);
1029             int yoe;
1030             if (resolverStyle != ResolverStyle.LENIENT) {
1031                 yoe = range(YEAR_OF_ERA).checkValidIntValue(yoeLong, YEAR_OF_ERA);
1032             } else {
1033                 yoe = Math.toIntExact(yoeLong);
1034             }
1035             if (eraLong != null) {
1036                 Era eraObj = eraOf(range(ERA).checkValidIntValue(eraLong, ERA));
1037                 addFieldValue(fieldValues, YEAR, prolepticYear(eraObj, yoe));
1038             } else {
1039                 if (fieldValues.containsKey(YEAR)) {
1040                     int year = range(YEAR).checkValidIntValue(fieldValues.get(YEAR), YEAR);
1041                     ChronoLocalDate chronoDate = dateYearDay(year, 1);
1042                     addFieldValue(fieldValues, YEAR, prolepticYear(chronoDate.getEra(), yoe));
1043                 } else if (resolverStyle == ResolverStyle.STRICT) {
1044                     // do not invent era if strict
1045                     // reinstate the field removed earlier, no cross-check issues
1046                     fieldValues.put(YEAR_OF_ERA, yoeLong);
1047                 } else {
1048                     List<Era> eras = eras();
1049                     if (eras.isEmpty()) {
1050                         addFieldValue(fieldValues, YEAR, yoe);
1051                     } else {
1052                         Era eraObj = eras.get(eras.size() - 1);
1053                         addFieldValue(fieldValues, YEAR, prolepticYear(eraObj, yoe));
1054                     }
1055                 }
1056             }
1057         } else if (fieldValues.containsKey(ERA)) {
1058             range(ERA).checkValidValue(fieldValues.get(ERA), ERA);  // always validated
1059         }
1060         return null;
1061     }
1062 
1063     ChronoLocalDate resolveYMD(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {



1064         int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR);
1065         if (resolverStyle == ResolverStyle.LENIENT) {
1066             long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1);
1067             long days = Math.subtractExact(fieldValues.remove(DAY_OF_MONTH), 1);
1068             return date(y, 1, 1).plus(months, MONTHS).plus(days, DAYS);
1069         }
1070         int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR);
1071         ValueRange domRange = range(DAY_OF_MONTH);
1072         int dom = domRange.checkValidIntValue(fieldValues.remove(DAY_OF_MONTH), DAY_OF_MONTH);
1073         if (resolverStyle == ResolverStyle.SMART) {  // previous valid
1074             try {
1075                 return date(y, moy, dom);
1076             } catch (DateTimeException ex) {
1077                 return date(y, moy, 1).with(TemporalAdjuster.lastDayOfMonth());
1078             }
1079         }
1080         return date(y, moy, dom);
1081     }
1082 
1083     ChronoLocalDate resolveYD(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
1084         int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR);
1085         if (resolverStyle == ResolverStyle.LENIENT) {
1086             long days = Math.subtractExact(fieldValues.remove(DAY_OF_YEAR), 1);
1087             return dateYearDay(y, 1).plus(days, DAYS);
1088         }
1089         int doy = range(DAY_OF_YEAR).checkValidIntValue(fieldValues.remove(DAY_OF_YEAR), DAY_OF_YEAR);
1090         return dateYearDay(y, doy);  // smart is same as strict
1091     }
1092 
1093     ChronoLocalDate resolveYMAA(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
1094         int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR);
1095         if (resolverStyle == ResolverStyle.LENIENT) {
1096             long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1);
1097             long weeks = Math.subtractExact(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), 1);
1098             long days = Math.subtractExact(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_MONTH), 1);
1099             return date(y, 1, 1).plus(months, MONTHS).plus(weeks, WEEKS).plus(days, DAYS);
1100         }
1101         int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR);
1102         int aw = range(ALIGNED_WEEK_OF_MONTH).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), ALIGNED_WEEK_OF_MONTH);
1103         int ad = range(ALIGNED_DAY_OF_WEEK_IN_MONTH).checkValidIntValue(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_MONTH), ALIGNED_DAY_OF_WEEK_IN_MONTH);
1104         ChronoLocalDate date = date(y, moy, 1).plus((aw - 1) * 7 + (ad - 1), DAYS);
1105         if (resolverStyle == ResolverStyle.STRICT && date.get(MONTH_OF_YEAR) != moy) {
1106             throw new DateTimeException("Strict mode rejected resolved date as it is in a different month");
1107         }
1108         return date;
1109     }
1110 
1111     ChronoLocalDate resolveYMAD(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
1112         int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR);
1113         if (resolverStyle == ResolverStyle.LENIENT) {
1114             long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1);
1115             long weeks = Math.subtractExact(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), 1);
1116             long dow = Math.subtractExact(fieldValues.remove(DAY_OF_WEEK), 1);
1117             return resolveAligned(date(y, 1, 1), months, weeks, dow);
1118         }
1119         int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR);
1120         int aw = range(ALIGNED_WEEK_OF_MONTH).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), ALIGNED_WEEK_OF_MONTH);
1121         int dow = range(DAY_OF_WEEK).checkValidIntValue(fieldValues.remove(DAY_OF_WEEK), DAY_OF_WEEK);
1122         ChronoLocalDate date = date(y, moy, 1).plus((aw - 1) * 7, DAYS).with(nextOrSame(DayOfWeek.of(dow)));
1123         if (resolverStyle == ResolverStyle.STRICT && date.get(MONTH_OF_YEAR) != moy) {
1124             throw new DateTimeException("Strict mode rejected resolved date as it is in a different month");
1125         }
1126         return date;
1127     }
1128 
1129     ChronoLocalDate resolveYAA(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
1130         int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR);
1131         if (resolverStyle == ResolverStyle.LENIENT) {
1132             long weeks = Math.subtractExact(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), 1);
1133             long days = Math.subtractExact(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_YEAR), 1);
1134             return dateYearDay(y, 1).plus(weeks, WEEKS).plus(days, DAYS);
1135         }



1136         int aw = range(ALIGNED_WEEK_OF_YEAR).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), ALIGNED_WEEK_OF_YEAR);
1137         int ad = range(ALIGNED_DAY_OF_WEEK_IN_YEAR).checkValidIntValue(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_YEAR), ALIGNED_DAY_OF_WEEK_IN_YEAR);
1138         ChronoLocalDate date = dateYearDay(y, 1).plus((aw - 1) * 7 + (ad - 1), DAYS);
1139         if (resolverStyle == ResolverStyle.STRICT && date.get(YEAR) != y) {
1140             throw new DateTimeException("Strict mode rejected resolved date as it is in a different year");
1141         }
1142         return date;
1143     }
1144 
1145     ChronoLocalDate resolveYAD(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
1146         int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR);
1147         if (resolverStyle == ResolverStyle.LENIENT) {
1148             long weeks = Math.subtractExact(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), 1);
1149             long dow = Math.subtractExact(fieldValues.remove(DAY_OF_WEEK), 1);
1150             return resolveAligned(dateYearDay(y, 1), 0, weeks, dow);
1151         }
1152         int aw = range(ALIGNED_WEEK_OF_YEAR).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), ALIGNED_WEEK_OF_YEAR);
1153         int dow = range(DAY_OF_WEEK).checkValidIntValue(fieldValues.remove(DAY_OF_WEEK), DAY_OF_WEEK);
1154         ChronoLocalDate date = dateYearDay(y, 1).plus((aw - 1) * 7, DAYS).with(nextOrSame(DayOfWeek.of(dow)));
1155         if (resolverStyle == ResolverStyle.STRICT && date.get(YEAR) != y) {
1156             throw new DateTimeException("Strict mode rejected resolved date as it is in a different year");
1157         }
1158         return date;
1159     }
1160 
1161     ChronoLocalDate resolveAligned(ChronoLocalDate base, long months, long weeks, long dow) {
1162         ChronoLocalDate date = base.plus(months, MONTHS).plus(weeks, WEEKS);
1163         if (dow > 7) {
1164             date = date.plus((dow - 1) / 7, WEEKS);
1165             dow = ((dow - 1) % 7) + 1;
1166         } else if (dow < 1) {
1167             date = date.plus(Math.subtractExact(dow,  7) / 7, WEEKS);
1168             dow = ((dow + 6) % 7) + 1;
1169         }
1170         return date.with(nextOrSame(DayOfWeek.of((int) dow)));


1171     }
1172 
1173     /**
1174      * Adds a field-value pair to the map, checking for conflicts.
1175      * <p>
1176      * If the field is not already present, then the field-value pair is added to the map.
1177      * If the field is already present and it has the same value as that specified, no action occurs.
1178      * If the field is already present and it has a different value to that specified, then
1179      * an exception is thrown.
1180      *
1181      * @param field  the field to add, not null
1182      * @param value  the value to add, not null
1183      * @throws DateTimeException if the field is already present with a different value
1184      */
1185     void addFieldValue(Map<TemporalField, Long> fieldValues, ChronoField field, long value) {
1186         Long old = fieldValues.get(field);  // check first for better error message
1187         if (old != null && old.longValue() != value) {
1188             throw new DateTimeException("Conflict found: " + field + " " + old + " differs from " + field + " " + value);
1189         }
1190         fieldValues.put(field, value);