• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2012, 2016, 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     private static final long serialVersionUID = -1440403870442975015L;
137 
138     private static final long DAYS_0000_TO_1970 = (146097 * 5L) - (30L * 365L + 7L); // taken from LocalDate
139 
140     /**
141      * Restricted constructor.
142      */
IsoChronology()143     private IsoChronology() {
144     }
145 
146     //-----------------------------------------------------------------------
147     /**
148      * Gets the ID of the chronology - 'ISO'.
149      * <p>
150      * The ID uniquely identifies the {@code Chronology}.
151      * It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}.
152      *
153      * @return the chronology ID - 'ISO'
154      * @see #getCalendarType()
155      */
156     @Override
getId()157     public String getId() {
158         return "ISO";
159     }
160 
161     /**
162      * Gets the calendar type of the underlying calendar system - 'iso8601'.
163      * <p>
164      * The calendar type is an identifier defined by the
165      * <em>Unicode Locale Data Markup Language (LDML)</em> specification.
166      * It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}.
167      * It can also be used as part of a locale, accessible via
168      * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'.
169      *
170      * @return the calendar system type - 'iso8601'
171      * @see #getId()
172      */
173     @Override
getCalendarType()174     public String getCalendarType() {
175         return "iso8601";
176     }
177 
178     //-----------------------------------------------------------------------
179     /**
180      * Obtains an ISO local date from the era, year-of-era, month-of-year
181      * and day-of-month fields.
182      *
183      * @param era  the ISO era, not null
184      * @param yearOfEra  the ISO year-of-era
185      * @param month  the ISO month-of-year
186      * @param dayOfMonth  the ISO day-of-month
187      * @return the ISO local date, not null
188      * @throws DateTimeException if unable to create the date
189      * @throws ClassCastException if the type of {@code era} is not {@code IsoEra}
190      */
191     @Override  // override with covariant return type
date(Era era, int yearOfEra, int month, int dayOfMonth)192     public LocalDate date(Era era, int yearOfEra, int month, int dayOfMonth) {
193         return date(prolepticYear(era, yearOfEra), month, dayOfMonth);
194     }
195 
196     /**
197      * Obtains an ISO local date from the proleptic-year, month-of-year
198      * and day-of-month fields.
199      * <p>
200      * This is equivalent to {@link LocalDate#of(int, int, int)}.
201      *
202      * @param prolepticYear  the ISO proleptic-year
203      * @param month  the ISO month-of-year
204      * @param dayOfMonth  the ISO day-of-month
205      * @return the ISO local date, not null
206      * @throws DateTimeException if unable to create the date
207      */
208     @Override  // override with covariant return type
date(int prolepticYear, int month, int dayOfMonth)209     public LocalDate date(int prolepticYear, int month, int dayOfMonth) {
210         return LocalDate.of(prolepticYear, month, dayOfMonth);
211     }
212 
213     /**
214      * Obtains an ISO local date from the era, year-of-era and day-of-year fields.
215      *
216      * @param era  the ISO era, not null
217      * @param yearOfEra  the ISO year-of-era
218      * @param dayOfYear  the ISO day-of-year
219      * @return the ISO local date, not null
220      * @throws DateTimeException if unable to create the date
221      */
222     @Override  // override with covariant return type
dateYearDay(Era era, int yearOfEra, int dayOfYear)223     public LocalDate dateYearDay(Era era, int yearOfEra, int dayOfYear) {
224         return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear);
225     }
226 
227     /**
228      * Obtains an ISO local date from the proleptic-year and day-of-year fields.
229      * <p>
230      * This is equivalent to {@link LocalDate#ofYearDay(int, int)}.
231      *
232      * @param prolepticYear  the ISO proleptic-year
233      * @param dayOfYear  the ISO day-of-year
234      * @return the ISO local date, not null
235      * @throws DateTimeException if unable to create the date
236      */
237     @Override  // override with covariant return type
dateYearDay(int prolepticYear, int dayOfYear)238     public LocalDate dateYearDay(int prolepticYear, int dayOfYear) {
239         return LocalDate.ofYearDay(prolepticYear, dayOfYear);
240     }
241 
242     /**
243      * Obtains an ISO local date from the epoch-day.
244      * <p>
245      * This is equivalent to {@link LocalDate#ofEpochDay(long)}.
246      *
247      * @param epochDay  the epoch day
248      * @return the ISO local date, not null
249      * @throws DateTimeException if unable to create the date
250      */
251     @Override  // override with covariant return type
dateEpochDay(long epochDay)252     public LocalDate dateEpochDay(long epochDay) {
253         return LocalDate.ofEpochDay(epochDay);
254     }
255 
256     //-----------------------------------------------------------------------
257     /**
258      * Obtains an ISO local date from another date-time object.
259      * <p>
260      * This is equivalent to {@link LocalDate#from(TemporalAccessor)}.
261      *
262      * @param temporal  the date-time object to convert, not null
263      * @return the ISO local date, not null
264      * @throws DateTimeException if unable to create the date
265      */
266     @Override  // override with covariant return type
date(TemporalAccessor temporal)267     public LocalDate date(TemporalAccessor temporal) {
268         return LocalDate.from(temporal);
269     }
270 
271     //-----------------------------------------------------------------------
272     /**
273      * Gets the number of seconds from the epoch of 1970-01-01T00:00:00Z.
274      * <p>
275      * The number of seconds is calculated using the year,
276      * month, day-of-month, hour, minute, second, and zoneOffset.
277      *
278      * @param prolepticYear  the year, from MIN_YEAR to MAX_YEAR
279      * @param month  the month-of-year, from 1 to 12
280      * @param dayOfMonth  the day-of-month, from 1 to 31
281      * @param hour  the hour-of-day, from 0 to 23
282      * @param minute  the minute-of-hour, from 0 to 59
283      * @param second  the second-of-minute, from 0 to 59
284      * @param zoneOffset the zone offset, not null
285      * @return the number of seconds relative to 1970-01-01T00:00:00Z, may be negative
286      * @throws DateTimeException if the value of any argument is out of range,
287      *         or if the day-of-month is invalid for the month-of-year
288      * @since 9
289      */
290     @Override
epochSecond(int prolepticYear, int month, int dayOfMonth, int hour, int minute, int second, ZoneOffset zoneOffset)291     public long epochSecond(int prolepticYear, int month, int dayOfMonth,
292                             int hour, int minute, int second, ZoneOffset zoneOffset) {
293         YEAR.checkValidValue(prolepticYear);
294         MONTH_OF_YEAR.checkValidValue(month);
295         DAY_OF_MONTH.checkValidValue(dayOfMonth);
296         HOUR_OF_DAY.checkValidValue(hour);
297         MINUTE_OF_HOUR.checkValidValue(minute);
298         SECOND_OF_MINUTE.checkValidValue(second);
299         Objects.requireNonNull(zoneOffset, "zoneOffset");
300         if (dayOfMonth > 28) {
301             int dom = numberOfDaysOfMonth(prolepticYear, month);
302             if (dayOfMonth > dom) {
303                 if (dayOfMonth == 29) {
304                     throw new DateTimeException("Invalid date 'February 29' as '" + prolepticYear + "' is not a leap year");
305                 } else {
306                     throw new DateTimeException("Invalid date '" + Month.of(month).name() + " " + dayOfMonth + "'");
307                 }
308             }
309         }
310 
311         long totalDays = 0;
312         int timeinSec = 0;
313         totalDays += 365L * prolepticYear;
314         if (prolepticYear >= 0) {
315             totalDays += (prolepticYear + 3L) / 4 - (prolepticYear + 99L) / 100 + (prolepticYear + 399L) / 400;
316         } else {
317             totalDays -= prolepticYear / -4 - prolepticYear / -100 + prolepticYear / -400;
318         }
319         totalDays += (367 * month - 362) / 12;
320         totalDays += dayOfMonth - 1;
321         if (month > 2) {
322             totalDays--;
323             if (IsoChronology.INSTANCE.isLeapYear(prolepticYear) == false) {
324                 totalDays--;
325             }
326         }
327         totalDays -= DAYS_0000_TO_1970;
328         timeinSec = (hour * 60 + minute ) * 60 + second;
329         return Math.addExact(Math.multiplyExact(totalDays, 86400L), timeinSec - zoneOffset.getTotalSeconds());
330      }
331 
332     /**
333      * Gets the number of days for the given month in the given year.
334      *
335      * @param year the year to represent, from MIN_YEAR to MAX_YEAR
336      * @param month the month-of-year to represent, from 1 to 12
337      * @return the number of days for the given month in the given year
338      */
numberOfDaysOfMonth(int year, int month)339     private int numberOfDaysOfMonth(int year, int month) {
340         int dom;
341         switch (month) {
342             case 2:
343                 dom = (IsoChronology.INSTANCE.isLeapYear(year) ? 29 : 28);
344                 break;
345             case 4:
346             case 6:
347             case 9:
348             case 11:
349                 dom = 30;
350                 break;
351             default:
352                 dom = 31;
353                 break;
354         }
355         return dom;
356     }
357 
358 
359     /**
360      * Obtains an ISO local date-time from another date-time object.
361      * <p>
362      * This is equivalent to {@link LocalDateTime#from(TemporalAccessor)}.
363      *
364      * @param temporal  the date-time object to convert, not null
365      * @return the ISO local date-time, not null
366      * @throws DateTimeException if unable to create the date-time
367      */
368     @Override  // override with covariant return type
localDateTime(TemporalAccessor temporal)369     public LocalDateTime localDateTime(TemporalAccessor temporal) {
370         return LocalDateTime.from(temporal);
371     }
372 
373     /**
374      * Obtains an ISO zoned date-time from another date-time object.
375      * <p>
376      * This is equivalent to {@link ZonedDateTime#from(TemporalAccessor)}.
377      *
378      * @param temporal  the date-time object to convert, not null
379      * @return the ISO zoned date-time, not null
380      * @throws DateTimeException if unable to create the date-time
381      */
382     @Override  // override with covariant return type
zonedDateTime(TemporalAccessor temporal)383     public ZonedDateTime zonedDateTime(TemporalAccessor temporal) {
384         return ZonedDateTime.from(temporal);
385     }
386 
387     /**
388      * Obtains an ISO zoned date-time in this chronology from an {@code Instant}.
389      * <p>
390      * This is equivalent to {@link ZonedDateTime#ofInstant(Instant, ZoneId)}.
391      *
392      * @param instant  the instant to create the date-time from, not null
393      * @param zone  the time-zone, not null
394      * @return the zoned date-time, not null
395      * @throws DateTimeException if the result exceeds the supported range
396      */
397     @Override
zonedDateTime(Instant instant, ZoneId zone)398     public ZonedDateTime zonedDateTime(Instant instant, ZoneId zone) {
399         return ZonedDateTime.ofInstant(instant, zone);
400     }
401 
402     //-----------------------------------------------------------------------
403     /**
404      * Obtains the current ISO local date from the system clock in the default time-zone.
405      * <p>
406      * This will query the {@link Clock#systemDefaultZone() system clock} in the default
407      * time-zone to obtain the current date.
408      * <p>
409      * Using this method will prevent the ability to use an alternate clock for testing
410      * because the clock is hard-coded.
411      *
412      * @return the current ISO local date using the system clock and default time-zone, not null
413      * @throws DateTimeException if unable to create the date
414      */
415     @Override  // override with covariant return type
dateNow()416     public LocalDate dateNow() {
417         return dateNow(Clock.systemDefaultZone());
418     }
419 
420     /**
421      * Obtains the current ISO local date from the system clock in the specified time-zone.
422      * <p>
423      * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date.
424      * Specifying the time-zone avoids dependence on the default time-zone.
425      * <p>
426      * Using this method will prevent the ability to use an alternate clock for testing
427      * because the clock is hard-coded.
428      *
429      * @return the current ISO local date using the system clock, not null
430      * @throws DateTimeException if unable to create the date
431      */
432     @Override  // override with covariant return type
dateNow(ZoneId zone)433     public LocalDate dateNow(ZoneId zone) {
434         return dateNow(Clock.system(zone));
435     }
436 
437     /**
438      * Obtains the current ISO local date from the specified clock.
439      * <p>
440      * This will query the specified clock to obtain the current date - today.
441      * Using this method allows the use of an alternate clock for testing.
442      * The alternate clock may be introduced using {@link Clock dependency injection}.
443      *
444      * @param clock  the clock to use, not null
445      * @return the current ISO local date, not null
446      * @throws DateTimeException if unable to create the date
447      */
448     @Override  // override with covariant return type
dateNow(Clock clock)449     public LocalDate dateNow(Clock clock) {
450         Objects.requireNonNull(clock, "clock");
451         return date(LocalDate.now(clock));
452     }
453 
454     //-----------------------------------------------------------------------
455     /**
456      * Checks if the year is a leap year, according to the ISO proleptic
457      * calendar system rules.
458      * <p>
459      * This method applies the current rules for leap years across the whole time-line.
460      * In general, a year is a leap year if it is divisible by four without
461      * remainder. However, years divisible by 100, are not leap years, with
462      * the exception of years divisible by 400 which are.
463      * <p>
464      * For example, 1904 is a leap year it is divisible by 4.
465      * 1900 was not a leap year as it is divisible by 100, however 2000 was a
466      * leap year as it is divisible by 400.
467      * <p>
468      * The calculation is proleptic - applying the same rules into the far future and far past.
469      * This is historically inaccurate, but is correct for the ISO-8601 standard.
470      *
471      * @param prolepticYear  the ISO proleptic year to check
472      * @return true if the year is leap, false otherwise
473      */
474     @Override
isLeapYear(long prolepticYear)475     public boolean isLeapYear(long prolepticYear) {
476         return ((prolepticYear & 3) == 0) && ((prolepticYear % 100) != 0 || (prolepticYear % 400) == 0);
477     }
478 
479     @Override
prolepticYear(Era era, int yearOfEra)480     public int prolepticYear(Era era, int yearOfEra) {
481         if (era instanceof IsoEra == false) {
482             throw new ClassCastException("Era must be IsoEra");
483         }
484         return (era == IsoEra.CE ? yearOfEra : 1 - yearOfEra);
485     }
486 
487     @Override
eraOf(int eraValue)488     public IsoEra eraOf(int eraValue) {
489         return IsoEra.of(eraValue);
490     }
491 
492     @Override
eras()493     public List<Era> eras() {
494         return List.of(IsoEra.values());
495     }
496 
497     //-----------------------------------------------------------------------
498     /**
499      * Resolves parsed {@code ChronoField} values into a date during parsing.
500      * <p>
501      * Most {@code TemporalField} implementations are resolved using the
502      * resolve method on the field. By contrast, the {@code ChronoField} class
503      * defines fields that only have meaning relative to the chronology.
504      * As such, {@code ChronoField} date fields are resolved here in the
505      * context of a specific chronology.
506      * <p>
507      * {@code ChronoField} instances on the ISO calendar system are resolved
508      * as follows.
509      * <ul>
510      * <li>{@code EPOCH_DAY} - If present, this is converted to a {@code LocalDate}
511      *  and all other date fields are then cross-checked against the date.
512      * <li>{@code PROLEPTIC_MONTH} - If present, then it is split into the
513      *  {@code YEAR} and {@code MONTH_OF_YEAR}. If the mode is strict or smart
514      *  then the field is validated.
515      * <li>{@code YEAR_OF_ERA} and {@code ERA} - If both are present, then they
516      *  are combined to form a {@code YEAR}. In lenient mode, the {@code YEAR_OF_ERA}
517      *  range is not validated, in smart and strict mode it is. The {@code ERA} is
518      *  validated for range in all three modes. If only the {@code YEAR_OF_ERA} is
519      *  present, and the mode is smart or lenient, then the current era (CE/AD)
520      *  is assumed. In strict mode, no era is assumed and the {@code YEAR_OF_ERA} is
521      *  left untouched. If only the {@code ERA} is present, then it is left untouched.
522      * <li>{@code YEAR}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} -
523      *  If all three are present, then they are combined to form a {@code LocalDate}.
524      *  In all three modes, the {@code YEAR} is validated. If the mode is smart or strict,
525      *  then the month and day are validated, with the day validated from 1 to 31.
526      *  If the mode is lenient, then the date is combined in a manner equivalent to
527      *  creating a date on the first of January in the requested year, then adding
528      *  the difference in months, then the difference in days.
529      *  If the mode is smart, and the day-of-month is greater than the maximum for
530      *  the year-month, then the day-of-month is adjusted to the last day-of-month.
531      *  If the mode is strict, then the three fields must form a valid date.
532      * <li>{@code YEAR} and {@code DAY_OF_YEAR} -
533      *  If both are present, then they are combined to form a {@code LocalDate}.
534      *  In all three modes, the {@code YEAR} is validated.
535      *  If the mode is lenient, then the date is combined in a manner equivalent to
536      *  creating a date on the first of January in the requested year, then adding
537      *  the difference in days.
538      *  If the mode is smart or strict, then the two fields must form a valid date.
539      * <li>{@code YEAR}, {@code MONTH_OF_YEAR}, {@code ALIGNED_WEEK_OF_MONTH} and
540      *  {@code ALIGNED_DAY_OF_WEEK_IN_MONTH} -
541      *  If all four are present, then they are combined to form a {@code LocalDate}.
542      *  In all three modes, the {@code YEAR} is validated.
543      *  If the mode is lenient, then the date is combined in a manner equivalent to
544      *  creating a date on the first of January in the requested year, then adding
545      *  the difference in months, then the difference in weeks, then in days.
546      *  If the mode is smart or strict, then the all four fields are validated to
547      *  their outer ranges. The date is then combined in a manner equivalent to
548      *  creating a date on the first day of the requested year and month, then adding
549      *  the amount in weeks and days to reach their values. If the mode is strict,
550      *  the date is additionally validated to check that the day and week adjustment
551      *  did not change the month.
552      * <li>{@code YEAR}, {@code MONTH_OF_YEAR}, {@code ALIGNED_WEEK_OF_MONTH} and
553      *  {@code DAY_OF_WEEK} - If all four are present, then they are combined to
554      *  form a {@code LocalDate}. The approach is the same as described above for
555      *  years, months and weeks in {@code ALIGNED_DAY_OF_WEEK_IN_MONTH}.
556      *  The day-of-week is adjusted as the next or same matching day-of-week once
557      *  the years, months and weeks have been handled.
558      * <li>{@code YEAR}, {@code ALIGNED_WEEK_OF_YEAR} and {@code ALIGNED_DAY_OF_WEEK_IN_YEAR} -
559      *  If all three are present, then they are combined to form a {@code LocalDate}.
560      *  In all three modes, the {@code YEAR} is validated.
561      *  If the mode is lenient, then the date is combined in a manner equivalent to
562      *  creating a date on the first of January in the requested year, then adding
563      *  the difference in weeks, then in days.
564      *  If the mode is smart or strict, then the all three fields are validated to
565      *  their outer ranges. The date is then combined in a manner equivalent to
566      *  creating a date on the first day of the requested year, then adding
567      *  the amount in weeks and days to reach their values. If the mode is strict,
568      *  the date is additionally validated to check that the day and week adjustment
569      *  did not change the year.
570      * <li>{@code YEAR}, {@code ALIGNED_WEEK_OF_YEAR} and {@code DAY_OF_WEEK} -
571      *  If all three are present, then they are combined to form a {@code LocalDate}.
572      *  The approach is the same as described above for years and weeks in
573      *  {@code ALIGNED_DAY_OF_WEEK_IN_YEAR}. The day-of-week is adjusted as the
574      *  next or same matching day-of-week once the years and weeks have been handled.
575      * </ul>
576      *
577      * @param fieldValues  the map of fields to values, which can be updated, not null
578      * @param resolverStyle  the requested type of resolve, not null
579      * @return the resolved date, null if insufficient information to create a date
580      * @throws DateTimeException if the date cannot be resolved, typically
581      *  because of a conflict in the input data
582      */
583     @Override  // override for performance
resolveDate(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle)584     public LocalDate resolveDate(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
585         return (LocalDate) super.resolveDate(fieldValues, resolverStyle);
586     }
587 
588     @Override  // override for better proleptic algorithm
resolveProlepticMonth(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle)589     void resolveProlepticMonth(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
590         Long pMonth = fieldValues.remove(PROLEPTIC_MONTH);
591         if (pMonth != null) {
592             if (resolverStyle != ResolverStyle.LENIENT) {
593                 PROLEPTIC_MONTH.checkValidValue(pMonth);
594             }
595             addFieldValue(fieldValues, MONTH_OF_YEAR, Math.floorMod(pMonth, 12) + 1);
596             addFieldValue(fieldValues, YEAR, Math.floorDiv(pMonth, 12));
597         }
598     }
599 
600     @Override  // override for enhanced behaviour
resolveYearOfEra(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle)601     LocalDate resolveYearOfEra(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
602         Long yoeLong = fieldValues.remove(YEAR_OF_ERA);
603         if (yoeLong != null) {
604             if (resolverStyle != ResolverStyle.LENIENT) {
605                 YEAR_OF_ERA.checkValidValue(yoeLong);
606             }
607             Long era = fieldValues.remove(ERA);
608             if (era == null) {
609                 Long year = fieldValues.get(YEAR);
610                 if (resolverStyle == ResolverStyle.STRICT) {
611                     // do not invent era if strict, but do cross-check with year
612                     if (year != null) {
613                         addFieldValue(fieldValues, YEAR, (year > 0 ? yoeLong: Math.subtractExact(1, yoeLong)));
614                     } else {
615                         // reinstate the field removed earlier, no cross-check issues
616                         fieldValues.put(YEAR_OF_ERA, yoeLong);
617                     }
618                 } else {
619                     // invent era
620                     addFieldValue(fieldValues, YEAR, (year == null || year > 0 ? yoeLong: Math.subtractExact(1, yoeLong)));
621                 }
622             } else if (era.longValue() == 1L) {
623                 addFieldValue(fieldValues, YEAR, yoeLong);
624             } else if (era.longValue() == 0L) {
625                 addFieldValue(fieldValues, YEAR, Math.subtractExact(1, yoeLong));
626             } else {
627                 throw new DateTimeException("Invalid value for era: " + era);
628             }
629         } else if (fieldValues.containsKey(ERA)) {
630             ERA.checkValidValue(fieldValues.get(ERA));  // always validated
631         }
632         return null;
633     }
634 
635     @Override  // override for performance
resolveYMD(Map <TemporalField, Long> fieldValues, ResolverStyle resolverStyle)636     LocalDate resolveYMD(Map <TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
637         int y = YEAR.checkValidIntValue(fieldValues.remove(YEAR));
638         if (resolverStyle == ResolverStyle.LENIENT) {
639             long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1);
640             long days = Math.subtractExact(fieldValues.remove(DAY_OF_MONTH), 1);
641             return LocalDate.of(y, 1, 1).plusMonths(months).plusDays(days);
642         }
643         int moy = MONTH_OF_YEAR.checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR));
644         int dom = DAY_OF_MONTH.checkValidIntValue(fieldValues.remove(DAY_OF_MONTH));
645         if (resolverStyle == ResolverStyle.SMART) {  // previous valid
646             if (moy == 4 || moy == 6 || moy == 9 || moy == 11) {
647                 dom = Math.min(dom, 30);
648             } else if (moy == 2) {
649                 dom = Math.min(dom, Month.FEBRUARY.length(Year.isLeap(y)));
650 
651             }
652         }
653         return LocalDate.of(y, moy, dom);
654     }
655 
656     //-----------------------------------------------------------------------
657     @Override
range(ChronoField field)658     public ValueRange range(ChronoField field) {
659         return field.range();
660     }
661 
662     //-----------------------------------------------------------------------
663     /**
664      * Obtains a period for this chronology based on years, months and days.
665      * <p>
666      * This returns a period tied to the ISO chronology using the specified
667      * years, months and days. See {@link Period} for further details.
668      *
669      * @param years  the number of years, may be negative
670      * @param months  the number of years, may be negative
671      * @param days  the number of years, may be negative
672      * @return the period in terms of this chronology, not null
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="../../../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
writeReplace()693     Object writeReplace() {
694         return super.writeReplace();
695     }
696 
697     /**
698      * Defend against malicious streams.
699      *
700      * @param s the stream to read
701      * @throws InvalidObjectException always
702      */
readObject(ObjectInputStream s)703     private void readObject(ObjectInputStream s) throws InvalidObjectException {
704         throw new InvalidObjectException("Deserialization via serialization delegate");
705     }
706 }
707