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<ThaiBuddhistChrono> 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