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 static org.threeten.bp.temporal.ChronoField.DAY_OF_MONTH; 35 import static org.threeten.bp.temporal.ChronoField.EPOCH_DAY; 36 import static org.threeten.bp.temporal.ChronoField.ERA; 37 import static org.threeten.bp.temporal.ChronoField.MONTH_OF_YEAR; 38 import static org.threeten.bp.temporal.ChronoField.YEAR; 39 import static org.threeten.bp.temporal.ChronoField.YEAR_OF_ERA; 40 41 import java.util.Comparator; 42 43 import org.threeten.bp.DateTimeException; 44 import org.threeten.bp.LocalDate; 45 import org.threeten.bp.LocalTime; 46 import org.threeten.bp.format.DateTimeFormatter; 47 import org.threeten.bp.jdk8.DefaultInterfaceTemporal; 48 import org.threeten.bp.jdk8.Jdk8Methods; 49 import org.threeten.bp.temporal.ChronoField; 50 import org.threeten.bp.temporal.ChronoUnit; 51 import org.threeten.bp.temporal.Temporal; 52 import org.threeten.bp.temporal.TemporalAccessor; 53 import org.threeten.bp.temporal.TemporalAdjuster; 54 import org.threeten.bp.temporal.TemporalAmount; 55 import org.threeten.bp.temporal.TemporalField; 56 import org.threeten.bp.temporal.TemporalQueries; 57 import org.threeten.bp.temporal.TemporalQuery; 58 import org.threeten.bp.temporal.TemporalUnit; 59 60 /** 61 * A date without time-of-day or time-zone in an arbitrary chronology, intended 62 * for advanced globalization use cases. 63 * <p> 64 * <b>Most applications should declare method signatures, fields and variables 65 * as {@link LocalDate}, not this interface.</b> 66 * <p> 67 * A {@code ChronoLocalDate} is the abstract representation of a date where the 68 * {@code Chronology chronology}, or calendar system, is pluggable. 69 * The date is defined in terms of fields expressed by {@link TemporalField}, 70 * where most common implementations are defined in {@link ChronoField}. 71 * The chronology defines how the calendar system operates and the meaning of 72 * the standard fields. 73 * 74 * <h4>When to use this interface</h4> 75 * The design of the API encourages the use of {@code LocalDate} rather than this 76 * interface, even in the case where the application needs to deal with multiple 77 * calendar systems. The rationale for this is explored in the following documentation. 78 * <p> 79 * The primary use case where this interface should be used is where the generic 80 * type parameter {@code <C>} is fully defined as a specific chronology. 81 * In that case, the assumptions of that chronology are known at development 82 * time and specified in the code. 83 * <p> 84 * When the chronology is defined in the generic type parameter as ? or otherwise 85 * unknown at development time, the rest of the discussion below applies. 86 * <p> 87 * To emphasize the point, declaring a method signature, field or variable as this 88 * interface type can initially seem like the sensible way to globalize an application, 89 * however it is usually the wrong approach. 90 * As such, it should be considered an application-wide architectural decision to choose 91 * to use this interface as opposed to {@code LocalDate}. 92 * 93 * <h4>Architectural issues to consider</h4> 94 * These are some of the points that must be considered before using this interface 95 * throughout an application. 96 * <p> 97 * 1) Applications using this interface, as opposed to using just {@code LocalDate}, 98 * face a significantly higher probability of bugs. This is because the calendar system 99 * in use is not known at development time. A key cause of bugs is where the developer 100 * applies assumptions from their day-to-day knowledge of the ISO calendar system 101 * to code that is intended to deal with any arbitrary calendar system. 102 * The section below outlines how those assumptions can cause problems 103 * The primary mechanism for reducing this increased risk of bugs is a strong code review process. 104 * This should also be considered a extra cost in maintenance for the lifetime of the code. 105 * <p> 106 * 2) This interface does not enforce immutability of implementations. 107 * While the implementation notes indicate that all implementations must be immutable 108 * there is nothing in the code or type system to enforce this. Any method declared 109 * to accept a {@code ChronoLocalDate} could therefore be passed a poorly or 110 * maliciously written mutable implementation. 111 * <p> 112 * 3) Applications using this interface must consider the impact of eras. 113 * {@code LocalDate} shields users from the concept of eras, by ensuring that {@code getYear()} 114 * returns the proleptic year. That decision ensures that developers can think of 115 * {@code LocalDate} instances as consisting of three fields - year, month-of-year and day-of-month. 116 * By contrast, users of this interface must think of dates as consisting of four fields - 117 * era, year-of-era, month-of-year and day-of-month. The extra era field is frequently 118 * forgotten, yet it is of vital importance to dates in an arbitrary calendar system. 119 * For example, in the Japanese calendar system, the era represents the reign of an Emperor. 120 * Whenever one reign ends and another starts, the year-of-era is reset to one. 121 * <p> 122 * 4) The only agreed international standard for passing a date between two systems 123 * is the ISO-8601 standard which requires the ISO calendar system. Using this interface 124 * throughout the application will inevitably lead to the requirement to pass the date 125 * across a network or component boundary, requiring an application specific protocol or format. 126 * <p> 127 * 5) Long term persistence, such as a database, will almost always only accept dates in the 128 * ISO-8601 calendar system (or the related Julian-Gregorian). Passing around dates in other 129 * calendar systems increases the complications of interacting with persistence. 130 * <p> 131 * 6) Most of the time, passing a {@code ChronoLocalDate} throughout an application 132 * is unnecessary, as discussed in the last section below. 133 * 134 * <h4>False assumptions causing bugs in multi-calendar system code</h4> 135 * As indicated above, there are many issues to consider when try to use and manipulate a 136 * date in an arbitrary calendar system. These are some of the key issues. 137 * <p> 138 * Code that queries the day-of-month and assumes that the value will never be more than 139 * 31 is invalid. Some calendar systems have more than 31 days in some months. 140 * <p> 141 * Code that adds 12 months to a date and assumes that a year has been added is invalid. 142 * Some calendar systems have a different number of months, such as 13 in the Coptic or Ethiopic. 143 * <p> 144 * Code that adds one month to a date and assumes that the month-of-year value will increase 145 * by one or wrap to the next year is invalid. Some calendar systems have a variable number 146 * of months in a year, such as the Hebrew. 147 * <p> 148 * Code that adds one month, then adds a second one month and assumes that the day-of-month 149 * will remain close to its original value is invalid. Some calendar systems have a large difference 150 * between the length of the longest month and the length of the shortest month. 151 * For example, the Coptic or Ethiopic have 12 months of 30 days and 1 month of 5 days. 152 * <p> 153 * Code that adds seven days and assumes that a week has been added is invalid. 154 * Some calendar systems have weeks of other than seven days, such as the French Revolutionary. 155 * <p> 156 * Code that assumes that because the year of {@code date1} is greater than the year of {@code date2} 157 * then {@code date1} is after {@code date2} is invalid. This is invalid for all calendar systems 158 * when referring to the year-of-era, and especially untrue of the Japanese calendar system 159 * where the year-of-era restarts with the reign of every new Emperor. 160 * <p> 161 * Code that treats month-of-year one and day-of-month one as the start of the year is invalid. 162 * Not all calendar systems start the year when the month value is one. 163 * <p> 164 * In general, manipulating a date, and even querying a date, is wide open to bugs when the 165 * calendar system is unknown at development time. This is why it is essential that code using 166 * this interface is subjected to additional code reviews. It is also why an architectural 167 * decision to avoid this interface type is usually the correct one. 168 * 169 * <h4>Using LocalDate instead</h4> 170 * The primary alternative to using this interface throughout your application is as follows. 171 * <p><ul> 172 * <li>Declare all method signatures referring to dates in terms of {@code LocalDate}. 173 * <li>Either store the chronology (calendar system) in the user profile or lookup 174 * the chronology from the user locale 175 * <li>Convert the ISO {@code LocalDate} to and from the user's preferred calendar system during 176 * printing and parsing 177 * </ul><p> 178 * This approach treats the problem of globalized calendar systems as a localization issue 179 * and confines it to the UI layer. This approach is in keeping with other localization 180 * issues in the java platform. 181 * <p> 182 * As discussed above, performing calculations on a date where the rules of the calendar system 183 * are pluggable requires skill and is not recommended. 184 * Fortunately, the need to perform calculations on a date in an arbitrary calendar system 185 * is extremely rare. For example, it is highly unlikely that the business rules of a library 186 * book rental scheme will allow rentals to be for one month, where meaning of the month 187 * is dependent on the user's preferred calendar system. 188 * <p> 189 * A key use case for calculations on a date in an arbitrary calendar system is producing 190 * a month-by-month calendar for display and user interaction. Again, this is a UI issue, 191 * and use of this interface solely within a few methods of the UI layer may be justified. 192 * <p> 193 * In any other part of the system, where a date must be manipulated in a calendar system 194 * other than ISO, the use case will generally specify the calendar system to use. 195 * For example, an application may need to calculate the next Islamic or Hebrew holiday 196 * which may require manipulating the date. 197 * This kind of use case can be handled as follows: 198 * <p><ul> 199 * <li>start from the ISO {@code LocalDate} being passed to the method 200 * <li>convert the date to the alternate calendar system, which for this use case is known 201 * rather than arbitrary 202 * <li>perform the calculation 203 * <li>convert back to {@code LocalDate} 204 * </ul><p> 205 * Developers writing low-level frameworks or libraries should also avoid this interface. 206 * Instead, one of the two general purpose access interfaces should be used. 207 * Use {@link TemporalAccessor} if read-only access is required, or use {@link Temporal} 208 * if read-write access is required. 209 * 210 * <h3>Specification for implementors</h3> 211 * This interface must be implemented with care to ensure other classes operate correctly. 212 * All implementations that can be instantiated must be final, immutable and thread-safe. 213 * Subclasses should be Serializable wherever possible. 214 * <p> 215 * Additional calendar systems may be added to the system. 216 * See {@link Chronology} for more details. 217 * <p> 218 * In JDK 8, this is an interface with default methods. 219 * Since there are no default methods in JDK 7, an abstract class is used. 220 */ 221 public abstract class ChronoLocalDate 222 extends DefaultInterfaceTemporal 223 implements Temporal, TemporalAdjuster, Comparable<ChronoLocalDate> { 224 225 /** 226 * Gets a comparator that compares {@code ChronoLocalDate} in 227 * time-line order ignoring the chronology. 228 * <p> 229 * This comparator differs from the comparison in {@link #compareTo} in that it 230 * only compares the underlying date and not the chronology. 231 * This allows dates in different calendar systems to be compared based 232 * on the position of the date on the local time-line. 233 * The underlying comparison is equivalent to comparing the epoch-day. 234 * 235 * @return a comparator that compares in time-line order ignoring the chronology 236 * @see #isAfter 237 * @see #isBefore 238 * @see #isEqual 239 */ timeLineOrder()240 public static Comparator<ChronoLocalDate> timeLineOrder() { 241 return DATE_COMPARATOR; 242 } 243 private static final Comparator<ChronoLocalDate> DATE_COMPARATOR = 244 new Comparator<ChronoLocalDate>() { 245 @Override 246 public int compare(ChronoLocalDate date1, ChronoLocalDate date2) { 247 return Jdk8Methods.compareLongs(date1.toEpochDay(), date2.toEpochDay()); 248 } 249 }; 250 251 //----------------------------------------------------------------------- 252 /** 253 * Obtains an instance of {@code ChronoLocalDate} from a temporal object. 254 * <p> 255 * This obtains a local date based on the specified temporal. 256 * A {@code TemporalAccessor} represents an arbitrary set of date and time information, 257 * which this factory converts to an instance of {@code ChronoLocalDate}. 258 * <p> 259 * The conversion extracts and combines the chronology and the date 260 * from the temporal object. The behavior is equivalent to using 261 * {@link Chronology#date(TemporalAccessor)} with the extracted chronology. 262 * Implementations are permitted to perform optimizations such as accessing 263 * those fields that are equivalent to the relevant objects. 264 * <p> 265 * This method matches the signature of the functional interface {@link TemporalQuery} 266 * allowing it to be used as a query via method reference, {@code ChronoLocalDate::from}. 267 * 268 * @param temporal the temporal object to convert, not null 269 * @return the date, not null 270 * @throws DateTimeException if unable to convert to a {@code ChronoLocalDate} 271 * @see Chronology#date(TemporalAccessor) 272 */ from(TemporalAccessor temporal)273 public static ChronoLocalDate from(TemporalAccessor temporal) { 274 Jdk8Methods.requireNonNull(temporal, "temporal"); 275 if (temporal instanceof ChronoLocalDate) { 276 return (ChronoLocalDate) temporal; 277 } 278 Chronology chrono = temporal.query(TemporalQueries.chronology()); 279 if (chrono == null) { 280 throw new DateTimeException("No Chronology found to create ChronoLocalDate: " + temporal.getClass()); 281 } 282 return chrono.date(temporal); 283 } 284 285 //----------------------------------------------------------------------- 286 /** 287 * Gets the chronology of this date. 288 * <p> 289 * The {@code Chronology} represents the calendar system in use. 290 * The era and other fields in {@link ChronoField} are defined by the chronology. 291 * 292 * @return the chronology, not null 293 */ getChronology()294 public abstract Chronology getChronology(); 295 296 /** 297 * Gets the era, as defined by the chronology. 298 * <p> 299 * The era is, conceptually, the largest division of the time-line. 300 * Most calendar systems have a single epoch dividing the time-line into two eras. 301 * However, some have multiple eras, such as one for the reign of each leader. 302 * The exact meaning is determined by the {@code Chronology}. 303 * <p> 304 * All correctly implemented {@code Era} classes are singletons, thus it 305 * is valid code to write {@code date.getEra() == SomeEra.NAME)}. 306 * 307 * @return the chronology specific era constant applicable at this date, not null 308 */ getEra()309 public Era getEra() { 310 return getChronology().eraOf(get(ERA)); 311 } 312 313 //----------------------------------------------------------------------- 314 /** 315 * Checks if the year is a leap year, as defined by the calendar system. 316 * <p> 317 * A leap-year is a year of a longer length than normal. 318 * The exact meaning is determined by the chronology with the constraint that 319 * a leap-year must imply a year-length longer than a non leap-year. 320 * <p> 321 * The default implementation uses {@link Chronology#isLeapYear(long)}. 322 * 323 * @return true if this date is in a leap year, false otherwise 324 */ isLeapYear()325 public boolean isLeapYear() { 326 return getChronology().isLeapYear(getLong(YEAR)); 327 } 328 329 /** 330 * Returns the length of the month represented by this date, as defined by the calendar system. 331 * <p> 332 * This returns the length of the month in days. 333 * 334 * @return the length of the month in days 335 */ lengthOfMonth()336 public abstract int lengthOfMonth(); 337 338 /** 339 * Returns the length of the year represented by this date, as defined by the calendar system. 340 * <p> 341 * This returns the length of the year in days. 342 * <p> 343 * The default implementation uses {@link #isLeapYear()} and returns 365 or 366. 344 * 345 * @return the length of the year in days 346 */ lengthOfYear()347 public int lengthOfYear() { 348 return (isLeapYear() ? 366 : 365); 349 } 350 351 @Override isSupported(TemporalField field)352 public boolean isSupported(TemporalField field) { 353 if (field instanceof ChronoField) { 354 return field.isDateBased(); 355 } 356 return field != null && field.isSupportedBy(this); 357 } 358 359 @Override isSupported(TemporalUnit unit)360 public boolean isSupported(TemporalUnit unit) { 361 if (unit instanceof ChronoUnit) { 362 return unit.isDateBased(); 363 } 364 return unit != null && unit.isSupportedBy(this); 365 } 366 367 //------------------------------------------------------------------------- 368 // override for covariant return type 369 @Override with(TemporalAdjuster adjuster)370 public ChronoLocalDate with(TemporalAdjuster adjuster) { 371 return getChronology().ensureChronoLocalDate(super.with(adjuster)); 372 } 373 374 @Override with(TemporalField field, long newValue)375 public abstract ChronoLocalDate with(TemporalField field, long newValue); 376 377 @Override plus(TemporalAmount amount)378 public ChronoLocalDate plus(TemporalAmount amount) { 379 return getChronology().ensureChronoLocalDate(super.plus(amount)); 380 } 381 382 @Override plus(long amountToAdd, TemporalUnit unit)383 public abstract ChronoLocalDate plus(long amountToAdd, TemporalUnit unit); 384 385 @Override minus(TemporalAmount amount)386 public ChronoLocalDate minus(TemporalAmount amount) { 387 return getChronology().ensureChronoLocalDate(super.minus(amount)); 388 } 389 390 @Override minus(long amountToSubtract, TemporalUnit unit)391 public ChronoLocalDate minus(long amountToSubtract, TemporalUnit unit) { 392 return getChronology().ensureChronoLocalDate(super.minus(amountToSubtract, unit)); 393 } 394 395 //----------------------------------------------------------------------- 396 @SuppressWarnings("unchecked") 397 @Override query(TemporalQuery<R> query)398 public <R> R query(TemporalQuery<R> query) { 399 if (query == TemporalQueries.chronology()) { 400 return (R) getChronology(); 401 } else if (query == TemporalQueries.precision()) { 402 return (R) ChronoUnit.DAYS; 403 } else if (query == TemporalQueries.localDate()) { 404 return (R) LocalDate.ofEpochDay(toEpochDay()); 405 } else if (query == TemporalQueries.localTime() || query == TemporalQueries.zone() || 406 query == TemporalQueries.zoneId() || query == TemporalQueries.offset()) { 407 return null; 408 } 409 return super.query(query); 410 } 411 412 @Override adjustInto(Temporal temporal)413 public Temporal adjustInto(Temporal temporal) { 414 return temporal.with(EPOCH_DAY, toEpochDay()); 415 } 416 417 //----------------------------------------------------------------------- 418 /** 419 * Calculates the period between this date and another date as a {@code ChronoPeriod}. 420 * <p> 421 * This calculates the period between two dates. All supplied chronologies 422 * calculate the period using years, months and days, however the 423 * {@code ChronoPeriod} API allows the period to be represented using other units. 424 * <p> 425 * The start and end points are {@code this} and the specified date. 426 * The result will be negative if the end is before the start. 427 * The negative sign will be the same in each of year, month and day. 428 * <p> 429 * The calculation is performed using the chronology of this date. 430 * If necessary, the input date will be converted to match. 431 * <p> 432 * This instance is immutable and unaffected by this method call. 433 * 434 * @param endDateExclusive the end date, exclusive, which may be in any chronology, not null 435 * @return the period between this date and the end date, not null 436 * @throws DateTimeException if the period cannot be calculated 437 * @throws ArithmeticException if numeric overflow occurs 438 */ until(ChronoLocalDate endDateExclusive)439 public abstract ChronoPeriod until(ChronoLocalDate endDateExclusive); 440 441 /** 442 * Formats this date using the specified formatter. 443 * <p> 444 * This date will be passed to the formatter to produce a string. 445 * <p> 446 * The default implementation must behave as follows: 447 * <pre> 448 * return formatter.format(this); 449 * </pre> 450 * 451 * @param formatter the formatter to use, not null 452 * @return the formatted date string, not null 453 * @throws DateTimeException if an error occurs during printing 454 */ format(DateTimeFormatter formatter)455 public String format(DateTimeFormatter formatter) { 456 Jdk8Methods.requireNonNull(formatter, "formatter"); 457 return formatter.format(this); 458 } 459 460 //----------------------------------------------------------------------- 461 /** 462 * Combines this date with a time to create a {@code ChronoLocalDateTime}. 463 * <p> 464 * This returns a {@code ChronoLocalDateTime} formed from this date at the specified time. 465 * All possible combinations of date and time are valid. 466 * 467 * @param localTime the local time to use, not null 468 * @return the local date-time formed from this date and the specified time, not null 469 */ atTime(LocalTime localTime)470 public ChronoLocalDateTime<?> atTime(LocalTime localTime) { 471 return ChronoLocalDateTimeImpl.of(this, localTime); 472 } 473 474 //----------------------------------------------------------------------- 475 /** 476 * Converts this date to the Epoch Day. 477 * <p> 478 * The {@link ChronoField#EPOCH_DAY Epoch Day count} is a simple 479 * incrementing count of days where day 0 is 1970-01-01 (ISO). 480 * This definition is the same for all chronologies, enabling conversion. 481 * 482 * @return the Epoch Day equivalent to this date 483 */ toEpochDay()484 public long toEpochDay() { 485 return getLong(EPOCH_DAY); 486 } 487 488 //----------------------------------------------------------------------- 489 /** 490 * Compares this date to another date, including the chronology. 491 * <p> 492 * The comparison is based first on the underlying time-line date, then 493 * on the chronology. 494 * It is "consistent with equals", as defined by {@link Comparable}. 495 * <p> 496 * For example, the following is the comparator order: 497 * <ol> 498 * <li>{@code 2012-12-03 (ISO)}</li> 499 * <li>{@code 2012-12-04 (ISO)}</li> 500 * <li>{@code 2555-12-04 (ThaiBuddhist)}</li> 501 * <li>{@code 2012-12-05 (ISO)}</li> 502 * </ol> 503 * Values #2 and #3 represent the same date on the time-line. 504 * When two values represent the same date, the chronology ID is compared to distinguish them. 505 * This step is needed to make the ordering "consistent with equals". 506 * <p> 507 * If all the date objects being compared are in the same chronology, then the 508 * additional chronology stage is not required and only the local date is used. 509 * To compare the dates of two {@code TemporalAccessor} instances, including dates 510 * in two different chronologies, use {@link ChronoField#EPOCH_DAY} as a comparator. 511 * 512 * @param other the other date to compare to, not null 513 * @return the comparator value, negative if less, positive if greater 514 */ 515 @Override compareTo(ChronoLocalDate other)516 public int compareTo(ChronoLocalDate other) { 517 int cmp = Jdk8Methods.compareLongs(toEpochDay(), other.toEpochDay()); 518 if (cmp == 0) { 519 cmp = getChronology().compareTo(other.getChronology()); 520 } 521 return cmp; 522 } 523 524 //----------------------------------------------------------------------- 525 /** 526 * Checks if this date is after the specified date ignoring the chronology. 527 * <p> 528 * This method differs from the comparison in {@link #compareTo} in that it 529 * only compares the underlying date and not the chronology. 530 * This allows dates in different calendar systems to be compared based 531 * on the time-line position. 532 * This is equivalent to using {@code date1.toEpochDay() > date2.toEpochDay()}. 533 * 534 * @param other the other date to compare to, not null 535 * @return true if this is after the specified date 536 */ isAfter(ChronoLocalDate other)537 public boolean isAfter(ChronoLocalDate other) { 538 return this.toEpochDay() > other.toEpochDay(); 539 } 540 541 /** 542 * Checks if this date is before the specified date ignoring the chronology. 543 * <p> 544 * This method differs from the comparison in {@link #compareTo} in that it 545 * only compares the underlying date and not the chronology. 546 * This allows dates in different calendar systems to be compared based 547 * on the time-line position. 548 * This is equivalent to using {@code date1.toEpochDay() < date2.toEpochDay()}. 549 * 550 * @param other the other date to compare to, not null 551 * @return true if this is before the specified date 552 */ isBefore(ChronoLocalDate other)553 public boolean isBefore(ChronoLocalDate other) { 554 return this.toEpochDay() < other.toEpochDay(); 555 } 556 557 /** 558 * Checks if this date is equal to the specified date ignoring the chronology. 559 * <p> 560 * This method differs from the comparison in {@link #compareTo} in that it 561 * only compares the underlying date and not the chronology. 562 * This allows dates in different calendar systems to be compared based 563 * on the time-line position. 564 * This is equivalent to using {@code date1.toEpochDay() == date2.toEpochDay()}. 565 * 566 * @param other the other date to compare to, not null 567 * @return true if the underlying date is equal to the specified date 568 */ isEqual(ChronoLocalDate other)569 public boolean isEqual(ChronoLocalDate other) { 570 return this.toEpochDay() == other.toEpochDay(); 571 } 572 573 //----------------------------------------------------------------------- 574 /** 575 * Checks if this date is equal to another date, including the chronology. 576 * <p> 577 * Compares this date with another ensuring that the date and chronology are the same. 578 * <p> 579 * To compare the dates of two {@code TemporalAccessor} instances, including dates 580 * in two different chronologies, use {@link ChronoField#EPOCH_DAY} as a comparator. 581 * 582 * @param obj the object to check, null returns false 583 * @return true if this is equal to the other date 584 */ 585 @Override equals(Object obj)586 public boolean equals(Object obj) { 587 if (this == obj) { 588 return true; 589 } 590 if (obj instanceof ChronoLocalDate) { 591 return compareTo((ChronoLocalDate) obj) == 0; 592 } 593 return false; 594 } 595 596 /** 597 * A hash code for this date. 598 * 599 * @return a suitable hash code 600 */ 601 @Override hashCode()602 public int hashCode() { 603 long epDay = toEpochDay(); 604 return getChronology().hashCode() ^ ((int) (epDay ^ (epDay >>> 32))); 605 } 606 607 //----------------------------------------------------------------------- 608 /** 609 * Outputs this date as a {@code String}. 610 * <p> 611 * The output will include the full local date and the chronology ID. 612 * 613 * @return the formatted date, not null 614 */ 615 @Override toString()616 public String toString() { 617 // getLong() reduces chances of exceptions in toString() 618 long yoe = getLong(YEAR_OF_ERA); 619 long moy = getLong(MONTH_OF_YEAR); 620 long dom = getLong(DAY_OF_MONTH); 621 StringBuilder buf = new StringBuilder(30); 622 buf.append(getChronology().toString()) 623 .append(" ") 624 .append(getEra()) 625 .append(" ") 626 .append(yoe) 627 .append(moy < 10 ? "-0" : "-").append(moy) 628 .append(dom < 10 ? "-0" : "-").append(dom); 629 return buf.toString(); 630 } 631 632 } 633