1 /* 2 * Copyright (c) 2012, 2013, 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.temporal; 63 64 import java.io.DataInput; 65 import java.io.DataOutput; 66 import java.io.IOException; 67 import java.io.InvalidObjectException; 68 import java.io.ObjectStreamException; 69 import java.time.Clock; 70 import java.time.DateTimeException; 71 import java.time.Instant; 72 import java.time.LocalDate; 73 import java.time.LocalTime; 74 import java.time.ZoneId; 75 import java.time.calendar.HijrahChrono; 76 import java.time.calendar.JapaneseChrono; 77 import java.time.calendar.MinguoChrono; 78 import java.time.calendar.ThaiBuddhistChrono; 79 import java.time.format.DateTimeFormatterBuilder; 80 import java.time.format.TextStyle; 81 import java.util.HashSet; 82 import java.util.List; 83 import java.util.Locale; 84 import java.util.Objects; 85 import java.util.ServiceLoader; 86 import java.util.Set; 87 import java.util.concurrent.ConcurrentHashMap; 88 89 /** 90 * A calendar system, used to organize and identify dates. 91 * <p> 92 * The main date and time API is built on the ISO calendar system. 93 * This class operates behind the scenes to represent the general concept of a calendar system. 94 * For example, the Japanese, Minguo, Thai Buddhist and others. 95 * <p> 96 * Most other calendar systems also operate on the shared concepts of year, month and day, 97 * linked to the cycles of the Earth around the Sun, and the Moon around the Earth. 98 * These shared concepts are defined by {@link ChronoField} and are availalbe 99 * for use by any {@code Chrono} implementation: 100 * <pre> 101 * LocalDate isoDate = ... 102 * ChronoLocalDate<ThaiBuddhistChrono> thaiDate = ... 103 * int isoYear = isoDate.get(ChronoField.YEAR); 104 * int thaiYear = thaiDate.get(ChronoField.YEAR); 105 * </pre> 106 * As shown, although the date objects are in different calendar systems, represented by different 107 * {@code Chrono} instances, both can be queried using the same constant on {@code ChronoField}. 108 * For a full discussion of the implications of this, see {@link ChronoLocalDate}. 109 * In general, the advice is to use the known ISO-based {@code LocalDate}, rather than 110 * {@code ChronoLocalDate}. 111 * <p> 112 * While a {@code Chrono} object typically uses {@code ChronoField} and is based on 113 * an era, year-of-era, month-of-year, day-of-month model of a date, this is not required. 114 * A {@code Chrono} instance may represent a totally different kind of calendar system, 115 * such as the Mayan. 116 * <p> 117 * In practical terms, the {@code Chrono} instance also acts as a factory. 118 * The {@link #of(String)} method allows an instance to be looked up by identifier, 119 * while the {@link #ofLocale(Locale)} method allows lookup by locale. 120 * <p> 121 * The {@code Chrono} instance provides a set of methods to create {@code ChronoLocalDate} instances. 122 * The date classes are used to manipulate specific dates. 123 * <p><ul> 124 * <li> {@link #dateNow() dateNow()} 125 * <li> {@link #dateNow(Clock) dateNow(clock)} 126 * <li> {@link #dateNow(ZoneId) dateNow(zone)} 127 * <li> {@link #date(int, int, int) date(yearProleptic, month, day)} 128 * <li> {@link #date(Era, int, int, int) date(era, yearOfEra, month, day)} 129 * <li> {@link #dateYearDay(int, int) dateYearDay(yearProleptic, dayOfYear)} 130 * <li> {@link #dateYearDay(Era, int, int) dateYearDay(era, yearOfEra, dayOfYear)} 131 * <li> {@link #date(TemporalAccessor) date(TemporalAccessor)} 132 * </ul><p> 133 * 134 * <p id="addcalendars">Adding New Calendars</p> 135 * The set of available chronologies can be extended by applications. 136 * Adding a new calendar system requires the writing of an implementation of 137 * {@code Chrono}, {@code ChronoLocalDate} and {@code Era}. 138 * The majority of the logic specific to the calendar system will be in 139 * {@code ChronoLocalDate}. The {@code Chrono} subclass acts as a factory. 140 * <p> 141 * To permit the discovery of additional chronologies, the {@link java.util.ServiceLoader ServiceLoader} 142 * is used. A file must be added to the {@code META-INF/services} directory with the 143 * name 'java.time.temporal.Chrono' listing the implementation classes. 144 * See the ServiceLoader for more details on service loading. 145 * For lookup by id or calendarType, the system provided calendars are found 146 * first followed by application provided calendars. 147 * <p> 148 * Each chronology must define a chronology ID that is unique within the system. 149 * If the chronology represents a calendar system defined by the 150 * <em>Unicode Locale Data Markup Language (LDML)</em> specification then that 151 * calendar type should also be specified. 152 * 153 * <h3>Specification for implementors</h3> 154 * This class must be implemented with care to ensure other classes operate correctly. 155 * All implementations that can be instantiated must be final, immutable and thread-safe. 156 * Subclasses should be Serializable wherever possible. 157 * 158 * @param <C> the type of the implementing subclass 159 * @since 1.8 160 */ 161 public abstract class Chrono<C extends Chrono<C>> implements Comparable<Chrono<?>> { 162 163 /** 164 * Map of available calendars by ID. 165 */ 166 private static final ConcurrentHashMap<String, Chrono<?>> CHRONOS_BY_ID = new ConcurrentHashMap<>(); 167 /** 168 * Map of available calendars by calendar type. 169 */ 170 private static final ConcurrentHashMap<String, Chrono<?>> CHRONOS_BY_TYPE = new ConcurrentHashMap<>(); 171 172 /** 173 * Register a Chrono by ID and type for lookup by {@link #of(java.lang.String)}. 174 * Chronos must not be registered until they are completely constructed. 175 * Specifically, not in the constructor of Chrono. 176 * @param chrono the chronology to register; not null 177 */ 178 private static void registerChrono(Chrono chrono) { 179 Chrono<?> prev = CHRONOS_BY_ID.putIfAbsent(chrono.getId(), chrono); 180 if (prev == null) { 181 String type = chrono.getCalendarType(); 182 if (type != null) { 183 CHRONOS_BY_TYPE.putIfAbsent(type, chrono); 184 } 185 } 186 } 187 188 /** 189 * Initialization of the maps from id and type to Chrono. 190 * The ServiceLoader is used to find and register any implementations 191 * of {@link javax.time.temporal.Chrono} found in the bootclass loader. 192 * The built-in chronologies are registered explicitly. 193 * Calendars configured via the Thread's context classloader are local 194 * to that thread and are ignored. 195 * <p> 196 * The initialization is done only once using the registration 197 * of the ISOChrono as the test and the final step. 198 * Multiple threads may perform the initialization concurrently. 199 * Only the first registration of each Chrono is retained by the 200 * ConcurrentHashMap. 201 * @return true if the cache was initialized 202 */ 203 private static boolean initCache() { 204 if (CHRONOS_BY_ID.get("ISO") == null) { 205 // Initialization is incomplete 206 @SuppressWarnings("rawtypes") 207 ServiceLoader<Chrono> loader = ServiceLoader.load(Chrono.class, null); 208 for (Chrono<?> chrono : loader) { 209 registerChrono(chrono); 210 } 211 212 // Register these calendars; the ServiceLoader configuration is not used 213 registerChrono(HijrahChrono.INSTANCE); 214 registerChrono(JapaneseChrono.INSTANCE); 215 registerChrono(MinguoChrono.INSTANCE); 216 registerChrono(ThaiBuddhistChrono.INSTANCE); 217 218 // finally, register ISOChrono to mark initialization is complete 219 registerChrono(ISOChrono.INSTANCE); 220 return true; 221 } 222 return false; 223 } 224 225 //----------------------------------------------------------------------- 226 /** 227 * Obtains an instance of {@code Chrono} from a temporal object. 228 * <p> 229 * A {@code TemporalAccessor} represents some form of date and time information. 230 * This factory converts the arbitrary temporal object to an instance of {@code Chrono}. 231 * If the specified temporal object does not have a chronology, {@link ISOChrono} is returned. 232 * <p> 233 * The conversion will obtain the chronology using {@link Queries#chrono()}. 234 * <p> 235 * This method matches the signature of the functional interface {@link TemporalQuery} 236 * allowing it to be used in queries via method reference, {@code Chrono::from}. 237 * 238 * @param temporal the temporal to convert, not null 239 * @return the chronology, not null 240 * @throws DateTimeException if unable to convert to an {@code Chrono} 241 */ 242 public static Chrono<?> from(TemporalAccessor temporal) { 243 Objects.requireNonNull(temporal, "temporal"); 244 Chrono<?> obj = temporal.query(Queries.chrono()); 245 return (obj != null ? obj : ISOChrono.INSTANCE); 246 } 247 248 //----------------------------------------------------------------------- 249 /** 250 * Obtains an instance of {@code Chrono} from a locale. 251 * <p> 252 * The locale can be used to identify a calendar. 253 * This uses {@link Locale#getUnicodeLocaleType(String)} to obtain the "ca" key 254 * to identify the calendar system. 255 * <p> 256 * If the locale does not contain calendar system information, the standard 257 * ISO calendar system is used. 258 * 259 * @param locale the locale to use to obtain the calendar system, not null 260 * @return the calendar system associated with the locale, not null 261 * @throws DateTimeException if the locale-specified calendar cannot be found 262 */ 263 public static Chrono<?> ofLocale(Locale locale) { 264 Objects.requireNonNull(locale, "locale"); 265 String type = locale.getUnicodeLocaleType("ca"); 266 if (type == null) { 267 return ISOChrono.INSTANCE; 268 } else if ("iso".equals(type) || "iso8601".equals(type)) { 269 return ISOChrono.INSTANCE; 270 } else { 271 Chrono<?> chrono = CHRONOS_BY_TYPE.get(type); 272 if (chrono == null) { 273 throw new DateTimeException("Unknown calendar system: " + type); 274 } 275 return chrono; 276 } 277 } 278 279 //----------------------------------------------------------------------- 280 /** 281 * Obtains an instance of {@code Chrono} from a chronology ID or 282 * calendar system type. 283 * <p> 284 * This returns a chronology based on either the ID or the type. 285 * The {@link #getId() chronology ID} uniquely identifies the chronology. 286 * The {@link #getCalendarType() calendar system type} is defined by the LDML specification. 287 * <p> 288 * The chronology may be a system chronology or a chronology 289 * provided by the application via ServiceLoader configuration. 290 * <p> 291 * Since some calendars can be customized, the ID or type typically refers 292 * to the default customization. For example, the Gregorian calendar can have multiple 293 * cutover dates from the Julian, but the lookup only provides the default cutover date. 294 * 295 * @param id the chronology ID or calendar system type, not null 296 * @return the chronology with the identifier requested, not null 297 * @throws DateTimeException if the chronology cannot be found 298 */ 299 public static Chrono<?> of(String id) { 300 Objects.requireNonNull(id, "id"); 301 do { 302 Chrono chrono = of0(id); 303 if (chrono != null) { 304 return chrono; 305 } 306 // If not found, do the initialization (once) and repeat the lookup 307 } while (initCache()); 308 309 // Look for a Chrono using ServiceLoader of the Thread's ContextClassLoader 310 // Application provided Chronologies must not be cached 311 @SuppressWarnings("rawtypes") 312 ServiceLoader<Chrono> loader = ServiceLoader.load(Chrono.class); 313 for (Chrono<?> chrono : loader) { 314 if (id.equals(chrono.getId()) || id.equals(chrono.getCalendarType())) { 315 return chrono; 316 } 317 } 318 throw new DateTimeException("Unknown chronology: " + id); 319 } 320 321 /** 322 * Obtains an instance of {@code Chrono} from a chronology ID or 323 * calendar system type. 324 * 325 * @param id the chronology ID or calendar system type, not null 326 * @return the chronology with the identifier requested, or {@code null} if not found 327 */ 328 private static Chrono<?> of0(String id) { 329 Chrono<?> chrono = CHRONOS_BY_ID.get(id); 330 if (chrono == null) { 331 chrono = CHRONOS_BY_TYPE.get(id); 332 } 333 return chrono; 334 } 335 336 /** 337 * Returns the available chronologies. 338 * <p> 339 * Each returned {@code Chrono} is available for use in the system. 340 * The set of chronologies includes the system chronologies and 341 * any chronologies provided by the application via ServiceLoader 342 * configuration. 343 * 344 * @return the independent, modifiable set of the available chronology IDs, not null 345 */ 346 public static Set<Chrono<?>> getAvailableChronologies() { 347 initCache(); // force initialization 348 HashSet<Chrono<?>> chronos = new HashSet<>(CHRONOS_BY_ID.values()); 349 350 /// Add in Chronologies from the ServiceLoader configuration 351 @SuppressWarnings("rawtypes") 352 ServiceLoader<Chrono> loader = ServiceLoader.load(Chrono.class); 353 for (Chrono<?> chrono : loader) { 354 chronos.add(chrono); 355 } 356 return chronos; 357 } 358 359 //----------------------------------------------------------------------- 360 /** 361 * Obtains a local date-time from the a date and time. 362 * <p> 363 * This combines a {@link ChronoLocalDate}, which provides the {@code Chrono}, 364 * with a {@link LocalTime} to produce a {@link ChronoLocalDateTime}. 365 * <p> 366 * This method is intended for chronology implementations. 367 * It uses a standard implementation that is shared for all chronologies. 368 * 369 * @param <R> the chronology of the date 370 * @param date the date, not null 371 * @param time the time, not null 372 * @return the local date-time combining the input date and time, not null 373 */ 374 public static <R extends Chrono<R>> ChronoLocalDateTime<R> dateTime(ChronoLocalDate<R> date, LocalTime time) { 375 return ChronoLocalDateTimeImpl.of(date, time); 376 } 377 378 //----------------------------------------------------------------------- 379 /** 380 * Creates an instance. 381 */ 382 protected Chrono() { 383 } 384 385 //----------------------------------------------------------------------- 386 /** 387 * Casts the {@code Temporal} to {@code ChronoLocalDate} with the same chronology. 388 * 389 * @param temporal a date-time to cast, not null 390 * @return the date-time checked and cast to {@code ChronoLocalDate}, not null 391 * @throws ClassCastException if the date-time cannot be cast to ChronoLocalDate 392 * or the chronology is not equal this Chrono 393 */ 394 ChronoLocalDate<C> ensureChronoLocalDate(Temporal temporal) { 395 @SuppressWarnings("unchecked") 396 ChronoLocalDate<C> other = (ChronoLocalDate<C>) temporal; 397 if (this.equals(other.getChrono()) == false) { 398 throw new ClassCastException("Chrono mismatch, expected: " + getId() + ", actual: " + other.getChrono().getId()); 399 } 400 return other; 401 } 402 403 /** 404 * Casts the {@code Temporal} to {@code ChronoLocalDateTime} with the same chronology. 405 * 406 * @param temporal a date-time to cast, not null 407 * @return the date-time checked and cast to {@code ChronoLocalDateTime}, not null 408 * @throws ClassCastException if the date-time cannot be cast to ChronoLocalDateTimeImpl 409 * or the chronology is not equal this Chrono 410 */ 411 ChronoLocalDateTimeImpl<C> ensureChronoLocalDateTime(Temporal temporal) { 412 @SuppressWarnings("unchecked") 413 ChronoLocalDateTimeImpl<C> other = (ChronoLocalDateTimeImpl<C>) temporal; 414 if (this.equals(other.getDate().getChrono()) == false) { 415 throw new ClassCastException("Chrono mismatch, required: " + getId() 416 + ", supplied: " + other.getDate().getChrono().getId()); 417 } 418 return other; 419 } 420 421 /** 422 * Casts the {@code Temporal} to {@code ChronoZonedDateTimeImpl} with the same chronology. 423 * 424 * @param temporal a date-time to cast, not null 425 * @return the date-time checked and cast to {@code ChronoZonedDateTimeImpl}, not null 426 * @throws ClassCastException if the date-time cannot be cast to ChronoZonedDateTimeImpl 427 * or the chronology is not equal this Chrono 428 */ 429 ChronoZonedDateTimeImpl<C> ensureChronoZonedDateTime(Temporal temporal) { 430 @SuppressWarnings("unchecked") 431 ChronoZonedDateTimeImpl<C> other = (ChronoZonedDateTimeImpl<C>) temporal; 432 if (this.equals(other.getDate().getChrono()) == false) { 433 throw new ClassCastException("Chrono mismatch, required: " + getId() 434 + ", supplied: " + other.getDate().getChrono().getId()); 435 } 436 return other; 437 } 438 439 //----------------------------------------------------------------------- 440 /** 441 * Gets the ID of the chronology. 442 * <p> 443 * The ID uniquely identifies the {@code Chrono}. 444 * It can be used to lookup the {@code Chrono} using {@link #of(String)}. 445 * 446 * @return the chronology ID, not null 447 * @see #getCalendarType() 448 */ 449 public abstract String getId(); 450 451 /** 452 * Gets the calendar type of the underlying calendar system. 453 * <p> 454 * The calendar type is an identifier defined by the 455 * <em>Unicode Locale Data Markup Language (LDML)</em> specification. 456 * It can be used to lookup the {@code Chrono} using {@link #of(String)}. 457 * It can also be used as part of a locale, accessible via 458 * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'. 459 * 460 * @return the calendar system type, null if the calendar is not defined by LDML 461 * @see #getId() 462 */ 463 public abstract String getCalendarType(); 464 465 //----------------------------------------------------------------------- 466 /** 467 * Obtains a local date in this chronology from the era, year-of-era, 468 * month-of-year and day-of-month fields. 469 * 470 * @param era the era of the correct type for the chronology, not null 471 * @param yearOfEra the chronology year-of-era 472 * @param month the chronology month-of-year 473 * @param dayOfMonth the chronology day-of-month 474 * @return the local date in this chronology, not null 475 * @throws DateTimeException if unable to create the date 476 */ 477 public ChronoLocalDate<C> date(Era<C> era, int yearOfEra, int month, int dayOfMonth) { 478 return date(prolepticYear(era, yearOfEra), month, dayOfMonth); 479 } 480 481 /** 482 * Obtains a local date in this chronology from the proleptic-year, 483 * month-of-year and day-of-month fields. 484 * 485 * @param prolepticYear the chronology proleptic-year 486 * @param month the chronology month-of-year 487 * @param dayOfMonth the chronology day-of-month 488 * @return the local date in this chronology, not null 489 * @throws DateTimeException if unable to create the date 490 */ 491 public abstract ChronoLocalDate<C> date(int prolepticYear, int month, int dayOfMonth); 492 493 /** 494 * Obtains a local date in this chronology from the era, year-of-era and 495 * day-of-year fields. 496 * 497 * @param era the era of the correct type for the chronology, not null 498 * @param yearOfEra the chronology year-of-era 499 * @param dayOfYear the chronology day-of-year 500 * @return the local date in this chronology, not null 501 * @throws DateTimeException if unable to create the date 502 */ 503 public ChronoLocalDate<C> dateYearDay(Era<C> era, int yearOfEra, int dayOfYear) { 504 return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear); 505 } 506 507 /** 508 * Obtains a local date in this chronology from the proleptic-year and 509 * day-of-year fields. 510 * 511 * @param prolepticYear the chronology proleptic-year 512 * @param dayOfYear the chronology day-of-year 513 * @return the local date in this chronology, not null 514 * @throws DateTimeException if unable to create the date 515 */ 516 public abstract ChronoLocalDate<C> dateYearDay(int prolepticYear, int dayOfYear); 517 518 /** 519 * Obtains a local date in this chronology from another temporal object. 520 * <p> 521 * This creates a date in this chronology based on the specified {@code TemporalAccessor}. 522 * <p> 523 * The standard mechanism for conversion between date types is the 524 * {@link ChronoField#EPOCH_DAY local epoch-day} field. 525 * 526 * @param temporal the temporal object to convert, not null 527 * @return the local date in this chronology, not null 528 * @throws DateTimeException if unable to create the date 529 */ 530 public abstract ChronoLocalDate<C> date(TemporalAccessor temporal); 531 532 //----------------------------------------------------------------------- 533 /** 534 * Obtains the current local date in this chronology from the system clock in the default time-zone. 535 * <p> 536 * This will query the {@link Clock#systemDefaultZone() system clock} in the default 537 * time-zone to obtain the current date. 538 * <p> 539 * Using this method will prevent the ability to use an alternate clock for testing 540 * because the clock is hard-coded. 541 * <p> 542 * This implementation uses {@link #dateNow(Clock)}. 543 * 544 * @return the current local date using the system clock and default time-zone, not null 545 * @throws DateTimeException if unable to create the date 546 */ 547 public ChronoLocalDate<C> dateNow() { 548 return dateNow(Clock.systemDefaultZone()); 549 } 550 551 /** 552 * Obtains the current local date in this chronology from the system clock in the specified time-zone. 553 * <p> 554 * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date. 555 * Specifying the time-zone avoids dependence on the default time-zone. 556 * <p> 557 * Using this method will prevent the ability to use an alternate clock for testing 558 * because the clock is hard-coded. 559 * 560 * @param zone the zone ID to use, not null 561 * @return the current local date using the system clock, not null 562 * @throws DateTimeException if unable to create the date 563 */ 564 public ChronoLocalDate<C> dateNow(ZoneId zone) { 565 return dateNow(Clock.system(zone)); 566 } 567 568 /** 569 * Obtains the current local date in this chronology from the specified clock. 570 * <p> 571 * This will query the specified clock to obtain the current date - today. 572 * Using this method allows the use of an alternate clock for testing. 573 * The alternate clock may be introduced using {@link Clock dependency injection}. 574 * 575 * @param clock the clock to use, not null 576 * @return the current local date, not null 577 * @throws DateTimeException if unable to create the date 578 */ 579 public ChronoLocalDate<C> dateNow(Clock clock) { 580 Objects.requireNonNull(clock, "clock"); 581 return date(LocalDate.now(clock)); 582 } 583 584 //----------------------------------------------------------------------- 585 /** 586 * Obtains a local 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 * The date of the date-time should be equivalent to that obtained by calling 591 * {@link #date(TemporalAccessor)}. 592 * The standard mechanism for conversion between time types is the 593 * {@link ChronoField#NANO_OF_DAY nano-of-day} field. 594 * 595 * @param temporal the temporal object to convert, not null 596 * @return the local date-time in this chronology, not null 597 * @throws DateTimeException if unable to create the date-time 598 */ 599 public ChronoLocalDateTime<C> localDateTime(TemporalAccessor temporal) { 600 try { 601 return date(temporal).atTime(LocalTime.from(temporal)); 602 } catch (DateTimeException ex) { 603 throw new DateTimeException("Unable to obtain ChronoLocalDateTime from TemporalAccessor: " + temporal.getClass(), ex); 604 } 605 } 606 607 /** 608 * Obtains a zoned date-time in this chronology from another temporal object. 609 * <p> 610 * This creates a date-time in this chronology based on the specified {@code TemporalAccessor}. 611 * <p> 612 * This should obtain a {@code ZoneId} using {@link ZoneId#from(TemporalAccessor)}. 613 * The date-time should be obtained by obtaining an {@code Instant}. 614 * If that fails, the local date-time should be used. 615 * 616 * @param temporal the temporal object to convert, not null 617 * @return the zoned date-time in this chronology, not null 618 * @throws DateTimeException if unable to create the date-time 619 */ 620 public ChronoZonedDateTime<C> zonedDateTime(TemporalAccessor temporal) { 621 try { 622 ZoneId zone = ZoneId.from(temporal); 623 try { 624 Instant instant = Instant.from(temporal); 625 return zonedDateTime(instant, zone); 626 627 } catch (DateTimeException ex1) { 628 ChronoLocalDateTimeImpl<C> cldt = ensureChronoLocalDateTime(localDateTime(temporal)); 629 return ChronoZonedDateTimeImpl.ofBest(cldt, zone, null); 630 } 631 } catch (DateTimeException ex) { 632 throw new DateTimeException("Unable to obtain ChronoZonedDateTime from TemporalAccessor: " + temporal.getClass(), ex); 633 } 634 } 635 636 /** 637 * Obtains a zoned date-time in this chronology from an {@code Instant}. 638 * <p> 639 * This creates a zoned date-time with the same instant as that specified. 640 * 641 * @param instant the instant to create the date-time from, not null 642 * @param zone the time-zone, not null 643 * @return the zoned date-time, not null 644 * @throws DateTimeException if the result exceeds the supported range 645 */ 646 public ChronoZonedDateTime<C> zonedDateTime(Instant instant, ZoneId zone) { 647 return ChronoZonedDateTimeImpl.ofInstant(this, instant, zone); 648 } 649 650 //----------------------------------------------------------------------- 651 /** 652 * Checks if the specified year is a leap year. 653 * <p> 654 * A leap-year is a year of a longer length than normal. 655 * The exact meaning is determined by the chronology according to the following constraints. 656 * <p><ul> 657 * <li>a leap-year must imply a year-length longer than a non leap-year. 658 * <li>a chronology that does not support the concept of a year must return false. 659 * </ul><p> 660 * 661 * @param prolepticYear the proleptic-year to check, not validated for range 662 * @return true if the year is a leap year 663 */ 664 public abstract boolean isLeapYear(long prolepticYear); 665 666 /** 667 * Calculates the proleptic-year given the era and year-of-era. 668 * <p> 669 * This combines the era and year-of-era into the single proleptic-year field. 670 * 671 * @param era the era of the correct type for the chronology, not null 672 * @param yearOfEra the chronology year-of-era 673 * @return the proleptic-year 674 * @throws DateTimeException if unable to convert 675 */ 676 public abstract int prolepticYear(Era<C> era, int yearOfEra); 677 678 /** 679 * Creates the chronology era object from the numeric value. 680 * <p> 681 * The era is, conceptually, the largest division of the time-line. 682 * Most calendar systems have a single epoch dividing the time-line into two eras. 683 * However, some have multiple eras, such as one for the reign of each leader. 684 * The exact meaning is determined by the chronology according to the following constraints. 685 * <p> 686 * The era in use at 1970-01-01 must have the value 1. 687 * Later eras must have sequentially higher values. 688 * Earlier eras must have sequentially lower values. 689 * Each chronology must refer to an enum or similar singleton to provide the era values. 690 * <p> 691 * This method returns the singleton era of the correct type for the specified era value. 692 * 693 * @param eraValue the era value 694 * @return the calendar system era, not null 695 * @throws DateTimeException if unable to create the era 696 */ 697 public abstract Era<C> eraOf(int eraValue); 698 699 /** 700 * Gets the list of eras for the chronology. 701 * <p> 702 * Most calendar systems have an era, within which the year has meaning. 703 * If the calendar system does not support the concept of eras, an empty 704 * list must be returned. 705 * 706 * @return the list of eras for the chronology, may be immutable, not null 707 */ 708 public abstract List<Era<C>> eras(); 709 710 //----------------------------------------------------------------------- 711 /** 712 * Gets the range of valid values for the specified field. 713 * <p> 714 * All fields can be expressed as a {@code long} integer. 715 * This method returns an object that describes the valid range for that value. 716 * <p> 717 * Note that the result only describes the minimum and maximum valid values 718 * and it is important not to read too much into them. For example, there 719 * could be values within the range that are invalid for the field. 720 * <p> 721 * This method will return a result whether or not the chronology supports the field. 722 * 723 * @param field the field to get the range for, not null 724 * @return the range of valid values for the field, not null 725 * @throws DateTimeException if the range for the field cannot be obtained 726 */ 727 public abstract ValueRange range(ChronoField field); 728 729 //----------------------------------------------------------------------- 730 /** 731 * Gets the textual representation of this chronology. 732 * <p> 733 * This returns the textual name used to identify the chronology. 734 * The parameters control the style of the returned text and the locale. 735 * 736 * @param style the style of the text required, not null 737 * @param locale the locale to use, not null 738 * @return the text value of the chronology, not null 739 */ 740 public String getText(TextStyle style, Locale locale) { 741 return new DateTimeFormatterBuilder().appendChronoText(style).toFormatter(locale).print(new TemporalAccessor() { 742 @Override 743 public boolean isSupported(TemporalField field) { 744 return false; 745 } 746 @Override 747 public long getLong(TemporalField field) { 748 throw new DateTimeException("Unsupported field: " + field); 749 } 750 @SuppressWarnings("unchecked") 751 @Override 752 public <R> R query(TemporalQuery<R> query) { 753 if (query == Queries.chrono()) { 754 return (R) Chrono.this; 755 } 756 return TemporalAccessor.super.query(query); 757 } 758 }); 759 } 760 761 //----------------------------------------------------------------------- 762 /** 763 * Compares this chronology to another chronology. 764 * <p> 765 * The comparison order first by the chronology ID string, then by any 766 * additional information specific to the subclass. 767 * It is "consistent with equals", as defined by {@link Comparable}. 768 * <p> 769 * The default implementation compares the chronology ID. 770 * Subclasses must compare any additional state that they store. 771 * 772 * @param other the other chronology to compare to, not null 773 * @return the comparator value, negative if less, positive if greater 774 */ 775 @Override 776 public int compareTo(Chrono<?> other) { 777 return getId().compareTo(other.getId()); 778 } 779 780 /** 781 * Checks if this chronology is equal to another chronology. 782 * <p> 783 * The comparison is based on the entire state of the object. 784 * <p> 785 * The default implementation checks the type and calls {@link #compareTo(Chrono)}. 786 * 787 * @param obj the object to check, null returns false 788 * @return true if this is equal to the other chronology 789 */ 790 @Override 791 public boolean equals(Object obj) { 792 if (this == obj) { 793 return true; 794 } 795 if (obj instanceof Chrono) { 796 return compareTo((Chrono<?>) obj) == 0; 797 } 798 return false; 799 } 800 801 /** 802 * A hash code for this chronology. 803 * <p> 804 * The default implementation is based on the ID and class. 805 * Subclasses should add any additional state that they store. 806 * 807 * @return a suitable hash code 808 */ 809 @Override 810 public int hashCode() { 811 return getClass().hashCode() ^ getId().hashCode(); 812 } 813 814 //----------------------------------------------------------------------- 815 /** 816 * Outputs this chronology as a {@code String}, using the ID. 817 * 818 * @return a string representation of this chronology, not null 819 */ 820 @Override 821 public String toString() { 822 return getId(); 823 } 824 825 //----------------------------------------------------------------------- 826 /** 827 * Writes the object using a 828 * <a href="../../../serialized-form.html#java.time.temporal.Ser">dedicated serialized form</a>. 829 * <pre> 830 * out.writeByte(7); // identifies this as a Chrono 831 * out.writeUTF(chronoId); 832 * </pre> 833 * 834 * @return the instance of {@code Ser}, not null 835 */ 836 private Object writeReplace() { 837 return new Ser(Ser.CHRONO_TYPE, this); 838 } 839 840 /** 841 * Defend against malicious streams. 842 * @return never 843 * @throws InvalidObjectException always 844 */ 845 private Object readResolve() throws ObjectStreamException { 846 throw new InvalidObjectException("Deserialization via serialization delegate"); 847 } 848 849 void writeExternal(DataOutput out) throws IOException { 850 out.writeUTF(getId()); 851 } 852 853 static Chrono<?> readExternal(DataInput in) throws IOException { 854 String id = in.readUTF(); 855 return Chrono.of(id); 856 } 857 858 }