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.temporal.Temporal;
13 
14 import hunt.time.Exceptions;
15 import hunt.time.temporal.TemporalAccessor;
16 import hunt.time.temporal.TemporalUnit;
17 import hunt.time.temporal.TemporalAdjuster;
18 import hunt.time.temporal.TemporalField;
19 import hunt.time.temporal.TemporalAmount;
20 
21 
22 /**
23  * Framework-level interface defining read-write access to a temporal object,
24  * such as a date, time, offset or some combination of these.
25  * !(p)
26  * This is the base interface type for date, time and offset objects that
27  * are complete enough to be manipulated using plus and minus.
28  * It is implemented by those classes that can provide and manipulate information
29  * as {@linkplain TemporalField fields} or {@linkplain TemporalQuery queries}.
30  * See {@link TemporalAccessor} for the read-only version of this interface.
31  * !(p)
32  * Most date and time information can be represented as a number.
33  * These are modeled using {@code TemporalField} with the number held using
34  * a {@code long} to handle large values. Year, month and day-of-month are
35  * simple examples of fields, but they also include instant and offsets.
36  * See {@link ChronoField} for the standard set of fields.
37  * !(p)
38  * Two pieces of date/time information cannot be represented by numbers,
39  * the {@linkplain hunt.time.chrono.Chronology chronology} and the
40  * {@linkplain hunt.time.ZoneId time-zone}.
41  * These can be accessed via {@link #query(TemporalQuery) queries} using
42  * the static methods defined on {@link TemporalQuery}.
43  * !(p)
44  * This interface is a framework-level interface that should not be widely
45  * used _in application code. Instead, applications should create and pass
46  * around instances of concrete types, such as {@code LocalDate}.
47  * There are many reasons for this, part of which is that implementations
48  * of this interface may be _in calendar systems other than ISO.
49  * See {@link hunt.time.chrono.ChronoLocalDate} for a fuller discussion of the issues.
50  *
51  * !(h3)When to implement</h3>
52  * !(p)
53  * A class should implement this interface if it meets three criteria:
54  * !(ul)
55  * !(li)it provides access to date/time/offset information, as per {@code TemporalAccessor}
56  * !(li)the set of fields are contiguous from the largest to the smallest
57  * !(li)the set of fields are complete, such that no other field is needed to define the
58  *  valid range of values for the fields that are represented
59  * </ul>
60  * !(p)
61  * Four examples make this clear:
62  * !(ul)
63  * !(li){@code LocalDate} implements this interface as it represents a set of fields
64  *  that are contiguous from days to forever and require no external information to determine
65  *  the validity of each date. It is therefore able to implement plus/minus correctly.
66  * !(li){@code LocalTime} implements this interface as it represents a set of fields
67  *  that are contiguous from nanos to within days and require no external information to determine
68  *  validity. It is able to implement plus/minus correctly, by wrapping around the day.
69  * !(li){@code MonthDay}, the combination of month-of-year and day-of-month, does not implement
70  *  this interface.  While the combination is contiguous, from days to months within years,
71  *  the combination does not have sufficient information to define the valid range of values
72  *  for day-of-month.  As such, it is unable to implement plus/minus correctly.
73  * !(li)The combination day-of-week and day-of-month ("Friday the 13th") should not implement
74  *  this interface. It does not represent a contiguous set of fields, as days to weeks overlaps
75  *  days to months.
76  * </ul>
77  *
78  * @implSpec
79  * This interface places no restrictions on the mutability of implementations,
80  * however immutability is strongly recommended.
81  * All implementations must be {@link Comparable}.
82  *
83  * @since 1.8
84  */
85 public interface Temporal : TemporalAccessor {
86 
87     /**
88      * Checks if the specified unit is supported.
89      * !(p)
90      * This checks if the specified unit can be added to, or subtracted from, this date-time.
91      * If false, then calling the {@link #plus(long, TemporalUnit)} and
92      * {@link #minus(long, TemporalUnit) minus} methods will throw an exception.
93      *
94      * @implSpec
95      * Implementations must check and handle all units defined _in {@link ChronoUnit}.
96      * If the unit is supported, then true must be returned, otherwise false must be returned.
97      * !(p)
98      * If the field is not a {@code ChronoUnit}, then the result of this method
99      * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)}
100      * passing {@code this} as the argument.
101      * !(p)
102      * Implementations must ensure that no observable state is altered when this
103      * read-only method is invoked.
104      *
105      * @param unit  the unit to check, null returns false
106      * @return true if the unit can be added/subtracted, false if not
107      */
108     bool isSupported(TemporalUnit unit);
109 
110     bool isSupported(TemporalField field);
111 
112     /**
113      * Returns an adjusted object of the same type as this object with the adjustment made.
114      * !(p)
115      * This adjusts this date-time according to the rules of the specified adjuster.
116      * A simple adjuster might simply set the one of the fields, such as the year field.
117      * A more complex adjuster might set the date to the last day of the month.
118      * A selection of common adjustments is provided _in
119      * {@link hunt.time.temporal.TemporalAdjusters TemporalAdjusters}.
120      * These include finding the "last day of the month" and "next Wednesday".
121      * The adjuster is responsible for handling special cases, such as the varying
122      * lengths of month and leap years.
123      * !(p)
124      * Some example code indicating how and why this method is used:
125      * !(pre)
126      *  date = date._with(Month.JULY);        // most key classes implement TemporalAdjuster
127      *  date = date._with(lastDayOfMonth());  // static import from Adjusters
128      *  date = date._with(next(WEDNESDAY));   // static import from Adjusters and DayOfWeek
129      * </pre>
130      *
131      * @implSpec
132      * !(p)
133      * Implementations must not alter either this object or the specified temporal object.
134      * Instead, an adjusted copy of the original must be returned.
135      * This provides equivalent, safe behavior for immutable and mutable implementations.
136      * !(p)
137      * The  implementation must behave equivalent to this code:
138      * !(pre)
139      *  return adjuster.adjustInto(this);
140      * </pre>
141      *
142      * @param adjuster  the adjuster to use, not null
143      * @return an object of the same type with the specified adjustment made, not null
144      * @throws DateTimeException if unable to make the adjustment
145      * @throws ArithmeticException if numeric overflow occurs
146      */
147      Temporal _with(TemporalAdjuster adjuster);
148     //  Temporal _with(TemporalAdjuster adjuster) {
149     //     return adjuster.adjustInto(this);
150     // }
151 
152     /**
153      * Returns an object of the same type as this object with the specified field altered.
154      * !(p)
155      * This returns a new object based on this one with the value for the specified field changed.
156      * For example, on a {@code LocalDate}, this could be used to set the year, month or day-of-month.
157      * The returned object will have the same observable type as this object.
158      * !(p)
159      * In some cases, changing a field is not fully defined. For example, if the target object is
160      * a date representing the 31st January, then changing the month to February would be unclear.
161      * In cases like this, the field is responsible for resolving the result. Typically it will choose
162      * the previous valid date, which would be the last valid day of February _in this example.
163      *
164      * @implSpec
165      * Implementations must check and handle all fields defined _in {@link ChronoField}.
166      * If the field is supported, then the adjustment must be performed.
167      * If unsupported, then an {@code UnsupportedTemporalTypeException} must be thrown.
168      * !(p)
169      * If the field is not a {@code ChronoField}, then the result of this method
170      * is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)}
171      * passing {@code this} as the first argument.
172      * !(p)
173      * Implementations must not alter this object.
174      * Instead, an adjusted copy of the original must be returned.
175      * This provides equivalent, safe behavior for immutable and mutable implementations.
176      *
177      * @param field  the field to set _in the result, not null
178      * @param newValue  the new value of the field _in the result
179      * @return an object of the same type with the specified field set, not null
180      * @throws DateTimeException if the field cannot be set
181      * @throws UnsupportedTemporalTypeException if the field is not supported
182      * @throws ArithmeticException if numeric overflow occurs
183      */
184     Temporal _with(TemporalField field, long newValue);
185 
186     //-----------------------------------------------------------------------
187     /**
188      * Returns an object of the same type as this object with an amount added.
189      * !(p)
190      * This adjusts this temporal, adding according to the rules of the specified amount.
191      * The amount is typically a {@link hunt.time.Period} but may be any other type implementing
192      * the {@link TemporalAmount} interface, such as {@link hunt.time.Duration}.
193      * !(p)
194      * Some example code indicating how and why this method is used:
195      * !(pre)
196      *  date = date.plus(period);                // add a Period instance
197      *  date = date.plus(duration);              // add a Duration instance
198      *  date = date.plus(workingDays(6));        // example user-written workingDays method
199      * </pre>
200      * !(p)
201      * Note that calling {@code plus} followed by {@code minus} is not guaranteed to
202      * return the same date-time.
203      *
204      * @implSpec
205      * !(p)
206      * Implementations must not alter either this object or the specified temporal object.
207      * Instead, an adjusted copy of the original must be returned.
208      * This provides equivalent, safe behavior for immutable and mutable implementations.
209      * !(p)
210      * The  implementation must behave equivalent to this code:
211      * !(pre)
212      *  return amount.addTo(this);
213      * </pre>
214      *
215      * @param amount  the amount to add, not null
216      * @return an object of the same type with the specified adjustment made, not null
217      * @throws DateTimeException if the addition cannot be made
218      * @throws ArithmeticException if numeric overflow occurs
219      */
220      Temporal plus(TemporalAmount amount);
221     //  Temporal plus(TemporalAmount amount) {
222     //     return amount.addTo(this);
223     // }
224 
225     /**
226      * Returns an object of the same type as this object with the specified period added.
227      * !(p)
228      * This method returns a new object based on this one with the specified period added.
229      * For example, on a {@code LocalDate}, this could be used to add a number of years, months or days.
230      * The returned object will have the same observable type as this object.
231      * !(p)
232      * In some cases, changing a field is not fully defined. For example, if the target object is
233      * a date representing the 31st January, then adding one month would be unclear.
234      * In cases like this, the field is responsible for resolving the result. Typically it will choose
235      * the previous valid date, which would be the last valid day of February _in this example.
236      *
237      * @implSpec
238      * Implementations must check and handle all units defined _in {@link ChronoUnit}.
239      * If the unit is supported, then the addition must be performed.
240      * If unsupported, then an {@code UnsupportedTemporalTypeException} must be thrown.
241      * !(p)
242      * If the unit is not a {@code ChronoUnit}, then the result of this method
243      * is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)}
244      * passing {@code this} as the first argument.
245      * !(p)
246      * Implementations must not alter this object.
247      * Instead, an adjusted copy of the original must be returned.
248      * This provides equivalent, safe behavior for immutable and mutable implementations.
249      *
250      * @param amountToAdd  the amount of the specified unit to add, may be negative
251      * @param unit  the unit of the amount to add, not null
252      * @return an object of the same type with the specified period added, not null
253      * @throws DateTimeException if the unit cannot be added
254      * @throws UnsupportedTemporalTypeException if the unit is not supported
255      * @throws ArithmeticException if numeric overflow occurs
256      */
257     Temporal plus(long amountToAdd, TemporalUnit unit);
258 
259     //-----------------------------------------------------------------------
260     /**
261      * Returns an object of the same type as this object with an amount subtracted.
262      * !(p)
263      * This adjusts this temporal, subtracting according to the rules of the specified amount.
264      * The amount is typically a {@link hunt.time.Period} but may be any other type implementing
265      * the {@link TemporalAmount} interface, such as {@link hunt.time.Duration}.
266      * !(p)
267      * Some example code indicating how and why this method is used:
268      * !(pre)
269      *  date = date.minus(period);               // subtract a Period instance
270      *  date = date.minus(duration);             // subtract a Duration instance
271      *  date = date.minus(workingDays(6));       // example user-written workingDays method
272      * </pre>
273      * !(p)
274      * Note that calling {@code plus} followed by {@code minus} is not guaranteed to
275      * return the same date-time.
276      *
277      * @implSpec
278      * !(p)
279      * Implementations must not alter either this object or the specified temporal object.
280      * Instead, an adjusted copy of the original must be returned.
281      * This provides equivalent, safe behavior for immutable and mutable implementations.
282      * !(p)
283      * The  implementation must behave equivalent to this code:
284      * !(pre)
285      *  return amount.subtractFrom(this);
286      * </pre>
287      *
288      * @param amount  the amount to subtract, not null
289      * @return an object of the same type with the specified adjustment made, not null
290      * @throws DateTimeException if the subtraction cannot be made
291      * @throws ArithmeticException if numeric overflow occurs
292      */
293      Temporal minus(TemporalAmount amount);
294     //  Temporal minus(TemporalAmount amount) {
295     //     return amount.subtractFrom(this);
296     // }
297 
298     /**
299      * Returns an object of the same type as this object with the specified period subtracted.
300      * !(p)
301      * This method returns a new object based on this one with the specified period subtracted.
302      * For example, on a {@code LocalDate}, this could be used to subtract a number of years, months or days.
303      * The returned object will have the same observable type as this object.
304      * !(p)
305      * In some cases, changing a field is not fully defined. For example, if the target object is
306      * a date representing the 31st March, then subtracting one month would be unclear.
307      * In cases like this, the field is responsible for resolving the result. Typically it will choose
308      * the previous valid date, which would be the last valid day of February _in this example.
309      *
310      * @implSpec
311      * Implementations must behave _in a manor equivalent to the  method behavior.
312      * !(p)
313      * Implementations must not alter this object.
314      * Instead, an adjusted copy of the original must be returned.
315      * This provides equivalent, safe behavior for immutable and mutable implementations.
316      * !(p)
317      * The  implementation must behave equivalent to this code:
318      * !(pre)
319      *  return (amountToSubtract == Long.MIN_VALUE ?
320      *      plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit));
321      * </pre>
322      *
323      * @param amountToSubtract  the amount of the specified unit to subtract, may be negative
324      * @param unit  the unit of the amount to subtract, not null
325      * @return an object of the same type with the specified period subtracted, not null
326      * @throws DateTimeException if the unit cannot be subtracted
327      * @throws UnsupportedTemporalTypeException if the unit is not supported
328      * @throws ArithmeticException if numeric overflow occurs
329      */
330      Temporal minus(long amountToSubtract, TemporalUnit unit);
331     //  Temporal minus(long amountToSubtract, TemporalUnit unit) {
332     //     return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit));
333     // }
334 
335     //-----------------------------------------------------------------------
336     /**
337      * Calculates the amount of time until another temporal _in terms of the specified unit.
338      * !(p)
339      * This calculates the amount of time between two temporal objects
340      * _in terms of a single {@code TemporalUnit}.
341      * The start and end points are {@code this} and the specified temporal.
342      * The end point is converted to be of the same type as the start point if different.
343      * The result will be negative if the end is before the start.
344      * For example, the amount _in hours between two temporal objects can be
345      * calculated using {@code startTime.until(endTime, HOURS)}.
346      * !(p)
347      * The calculation returns a whole number, representing the number of
348      * complete units between the two temporals.
349      * For example, the amount _in hours between the times 11:30 and 13:29
350      * will only be one hour as it is one minute short of two hours.
351      * !(p)
352      * There are two equivalent ways of using this method.
353      * The first is to invoke this method directly.
354      * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}:
355      * !(pre)
356      *   // these two lines are equivalent
357      *   temporal = start.until(end, unit);
358      *   temporal = unit.between(start, end);
359      * </pre>
360      * The choice should be made based on which makes the code more readable.
361      * !(p)
362      * For example, this method allows the number of days between two dates to
363      * be calculated:
364      * !(pre)
365      *  long daysBetween = start.until(end, DAYS);
366      *  // or alternatively
367      *  long daysBetween = DAYS.between(start, end);
368      * </pre>
369      *
370      * @implSpec
371      * Implementations must begin by checking to ensure that the input temporal
372      * object is of the same observable type as the implementation.
373      * They must then perform the calculation for all instances of {@link ChronoUnit}.
374      * An {@code UnsupportedTemporalTypeException} must be thrown for {@code ChronoUnit}
375      * instances that are unsupported.
376      * !(p)
377      * If the unit is not a {@code ChronoUnit}, then the result of this method
378      * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
379      * passing {@code this} as the first argument and the converted input temporal as
380      * the second argument.
381      * !(p)
382      * In summary, implementations must behave _in a manner equivalent to this pseudo-code:
383      * !(pre)
384      *  // convert the end temporal to the same type as this class
385      *  if (cast(ChronoUnit)(unit) !is null) {
386      *    // if unit is supported, then calculate and return result
387      *    // else throw UnsupportedTemporalTypeException for unsupported units
388      *  }
389      *  return unit.between(this, convertedEndTemporal);
390      * </pre>
391      * !(p)
392      * Note that the unit's {@code between} method must only be invoked if the
393      * two temporal objects have exactly the same type evaluated by {@code getClass()}.
394      * !(p)
395      * Implementations must ensure that no observable state is altered when this
396      * read-only method is invoked.
397      *
398      * @param endExclusive  the end temporal, exclusive, converted to be of the
399      *  same type as this object, not null
400      * @param unit  the unit to measure the amount _in, not null
401      * @return the amount of time between this temporal object and the specified one
402      *  _in terms of the unit; positive if the specified object is later than this one,
403      *  negative if it is earlier than this one
404      * @throws DateTimeException if the amount cannot be calculated, or the end
405      *  temporal cannot be converted to the same type as this temporal
406      * @throws UnsupportedTemporalTypeException if the unit is not supported
407      * @throws ArithmeticException if numeric overflow occurs
408      */
409     long until(Temporal endExclusive, TemporalUnit unit);
410 
411 }