• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos
3  *
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  *  * Redistributions of source code must retain the above copyright notice,
10  *    this list of conditions and the following disclaimer.
11  *
12  *  * Redistributions in binary form must reproduce the above copyright notice,
13  *    this list of conditions and the following disclaimer in the documentation
14  *    and/or other materials provided with the distribution.
15  *
16  *  * Neither the name of JSR-310 nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 package org.threeten.bp.chrono;
33 
34 import java.io.DataInput;
35 import java.io.DataOutput;
36 import java.io.IOException;
37 import java.io.InvalidObjectException;
38 import java.io.ObjectStreamException;
39 import java.lang.reflect.InvocationTargetException;
40 import java.lang.reflect.Method;
41 import java.util.HashSet;
42 import java.util.List;
43 import java.util.Locale;
44 import java.util.Map;
45 import java.util.ServiceLoader;
46 import java.util.Set;
47 import java.util.concurrent.ConcurrentHashMap;
48 
49 import org.threeten.bp.Clock;
50 import org.threeten.bp.DateTimeException;
51 import org.threeten.bp.Instant;
52 import org.threeten.bp.LocalDate;
53 import org.threeten.bp.LocalTime;
54 import org.threeten.bp.ZoneId;
55 import org.threeten.bp.format.DateTimeFormatterBuilder;
56 import org.threeten.bp.format.ResolverStyle;
57 import org.threeten.bp.format.TextStyle;
58 import org.threeten.bp.jdk8.DefaultInterfaceTemporalAccessor;
59 import org.threeten.bp.jdk8.Jdk8Methods;
60 import org.threeten.bp.temporal.ChronoField;
61 import org.threeten.bp.temporal.Temporal;
62 import org.threeten.bp.temporal.TemporalAccessor;
63 import org.threeten.bp.temporal.TemporalField;
64 import org.threeten.bp.temporal.TemporalQueries;
65 import org.threeten.bp.temporal.TemporalQuery;
66 import org.threeten.bp.temporal.UnsupportedTemporalTypeException;
67 import org.threeten.bp.temporal.ValueRange;
68 
69 /**
70  * A calendar system, used to organize and identify dates.
71  * <p>
72  * The main date and time API is built on the ISO calendar system.
73  * This class operates behind the scenes to represent the general concept of a calendar system.
74  * For example, the Japanese, Minguo, Thai Buddhist and others.
75  * <p>
76  * Most other calendar systems also operate on the shared concepts of year, month and day,
77  * linked to the cycles of the Earth around the Sun, and the Moon around the Earth.
78  * These shared concepts are defined by {@link ChronoField} and are availalbe
79  * for use by any {@code Chronology} implementation:
80  * <pre>
81  *   LocalDate isoDate = ...
82  *   ChronoLocalDate&lt;ThaiBuddhistChrono&gt; minguoDate = ...
83  *   int isoYear = isoDate.get(ChronoField.YEAR);
84  *   int thaiYear = thaiDate.get(ChronoField.YEAR);
85  * </pre>
86  * As shown, although the date objects are in different calendar systems, represented by different
87  * {@code Chronology} instances, both can be queried using the same constant on {@code ChronoField}.
88  * For a full discussion of the implications of this, see {@link ChronoLocalDate}.
89  * In general, the advice is to use the known ISO-based {@code LocalDate}, rather than
90  * {@code ChronoLocalDate}.
91  * <p>
92  * While a {@code Chronology} object typically uses {@code ChronoField} and is based on
93  * an era, year-of-era, month-of-year, day-of-month model of a date, this is not required.
94  * A {@code Chronology} instance may represent a totally different kind of calendar system,
95  * such as the Mayan.
96  * <p>
97  * In practical terms, the {@code Chronology} instance also acts as a factory.
98  * The {@link #of(String)} method allows an instance to be looked up by identifier,
99  * while the {@link #ofLocale(Locale)} method allows lookup by locale.
100  * <p>
101  * The {@code Chronology} instance provides a set of methods to create {@code ChronoLocalDate} instances.
102  * The date classes are used to manipulate specific dates.
103  * <p><ul>
104  * <li> {@link #dateNow() dateNow()}
105  * <li> {@link #dateNow(Clock) dateNow(clock)}
106  * <li> {@link #dateNow(ZoneId) dateNow(zone)}
107  * <li> {@link #date(int, int, int) date(yearProleptic, month, day)}
108  * <li> {@link #date(Era, int, int, int) date(era, yearOfEra, month, day)}
109  * <li> {@link #dateYearDay(int, int) dateYearDay(yearProleptic, dayOfYear)}
110  * <li> {@link #dateYearDay(Era, int, int) dateYearDay(era, yearOfEra, dayOfYear)}
111  * <li> {@link #date(TemporalAccessor) date(TemporalAccessor)}
112  * </ul><p>
113  *
114  * <p id="addcalendars">Adding New Calendars</p>
115  * The set of available chronologies can be extended by applications.
116  * Adding a new calendar system requires the writing of an implementation of
117  * {@code Chronology}, {@code ChronoLocalDate} and {@code Era}.
118  * The majority of the logic specific to the calendar system will be in
119  * {@code ChronoLocalDate}. The {@code Chronology} subclass acts as a factory.
120  * <p>
121  * To permit the discovery of additional chronologies, the {@link java.util.ServiceLoader ServiceLoader}
122  * is used. A file must be added to the {@code META-INF/services} directory with the
123  * name 'org.threeten.bp.chrono.Chrono' listing the implementation classes.
124  * See the ServiceLoader for more details on service loading.
125  * For lookup by id or calendarType, the system provided calendars are found
126  * first followed by application provided calendars.
127  * <p>
128  * Each chronology must define a chronology ID that is unique within the system.
129  * If the chronology represents a calendar system defined by the
130  * <em>Unicode Locale Data Markup Language (LDML)</em> specification then that
131  * calendar type should also be specified.
132  *
133  * <h3>Specification for implementors</h3>
134  * This class must be implemented with care to ensure other classes operate correctly.
135  * All implementations that can be instantiated must be final, immutable and thread-safe.
136  * Subclasses should be Serializable wherever possible.
137  * <p>
138  * In JDK 8, this is an interface with default methods.
139  * Since there are no default methods in JDK 7, an abstract class is used.
140  */
141 public abstract class Chronology implements Comparable<Chronology> {
142 
143     /**
144      * Simulate JDK 8 method reference Chronology::from.
145      */
146     public static final TemporalQuery<Chronology> FROM = new TemporalQuery<Chronology>() {
147         @Override
148         public Chronology queryFrom(TemporalAccessor temporal) {
149             return Chronology.from(temporal);
150         }
151     };
152 
153     /**
154      * Map of available calendars by ID.
155      */
156     private static final ConcurrentHashMap<String, Chronology> CHRONOS_BY_ID = new ConcurrentHashMap<String, Chronology>();
157     /**
158      * Map of available calendars by calendar type.
159      */
160     private static final ConcurrentHashMap<String, Chronology> CHRONOS_BY_TYPE = new ConcurrentHashMap<String, Chronology>();
161     /**
162      * Access JDK 7 method if on JDK 7.
163      */
164     private static final Method LOCALE_METHOD;
165     static {
166         Method method = null;
167         try {
168             method = Locale.class.getMethod("getUnicodeLocaleType", String.class);
169         } catch (Throwable ex) {
170             // ignore
171         }
172         LOCALE_METHOD = method;
173     }
174 
175     //-----------------------------------------------------------------------
176     /**
177      * Obtains an instance of {@code Chronology} from a temporal object.
178      * <p>
179      * A {@code TemporalAccessor} represents some form of date and time information.
180      * This factory converts the arbitrary temporal object to an instance of {@code Chronology}.
181      * If the specified temporal object does not have a chronology, {@link IsoChronology} is returned.
182      * <p>
183      * The conversion will obtain the chronology using {@link TemporalQueries#chronology()}.
184      * <p>
185      * This method matches the signature of the functional interface {@link TemporalQuery}
186      * allowing it to be used in queries via method reference, {@code Chrono::from}.
187      *
188      * @param temporal  the temporal to convert, not null
189      * @return the chronology, not null
190      * @throws DateTimeException if unable to convert to an {@code Chronology}
191      */
from(TemporalAccessor temporal)192     public static Chronology from(TemporalAccessor temporal) {
193         Jdk8Methods.requireNonNull(temporal, "temporal");
194         Chronology obj = temporal.query(TemporalQueries.chronology());
195         return (obj != null ? obj : IsoChronology.INSTANCE);
196     }
197 
198     //-----------------------------------------------------------------------
199     /**
200      * Obtains an instance of {@code Chronology} from a locale.
201      * <p>
202      * This returns a {@code Chronology} based on the specified locale,
203      * typically returning {@code IsoChronology}. Other calendar systems
204      * are only returned if they are explicitly selected within the locale.
205      * <p>
206      * The {@link Locale} class provide access to a range of information useful
207      * for localizing an application. This includes the language and region,
208      * such as "en-GB" for English as used in Great Britain.
209      * <p>
210      * The {@code Locale} class also supports an extension mechanism that
211      * can be used to identify a calendar system. The mechanism is a form
212      * of key-value pairs, where the calendar system has the key "ca".
213      * For example, the locale "en-JP-u-ca-japanese" represents the English
214      * language as used in Japan with the Japanese calendar system.
215      * <p>
216      * This method finds the desired calendar system by in a manner equivalent
217      * to passing "ca" to {@link Locale#getUnicodeLocaleType(String)}.
218      * If the "ca" key is not present, then {@code IsoChronology} is returned.
219      * <p>
220      * Note that the behavior of this method differs from the older
221      * {@link java.util.Calendar#getInstance(Locale)} method.
222      * If that method receives a locale of "th_TH" it will return {@code BuddhistCalendar}.
223      * By contrast, this method will return {@code IsoChronology}.
224      * Passing the locale "th-TH-u-ca-buddhist" into either method will
225      * result in the Thai Buddhist calendar system and is therefore the
226      * recommended approach going forward for Thai calendar system localization.
227      * <p>
228      * A similar, but simpler, situation occurs for the Japanese calendar system.
229      * The locale "jp_JP_JP" has previously been used to access the calendar.
230      * However, unlike the Thai locale, "ja_JP_JP" is automatically converted by
231      * {@code Locale} to the modern and recommended form of "ja-JP-u-ca-japanese".
232      * Thus, there is no difference in behavior between this method and
233      * {@code Calendar#getInstance(Locale)}.
234      *
235      * @param locale  the locale to use to obtain the calendar system, not null
236      * @return the calendar system associated with the locale, not null
237      * @throws DateTimeException if the locale-specified calendar cannot be found
238      */
ofLocale(Locale locale)239     public static Chronology ofLocale(Locale locale) {
240         init();
241         Jdk8Methods.requireNonNull(locale, "locale");
242         String type = "iso";
243         if (LOCALE_METHOD != null) {
244             // JDK 7: locale.getUnicodeLocaleType("ca");
245             try {
246                 type = (String) LOCALE_METHOD.invoke(locale, "ca");
247             } catch (IllegalArgumentException ex) {
248                 // ignore
249             } catch (IllegalAccessException ex) {
250                 // ignore
251             } catch (InvocationTargetException ex) {
252                 // ignore
253             }
254         } else if (locale.equals(JapaneseChronology.LOCALE)) {
255             type = "japanese";
256         }
257         if (type == null || "iso".equals(type) || "iso8601".equals(type)) {
258             return IsoChronology.INSTANCE;
259         } else {
260             Chronology chrono = CHRONOS_BY_TYPE.get(type);
261             if (chrono == null) {
262                 throw new DateTimeException("Unknown calendar system: " + type);
263             }
264             return chrono;
265         }
266     }
267 
268     //-----------------------------------------------------------------------
269     /**
270      * Obtains an instance of {@code Chronology} from a chronology ID or
271      * calendar system type.
272      * <p>
273      * This returns a chronology based on either the ID or the type.
274      * The {@link #getId() chronology ID} uniquely identifies the chronology.
275      * The {@link #getCalendarType() calendar system type} is defined by the LDML specification.
276      * <p>
277      * The chronology may be a system chronology or a chronology
278      * provided by the application via ServiceLoader configuration.
279      * <p>
280      * Since some calendars can be customized, the ID or type typically refers
281      * to the default customization. For example, the Gregorian calendar can have multiple
282      * cutover dates from the Julian, but the lookup only provides the default cutover date.
283      *
284      * @param id  the chronology ID or calendar system type, not null
285      * @return the chronology with the identifier requested, not null
286      * @throws DateTimeException if the chronology cannot be found
287      */
of(String id)288     public static Chronology of(String id) {
289         init();
290         Chronology chrono = CHRONOS_BY_ID.get(id);
291         if (chrono != null) {
292             return chrono;
293         }
294         chrono = CHRONOS_BY_TYPE.get(id);
295         if (chrono != null) {
296             return chrono;
297         }
298         throw new DateTimeException("Unknown chronology: " + id);
299     }
300 
301     /**
302      * Returns the available chronologies.
303      * <p>
304      * Each returned {@code Chronology} is available for use in the system.
305      *
306      * @return the independent, modifiable set of the available chronology IDs, not null
307      */
getAvailableChronologies()308     public static Set<Chronology> getAvailableChronologies() {
309         init();
310         return new HashSet<Chronology>(CHRONOS_BY_ID.values());
311     }
312 
init()313     private static void init() {
314         if (CHRONOS_BY_ID.isEmpty()) {
315             register(IsoChronology.INSTANCE);
316             register(ThaiBuddhistChronology.INSTANCE);
317             register(MinguoChronology.INSTANCE);
318             register(JapaneseChronology.INSTANCE);
319             register(HijrahChronology.INSTANCE);
320             CHRONOS_BY_ID.putIfAbsent("Hijrah", HijrahChronology.INSTANCE);
321             CHRONOS_BY_TYPE.putIfAbsent("islamic", HijrahChronology.INSTANCE);
322             ServiceLoader<Chronology> loader =  ServiceLoader.load(Chronology.class, Chronology.class.getClassLoader());
323             for (Chronology chrono : loader) {
324                 CHRONOS_BY_ID.putIfAbsent(chrono.getId(), chrono);
325                 String type = chrono.getCalendarType();
326                 if (type != null) {
327                     CHRONOS_BY_TYPE.putIfAbsent(type, chrono);
328                 }
329             }
330         }
331     }
332 
register(Chronology chrono)333     private static void register(Chronology chrono) {
334         CHRONOS_BY_ID.putIfAbsent(chrono.getId(), chrono);
335         String type = chrono.getCalendarType();
336         if (type != null) {
337             CHRONOS_BY_TYPE.putIfAbsent(type, chrono);
338         }
339     }
340 
341     //-----------------------------------------------------------------------
342     /**
343      * Creates an instance.
344      */
Chronology()345     protected Chronology() {
346     }
347 
348     //-----------------------------------------------------------------------
349     /**
350      * Casts the {@code Temporal} to {@code ChronoLocalDate} with the same chronology.
351      *
352      * @param temporal  a date-time to cast, not null
353      * @return the date-time checked and cast to {@code ChronoLocalDate}, not null
354      * @throws ClassCastException if the date-time cannot be cast to ChronoLocalDate
355      *  or the chronology is not equal this Chrono
356      */
ensureChronoLocalDate(Temporal temporal)357     <D extends ChronoLocalDate> D ensureChronoLocalDate(Temporal temporal) {
358         @SuppressWarnings("unchecked")
359         D other = (D) temporal;
360         if (this.equals(other.getChronology()) == false) {
361             throw new ClassCastException("Chrono mismatch, expected: " + getId() + ", actual: " + other.getChronology().getId());
362         }
363         return other;
364     }
365 
366     /**
367      * Casts the {@code Temporal} to {@code ChronoLocalDateTime} with the same chronology.
368      *
369      * @param temporal   a date-time to cast, not null
370      * @return the date-time checked and cast to {@code ChronoLocalDateTime}, not null
371      * @throws ClassCastException if the date-time cannot be cast to ChronoLocalDateTimeImpl
372      *  or the chronology is not equal this Chrono
373      */
ensureChronoLocalDateTime(Temporal temporal)374     <D extends ChronoLocalDate> ChronoLocalDateTimeImpl<D> ensureChronoLocalDateTime(Temporal temporal) {
375         @SuppressWarnings("unchecked")
376         ChronoLocalDateTimeImpl<D> other = (ChronoLocalDateTimeImpl<D>) temporal;
377         if (this.equals(other.toLocalDate().getChronology()) == false) {
378             throw new ClassCastException("Chrono mismatch, required: " + getId()
379                     + ", supplied: " + other.toLocalDate().getChronology().getId());
380         }
381         return other;
382     }
383 
384     /**
385      * Casts the {@code Temporal} to {@code ChronoZonedDateTimeImpl} with the same chronology.
386      *
387      * @param temporal  a date-time to cast, not null
388      * @return the date-time checked and cast to {@code ChronoZonedDateTimeImpl}, not null
389      * @throws ClassCastException if the date-time cannot be cast to ChronoZonedDateTimeImpl
390      *  or the chronology is not equal this Chrono
391      */
ensureChronoZonedDateTime(Temporal temporal)392     <D extends ChronoLocalDate> ChronoZonedDateTimeImpl<D> ensureChronoZonedDateTime(Temporal temporal) {
393         @SuppressWarnings("unchecked")
394         ChronoZonedDateTimeImpl<D> other = (ChronoZonedDateTimeImpl<D>) temporal;
395         if (this.equals(other.toLocalDate().getChronology()) == false) {
396             throw new ClassCastException("Chrono mismatch, required: " + getId()
397                     + ", supplied: " + other.toLocalDate().getChronology().getId());
398         }
399         return other;
400     }
401 
402     //-----------------------------------------------------------------------
403     /**
404      * Gets the ID of the chronology.
405      * <p>
406      * The ID uniquely identifies the {@code Chronology}.
407      * It can be used to lookup the {@code Chronology} using {@link #of(String)}.
408      *
409      * @return the chronology ID, not null
410      * @see #getCalendarType()
411      */
getId()412     public abstract String getId();
413 
414     /**
415      * Gets the calendar type of the underlying calendar system.
416      * <p>
417      * The calendar type is an identifier defined by the
418      * <em>Unicode Locale Data Markup Language (LDML)</em> specification.
419      * It can be used to lookup the {@code Chronology} using {@link #of(String)}.
420      * It can also be used as part of a locale, accessible via
421      * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'.
422      *
423      * @return the calendar system type, null if the calendar is not defined by LDML
424      * @see #getId()
425      */
getCalendarType()426     public abstract String getCalendarType();
427 
428     //-----------------------------------------------------------------------
429     /**
430      * Obtains a local date in this chronology from the era, year-of-era,
431      * month-of-year and day-of-month fields.
432      *
433      * @param era  the era of the correct type for the chronology, not null
434      * @param yearOfEra  the chronology year-of-era
435      * @param month  the chronology month-of-year
436      * @param dayOfMonth  the chronology day-of-month
437      * @return the local date in this chronology, not null
438      * @throws DateTimeException if unable to create the date
439      * @throws ClassCastException if the {@code era} is not of the correct type for the chronology
440      */
date(Era era, int yearOfEra, int month, int dayOfMonth)441     public ChronoLocalDate date(Era era, int yearOfEra, int month, int dayOfMonth) {
442         return date(prolepticYear(era, yearOfEra), month, dayOfMonth);
443     }
444 
445     /**
446      * Obtains a local date in this chronology from the proleptic-year,
447      * month-of-year and day-of-month fields.
448      *
449      * @param prolepticYear  the chronology proleptic-year
450      * @param month  the chronology month-of-year
451      * @param dayOfMonth  the chronology day-of-month
452      * @return the local date in this chronology, not null
453      * @throws DateTimeException if unable to create the date
454      */
date(int prolepticYear, int month, int dayOfMonth)455     public abstract ChronoLocalDate date(int prolepticYear, int month, int dayOfMonth);
456 
457     /**
458      * Obtains a local date in this chronology from the era, year-of-era and
459      * day-of-year fields.
460      *
461      * @param era  the era of the correct type for the chronology, not null
462      * @param yearOfEra  the chronology year-of-era
463      * @param dayOfYear  the chronology day-of-year
464      * @return the local date in this chronology, not null
465      * @throws DateTimeException if unable to create the date
466      * @throws ClassCastException if the {@code era} is not of the correct type for the chronology
467      */
dateYearDay(Era era, int yearOfEra, int dayOfYear)468     public ChronoLocalDate dateYearDay(Era era, int yearOfEra, int dayOfYear) {
469         return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear);
470     }
471 
472     /**
473      * Obtains a local date in this chronology from the proleptic-year and
474      * day-of-year fields.
475      *
476      * @param prolepticYear  the chronology proleptic-year
477      * @param dayOfYear  the chronology day-of-year
478      * @return the local date in this chronology, not null
479      * @throws DateTimeException if unable to create the date
480      */
dateYearDay(int prolepticYear, int dayOfYear)481     public abstract ChronoLocalDate dateYearDay(int prolepticYear, int dayOfYear);
482 
483     /**
484      * Obtains a local date in this chronology from the epoch-day.
485      * <p>
486      * The definition of {@link ChronoField#EPOCH_DAY EPOCH_DAY} is the same
487      * for all calendar systems, thus it can be used for conversion.
488      *
489      * @param epochDay  the epoch day
490      * @return the local date in this chronology, not null
491      * @throws DateTimeException if unable to create the date
492      */
dateEpochDay(long epochDay)493     public abstract ChronoLocalDate dateEpochDay(long epochDay);
494 
495     /**
496      * Obtains a local date in this chronology from another temporal object.
497      * <p>
498      * This creates a date in this chronology based on the specified {@code TemporalAccessor}.
499      * <p>
500      * The standard mechanism for conversion between date types is the
501      * {@link ChronoField#EPOCH_DAY local epoch-day} field.
502      *
503      * @param temporal  the temporal object to convert, not null
504      * @return the local date in this chronology, not null
505      * @throws DateTimeException if unable to create the date
506      */
date(TemporalAccessor temporal)507     public abstract ChronoLocalDate date(TemporalAccessor temporal);
508 
509     //-----------------------------------------------------------------------
510     /**
511      * Obtains the current local date in this chronology from the system clock in the default time-zone.
512      * <p>
513      * This will query the {@link Clock#systemDefaultZone() system clock} in the default
514      * time-zone to obtain the current date.
515      * <p>
516      * Using this method will prevent the ability to use an alternate clock for testing
517      * because the clock is hard-coded.
518      * <p>
519      * This implementation uses {@link #dateNow(Clock)}.
520      *
521      * @return the current local date using the system clock and default time-zone, not null
522      * @throws DateTimeException if unable to create the date
523      */
dateNow()524     public ChronoLocalDate dateNow() {
525         return dateNow(Clock.systemDefaultZone());
526     }
527 
528     /**
529      * Obtains the current local date in this chronology from the system clock in the specified time-zone.
530      * <p>
531      * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date.
532      * Specifying the time-zone avoids dependence on the default time-zone.
533      * <p>
534      * Using this method will prevent the ability to use an alternate clock for testing
535      * because the clock is hard-coded.
536      *
537      * @param zone  the zone ID to use, not null
538      * @return the current local date using the system clock, not null
539      * @throws DateTimeException if unable to create the date
540      */
dateNow(ZoneId zone)541     public ChronoLocalDate dateNow(ZoneId zone) {
542         return dateNow(Clock.system(zone));
543     }
544 
545     /**
546      * Obtains the current local date in this chronology from the specified clock.
547      * <p>
548      * This will query the specified clock to obtain the current date - today.
549      * Using this method allows the use of an alternate clock for testing.
550      * The alternate clock may be introduced using {@link Clock dependency injection}.
551      *
552      * @param clock  the clock to use, not null
553      * @return the current local date, not null
554      * @throws DateTimeException if unable to create the date
555      */
dateNow(Clock clock)556     public ChronoLocalDate dateNow(Clock clock) {
557         Jdk8Methods.requireNonNull(clock, "clock");
558         return date(LocalDate.now(clock));
559     }
560 
561     //-----------------------------------------------------------------------
562     /**
563      * Obtains a local date-time in this chronology from another temporal object.
564      * <p>
565      * This creates a date-time in this chronology based on the specified {@code TemporalAccessor}.
566      * <p>
567      * The date of the date-time should be equivalent to that obtained by calling
568      * {@link #date(TemporalAccessor)}.
569      * The standard mechanism for conversion between time types is the
570      * {@link ChronoField#NANO_OF_DAY nano-of-day} field.
571      *
572      * @param temporal  the temporal object to convert, not null
573      * @return the local date-time in this chronology, not null
574      * @throws DateTimeException if unable to create the date-time
575      */
localDateTime(TemporalAccessor temporal)576     public ChronoLocalDateTime<?> localDateTime(TemporalAccessor temporal) {
577         try {
578             ChronoLocalDate date = date(temporal);
579             return date.atTime(LocalTime.from(temporal));
580         } catch (DateTimeException ex) {
581             throw new DateTimeException("Unable to obtain ChronoLocalDateTime from TemporalAccessor: " + temporal.getClass(), ex);
582         }
583     }
584 
585     /**
586      * Obtains a zoned date-time in this chronology from another temporal object.
587      * <p>
588      * This creates a date-time in this chronology based on the specified {@code TemporalAccessor}.
589      * <p>
590      * This should obtain a {@code ZoneId} using {@link ZoneId#from(TemporalAccessor)}.
591      * The date-time should be obtained by obtaining an {@code Instant}.
592      * If that fails, the local date-time should be used.
593      *
594      * @param temporal  the temporal object to convert, not null
595      * @return the zoned date-time in this chronology, not null
596      * @throws DateTimeException if unable to create the date-time
597      */
598     @SuppressWarnings({ "rawtypes", "unchecked" })
zonedDateTime(TemporalAccessor temporal)599     public ChronoZonedDateTime<?> zonedDateTime(TemporalAccessor temporal) {
600         try {
601             ZoneId zone = ZoneId.from(temporal);
602             try {
603                 Instant instant = Instant.from(temporal);
604                 return zonedDateTime(instant, zone);
605 
606             } catch (DateTimeException ex1) {
607                 ChronoLocalDateTime cldt = localDateTime(temporal);
608                 ChronoLocalDateTimeImpl cldtImpl = ensureChronoLocalDateTime(cldt);
609                 return ChronoZonedDateTimeImpl.ofBest(cldtImpl, zone, null);
610             }
611         } catch (DateTimeException ex) {
612             throw new DateTimeException("Unable to obtain ChronoZonedDateTime from TemporalAccessor: " + temporal.getClass(), ex);
613         }
614     }
615 
616     /**
617      * Obtains a zoned date-time in this chronology from an {@code Instant}.
618      * <p>
619      * This creates a zoned date-time with the same instant as that specified.
620      *
621      * @param instant  the instant to create the date-time from, not null
622      * @param zone  the time-zone, not null
623      * @return the zoned date-time, not null
624      * @throws DateTimeException if the result exceeds the supported range
625      */
zonedDateTime(Instant instant, ZoneId zone)626     public ChronoZonedDateTime<?> zonedDateTime(Instant instant, ZoneId zone) {
627         ChronoZonedDateTime<? extends ChronoLocalDate> result = ChronoZonedDateTimeImpl.ofInstant(this, instant, zone);
628         return result;
629     }
630 
631     //-----------------------------------------------------------------------
632     /**
633      * Obtains a period for this chronology based on years, months and days.
634      * <p>
635      * This returns a period tied to this chronology using the specified
636      * years, months and days.  All supplied chronologies use periods
637      * based on years, months and days, however the {@code ChronoPeriod} API
638      * allows the period to be represented using other units.
639      * <p>
640      * The default implementation returns an implementation class suitable
641      * for most calendar systems. It is based solely on the three units.
642      * Normalization, addition and subtraction derive the number of months
643      * in a year from the {@link #range(ChronoField)}. If the number of
644      * months within a year is fixed, then the calculation approach for
645      * addition, subtraction and normalization is slightly different.
646      * <p>
647      * If implementing an unusual calendar system that is not based on
648      * years, months and days, or where you want direct control, then
649      * the {@code ChronoPeriod} interface must be directly implemented.
650      * <p>
651      * The returned period is immutable and thread-safe.
652      *
653      * @param years  the number of years, may be negative
654      * @param months  the number of years, may be negative
655      * @param days  the number of years, may be negative
656      * @return the period in terms of this chronology, not null
657      */
period(int years, int months, int days)658     public ChronoPeriod period(int years, int months, int days) {
659         return new ChronoPeriodImpl(this, years, months, days);
660     }
661 
662     //-----------------------------------------------------------------------
663     /**
664      * Checks if the specified year is a leap year.
665      * <p>
666      * A leap-year is a year of a longer length than normal.
667      * The exact meaning is determined by the chronology according to the following constraints.
668      * <p><ul>
669      * <li>a leap-year must imply a year-length longer than a non leap-year.
670      * <li>a chronology that does not support the concept of a year must return false.
671      * </ul><p>
672      *
673      * @param prolepticYear  the proleptic-year to check, not validated for range
674      * @return true if the year is a leap year
675      */
isLeapYear(long prolepticYear)676     public abstract boolean isLeapYear(long prolepticYear);
677 
678     /**
679      * Calculates the proleptic-year given the era and year-of-era.
680      * <p>
681      * This combines the era and year-of-era into the single proleptic-year field.
682      *
683      * @param era  the era of the correct type for the chronology, not null
684      * @param yearOfEra  the chronology year-of-era
685      * @return the proleptic-year
686      * @throws DateTimeException if unable to convert
687      * @throws ClassCastException if the {@code era} is not of the correct type for the chronology
688      */
prolepticYear(Era era, int yearOfEra)689     public abstract int prolepticYear(Era era, int yearOfEra);
690 
691     /**
692      * Creates the chronology era object from the numeric value.
693      * <p>
694      * The era is, conceptually, the largest division of the time-line.
695      * Most calendar systems have a single epoch dividing the time-line into two eras.
696      * However, some have multiple eras, such as one for the reign of each leader.
697      * The exact meaning is determined by the chronology according to the following constraints.
698      * <p>
699      * The era in use at 1970-01-01 must have the value 1.
700      * Later eras must have sequentially higher values.
701      * Earlier eras must have sequentially lower values.
702      * Each chronology must refer to an enum or similar singleton to provide the era values.
703      * <p>
704      * This method returns the singleton era of the correct type for the specified era value.
705      *
706      * @param eraValue  the era value
707      * @return the calendar system era, not null
708      * @throws DateTimeException if unable to create the era
709      */
eraOf(int eraValue)710     public abstract Era eraOf(int eraValue);
711 
712     /**
713      * Gets the list of eras for the chronology.
714      * <p>
715      * Most calendar systems have an era, within which the year has meaning.
716      * If the calendar system does not support the concept of eras, an empty
717      * list must be returned.
718      *
719      * @return the list of eras for the chronology, may be immutable, not null
720      */
eras()721     public abstract List<Era> eras();
722 
723     //-----------------------------------------------------------------------
724     /**
725      * Gets the range of valid values for the specified field.
726      * <p>
727      * All fields can be expressed as a {@code long} integer.
728      * This method returns an object that describes the valid range for that value.
729      * <p>
730      * Note that the result only describes the minimum and maximum valid values
731      * and it is important not to read too much into them. For example, there
732      * could be values within the range that are invalid for the field.
733      * <p>
734      * This method will return a result whether or not the chronology supports the field.
735      *
736      * @param field  the field to get the range for, not null
737      * @return the range of valid values for the field, not null
738      * @throws DateTimeException if the range for the field cannot be obtained
739      */
range(ChronoField field)740     public abstract ValueRange range(ChronoField field);
741 
742     //-----------------------------------------------------------------------
743     /**
744      * Gets the textual representation of this chronology.
745      * <p>
746      * This returns the textual name used to identify the chronology.
747      * The parameters control the style of the returned text and the locale.
748      *
749      * @param style  the style of the text required, not null
750      * @param locale  the locale to use, not null
751      * @return the text value of the chronology, not null
752      */
getDisplayName(TextStyle style, Locale locale)753     public String getDisplayName(TextStyle style, Locale locale) {
754         return new DateTimeFormatterBuilder().appendChronologyText(style).toFormatter(locale).format(new DefaultInterfaceTemporalAccessor() {
755             @Override
756             public boolean isSupported(TemporalField field) {
757                 return false;
758             }
759             @Override
760             public long getLong(TemporalField field) {
761                 throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
762             }
763             @SuppressWarnings("unchecked")
764             @Override
765             public <R> R query(TemporalQuery<R> query) {
766                 if (query == TemporalQueries.chronology()) {
767                     return (R) Chronology.this;
768                 }
769                 return super.query(query);
770             }
771         });
772     }
773 
774     //-----------------------------------------------------------------------
775     /**
776      * Resolves parsed {@code ChronoField} values into a date during parsing.
777      * <p>
778      * Most {@code TemporalField} implementations are resolved using the
779      * resolve method on the field. By contrast, the {@code ChronoField} class
780      * defines fields that only have meaning relative to the chronology.
781      * As such, {@code ChronoField} date fields are resolved here in the
782      * context of a specific chronology.
783      * <p>
784      * The default implementation, which explains typical resolve behaviour,
785      * is provided in {@link AbstractChronology}.
786      *
787      * @param fieldValues  the map of fields to values, which can be updated, not null
788      * @param resolverStyle  the requested type of resolve, not null
789      * @return the resolved date, null if insufficient information to create a date
790      * @throws DateTimeException if the date cannot be resolved, typically
791      *  because of a conflict in the input data
792      */
793     public abstract ChronoLocalDate resolveDate(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle);
794 
795     /**
796      * Updates the map of field-values during resolution.
797      *
798      * @param field  the field to update, not null
799      * @param value  the value to update, not null
800      * @throws DateTimeException if a conflict occurs
801      */
802     void updateResolveMap(Map<TemporalField, Long> fieldValues, ChronoField field, long value) {
803         Long current = fieldValues.get(field);
804         if (current != null && current.longValue() != value) {
805             throw new DateTimeException("Invalid state, field: " + field + " " + current + " conflicts with " + field + " " + value);
806         }
807         fieldValues.put(field, value);
808     }
809 
810     //-----------------------------------------------------------------------
811     /**
812      * Compares this chronology to another chronology.
813      * <p>
814      * The comparison order first by the chronology ID string, then by any
815      * additional information specific to the subclass.
816      * It is "consistent with equals", as defined by {@link Comparable}.
817      * <p>
818      * The default implementation compares the chronology ID.
819      * Subclasses must compare any additional state that they store.
820      *
821      * @param other  the other chronology to compare to, not null
822      * @return the comparator value, negative if less, positive if greater
823      */
824     @Override
825     public int compareTo(Chronology other) {
826         return getId().compareTo(other.getId());
827     }
828 
829     /**
830      * Checks if this chronology is equal to another chronology.
831      * <p>
832      * The comparison is based on the entire state of the object.
833      * <p>
834      * The default implementation checks the type and calls {@link #compareTo(Chronology)}.
835      *
836      * @param obj  the object to check, null returns false
837      * @return true if this is equal to the other chronology
838      */
839     @Override
840     public boolean equals(Object obj) {
841         if (this == obj) {
842            return true;
843         }
844         if (obj instanceof Chronology) {
845             return compareTo((Chronology) obj) == 0;
846         }
847         return false;
848     }
849 
850     /**
851      * A hash code for this chronology.
852      * <p>
853      * The default implementation is based on the ID and class.
854      * Subclasses should add any additional state that they store.
855      *
856      * @return a suitable hash code
857      */
858     @Override
859     public int hashCode() {
860         return getClass().hashCode() ^ getId().hashCode();
861     }
862 
863     //-----------------------------------------------------------------------
864     /**
865      * Outputs this chronology as a {@code String}, using the ID.
866      *
867      * @return a string representation of this chronology, not null
868      */
869     @Override
870     public String toString() {
871         return getId();
872     }
873 
874     //-----------------------------------------------------------------------
875     private Object writeReplace() {
876         return new Ser(Ser.CHRONO_TYPE, this);
877     }
878 
879     /**
880      * Defend against malicious streams.
881      * @return never
882      * @throws InvalidObjectException always
883      */
884     private Object readResolve() throws ObjectStreamException {
885         throw new InvalidObjectException("Deserialization via serialization delegate");
886     }
887 
888     void writeExternal(DataOutput out) throws IOException {
889         out.writeUTF(getId());
890     }
891 
892     static Chronology readExternal(DataInput in) throws IOException {
893         String id = in.readUTF();
894         return Chronology.of(id);
895     }
896 
897 }
898