1 /*
2  * Copyright (c) 2012, 2015, 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 java.io.InvalidObjectException;
65 import static java.time.temporal.ChronoField.DAY_OF_MONTH;
66 import static java.time.temporal.ChronoField.ERA;
67 import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
68 import static java.time.temporal.ChronoField.PROLEPTIC_MONTH;
69 import static java.time.temporal.ChronoField.YEAR;
70 import static java.time.temporal.ChronoField.YEAR_OF_ERA;
71 
72 import java.io.ObjectInputStream;
73 import java.io.Serializable;
74 import java.time.Clock;
75 import java.time.DateTimeException;
76 import java.time.Instant;
77 import java.time.LocalDate;
78 import java.time.LocalDateTime;
79 import java.time.Month;
80 import java.time.Period;
81 import java.time.Year;
82 import java.time.ZoneId;
83 import java.time.ZonedDateTime;
84 import java.time.format.ResolverStyle;
85 import java.time.temporal.ChronoField;
86 import java.time.temporal.TemporalAccessor;
87 import java.time.temporal.TemporalField;
88 import java.time.temporal.ValueRange;
89 import java.util.Arrays;
90 import java.util.List;
91 import java.util.Locale;
92 import java.util.Map;
93 import java.util.Objects;
94 
95 /**
96  * The ISO calendar system.
97  * <p>
98  * This chronology defines the rules of the ISO calendar system.
99  * This calendar system is based on the ISO-8601 standard, which is the
100  * <i>de facto</i> world calendar.
101  * <p>
102  * The fields are defined as follows:
103  * <ul>
104  * <li>era - There are two eras, 'Current Era' (CE) and 'Before Current Era' (BCE).
105  * <li>year-of-era - The year-of-era is the same as the proleptic-year for the current CE era.
106  *  For the BCE era before the ISO epoch the year increases from 1 upwards as time goes backwards.
107  * <li>proleptic-year - The proleptic year is the same as the year-of-era for the
108  *  current era. For the previous era, years have zero, then negative values.
109  * <li>month-of-year - There are 12 months in an ISO year, numbered from 1 to 12.
110  * <li>day-of-month - There are between 28 and 31 days in each of the ISO month, numbered from 1 to 31.
111  *  Months 4, 6, 9 and 11 have 30 days, Months 1, 3, 5, 7, 8, 10 and 12 have 31 days.
112  *  Month 2 has 28 days, or 29 in a leap year.
113  * <li>day-of-year - There are 365 days in a standard ISO year and 366 in a leap year.
114  *  The days are numbered from 1 to 365 or 1 to 366.
115  * <li>leap-year - Leap years occur every 4 years, except where the year is divisble by 100 and not divisble by 400.
116  * </ul>
117  *
118  * @implSpec
119  * This class is immutable and thread-safe.
120  *
121  * @since 1.8
122  */
123 public final class IsoChronology extends AbstractChronology implements Serializable {
124 
125     /**
126      * Singleton instance of the ISO chronology.
127      */
128     public static final IsoChronology INSTANCE = new IsoChronology();
129 
130     /**
131      * Serialization version.
132      */
133     private static final long serialVersionUID = -1440403870442975015L;
134 
135     /**
136      * Restricted constructor.
137      */
IsoChronology()138     private IsoChronology() {
139     }
140 
141     //-----------------------------------------------------------------------
142     /**
143      * Gets the ID of the chronology - 'ISO'.
144      * <p>
145      * The ID uniquely identifies the {@code Chronology}.
146      * It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}.
147      *
148      * @return the chronology ID - 'ISO'
149      * @see #getCalendarType()
150      */
151     @Override
getId()152     public String getId() {
153         return "ISO";
154     }
155 
156     /**
157      * Gets the calendar type of the underlying calendar system - 'iso8601'.
158      * <p>
159      * The calendar type is an identifier defined by the
160      * <em>Unicode Locale Data Markup Language (LDML)</em> specification.
161      * It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}.
162      * It can also be used as part of a locale, accessible via
163      * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'.
164      *
165      * @return the calendar system type - 'iso8601'
166      * @see #getId()
167      */
168     @Override
getCalendarType()169     public String getCalendarType() {
170         return "iso8601";
171     }
172 
173     //-----------------------------------------------------------------------
174     /**
175      * Obtains an ISO local date from the era, year-of-era, month-of-year
176      * and day-of-month fields.
177      *
178      * @param era  the ISO era, not null
179      * @param yearOfEra  the ISO year-of-era
180      * @param month  the ISO month-of-year
181      * @param dayOfMonth  the ISO day-of-month
182      * @return the ISO local date, not null
183      * @throws DateTimeException if unable to create the date
184      * @throws ClassCastException if the type of {@code era} is not {@code IsoEra}
185      */
186     @Override  // override with covariant return type
date(Era era, int yearOfEra, int month, int dayOfMonth)187     public LocalDate date(Era era, int yearOfEra, int month, int dayOfMonth) {
188         return date(prolepticYear(era, yearOfEra), month, dayOfMonth);
189     }
190 
191     /**
192      * Obtains an ISO local date from the proleptic-year, month-of-year
193      * and day-of-month fields.
194      * <p>
195      * This is equivalent to {@link LocalDate#of(int, int, int)}.
196      *
197      * @param prolepticYear  the ISO proleptic-year
198      * @param month  the ISO month-of-year
199      * @param dayOfMonth  the ISO day-of-month
200      * @return the ISO local date, not null
201      * @throws DateTimeException if unable to create the date
202      */
203     @Override  // override with covariant return type
date(int prolepticYear, int month, int dayOfMonth)204     public LocalDate date(int prolepticYear, int month, int dayOfMonth) {
205         return LocalDate.of(prolepticYear, month, dayOfMonth);
206     }
207 
208     /**
209      * Obtains an ISO local date from the era, year-of-era and day-of-year fields.
210      *
211      * @param era  the ISO era, not null
212      * @param yearOfEra  the ISO year-of-era
213      * @param dayOfYear  the ISO day-of-year
214      * @return the ISO local date, not null
215      * @throws DateTimeException if unable to create the date
216      */
217     @Override  // override with covariant return type
dateYearDay(Era era, int yearOfEra, int dayOfYear)218     public LocalDate dateYearDay(Era era, int yearOfEra, int dayOfYear) {
219         return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear);
220     }
221 
222     /**
223      * Obtains an ISO local date from the proleptic-year and day-of-year fields.
224      * <p>
225      * This is equivalent to {@link LocalDate#ofYearDay(int, int)}.
226      *
227      * @param prolepticYear  the ISO proleptic-year
228      * @param dayOfYear  the ISO day-of-year
229      * @return the ISO local date, not null
230      * @throws DateTimeException if unable to create the date
231      */
232     @Override  // override with covariant return type
dateYearDay(int prolepticYear, int dayOfYear)233     public LocalDate dateYearDay(int prolepticYear, int dayOfYear) {
234         return LocalDate.ofYearDay(prolepticYear, dayOfYear);
235     }
236 
237     /**
238      * Obtains an ISO local date from the epoch-day.
239      * <p>
240      * This is equivalent to {@link LocalDate#ofEpochDay(long)}.
241      *
242      * @param epochDay  the epoch day
243      * @return the ISO local date, not null
244      * @throws DateTimeException if unable to create the date
245      */
246     @Override  // override with covariant return type
dateEpochDay(long epochDay)247     public LocalDate dateEpochDay(long epochDay) {
248         return LocalDate.ofEpochDay(epochDay);
249     }
250 
251     //-----------------------------------------------------------------------
252     /**
253      * Obtains an ISO local date from another date-time object.
254      * <p>
255      * This is equivalent to {@link LocalDate#from(TemporalAccessor)}.
256      *
257      * @param temporal  the date-time object to convert, not null
258      * @return the ISO local date, not null
259      * @throws DateTimeException if unable to create the date
260      */
261     @Override  // override with covariant return type
date(TemporalAccessor temporal)262     public LocalDate date(TemporalAccessor temporal) {
263         return LocalDate.from(temporal);
264     }
265 
266     /**
267      * Obtains an ISO local date-time from another date-time object.
268      * <p>
269      * This is equivalent to {@link LocalDateTime#from(TemporalAccessor)}.
270      *
271      * @param temporal  the date-time object to convert, not null
272      * @return the ISO local date-time, not null
273      * @throws DateTimeException if unable to create the date-time
274      */
275     @Override  // override with covariant return type
localDateTime(TemporalAccessor temporal)276     public LocalDateTime localDateTime(TemporalAccessor temporal) {
277         return LocalDateTime.from(temporal);
278     }
279 
280     /**
281      * Obtains an ISO zoned date-time from another date-time object.
282      * <p>
283      * This is equivalent to {@link ZonedDateTime#from(TemporalAccessor)}.
284      *
285      * @param temporal  the date-time object to convert, not null
286      * @return the ISO zoned date-time, not null
287      * @throws DateTimeException if unable to create the date-time
288      */
289     @Override  // override with covariant return type
zonedDateTime(TemporalAccessor temporal)290     public ZonedDateTime zonedDateTime(TemporalAccessor temporal) {
291         return ZonedDateTime.from(temporal);
292     }
293 
294     /**
295      * Obtains an ISO zoned date-time in this chronology from an {@code Instant}.
296      * <p>
297      * This is equivalent to {@link ZonedDateTime#ofInstant(Instant, ZoneId)}.
298      *
299      * @param instant  the instant to create the date-time from, not null
300      * @param zone  the time-zone, not null
301      * @return the zoned date-time, not null
302      * @throws DateTimeException if the result exceeds the supported range
303      */
304     @Override
zonedDateTime(Instant instant, ZoneId zone)305     public ZonedDateTime zonedDateTime(Instant instant, ZoneId zone) {
306         return ZonedDateTime.ofInstant(instant, zone);
307     }
308 
309     //-----------------------------------------------------------------------
310     /**
311      * Obtains the current ISO local date from the system clock in the default time-zone.
312      * <p>
313      * This will query the {@link Clock#systemDefaultZone() system clock} in the default
314      * time-zone to obtain the current date.
315      * <p>
316      * Using this method will prevent the ability to use an alternate clock for testing
317      * because the clock is hard-coded.
318      *
319      * @return the current ISO local date using the system clock and default time-zone, not null
320      * @throws DateTimeException if unable to create the date
321      */
322     @Override  // override with covariant return type
dateNow()323     public LocalDate dateNow() {
324         return dateNow(Clock.systemDefaultZone());
325     }
326 
327     /**
328      * Obtains the current ISO local date from the system clock in the specified time-zone.
329      * <p>
330      * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date.
331      * Specifying the time-zone avoids dependence on the default time-zone.
332      * <p>
333      * Using this method will prevent the ability to use an alternate clock for testing
334      * because the clock is hard-coded.
335      *
336      * @return the current ISO local date using the system clock, not null
337      * @throws DateTimeException if unable to create the date
338      */
339     @Override  // override with covariant return type
dateNow(ZoneId zone)340     public LocalDate dateNow(ZoneId zone) {
341         return dateNow(Clock.system(zone));
342     }
343 
344     /**
345      * Obtains the current ISO local date from the specified clock.
346      * <p>
347      * This will query the specified clock to obtain the current date - today.
348      * Using this method allows the use of an alternate clock for testing.
349      * The alternate clock may be introduced using {@link Clock dependency injection}.
350      *
351      * @param clock  the clock to use, not null
352      * @return the current ISO local date, not null
353      * @throws DateTimeException if unable to create the date
354      */
355     @Override  // override with covariant return type
dateNow(Clock clock)356     public LocalDate dateNow(Clock clock) {
357         Objects.requireNonNull(clock, "clock");
358         return date(LocalDate.now(clock));
359     }
360 
361     //-----------------------------------------------------------------------
362     /**
363      * Checks if the year is a leap year, according to the ISO proleptic
364      * calendar system rules.
365      * <p>
366      * This method applies the current rules for leap years across the whole time-line.
367      * In general, a year is a leap year if it is divisible by four without
368      * remainder. However, years divisible by 100, are not leap years, with
369      * the exception of years divisible by 400 which are.
370      * <p>
371      * For example, 1904 is a leap year it is divisible by 4.
372      * 1900 was not a leap year as it is divisible by 100, however 2000 was a
373      * leap year as it is divisible by 400.
374      * <p>
375      * The calculation is proleptic - applying the same rules into the far future and far past.
376      * This is historically inaccurate, but is correct for the ISO-8601 standard.
377      *
378      * @param prolepticYear  the ISO proleptic year to check
379      * @return true if the year is leap, false otherwise
380      */
381     @Override
isLeapYear(long prolepticYear)382     public boolean isLeapYear(long prolepticYear) {
383         return ((prolepticYear & 3) == 0) && ((prolepticYear % 100) != 0 || (prolepticYear % 400) == 0);
384     }
385 
386     @Override
prolepticYear(Era era, int yearOfEra)387     public int prolepticYear(Era era, int yearOfEra) {
388         if (era instanceof IsoEra == false) {
389             throw new ClassCastException("Era must be IsoEra");
390         }
391         return (era == IsoEra.CE ? yearOfEra : 1 - yearOfEra);
392     }
393 
394     @Override
eraOf(int eraValue)395     public IsoEra eraOf(int eraValue) {
396         return IsoEra.of(eraValue);
397     }
398 
399     @Override
eras()400     public List<Era> eras() {
401         return Arrays.<Era>asList(IsoEra.values());
402     }
403 
404     //-----------------------------------------------------------------------
405     /**
406      * Resolves parsed {@code ChronoField} values into a date during parsing.
407      * <p>
408      * Most {@code TemporalField} implementations are resolved using the
409      * resolve method on the field. By contrast, the {@code ChronoField} class
410      * defines fields that only have meaning relative to the chronology.
411      * As such, {@code ChronoField} date fields are resolved here in the
412      * context of a specific chronology.
413      * <p>
414      * {@code ChronoField} instances on the ISO calendar system are resolved
415      * as follows.
416      * <ul>
417      * <li>{@code EPOCH_DAY} - If present, this is converted to a {@code LocalDate}
418      *  and all other date fields are then cross-checked against the date.
419      * <li>{@code PROLEPTIC_MONTH} - If present, then it is split into the
420      *  {@code YEAR} and {@code MONTH_OF_YEAR}. If the mode is strict or smart
421      *  then the field is validated.
422      * <li>{@code YEAR_OF_ERA} and {@code ERA} - If both are present, then they
423      *  are combined to form a {@code YEAR}. In lenient mode, the {@code YEAR_OF_ERA}
424      *  range is not validated, in smart and strict mode it is. The {@code ERA} is
425      *  validated for range in all three modes. If only the {@code YEAR_OF_ERA} is
426      *  present, and the mode is smart or lenient, then the current era (CE/AD)
427      *  is assumed. In strict mode, no era is assumed and the {@code YEAR_OF_ERA} is
428      *  left untouched. If only the {@code ERA} is present, then it is left untouched.
429      * <li>{@code YEAR}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} -
430      *  If all three are present, then they are combined to form a {@code LocalDate}.
431      *  In all three modes, the {@code YEAR} is validated. If the mode is smart or strict,
432      *  then the month and day are validated, with the day validated from 1 to 31.
433      *  If the mode is lenient, then the date is combined in a manner equivalent to
434      *  creating a date on the first of January in the requested year, then adding
435      *  the difference in months, then the difference in days.
436      *  If the mode is smart, and the day-of-month is greater than the maximum for
437      *  the year-month, then the day-of-month is adjusted to the last day-of-month.
438      *  If the mode is strict, then the three fields must form a valid date.
439      * <li>{@code YEAR} and {@code DAY_OF_YEAR} -
440      *  If both are present, then they are combined to form a {@code LocalDate}.
441      *  In all three modes, the {@code YEAR} is validated.
442      *  If the mode is lenient, then the date is combined in a manner equivalent to
443      *  creating a date on the first of January in the requested year, then adding
444      *  the difference in days.
445      *  If the mode is smart or strict, then the two fields must form a valid date.
446      * <li>{@code YEAR}, {@code MONTH_OF_YEAR}, {@code ALIGNED_WEEK_OF_MONTH} and
447      *  {@code ALIGNED_DAY_OF_WEEK_IN_MONTH} -
448      *  If all four are present, then they are combined to form a {@code LocalDate}.
449      *  In all three modes, the {@code YEAR} is validated.
450      *  If the mode is lenient, then the date is combined in a manner equivalent to
451      *  creating a date on the first of January in the requested year, then adding
452      *  the difference in months, then the difference in weeks, then in days.
453      *  If the mode is smart or strict, then the all four fields are validated to
454      *  their outer ranges. The date is then combined in a manner equivalent to
455      *  creating a date on the first day of the requested year and month, then adding
456      *  the amount in weeks and days to reach their values. If the mode is strict,
457      *  the date is additionally validated to check that the day and week adjustment
458      *  did not change the month.
459      * <li>{@code YEAR}, {@code MONTH_OF_YEAR}, {@code ALIGNED_WEEK_OF_MONTH} and
460      *  {@code DAY_OF_WEEK} - If all four are present, then they are combined to
461      *  form a {@code LocalDate}. The approach is the same as described above for
462      *  years, months and weeks in {@code ALIGNED_DAY_OF_WEEK_IN_MONTH}.
463      *  The day-of-week is adjusted as the next or same matching day-of-week once
464      *  the years, months and weeks have been handled.
465      * <li>{@code YEAR}, {@code ALIGNED_WEEK_OF_YEAR} and {@code ALIGNED_DAY_OF_WEEK_IN_YEAR} -
466      *  If all three are present, then they are combined to form a {@code LocalDate}.
467      *  In all three modes, the {@code YEAR} is validated.
468      *  If the mode is lenient, then the date is combined in a manner equivalent to
469      *  creating a date on the first of January in the requested year, then adding
470      *  the difference in weeks, then in days.
471      *  If the mode is smart or strict, then the all three fields are validated to
472      *  their outer ranges. The date is then combined in a manner equivalent to
473      *  creating a date on the first day of the requested year, then adding
474      *  the amount in weeks and days to reach their values. If the mode is strict,
475      *  the date is additionally validated to check that the day and week adjustment
476      *  did not change the year.
477      * <li>{@code YEAR}, {@code ALIGNED_WEEK_OF_YEAR} and {@code DAY_OF_WEEK} -
478      *  If all three are present, then they are combined to form a {@code LocalDate}.
479      *  The approach is the same as described above for years and weeks in
480      *  {@code ALIGNED_DAY_OF_WEEK_IN_YEAR}. The day-of-week is adjusted as the
481      *  next or same matching day-of-week once the years and weeks have been handled.
482      * </ul>
483      *
484      * @param fieldValues  the map of fields to values, which can be updated, not null
485      * @param resolverStyle  the requested type of resolve, not null
486      * @return the resolved date, null if insufficient information to create a date
487      * @throws DateTimeException if the date cannot be resolved, typically
488      *  because of a conflict in the input data
489      */
490     @Override  // override for performance
resolveDate(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle)491     public LocalDate resolveDate(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
492         return (LocalDate) super.resolveDate(fieldValues, resolverStyle);
493     }
494 
495     @Override  // override for better proleptic algorithm
resolveProlepticMonth(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle)496     void resolveProlepticMonth(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
497         Long pMonth = fieldValues.remove(PROLEPTIC_MONTH);
498         if (pMonth != null) {
499             if (resolverStyle != ResolverStyle.LENIENT) {
500                 PROLEPTIC_MONTH.checkValidValue(pMonth);
501             }
502             addFieldValue(fieldValues, MONTH_OF_YEAR, Math.floorMod(pMonth, 12) + 1);
503             addFieldValue(fieldValues, YEAR, Math.floorDiv(pMonth, 12));
504         }
505     }
506 
507     @Override  // override for enhanced behaviour
resolveYearOfEra(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle)508     LocalDate resolveYearOfEra(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
509         Long yoeLong = fieldValues.remove(YEAR_OF_ERA);
510         if (yoeLong != null) {
511             if (resolverStyle != ResolverStyle.LENIENT) {
512                 YEAR_OF_ERA.checkValidValue(yoeLong);
513             }
514             Long era = fieldValues.remove(ERA);
515             if (era == null) {
516                 Long year = fieldValues.get(YEAR);
517                 if (resolverStyle == ResolverStyle.STRICT) {
518                     // do not invent era if strict, but do cross-check with year
519                     if (year != null) {
520                         addFieldValue(fieldValues, YEAR, (year > 0 ? yoeLong: Math.subtractExact(1, yoeLong)));
521                     } else {
522                         // reinstate the field removed earlier, no cross-check issues
523                         fieldValues.put(YEAR_OF_ERA, yoeLong);
524                     }
525                 } else {
526                     // invent era
527                     addFieldValue(fieldValues, YEAR, (year == null || year > 0 ? yoeLong: Math.subtractExact(1, yoeLong)));
528                 }
529             } else if (era.longValue() == 1L) {
530                 addFieldValue(fieldValues, YEAR, yoeLong);
531             } else if (era.longValue() == 0L) {
532                 addFieldValue(fieldValues, YEAR, Math.subtractExact(1, yoeLong));
533             } else {
534                 throw new DateTimeException("Invalid value for era: " + era);
535             }
536         } else if (fieldValues.containsKey(ERA)) {
537             ERA.checkValidValue(fieldValues.get(ERA));  // always validated
538         }
539         return null;
540     }
541 
542     @Override  // override for performance
resolveYMD(Map <TemporalField, Long> fieldValues, ResolverStyle resolverStyle)543     LocalDate resolveYMD(Map <TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
544         int y = YEAR.checkValidIntValue(fieldValues.remove(YEAR));
545         if (resolverStyle == ResolverStyle.LENIENT) {
546             long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1);
547             long days = Math.subtractExact(fieldValues.remove(DAY_OF_MONTH), 1);
548             return LocalDate.of(y, 1, 1).plusMonths(months).plusDays(days);
549         }
550         int moy = MONTH_OF_YEAR.checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR));
551         int dom = DAY_OF_MONTH.checkValidIntValue(fieldValues.remove(DAY_OF_MONTH));
552         if (resolverStyle == ResolverStyle.SMART) {  // previous valid
553             if (moy == 4 || moy == 6 || moy == 9 || moy == 11) {
554                 dom = Math.min(dom, 30);
555             } else if (moy == 2) {
556                 dom = Math.min(dom, Month.FEBRUARY.length(Year.isLeap(y)));
557 
558             }
559         }
560         return LocalDate.of(y, moy, dom);
561     }
562 
563     //-----------------------------------------------------------------------
564     @Override
range(ChronoField field)565     public ValueRange range(ChronoField field) {
566         return field.range();
567     }
568 
569     //-----------------------------------------------------------------------
570     /**
571      * Obtains a period for this chronology based on years, months and days.
572      * <p>
573      * This returns a period tied to the ISO chronology using the specified
574      * years, months and days. See {@link Period} for further details.
575      *
576      * @param years  the number of years, may be negative
577      * @param months  the number of years, may be negative
578      * @param days  the number of years, may be negative
579      * @return the period in terms of this chronology, not null
580      * @return the ISO period, not null
581      */
582     @Override  // override with covariant return type
period(int years, int months, int days)583     public Period period(int years, int months, int days) {
584         return Period.of(years, months, days);
585     }
586 
587     //-----------------------------------------------------------------------
588     /**
589      * Writes the Chronology using a
590      * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
591      * @serialData
592      * <pre>
593      *  out.writeByte(1);     // identifies a Chronology
594      *  out.writeUTF(getId());
595      * </pre>
596      *
597      * @return the instance of {@code Ser}, not null
598      */
599     @Override
writeReplace()600     Object writeReplace() {
601         return super.writeReplace();
602     }
603 
604     /**
605      * Defend against malicious streams.
606      *
607      * @param s the stream to read
608      * @throws InvalidObjectException always
609      */
readObject(ObjectInputStream s)610     private void readObject(ObjectInputStream s) throws InvalidObjectException {
611         throw new InvalidObjectException("Deserialization via serialization delegate");
612     }
613 }
614