1 /* 2 * hunt-time: A time library for D programming language. 3 * 4 * Copyright (C) 2015-2018 HuntLabs 5 * 6 * Website: https://www.huntlabs.net/ 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 12 module hunt.time.chrono.ChronoLocalDate; 13 14 import hunt.time.temporal.ChronoField; 15 16 import hunt.stream.Common; 17 import hunt.time.Exceptions; 18 import hunt.time.LocalDate; 19 import hunt.time.LocalTime; 20 // import hunt.time.format.DateTimeFormatter; 21 import hunt.time.temporal.ChronoField; 22 import hunt.time.temporal.ChronoUnit; 23 import hunt.time.temporal.Temporal; 24 import hunt.time.temporal.TemporalAccessor; 25 import hunt.time.temporal.TemporalAdjuster; 26 import hunt.time.temporal.TemporalAmount; 27 import hunt.time.temporal.TemporalField; 28 import hunt.time.temporal.TemporalQueries; 29 import hunt.time.temporal.TemporalQuery; 30 import hunt.time.temporal.TemporalUnit; 31 import hunt.time.Exceptions; 32 import hunt.util.Comparator; 33 import hunt.Functions; 34 import hunt.time.chrono.Chronology; 35 import hunt.time.chrono.Era; 36 import hunt.time.chrono.ChronoPeriod; 37 import hunt.time.chrono.ChronoLocalDateTime; 38 import hunt.util.Comparator; 39 import hunt.util.Common; 40 import hunt.time.util.QueryHelper; 41 42 /** 43 * A date without time-of-day or time-zone _in an arbitrary chronology, intended 44 * for advanced globalization use cases. 45 * !(p) 46 * !(b)Most applications should declare method signatures, fields and variables 47 * as {@link LocalDate}, not this interface.</b> 48 * !(p) 49 * A {@code ChronoLocalDate} is the abstract representation of a date where the 50 * {@code Chronology chronology}, or calendar system, is pluggable. 51 * The date is defined _in terms of fields expressed by {@link TemporalField}, 52 * where most common implementations are defined _in {@link ChronoField}. 53 * The chronology defines how the calendar system operates and the meaning of 54 * the standard fields. 55 * 56 * !(h3)When to use this interface</h3> 57 * The design of the API encourages the use of {@code LocalDate} rather than this 58 * interface, even _in the case where the application needs to deal with multiple 59 * calendar systems. 60 * !(p) 61 * This concept can seem surprising at first, as the natural way to globalize an 62 * application might initially appear to be to abstract the calendar system. 63 * However, as explored below, abstracting the calendar system is usually the wrong 64 * approach, resulting _in logic errors and hard to find bugs. 65 * As such, it should be considered an application-wide architectural decision to choose 66 * to use this interface as opposed to {@code LocalDate}. 67 * 68 * !(h3)Architectural issues to consider</h3> 69 * These are some of the points that must be considered before using this interface 70 * throughout an application. 71 * !(p) 72 * 1) Applications using this interface, as opposed to using just {@code LocalDate}, 73 * face a significantly higher probability of bugs. This is because the calendar system 74 * _in use is not known at development time. A key cause of bugs is where the developer 75 * applies assumptions from their day-to-day knowledge of the ISO calendar system 76 * to code that is intended to deal with any arbitrary calendar system. 77 * The section below outlines how those assumptions can cause problems 78 * The primary mechanism for reducing this increased risk of bugs is a strong code review process. 79 * This should also be considered a extra cost _in maintenance for the lifetime of the code. 80 * !(p) 81 * 2) This interface does not enforce immutability of implementations. 82 * While the implementation notes indicate that all implementations must be immutable 83 * there is nothing _in the code or type system to enforce this. Any method declared 84 * to accept a {@code ChronoLocalDate} could therefore be passed a poorly or 85 * maliciously written mutable implementation. 86 * !(p) 87 * 3) Applications using this interface must consider the impact of eras. 88 * {@code LocalDate} shields users from the concept of eras, by ensuring that {@code getYear()} 89 * returns the proleptic year. That decision ensures that developers can think of 90 * {@code LocalDate} instances as consisting of three fields - year, month-of-year and day-of-month. 91 * By contrast, users of this interface must think of dates as consisting of four fields - 92 * era, year-of-era, month-of-year and day-of-month. The extra era field is frequently 93 * forgotten, yet it is of vital importance to dates _in an arbitrary calendar system. 94 * For example, _in the Japanese calendar system, the era represents the reign of an Emperor. 95 * Whenever one reign ends and another starts, the year-of-era is reset to one. 96 * !(p) 97 * 4) The only agreed international standard for passing a date between two systems 98 * is the ISO-8601 standard which requires the ISO calendar system. Using this interface 99 * throughout the application will inevitably lead to the requirement to pass the date 100 * across a network or component boundary, requiring an application specific protocol or format. 101 * !(p) 102 * 5) Long term persistence, such as a database, will almost always only accept dates _in the 103 * ISO-8601 calendar system (or the related Julian-Gregorian). Passing around dates _in other 104 * calendar systems increases the complications of interacting with persistence. 105 * !(p) 106 * 6) Most of the time, passing a {@code ChronoLocalDate} throughout an application 107 * is unnecessary, as discussed _in the last section below. 108 * 109 * !(h3)False assumptions causing bugs _in multi-calendar system code</h3> 110 * As indicated above, there are many issues to consider when try to use and manipulate a 111 * date _in an arbitrary calendar system. These are some of the key issues. 112 * !(p) 113 * Code that queries the day-of-month and assumes that the value will never be more than 114 * 31 is invalid. Some calendar systems have more than 31 days _in some months. 115 * !(p) 116 * Code that adds 12 months to a date and assumes that a year has been added is invalid. 117 * Some calendar systems have a different number of months, such as 13 _in the Coptic or Ethiopic. 118 * !(p) 119 * Code that adds one month to a date and assumes that the month-of-year value will increase 120 * by one or wrap to the next year is invalid. Some calendar systems have a variable number 121 * of months _in a year, such as the Hebrew. 122 * !(p) 123 * Code that adds one month, then adds a second one month and assumes that the day-of-month 124 * will remain close to its original value is invalid. Some calendar systems have a large difference 125 * between the length of the longest month and the length of the shortest month. 126 * For example, the Coptic or Ethiopic have 12 months of 30 days and 1 month of 5 days. 127 * !(p) 128 * Code that adds seven days and assumes that a week has been added is invalid. 129 * Some calendar systems have weeks of other than seven days, such as the French Revolutionary. 130 * !(p) 131 * Code that assumes that because the year of {@code date1} is greater than the year of {@code date2} 132 * then {@code date1} is after {@code date2} is invalid. This is invalid for all calendar systems 133 * when referring to the year-of-era, and especially untrue of the Japanese calendar system 134 * where the year-of-era restarts with the reign of every new Emperor. 135 * !(p) 136 * Code that treats month-of-year one and day-of-month one as the start of the year is invalid. 137 * Not all calendar systems start the year when the month value is one. 138 * !(p) 139 * In general, manipulating a date, and even querying a date, is wide open to bugs when the 140 * calendar system is unknown at development time. This is why it is essential that code using 141 * this interface is subjected to additional code reviews. It is also why an architectural 142 * decision to avoid this interface type is usually the correct one. 143 * 144 * !(h3)Using LocalDate instead</h3> 145 * The primary alternative to using this interface throughout your application is as follows. 146 * !(ul) 147 * !(li)Declare all method signatures referring to dates _in terms of {@code LocalDate}. 148 * !(li)Either store the chronology (calendar system) _in the user profile or lookup 149 * the chronology from the user locale 150 * !(li)Convert the ISO {@code LocalDate} to and from the user's preferred calendar system during 151 * printing and parsing 152 * </ul> 153 * This approach treats the problem of globalized calendar systems as a localization issue 154 * and confines it to the UI layer. This approach is _in keeping with other localization 155 * issues _in the java platform. 156 * !(p) 157 * As discussed above, performing calculations on a date where the rules of the calendar system 158 * are pluggable requires skill and is not recommended. 159 * Fortunately, the need to perform calculations on a date _in an arbitrary calendar system 160 * is extremely rare. For example, it is highly unlikely that the business rules of a library 161 * book rental scheme will allow rentals to be for one month, where meaning of the month 162 * is dependent on the user's preferred calendar system. 163 * !(p) 164 * A key use case for calculations on a date _in an arbitrary calendar system is producing 165 * a month-by-month calendar for display and user interaction. Again, this is a UI issue, 166 * and use of this interface solely within a few methods of the UI layer may be justified. 167 * !(p) 168 * In any other part of the system, where a date must be manipulated _in a calendar system 169 * other than ISO, the use case will generally specify the calendar system to use. 170 * For example, an application may need to calculate the next Islamic or Hebrew holiday 171 * which may require manipulating the date. 172 * This kind of use case can be handled as follows: 173 * !(ul) 174 * !(li)start from the ISO {@code LocalDate} being passed to the method 175 * !(li)convert the date to the alternate calendar system, which for this use case is known 176 * rather than arbitrary 177 * !(li)perform the calculation 178 * !(li)convert back to {@code LocalDate} 179 * </ul> 180 * Developers writing low-level frameworks or libraries should also avoid this interface. 181 * Instead, one of the two general purpose access interfaces should be used. 182 * Use {@link TemporalAccessor} if read-only access is required, or use {@link Temporal} 183 * if read-write access is required. 184 * 185 * @implSpec 186 * This interface must be implemented with care to ensure other classes operate correctly. 187 * All implementations that can be instantiated must be final, immutable and thread-safe. 188 * Subclasses should be Serializable wherever possible. 189 * !(p) 190 * Additional calendar systems may be added to the system. 191 * See {@link Chronology} for more details. 192 * 193 * @since 1.8 194 */ 195 public interface ChronoLocalDate 196 : Temporal, TemporalAdjuster, Comparable!(ChronoLocalDate) { 197 198 /** 199 * Gets a comparator that compares {@code ChronoLocalDate} _in 200 * time-line order ignoring the chronology. 201 * !(p) 202 * This comparator differs from the comparison _in {@link #compareTo} _in that it 203 * only compares the underlying date and not the chronology. 204 * This allows dates _in different calendar systems to be compared based 205 * on the position of the date on the local time-line. 206 * The underlying comparison is equivalent to comparing the epoch-day. 207 * 208 * @return a comparator that compares _in time-line order ignoring the chronology 209 * @see #isAfter 210 * @see #isBefore 211 * @see #isEqual 212 */ 213 static Comparator!(ChronoLocalDate) timeLineOrder() { 214 return new class Comparator!(ChronoLocalDate) { 215 int compare(ChronoLocalDate date1, ChronoLocalDate date2) nothrow { 216 try { 217 return hunt.util.Comparator.compare(date1.toEpochDay(), date2.toEpochDay()); 218 } catch(Exception) { 219 // FIXME: Needing refactor or cleanup -@zxp at 12/29/2018, 11:28:15 PM 220 // 221 return 0; 222 } 223 } 224 }; 225 } 226 227 //----------------------------------------------------------------------- 228 /** 229 * Obtains an instance of {@code ChronoLocalDate} from a temporal object. 230 * !(p) 231 * This obtains a local date based on the specified temporal. 232 * A {@code TemporalAccessor} represents an arbitrary set of date and time information, 233 * which this factory converts to an instance of {@code ChronoLocalDate}. 234 * !(p) 235 * The conversion extracts and combines the chronology and the date 236 * from the temporal object. The behavior is equivalent to using 237 * {@link Chronology#date(TemporalAccessor)} with the extracted chronology. 238 * Implementations are permitted to perform optimizations such as accessing 239 * those fields that are equivalent to the relevant objects. 240 * !(p) 241 * This method matches the signature of the functional interface {@link TemporalQuery} 242 * allowing it to be used as a query via method reference, {@code ChronoLocalDate::from}. 243 * 244 * @param temporal the temporal object to convert, not null 245 * @return the date, not null 246 * @throws DateTimeException if unable to convert to a {@code ChronoLocalDate} 247 * @see Chronology#date(TemporalAccessor) 248 */ 249 static ChronoLocalDate from(TemporalAccessor temporal) { 250 if (cast(ChronoLocalDate)(temporal) !is null) { 251 return cast(ChronoLocalDate) temporal; 252 } 253 assert(temporal, "temporal"); 254 Chronology chrono = QueryHelper.query!Chronology(temporal,TemporalQueries.chronology()); 255 if (chrono is null) { 256 throw new DateTimeException("Unable to obtain ChronoLocalDate from TemporalAccessor: " ~ typeid(temporal).stringof); 257 } 258 return chrono.date(temporal); 259 } 260 261 //----------------------------------------------------------------------- 262 /** 263 * Gets the chronology of this date. 264 * !(p) 265 * The {@code Chronology} represents the calendar system _in use. 266 * The era and other fields _in {@link ChronoField} are defined by the chronology. 267 * 268 * @return the chronology, not null 269 */ 270 Chronology getChronology(); 271 272 /** 273 * Gets the era, as defined by the chronology. 274 * !(p) 275 * The era is, conceptually, the largest division of the time-line. 276 * Most calendar systems have a single epoch dividing the time-line into two eras. 277 * However, some have multiple eras, such as one for the reign of each leader. 278 * The exact meaning is determined by the {@code Chronology}. 279 * !(p) 280 * All correctly implemented {@code Era} classes are singletons, thus it 281 * is valid code to write {@code date.getEra() == SomeChrono.ERA_NAME)}. 282 * !(p) 283 * This implementation uses {@link Chronology#eraOf(int)}. 284 * 285 * @return the chronology specific era constant applicable at this date, not null 286 */ 287 Era getEra(); 288 // Era getEra() { 289 // return getChronology().eraOf(get(ERA)); 290 // } 291 292 /** 293 * Checks if the year is a leap year, as defined by the calendar system. 294 * !(p) 295 * A leap-year is a year of a longer length than normal. 296 * The exact meaning is determined by the chronology with the constraint that 297 * a leap-year must imply a year-length longer than a non leap-year. 298 * !(p) 299 * This implementation uses {@link Chronology#isLeapYear(long)}. 300 * 301 * @return true if this date is _in a leap year, false otherwise 302 */ 303 bool isLeapYear(); 304 // bool isLeapYear() { 305 // return getChronology().isLeapYear(getLong(YEAR)); 306 // } 307 308 /** 309 * Returns the length of the month represented by this date, as defined by the calendar system. 310 * !(p) 311 * This returns the length of the month _in days. 312 * 313 * @return the length of the month _in days 314 */ 315 int lengthOfMonth(); 316 317 /** 318 * Returns the length of the year represented by this date, as defined by the calendar system. 319 * !(p) 320 * This returns the length of the year _in days. 321 * !(p) 322 * The implementation uses {@link #isLeapYear()} and returns 365 or 366. 323 * 324 * @return the length of the year _in days 325 */ 326 int lengthOfYear(); 327 // int lengthOfYear() { 328 // return (isLeapYear() ? 366 : 365); 329 // } 330 331 /** 332 * Checks if the specified field is supported. 333 * !(p) 334 * This checks if the specified field can be queried on this date. 335 * If false, then calling the {@link #range(TemporalField) range}, 336 * {@link #get(TemporalField) get} and {@link #_with(TemporalField, long)} 337 * methods will throw an exception. 338 * !(p) 339 * The set of supported fields is defined by the chronology and normally includes 340 * all {@code ChronoField} date fields. 341 * !(p) 342 * If the field is not a {@code ChronoField}, then the result of this method 343 * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)} 344 * passing {@code this} as the argument. 345 * Whether the field is supported is determined by the field. 346 * 347 * @param field the field to check, null returns false 348 * @return true if the field can be queried, false if not 349 */ 350 bool isSupported(TemporalField field); 351 // override 352 // bool isSupported(TemporalField field) { 353 // if (cast(ChronoField)(field) !is null) { 354 // return field.isDateBased(); 355 // } 356 // return field !is null && field.isSupportedBy(this); 357 // } 358 359 /** 360 * Checks if the specified unit is supported. 361 * !(p) 362 * This checks if the specified unit can be added to or subtracted from this date. 363 * If false, then calling the {@link #plus(long, TemporalUnit)} and 364 * {@link #minus(long, TemporalUnit) minus} methods will throw an exception. 365 * !(p) 366 * The set of supported units is defined by the chronology and normally includes 367 * all {@code ChronoUnit} date units except {@code FOREVER}. 368 * !(p) 369 * If the unit is not a {@code ChronoUnit}, then the result of this method 370 * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)} 371 * passing {@code this} as the argument. 372 * Whether the unit is supported is determined by the unit. 373 * 374 * @param unit the unit to check, null returns false 375 * @return true if the unit can be added/subtracted, false if not 376 */ 377 bool isSupported(TemporalUnit unit); 378 // override 379 // bool isSupported(TemporalUnit unit) { 380 // if (cast(ChronoUnit)(unit) !is null) { 381 // return unit.isDateBased(); 382 // } 383 // return unit !is null && unit.isSupportedBy(this); 384 // } 385 386 //----------------------------------------------------------------------- 387 // override for covariant return type 388 /** 389 * {@inheritDoc} 390 * @throws DateTimeException {@inheritDoc} 391 * @throws ArithmeticException {@inheritDoc} 392 */ 393 ChronoLocalDate _with(TemporalAdjuster adjuster); 394 // override 395 // ChronoLocalDate _with(TemporalAdjuster adjuster) { 396 // return ChronoLocalDateImpl.ensureValid(getChronology(), /* Temporal. */super._with(adjuster)); 397 // } 398 399 /** 400 * {@inheritDoc} 401 * @throws DateTimeException {@inheritDoc} 402 * @throws UnsupportedTemporalTypeException {@inheritDoc} 403 * @throws ArithmeticException {@inheritDoc} 404 */ 405 ChronoLocalDate _with(TemporalField field, long newValue); 406 // override 407 // ChronoLocalDate _with(TemporalField field, long newValue) { 408 // if (cast(ChronoField)(field) !is null) { 409 // throw new UnsupportedTemporalTypeException("Unsupported field: " ~ field); 410 // } 411 // return ChronoLocalDateImpl.ensureValid(getChronology(), field.adjustInto(this, newValue)); 412 // } 413 414 /** 415 * {@inheritDoc} 416 * @throws DateTimeException {@inheritDoc} 417 * @throws ArithmeticException {@inheritDoc} 418 */ 419 ChronoLocalDate plus(TemporalAmount amount); 420 // override 421 // ChronoLocalDate plus(TemporalAmount amount) { 422 // return ChronoLocalDateImpl.ensureValid(getChronology(), /* Temporal. */super.plus(amount)); 423 // } 424 425 /** 426 * {@inheritDoc} 427 * @throws DateTimeException {@inheritDoc} 428 * @throws ArithmeticException {@inheritDoc} 429 */ 430 ChronoLocalDate plus(long amountToAdd, TemporalUnit unit); 431 // override 432 // ChronoLocalDate plus(long amountToAdd, TemporalUnit unit) { 433 // if (cast(ChronoUnit)(unit) !is null) { 434 // throw new UnsupportedTemporalTypeException("Unsupported unit: " ~ unit); 435 // } 436 // return ChronoLocalDateImpl.ensureValid(getChronology(), unit.addTo(this, amountToAdd)); 437 // } 438 439 /** 440 * {@inheritDoc} 441 * @throws DateTimeException {@inheritDoc} 442 * @throws ArithmeticException {@inheritDoc} 443 */ 444 ChronoLocalDate minus(TemporalAmount amount); 445 // override 446 // ChronoLocalDate minus(TemporalAmount amount) { 447 // return ChronoLocalDateImpl.ensureValid(getChronology(), /* Temporal. */super.minus(amount)); 448 // } 449 450 /** 451 * {@inheritDoc} 452 * @throws DateTimeException {@inheritDoc} 453 * @throws UnsupportedTemporalTypeException {@inheritDoc} 454 * @throws ArithmeticException {@inheritDoc} 455 */ 456 ChronoLocalDate minus(long amountToSubtract, TemporalUnit unit); 457 // override 458 // ChronoLocalDate minus(long amountToSubtract, TemporalUnit unit) { 459 // return ChronoLocalDateImpl.ensureValid(getChronology(), /* Temporal. */super.minus(amountToSubtract, unit)); 460 // } 461 462 //----------------------------------------------------------------------- 463 /** 464 * Queries this date using the specified query. 465 * !(p) 466 * This queries this date using the specified query strategy object. 467 * The {@code TemporalQuery} object defines the logic to be used to 468 * obtain the result. Read the documentation of the query to understand 469 * what the result of this method will be. 470 * !(p) 471 * The result of this method is obtained by invoking the 472 * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the 473 * specified query passing {@code this} as the argument. 474 * 475 * @param !(R) the type of the result 476 * @param query the query to invoke, not null 477 * @return the query result, null may be returned (defined by the query) 478 * @throws DateTimeException if unable to query (defined by the query) 479 * @throws ArithmeticException if numeric overflow occurs (defined by the query) 480 */ 481 /*@SuppressWarnings("unchecked")*/ 482 R query(R)(TemporalQuery!(R) query); 483 // override 484 // R query(R)(TemporalQuery!(R) query) { 485 // if (query == TemporalQueries.zoneId() || query == TemporalQueries.zone() || query == TemporalQueries.offset()) { 486 // return null; 487 // } else if (query == TemporalQueries.localTime()) { 488 // return null; 489 // } else if (query == TemporalQueries.chronology()) { 490 // return cast(R) getChronology(); 491 // } else if (query == TemporalQueries.precision()) { 492 // return cast(R) DAYS; 493 // } 494 // // inline TemporalAccessor.super.query(query) as an optimization 495 // // non-JDK classes are not permitted to make this optimization 496 // return query.queryFrom(this); 497 // } 498 499 /** 500 * Adjusts the specified temporal object to have the same date as this object. 501 * !(p) 502 * This returns a temporal object of the same observable type as the input 503 * with the date changed to be the same as this. 504 * !(p) 505 * The adjustment is equivalent to using {@link Temporal#_with(TemporalField, long)} 506 * passing {@link ChronoField#EPOCH_DAY} as the field. 507 * !(p) 508 * In most cases, it is clearer to reverse the calling pattern by using 509 * {@link Temporal#_with(TemporalAdjuster)}: 510 * !(pre) 511 * // these two lines are equivalent, but the second approach is recommended 512 * temporal = thisLocalDate.adjustInto(temporal); 513 * temporal = temporal._with(thisLocalDate); 514 * </pre> 515 * !(p) 516 * This instance is immutable and unaffected by this method call. 517 * 518 * @param temporal the target object to be adjusted, not null 519 * @return the adjusted object, not null 520 * @throws DateTimeException if unable to make the adjustment 521 * @throws ArithmeticException if numeric overflow occurs 522 */ 523 Temporal adjustInto(Temporal temporal); 524 // override 525 // Temporal adjustInto(Temporal temporal) { 526 // return temporal._with(EPOCH_DAY, toEpochDay()); 527 // } 528 529 /** 530 * Calculates the amount of time until another date _in terms of the specified unit. 531 * !(p) 532 * This calculates the amount of time between two {@code ChronoLocalDate} 533 * objects _in terms of a single {@code TemporalUnit}. 534 * The start and end points are {@code this} and the specified date. 535 * The result will be negative if the end is before the start. 536 * The {@code Temporal} passed to this method is converted to a 537 * {@code ChronoLocalDate} using {@link Chronology#date(TemporalAccessor)}. 538 * The calculation returns a whole number, representing the number of 539 * complete units between the two dates. 540 * For example, the amount _in days between two dates can be calculated 541 * using {@code startDate.until(endDate, DAYS)}. 542 * !(p) 543 * There are two equivalent ways of using this method. 544 * The first is to invoke this method. 545 * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}: 546 * !(pre) 547 * // these two lines are equivalent 548 * amount = start.until(end, MONTHS); 549 * amount = MONTHS.between(start, end); 550 * </pre> 551 * The choice should be made based on which makes the code more readable. 552 * !(p) 553 * The calculation is implemented _in this method for {@link ChronoUnit}. 554 * The units {@code DAYS}, {@code WEEKS}, {@code MONTHS}, {@code YEARS}, 555 * {@code DECADES}, {@code CENTURIES}, {@code MILLENNIA} and {@code ERAS} 556 * should be supported by all implementations. 557 * Other {@code ChronoUnit} values will throw an exception. 558 * !(p) 559 * If the unit is not a {@code ChronoUnit}, then the result of this method 560 * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} 561 * passing {@code this} as the first argument and the converted input temporal as 562 * the second argument. 563 * !(p) 564 * This instance is immutable and unaffected by this method call. 565 * 566 * @param endExclusive the end date, exclusive, which is converted to a 567 * {@code ChronoLocalDate} _in the same chronology, not null 568 * @param unit the unit to measure the amount _in, not null 569 * @return the amount of time between this date and the end date 570 * @throws DateTimeException if the amount cannot be calculated, or the end 571 * temporal cannot be converted to a {@code ChronoLocalDate} 572 * @throws UnsupportedTemporalTypeException if the unit is not supported 573 * @throws ArithmeticException if numeric overflow occurs 574 */ 575 override // override for Javadoc 576 long until(Temporal endExclusive, TemporalUnit unit); 577 578 /** 579 * Calculates the period between this date and another date as a {@code ChronoPeriod}. 580 * !(p) 581 * This calculates the period between two dates. All supplied chronologies 582 * calculate the period using years, months and days, however the 583 * {@code ChronoPeriod} API allows the period to be represented using other units. 584 * !(p) 585 * The start and end points are {@code this} and the specified date. 586 * The result will be negative if the end is before the start. 587 * The negative sign will be the same _in each of year, month and day. 588 * !(p) 589 * The calculation is performed using the chronology of this date. 590 * If necessary, the input date will be converted to match. 591 * !(p) 592 * This instance is immutable and unaffected by this method call. 593 * 594 * @param endDateExclusive the end date, exclusive, which may be _in any chronology, not null 595 * @return the period between this date and the end date, not null 596 * @throws DateTimeException if the period cannot be calculated 597 * @throws ArithmeticException if numeric overflow occurs 598 */ 599 ChronoPeriod until(ChronoLocalDate endDateExclusive); 600 601 /** 602 * Formats this date using the specified formatter. 603 * !(p) 604 * This date will be passed to the formatter to produce a string. 605 * !(p) 606 * The implementation must behave as follows: 607 * !(pre) 608 * return formatter.format(this); 609 * </pre> 610 * 611 * @param formatter the formatter to use, not null 612 * @return the formatted date string, not null 613 * @throws DateTimeException if an error occurs during printing 614 */ 615 // string format(DateTimeFormatter formatter); 616 // string format(DateTimeFormatter formatter) { 617 // assert(formatter, "formatter"); 618 // return formatter.format(this); 619 // } 620 621 //----------------------------------------------------------------------- 622 /** 623 * Combines this date with a time to create a {@code ChronoLocalDateTime}. 624 * !(p) 625 * This returns a {@code ChronoLocalDateTime} formed from this date at the specified time. 626 * All possible combinations of date and time are valid. 627 * 628 * @param localTime the local time to use, not null 629 * @return the local date-time formed from this date and the specified time, not null 630 */ 631 /*@SuppressWarnings("unchecked")*/ 632 ChronoLocalDateTime!(ChronoLocalDate) atTime(LocalTime localTime); 633 // ChronoLocalDateTime!(ChronoLocalDate) atTime(LocalTime localTime) { 634 // return ChronoLocalDateTimeImpl.of(this, localTime); 635 // } 636 637 //----------------------------------------------------------------------- 638 /** 639 * Converts this date to the Epoch Day. 640 * !(p) 641 * The {@link ChronoField#EPOCH_DAY Epoch Day count} is a simple 642 * incrementing count of days where day 0 is 1970-01-01 (ISO). 643 * This definition is the same for all chronologies, enabling conversion. 644 * !(p) 645 * This implementation queries the {@code EPOCH_DAY} field. 646 * 647 * @return the Epoch Day equivalent to this date 648 */ 649 long toEpochDay(); 650 // long toEpochDay() { 651 // return getLong(EPOCH_DAY); 652 // } 653 654 //----------------------------------------------------------------------- 655 /** 656 * Compares this date to another date, including the chronology. 657 * !(p) 658 * The comparison is based first on the underlying time-line date, then 659 * on the chronology. 660 * It is "consistent with equals", as defined by {@link Comparable}. 661 * !(p) 662 * For example, the following is the comparator order: 663 * !(ol) 664 * !(li){@code 2012-12-03 (ISO)}</li> 665 * !(li){@code 2012-12-04 (ISO)}</li> 666 * !(li){@code 2555-12-04 (ThaiBuddhist)}</li> 667 * !(li){@code 2012-12-05 (ISO)}</li> 668 * </ol> 669 * Values #2 and #3 represent the same date on the time-line. 670 * When two values represent the same date, the chronology ID is compared to distinguish them. 671 * This step is needed to make the ordering "consistent with equals". 672 * !(p) 673 * If all the date objects being compared are _in the same chronology, then the 674 * additional chronology stage is not required and only the local date is used. 675 * To compare the dates of two {@code TemporalAccessor} instances, including dates 676 * _in two different chronologies, use {@link ChronoField#EPOCH_DAY} as a comparator. 677 * !(p) 678 * This implementation performs the comparison defined above. 679 * 680 * @param other the other date to compare to, not null 681 * @return the comparator value, negative if less, positive if greater 682 */ 683 int compareTo(ChronoLocalDate other); 684 // override 685 // int compareTo(ChronoLocalDate other) { 686 // int cmp = Long.compare(toEpochDay(), other.toEpochDay()); 687 // if (cmp == 0) { 688 // cmp = getChronology().compareTo(other.getChronology()); 689 // } 690 // return cmp; 691 // } 692 693 /** 694 * Checks if this date is after the specified date ignoring the chronology. 695 * !(p) 696 * This method differs from the comparison _in {@link #compareTo} _in that it 697 * only compares the underlying date and not the chronology. 698 * This allows dates _in different calendar systems to be compared based 699 * on the time-line position. 700 * This is equivalent to using {@code date1.toEpochDay() > date2.toEpochDay()}. 701 * !(p) 702 * This implementation performs the comparison based on the epoch-day. 703 * 704 * @param other the other date to compare to, not null 705 * @return true if this is after the specified date 706 */ 707 bool isAfter(ChronoLocalDate other); 708 // bool isAfter(ChronoLocalDate other) { 709 // return this.toEpochDay() > other.toEpochDay(); 710 // } 711 712 /** 713 * Checks if this date is before the specified date ignoring the chronology. 714 * !(p) 715 * This method differs from the comparison _in {@link #compareTo} _in that it 716 * only compares the underlying date and not the chronology. 717 * This allows dates _in different calendar systems to be compared based 718 * on the time-line position. 719 * This is equivalent to using {@code date1.toEpochDay() < date2.toEpochDay()}. 720 * !(p) 721 * This implementation performs the comparison based on the epoch-day. 722 * 723 * @param other the other date to compare to, not null 724 * @return true if this is before the specified date 725 */ 726 bool isBefore(ChronoLocalDate other); 727 // bool isBefore(ChronoLocalDate other) { 728 // return this.toEpochDay() < other.toEpochDay(); 729 // } 730 731 /** 732 * Checks if this date is equal to the specified date ignoring the chronology. 733 * !(p) 734 * This method differs from the comparison _in {@link #compareTo} _in that it 735 * only compares the underlying date and not the chronology. 736 * This allows dates _in different calendar systems to be compared based 737 * on the time-line position. 738 * This is equivalent to using {@code date1.toEpochDay() == date2.toEpochDay()}. 739 * !(p) 740 * This implementation performs the comparison based on the epoch-day. 741 * 742 * @param other the other date to compare to, not null 743 * @return true if the underlying date is equal to the specified date 744 */ 745 bool isEqual(ChronoLocalDate other); 746 // bool isEqual(ChronoLocalDate other) { 747 // return this.toEpochDay() == other.toEpochDay(); 748 // } 749 750 //----------------------------------------------------------------------- 751 /** 752 * Checks if this date is equal to another date, including the chronology. 753 * !(p) 754 * Compares this date with another ensuring that the date and chronology are the same. 755 * !(p) 756 * To compare the dates of two {@code TemporalAccessor} instances, including dates 757 * _in two different chronologies, use {@link ChronoField#EPOCH_DAY} as a comparator. 758 * 759 * @param obj the object to check, null returns false 760 * @return true if this is equal to the other date 761 */ 762 // override 763 bool opEquals(Object obj); 764 765 /** 766 * A hash code for this date. 767 * 768 * @return a suitable hash code 769 */ 770 // override 771 size_t toHash() @trusted nothrow; 772 773 //----------------------------------------------------------------------- 774 /** 775 * Outputs this date as a {@code string}. 776 * !(p) 777 * The output will include the full local date. 778 * 779 * @return the formatted date, not null 780 */ 781 // override 782 string toString(); 783 784 }