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 }