1 /*
2  * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 /*
27  * This file is available under and governed by the GNU General Public
28  * License version 2 only, as published by the Free Software Foundation.
29  * However, the following notice accompanied the original version of this
30  * file:
31  *
32  * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
33  *
34  * All rights reserved.
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions are met:
38  *
39  *  * Redistributions of source code must retain the above copyright notice,
40  *    this list of conditions and the following disclaimer.
41  *
42  *  * Redistributions in binary form must reproduce the above copyright notice,
43  *    this list of conditions and the following disclaimer in the documentation
44  *    and/or other materials provided with the distribution.
45  *
46  *  * Neither the name of JSR-310 nor the names of its contributors
47  *    may be used to endorse or promote products derived from this software
48  *    without specific prior written permission.
49  *
50  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
51  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
52  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
53  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
54  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
55  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
56  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
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.DAY_OF_MONTH;
65 import static java.time.temporal.ChronoField.ERA;
66 import static java.time.temporal.ChronoField.HOUR_OF_DAY;
67 import static java.time.temporal.ChronoField.MINUTE_OF_HOUR;
68 import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
69 import static java.time.temporal.ChronoField.PROLEPTIC_MONTH;
70 import static java.time.temporal.ChronoField.SECOND_OF_MINUTE;
71 import static java.time.temporal.ChronoField.YEAR;
72 import static java.time.temporal.ChronoField.YEAR_OF_ERA;
73 
74 import java.io.InvalidObjectException;
75 import java.io.ObjectInputStream;
76 import java.io.Serializable;
77 import java.time.Clock;
78 import java.time.DateTimeException;
79 import java.time.Instant;
80 import java.time.LocalDate;
81 import java.time.LocalDateTime;
82 import java.time.Month;
83 import java.time.Period;
84 import java.time.Year;
85 import java.time.ZonedDateTime;
86 import java.time.ZoneId;
87 import java.time.ZoneOffset;
88 import java.time.format.ResolverStyle;
89 import java.time.temporal.ChronoField;
90 import java.time.temporal.TemporalAccessor;
91 import java.time.temporal.TemporalField;
92 import java.time.temporal.ValueRange;
93 import java.util.List;
94 import java.util.Locale;
95 import java.util.Map;
96 import java.util.Objects;
97 
98 /**
99  * The ISO calendar system.
100  * <p>
101  * This chronology defines the rules of the ISO calendar system.
102  * This calendar system is based on the ISO-8601 standard, which is the
103  * <i>de facto</i> world calendar.
104  * <p>
105  * The fields are defined as follows:
106  * <ul>
107  * <li>era - There are two eras, 'Current Era' (CE) and 'Before Current Era' (BCE).
108  * <li>year-of-era - The year-of-era is the same as the proleptic-year for the current CE era.
109  *  For the BCE era before the ISO epoch the year increases from 1 upwards as time goes backwards.
110  * <li>proleptic-year - The proleptic year is the same as the year-of-era for the
111  *  current era. For the previous era, years have zero, then negative values.
112  * <li>month-of-year - There are 12 months in an ISO year, numbered from 1 to 12.
113  * <li>day-of-month - There are between 28 and 31 days in each of the ISO month, numbered from 1 to 31.
114  *  Months 4, 6, 9 and 11 have 30 days, Months 1, 3, 5, 7, 8, 10 and 12 have 31 days.
115  *  Month 2 has 28 days, or 29 in a leap year.
116  * <li>day-of-year - There are 365 days in a standard ISO year and 366 in a leap year.
117  *  The days are numbered from 1 to 365 or 1 to 366.
118  * <li>leap-year - Leap years occur every 4 years, except where the year is divisble by 100 and not divisble by 400.
119  * </ul>
120  *
121  * @implSpec
122  * This class is immutable and thread-safe.
123  *
124  * @since 1.8
125  */
126 public final class IsoChronology extends AbstractChronology implements Serializable {
127 
128     /**
129      * Singleton instance of the ISO chronology.
130      */
131     public static final IsoChronology INSTANCE = new IsoChronology();
132 
133     /**
134      * Serialization version.
135      */
136     @java.io.Serial
137     private static final long serialVersionUID = -1440403870442975015L;
138 
139     private static final long DAYS_0000_TO_1970 = (146097 * 5L) - (30L * 365L + 7L); // taken from LocalDate
140 
141     /**
142      * Restricted constructor.
143      */
IsoChronology()144     private IsoChronology() {
145     }
146 
147     //-----------------------------------------------------------------------
148     /**
149      * Gets the ID of the chronology - 'ISO'.
150      * <p>
151      * The ID uniquely identifies the {@code Chronology}.
152      * It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}.
153      *
154      * @return the chronology ID - 'ISO'
155      * @see #getCalendarType()
156      */
157     @Override
getId()158     public String getId() {
159         return "ISO";
160     }
161 
162     /**
163      * Gets the calendar type of the underlying calendar system - 'iso8601'.
164      * <p>
165      * The calendar type is an identifier defined by the
166      * <em>Unicode Locale Data Markup Language (LDML)</em> specification.
167      * It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}.
168      * It can also be used as part of a locale, accessible via
169      * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'.
170      *
171      * @return the calendar system type - 'iso8601'
172      * @see #getId()
173      */
174     @Override
getCalendarType()175     public String getCalendarType() {
176         return "iso8601";
177     }
178 
179     //-----------------------------------------------------------------------
180     /**
181      * Obtains an ISO local date from the era, year-of-era, month-of-year
182      * and day-of-month fields.
183      *
184      * @param era  the ISO era, not null
185      * @param yearOfEra  the ISO year-of-era
186      * @param month  the ISO month-of-year
187      * @param dayOfMonth  the ISO day-of-month
188      * @return the ISO local date, not null
189      * @throws DateTimeException if unable to create the date
190      * @throws ClassCastException if the type of {@code era} is not {@code IsoEra}
191      */
192     @Override  // override with covariant return type
date(Era era, int yearOfEra, int month, int dayOfMonth)193     public LocalDate date(Era era, int yearOfEra, int month, int dayOfMonth) {
194         return date(prolepticYear(era, yearOfEra), month, dayOfMonth);
195     }
196 
197     /**
198      * Obtains an ISO local date from the proleptic-year, month-of-year
199      * and day-of-month fields.
200      * <p>
201      * This is equivalent to {@link LocalDate#of(int, int, int)}.
202      *
203      * @param prolepticYear  the ISO proleptic-year
204      * @param month  the ISO month-of-year
205      * @param dayOfMonth  the ISO day-of-month
206      * @return the ISO local date, not null
207      * @throws DateTimeException if unable to create the date
208      */
209     @Override  // override with covariant return type
date(int prolepticYear, int month, int dayOfMonth)210     public LocalDate date(int prolepticYear, int month, int dayOfMonth) {
211         return LocalDate.of(prolepticYear, month, dayOfMonth);
212     }
213 
214     /**
215      * Obtains an ISO local date from the era, year-of-era and day-of-year fields.
216      *
217      * @param era  the ISO era, not null
218      * @param yearOfEra  the ISO year-of-era
219      * @param dayOfYear  the ISO day-of-year
220      * @return the ISO local date, not null
221      * @throws DateTimeException if unable to create the date
222      */
223     @Override  // override with covariant return type
dateYearDay(Era era, int yearOfEra, int dayOfYear)224     public LocalDate dateYearDay(Era era, int yearOfEra, int dayOfYear) {
225         return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear);
226     }
227 
228     /**
229      * Obtains an ISO local date from the proleptic-year and day-of-year fields.
230      * <p>
231      * This is equivalent to {@link LocalDate#ofYearDay(int, int)}.
232      *
233      * @param prolepticYear  the ISO proleptic-year
234      * @param dayOfYear  the ISO day-of-year
235      * @return the ISO local date, not null
236      * @throws DateTimeException if unable to create the date
237      */
238     @Override  // override with covariant return type
dateYearDay(int prolepticYear, int dayOfYear)239     public LocalDate dateYearDay(int prolepticYear, int dayOfYear) {
240         return LocalDate.ofYearDay(prolepticYear, dayOfYear);
241     }
242 
243     /**
244      * Obtains an ISO local date from the epoch-day.
245      * <p>
246      * This is equivalent to {@link LocalDate#ofEpochDay(long)}.
247      *
248      * @param epochDay  the epoch day
249      * @return the ISO local date, not null
250      * @throws DateTimeException if unable to create the date
251      */
252     @Override  // override with covariant return type
dateEpochDay(long epochDay)253     public LocalDate dateEpochDay(long epochDay) {
254         return LocalDate.ofEpochDay(epochDay);
255     }
256 
257     //-----------------------------------------------------------------------
258     /**
259      * Obtains an ISO local date from another date-time object.
260      * <p>
261      * This is equivalent to {@link LocalDate#from(TemporalAccessor)}.
262      *
263      * @param temporal  the date-time object to convert, not null
264      * @return the ISO local date, not null
265      * @throws DateTimeException if unable to create the date
266      */
267     @Override  // override with covariant return type
date(TemporalAccessor temporal)268     public LocalDate date(TemporalAccessor temporal) {
269         return LocalDate.from(temporal);
270     }
271 
272     //-----------------------------------------------------------------------
273     /**
274      * Gets the number of seconds from the epoch of 1970-01-01T00:00:00Z.
275      * <p>
276      * The number of seconds is calculated using the year,
277      * month, day-of-month, hour, minute, second, and zoneOffset.
278      *
279      * @param prolepticYear  the year, from MIN_YEAR to MAX_YEAR
280      * @param month  the month-of-year, from 1 to 12
281      * @param dayOfMonth  the day-of-month, from 1 to 31
282      * @param hour  the hour-of-day, from 0 to 23
283      * @param minute  the minute-of-hour, from 0 to 59
284      * @param second  the second-of-minute, from 0 to 59
285      * @param zoneOffset the zone offset, not null
286      * @return the number of seconds relative to 1970-01-01T00:00:00Z, may be negative
287      * @throws DateTimeException if the value of any argument is out of range,
288      *         or if the day-of-month is invalid for the month-of-year
289      * @since 9
290      */
291     @Override
epochSecond(int prolepticYear, int month, int dayOfMonth, int hour, int minute, int second, ZoneOffset zoneOffset)292     public long epochSecond(int prolepticYear, int month, int dayOfMonth,
293                             int hour, int minute, int second, ZoneOffset zoneOffset) {
294         YEAR.checkValidValue(prolepticYear);
295         MONTH_OF_YEAR.checkValidValue(month);
296         DAY_OF_MONTH.checkValidValue(dayOfMonth);
297         HOUR_OF_DAY.checkValidValue(hour);
298         MINUTE_OF_HOUR.checkValidValue(minute);
299         SECOND_OF_MINUTE.checkValidValue(second);
300         Objects.requireNonNull(zoneOffset, "zoneOffset");
301         if (dayOfMonth > 28) {
302             int dom = numberOfDaysOfMonth(prolepticYear, month);
303             if (dayOfMonth > dom) {
304                 if (dayOfMonth == 29) {
305                     throw new DateTimeException("Invalid date 'February 29' as '" + prolepticYear + "' is not a leap year");
306                 } else {
307                     throw new DateTimeException("Invalid date '" + Month.of(month).name() + " " + dayOfMonth + "'");
308                 }
309             }
310         }
311 
312         long totalDays = 0;
313         int timeinSec = 0;
314         totalDays += 365L * prolepticYear;
315         if (prolepticYear >= 0) {
316             totalDays += (prolepticYear + 3L) / 4 - (prolepticYear + 99L) / 100 + (prolepticYear + 399L) / 400;
317         } else {
318             totalDays -= prolepticYear / -4 - prolepticYear / -100 + prolepticYear / -400;
319         }
320         totalDays += (367 * month - 362) / 12;
321         totalDays += dayOfMonth - 1;
322         if (month > 2) {
323             totalDays--;
324             if (IsoChronology.INSTANCE.isLeapYear(prolepticYear) == false) {
325                 totalDays--;
326             }
327         }
328         totalDays -= DAYS_0000_TO_1970;
329         timeinSec = (hour * 60 + minute ) * 60 + second;
330         return Math.addExact(Math.multiplyExact(totalDays, 86400L), timeinSec - zoneOffset.getTotalSeconds());
331      }
332 
333     /**
334      * Gets the number of days for the given month in the given year.
335      *
336      * @param year the year to represent, from MIN_YEAR to MAX_YEAR
337      * @param month the month-of-year to represent, from 1 to 12
338      * @return the number of days for the given month in the given year
339      */
numberOfDaysOfMonth(int year, int month)340     private int numberOfDaysOfMonth(int year, int month) {
341         int dom;
342         switch (month) {
343             case 2:
344                 dom = (IsoChronology.INSTANCE.isLeapYear(year) ? 29 : 28);
345                 break;
346             case 4:
347             case 6:
348             case 9:
349             case 11:
350                 dom = 30;
351                 break;
352             default:
353                 dom = 31;
354                 break;
355         }
356         return dom;
357     }
358 
359 
360     /**
361      * Obtains an ISO local date-time from another date-time object.
362      * <p>
363      * This is equivalent to {@link LocalDateTime#from(TemporalAccessor)}.
364      *
365      * @param temporal  the date-time object to convert, not null
366      * @return the ISO local date-time, not null
367      * @throws DateTimeException if unable to create the date-time
368      */
369     @Override  // override with covariant return type
localDateTime(TemporalAccessor temporal)370     public LocalDateTime localDateTime(TemporalAccessor temporal) {
371         return LocalDateTime.from(temporal);
372     }
373 
374     /**
375      * Obtains an ISO zoned date-time from another date-time object.
376      * <p>
377      * This is equivalent to {@link ZonedDateTime#from(TemporalAccessor)}.
378      *
379      * @param temporal  the date-time object to convert, not null
380      * @return the ISO zoned date-time, not null
381      * @throws DateTimeException if unable to create the date-time
382      */
383     @Override  // override with covariant return type
zonedDateTime(TemporalAccessor temporal)384     public ZonedDateTime zonedDateTime(TemporalAccessor temporal) {
385         return ZonedDateTime.from(temporal);
386     }
387 
388     /**
389      * Obtains an ISO zoned date-time in this chronology from an {@code Instant}.
390      * <p>
391      * This is equivalent to {@link ZonedDateTime#ofInstant(Instant, ZoneId)}.
392      *
393      * @param instant  the instant to create the date-time from, not null
394      * @param zone  the time-zone, not null
395      * @return the zoned date-time, not null
396      * @throws DateTimeException if the result exceeds the supported range
397      */
398     @Override
zonedDateTime(Instant instant, ZoneId zone)399     public ZonedDateTime zonedDateTime(Instant instant, ZoneId zone) {
400         return ZonedDateTime.ofInstant(instant, zone);
401     }
402 
403     //-----------------------------------------------------------------------
404     /**
405      * Obtains the current ISO local date from the system clock in the default time-zone.
406      * <p>
407      * This will query the {@link Clock#systemDefaultZone() system clock} in the default
408      * time-zone to obtain the current date.
409      * <p>
410      * Using this method will prevent the ability to use an alternate clock for testing
411      * because the clock is hard-coded.
412      *
413      * @return the current ISO local date using the system clock and default time-zone, not null
414      * @throws DateTimeException if unable to create the date
415      */
416     @Override  // override with covariant return type
dateNow()417     public LocalDate dateNow() {
418         return dateNow(Clock.systemDefaultZone());
419     }
420 
421     /**
422      * Obtains the current ISO local date from the system clock in the specified time-zone.
423      * <p>
424      * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date.
425      * Specifying the time-zone avoids dependence on the default time-zone.
426      * <p>
427      * Using this method will prevent the ability to use an alternate clock for testing
428      * because the clock is hard-coded.
429      *
430      * @return the current ISO local date using the system clock, not null
431      * @throws DateTimeException if unable to create the date
432      */
433     @Override  // override with covariant return type
dateNow(ZoneId zone)434     public LocalDate dateNow(ZoneId zone) {
435         return dateNow(Clock.system(zone));
436     }
437 
438     /**
439      * Obtains the current ISO local date from the specified clock.
440      * <p>
441      * This will query the specified clock to obtain the current date - today.
442      * Using this method allows the use of an alternate clock for testing.
443      * The alternate clock may be introduced using {@link Clock dependency injection}.
444      *
445      * @param clock  the clock to use, not null
446      * @return the current ISO local date, not null
447      * @throws DateTimeException if unable to create the date
448      */
449     @Override  // override with covariant return type
dateNow(Clock clock)450     public LocalDate dateNow(Clock clock) {
451         Objects.requireNonNull(clock, "clock");
452         return date(LocalDate.now(clock));
453     }
454 
455     //-----------------------------------------------------------------------
456     /**
457      * Checks if the year is a leap year, according to the ISO proleptic
458      * calendar system rules.
459      * <p>
460      * This method applies the current rules for leap years across the whole time-line.
461      * In general, a year is a leap year if it is divisible by four without
462      * remainder. However, years divisible by 100, are not leap years, with
463      * the exception of years divisible by 400 which are.
464      * <p>
465      * For example, 1904 is a leap year it is divisible by 4.
466      * 1900 was not a leap year as it is divisible by 100, however 2000 was a
467      * leap year as it is divisible by 400.
468      * <p>
469      * The calculation is proleptic - applying the same rules into the far future and far past.
470      * This is historically inaccurate, but is correct for the ISO-8601 standard.
471      *
472      * @param prolepticYear  the ISO proleptic year to check
473      * @return true if the year is leap, false otherwise
474      */
475     @Override
isLeapYear(long prolepticYear)476     public boolean isLeapYear(long prolepticYear) {
477         return ((prolepticYear & 3) == 0) && ((prolepticYear % 100) != 0 || (prolepticYear % 400) == 0);
478     }
479 
480     @Override
prolepticYear(Era era, int yearOfEra)481     public int prolepticYear(Era era, int yearOfEra) {
482         if (!(era instanceof IsoEra)) {
483             throw new ClassCastException("Era must be IsoEra");
484         }
485         return (era == IsoEra.CE ? yearOfEra : 1 - yearOfEra);
486     }
487 
488     @Override
eraOf(int eraValue)489     public IsoEra eraOf(int eraValue) {
490         return IsoEra.of(eraValue);
491     }
492 
493     @Override
eras()494     public List<Era> eras() {
495         return List.of(IsoEra.values());
496     }
497 
498     //-----------------------------------------------------------------------
499     /**
500      * Resolves parsed {@code ChronoField} values into a date during parsing.
501      * <p>
502      * Most {@code TemporalField} implementations are resolved using the
503      * resolve method on the field. By contrast, the {@code ChronoField} class
504      * defines fields that only have meaning relative to the chronology.
505      * As such, {@code ChronoField} date fields are resolved here in the
506      * context of a specific chronology.
507      * <p>
508      * {@code ChronoField} instances on the ISO calendar system are resolved
509      * as follows.
510      * <ul>
511      * <li>{@code EPOCH_DAY} - If present, this is converted to a {@code LocalDate}
512      *  and all other date fields are then cross-checked against the date.
513      * <li>{@code PROLEPTIC_MONTH} - If present, then it is split into the
514      *  {@code YEAR} and {@code MONTH_OF_YEAR}. If the mode is strict or smart
515      *  then the field is validated.
516      * <li>{@code YEAR_OF_ERA} and {@code ERA} - If both are present, then they
517      *  are combined to form a {@code YEAR}. In lenient mode, the {@code YEAR_OF_ERA}
518      *  range is not validated, in smart and strict mode it is. The {@code ERA} is
519      *  validated for range in all three modes. If only the {@code YEAR_OF_ERA} is
520      *  present, and the mode is smart or lenient, then the current era (CE/AD)
521      *  is assumed. In strict mode, no era is assumed and the {@code YEAR_OF_ERA} is
522      *  left untouched. If only the {@code ERA} is present, then it is left untouched.
523      * <li>{@code YEAR}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} -
524      *  If all three are present, then they are combined to form a {@code LocalDate}.
525      *  In all three modes, the {@code YEAR} is validated. If the mode is smart or strict,
526      *  then the month and day are validated, with the day validated from 1 to 31.
527      *  If the mode is lenient, then the date is combined in a manner equivalent to
528      *  creating a date on the first of January in the requested year, then adding
529      *  the difference in months, then the difference in days.
530      *  If the mode is smart, and the day-of-month is greater than the maximum for
531      *  the year-month, then the day-of-month is adjusted to the last day-of-month.
532      *  If the mode is strict, then the three fields must form a valid date.
533      * <li>{@code YEAR} and {@code DAY_OF_YEAR} -
534      *  If both are present, then they are combined to form a {@code LocalDate}.
535      *  In all three modes, the {@code YEAR} is validated.
536      *  If the mode is lenient, then the date is combined in a manner equivalent to
537      *  creating a date on the first of January in the requested year, then adding
538      *  the difference in days.
539      *  If the mode is smart or strict, then the two fields must form a valid date.
540      * <li>{@code YEAR}, {@code MONTH_OF_YEAR}, {@code ALIGNED_WEEK_OF_MONTH} and
541      *  {@code ALIGNED_DAY_OF_WEEK_IN_MONTH} -
542      *  If all four are present, then they are combined to form a {@code LocalDate}.
543      *  In all three modes, the {@code YEAR} is validated.
544      *  If the mode is lenient, then the date is combined in a manner equivalent to
545      *  creating a date on the first of January in the requested year, then adding
546      *  the difference in months, then the difference in weeks, then in days.
547      *  If the mode is smart or strict, then the all four fields are validated to
548      *  their outer ranges. The date is then combined in a manner equivalent to
549      *  creating a date on the first day of the requested year and month, then adding
550      *  the amount in weeks and days to reach their values. If the mode is strict,
551      *  the date is additionally validated to check that the day and week adjustment
552      *  did not change the month.
553      * <li>{@code YEAR}, {@code MONTH_OF_YEAR}, {@code ALIGNED_WEEK_OF_MONTH} and
554      *  {@code DAY_OF_WEEK} - If all four are present, then they are combined to
555      *  form a {@code LocalDate}. The approach is the same as described above for
556      *  years, months and weeks in {@code ALIGNED_DAY_OF_WEEK_IN_MONTH}.
557      *  The day-of-week is adjusted as the next or same matching day-of-week once
558      *  the years, months and weeks have been handled.
559      * <li>{@code YEAR}, {@code ALIGNED_WEEK_OF_YEAR} and {@code ALIGNED_DAY_OF_WEEK_IN_YEAR} -
560      *  If all three are present, then they are combined to form a {@code LocalDate}.
561      *  In all three modes, the {@code YEAR} is validated.
562      *  If the mode is lenient, then the date is combined in a manner equivalent to
563      *  creating a date on the first of January in the requested year, then adding
564      *  the difference in weeks, then in days.
565      *  If the mode is smart or strict, then the all three fields are validated to
566      *  their outer ranges. The date is then combined in a manner equivalent to
567      *  creating a date on the first day of the requested year, then adding
568      *  the amount in weeks and days to reach their values. If the mode is strict,
569      *  the date is additionally validated to check that the day and week adjustment
570      *  did not change the year.
571      * <li>{@code YEAR}, {@code ALIGNED_WEEK_OF_YEAR} and {@code DAY_OF_WEEK} -
572      *  If all three are present, then they are combined to form a {@code LocalDate}.
573      *  The approach is the same as described above for years and weeks in
574      *  {@code ALIGNED_DAY_OF_WEEK_IN_YEAR}. The day-of-week is adjusted as the
575      *  next or same matching day-of-week once the years and weeks have been handled.
576      * </ul>
577      *
578      * @param fieldValues  the map of fields to values, which can be updated, not null
579      * @param resolverStyle  the requested type of resolve, not null
580      * @return the resolved date, null if insufficient information to create a date
581      * @throws DateTimeException if the date cannot be resolved, typically
582      *  because of a conflict in the input data
583      */
584     @Override  // override for performance
resolveDate(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle)585     public LocalDate resolveDate(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
586         return (LocalDate) super.resolveDate(fieldValues, resolverStyle);
587     }
588 
589     @Override  // override for better proleptic algorithm
resolveProlepticMonth(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle)590     void resolveProlepticMonth(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
591         Long pMonth = fieldValues.remove(PROLEPTIC_MONTH);
592         if (pMonth != null) {
593             if (resolverStyle != ResolverStyle.LENIENT) {
594                 PROLEPTIC_MONTH.checkValidValue(pMonth);
595             }
596             addFieldValue(fieldValues, MONTH_OF_YEAR, Math.floorMod(pMonth, 12) + 1);
597             addFieldValue(fieldValues, YEAR, Math.floorDiv(pMonth, 12));
598         }
599     }
600 
601     @Override  // override for enhanced behaviour
resolveYearOfEra(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle)602     LocalDate resolveYearOfEra(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
603         Long yoeLong = fieldValues.remove(YEAR_OF_ERA);
604         if (yoeLong != null) {
605             if (resolverStyle != ResolverStyle.LENIENT) {
606                 YEAR_OF_ERA.checkValidValue(yoeLong);
607             }
608             Long era = fieldValues.remove(ERA);
609             if (era == null) {
610                 Long year = fieldValues.get(YEAR);
611                 if (resolverStyle == ResolverStyle.STRICT) {
612                     // do not invent era if strict, but do cross-check with year
613                     if (year != null) {
614                         addFieldValue(fieldValues, YEAR, (year > 0 ? yoeLong: Math.subtractExact(1, yoeLong)));
615                     } else {
616                         // reinstate the field removed earlier, no cross-check issues
617                         fieldValues.put(YEAR_OF_ERA, yoeLong);
618                     }
619                 } else {
620                     // invent era
621                     addFieldValue(fieldValues, YEAR, (year == null || year > 0 ? yoeLong: Math.subtractExact(1, yoeLong)));
622                 }
623             } else if (era.longValue() == 1L) {
624                 addFieldValue(fieldValues, YEAR, yoeLong);
625             } else if (era.longValue() == 0L) {
626                 addFieldValue(fieldValues, YEAR, Math.subtractExact(1, yoeLong));
627             } else {
628                 throw new DateTimeException("Invalid value for era: " + era);
629             }
630         } else if (fieldValues.containsKey(ERA)) {
631             ERA.checkValidValue(fieldValues.get(ERA));  // always validated
632         }
633         return null;
634     }
635 
636     @Override  // override for performance
resolveYMD(Map <TemporalField, Long> fieldValues, ResolverStyle resolverStyle)637     LocalDate resolveYMD(Map <TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
638         int y = YEAR.checkValidIntValue(fieldValues.remove(YEAR));
639         if (resolverStyle == ResolverStyle.LENIENT) {
640             long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1);
641             long days = Math.subtractExact(fieldValues.remove(DAY_OF_MONTH), 1);
642             return LocalDate.of(y, 1, 1).plusMonths(months).plusDays(days);
643         }
644         int moy = MONTH_OF_YEAR.checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR));
645         int dom = DAY_OF_MONTH.checkValidIntValue(fieldValues.remove(DAY_OF_MONTH));
646         if (resolverStyle == ResolverStyle.SMART) {  // previous valid
647             if (moy == 4 || moy == 6 || moy == 9 || moy == 11) {
648                 dom = Math.min(dom, 30);
649             } else if (moy == 2) {
650                 dom = Math.min(dom, Month.FEBRUARY.length(Year.isLeap(y)));
651 
652             }
653         }
654         return LocalDate.of(y, moy, dom);
655     }
656 
657     //-----------------------------------------------------------------------
658     @Override
range(ChronoField field)659     public ValueRange range(ChronoField field) {
660         return field.range();
661     }
662 
663     //-----------------------------------------------------------------------
664     /**
665      * Obtains a period for this chronology based on years, months and days.
666      * <p>
667      * This returns a period tied to the ISO chronology using the specified
668      * years, months and days. See {@link Period} for further details.
669      *
670      * @param years  the number of years, may be negative
671      * @param months  the number of years, may be negative
672      * @param days  the number of years, may be negative
673      * @return the ISO period, not null
674      */
675     @Override  // override with covariant return type
period(int years, int months, int days)676     public Period period(int years, int months, int days) {
677         return Period.of(years, months, days);
678     }
679 
680     //-----------------------------------------------------------------------
681     /**
682      * Writes the Chronology using a
683      * <a href="{@docRoot}/serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
684      * @serialData
685      * <pre>
686      *  out.writeByte(1);     // identifies a Chronology
687      *  out.writeUTF(getId());
688      * </pre>
689      *
690      * @return the instance of {@code Ser}, not null
691      */
692     @Override
693     @java.io.Serial
writeReplace()694     Object writeReplace() {
695         return super.writeReplace();
696     }
697 
698     /**
699      * Defend against malicious streams.
700      *
701      * @param s the stream to read
702      * @throws InvalidObjectException always
703      */
704     @java.io.Serial
readObject(ObjectInputStream s)705     private void readObject(ObjectInputStream s) throws InvalidObjectException {
706         throw new InvalidObjectException("Deserialization via serialization delegate");
707     }
708 }
709