1 | import { abstractMethodFail } from '../assert';
|
2 |
|
3 | /**
|
4 | * @copyright (c) 2016, Philipp Thürwächter & Pattrick Hüper
|
5 | * @copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos
|
6 | * @license BSD-3-Clause (see LICENSE in the root directory of this source tree)
|
7 | */
|
8 |
|
9 | /**
|
10 | * A field of date-time, such as month-of-year or hour-of-minute.
|
11 | *
|
12 | * Date and time is expressed using fields which partition the time-line into something
|
13 | * meaningful for humans. Implementations of this interface represent those fields.
|
14 | *
|
15 | * The most commonly used units are defined in {@link ChronoField}.
|
16 | * Further fields are supplied in {@link IsoFields}, {@link WeekFields} and {@link JulianFields}.
|
17 | * Fields can also be written by application code by implementing this interface.
|
18 | *
|
19 | * The field works using double dispatch. Client code calls methods on a date-time like
|
20 | * {@link LocalDateTime} which check if the field is a {@link ChronoField}.
|
21 | * If it is, then the date-time must handle it.
|
22 | * Otherwise, the method call is re-dispatched to the matching method in this interface.
|
23 | *
|
24 | * @interface
|
25 | */
|
26 | export class TemporalField {
|
27 | /**
|
28 | * Checks if this field represents a component of a date.
|
29 | *
|
30 | * @return {boolean} `true` if it is a component of a date, `false` otherwise.
|
31 | */
|
32 | isDateBased() {
|
33 | abstractMethodFail('isDateBased');
|
34 | }
|
35 |
|
36 | /**
|
37 | * Checks if this field represents a component of a time.
|
38 | *
|
39 | * @return {boolean} `true` if it is a component of a time, `false` otherwise.
|
40 | */
|
41 | isTimeBased() {
|
42 | abstractMethodFail('isTimeBased');
|
43 | }
|
44 |
|
45 | /**
|
46 | * Gets the unit that the field is measured in.
|
47 | *
|
48 | * The unit of the field is the period that varies within the range.
|
49 | * For example, in the field 'MonthOfYear', the unit is 'Months'.
|
50 | * See also {@link rangeUnit}.
|
51 | *
|
52 | * @return {TemporalUnit} the period unit defining the base unit of the field.
|
53 | */
|
54 | baseUnit() {
|
55 | abstractMethodFail('baseUnit');
|
56 | }
|
57 |
|
58 | /**
|
59 | * Gets the range that the field is bound by.
|
60 | *
|
61 | * The range of the field is the period that the field varies within.
|
62 | * For example, in the field 'MonthOfYear', the range is 'Years'.
|
63 | * See also {@link baseUnit}.
|
64 | *
|
65 | * The range is never null. For example, the 'Year' field is shorthand for
|
66 | * 'YearOfForever'. It therefore has a unit of 'Years' and a range of 'Forever'.
|
67 | *
|
68 | * @return {TemporalUnit} the period unit defining the range of the field.
|
69 | */
|
70 | rangeUnit() {
|
71 | abstractMethodFail('rangeUnit');
|
72 | }
|
73 |
|
74 | /**
|
75 | * Gets the range of valid values for the field.
|
76 | *
|
77 | * All fields can be expressed as an integer.
|
78 | * This method returns an object that describes the valid range for that value.
|
79 | * This method is generally only applicable to the ISO-8601 calendar system.
|
80 | *
|
81 | * Note that the result only describes the minimum and maximum valid values
|
82 | * and it is important not to read too much into them. For example, there
|
83 | * could be values within the range that are invalid for the field.
|
84 | *
|
85 | * @return {ValueRange} the range of valid values for the field.
|
86 | */
|
87 | range() {
|
88 | abstractMethodFail('range');
|
89 | }
|
90 |
|
91 | /**
|
92 | * Get the range of valid values for this field using the temporal object to
|
93 | * refine the result.
|
94 | *
|
95 | * This uses the temporal object to find the range of valid values for the field.
|
96 | * This is similar to {@link range}, however this method refines the result
|
97 | * using the temporal. For example, if the field is {@link DAY_OF_MONTH} the
|
98 | * {@link range} method is not accurate as there are four possible month lengths,
|
99 | * 28, 29, 30 and 31 days. Using this method with a date allows the range to be
|
100 | * accurate, returning just one of those four options.
|
101 | *
|
102 | * There are two equivalent ways of using this method.
|
103 | * The first is to invoke this method directly.
|
104 | * The second is to use {@link TemporalAccessor#range}:
|
105 | * <pre>
|
106 | * // these two lines are equivalent, but the second approach is recommended
|
107 | * temporal = thisField.rangeRefinedBy(temporal);
|
108 | * temporal = temporal.range(thisField);
|
109 | * </pre>
|
110 | * It is recommended to use the second approach, {@link range},
|
111 | * as it is a lot clearer to read in code.
|
112 | *
|
113 | * Implementations should perform any queries or calculations using the fields
|
114 | * available in {@link ChronoField}.
|
115 | * If the field is not supported a {@link DateTimeException} must be thrown.
|
116 | *
|
117 | * @param {!TemporalAccessor} temporal the temporal object used to refine the result.
|
118 | * @return {ValueRange} the range of valid values for this field.
|
119 | * @throws {DateTimeException} if the range for the field cannot be obtained.
|
120 | *
|
121 | */
|
122 | // eslint-disable-next-line no-unused-vars
|
123 | rangeRefinedBy(temporal) {
|
124 | abstractMethodFail('rangeRefinedBy');
|
125 | }
|
126 |
|
127 | /**
|
128 | * Gets the value of this field from the specified temporal object.
|
129 | *
|
130 | * This queries the temporal object for the value of this field.
|
131 | *
|
132 | * There are two equivalent ways of using this method.
|
133 | * The first is to invoke this method directly.
|
134 | * The second is to use {@link TemporalAccessor#get}:
|
135 | * <pre>
|
136 | * // these two lines are equivalent, but the second approach is recommended
|
137 | * temporal = thisField.getFrom(temporal);
|
138 | * temporal = temporal.get(thisField);
|
139 | * </pre>
|
140 | * It is recommended to use the second approach, as it is a lot clearer to read in code.
|
141 | *
|
142 | * Implementations should perform any queries or calculations using the fields
|
143 | * available in {@link ChronoField}.
|
144 | * If the field is not supported a {@link DateTimeException} must be thrown.
|
145 | *
|
146 | * @param {!TemporalAccesor} temporal the temporal object to query.
|
147 | * @return {number} the value of this field.
|
148 | * @throws {DateTimeException} if a value for the field cannot be obtained.
|
149 | */
|
150 | // eslint-disable-next-line no-unused-vars
|
151 | getFrom(temporal) {
|
152 | abstractMethodFail('getFrom');
|
153 | }
|
154 |
|
155 | /**
|
156 | * Returns a copy of the specified temporal object with the value of this field set.
|
157 | *
|
158 | * This returns a new temporal object based on the specified one with the value for
|
159 | * this field changed. For example, on a {@link LocalDate}, this could be used to
|
160 | * set the year, month or day-of-month.
|
161 | * The returned object has the same observable type as the specified object.
|
162 | *
|
163 | * In some cases, changing a field is not fully defined. For example, if the target object is
|
164 | * a date representing the 31st January, then changing the month to February would be unclear.
|
165 | * In cases like this, the implementation is responsible for resolving the result.
|
166 | * Typically it will choose the previous valid date, which would be the last valid
|
167 | * day of February in this example.
|
168 | *
|
169 | * There are two equivalent ways of using this method.
|
170 | * The first is to invoke this method directly.
|
171 | * The second is to use {@link Temporal#with}:
|
172 | * <pre>
|
173 | * // these two lines are equivalent, but the second approach is recommended
|
174 | * temporal = thisField.adjustInto(temporal);
|
175 | * temporal = temporal.with(thisField);
|
176 | * </pre>
|
177 | * It is recommended to use the second approach, `with(temporal)`,
|
178 | * as it is a lot clearer to read in code.
|
179 | *
|
180 | * Implementations should perform any queries or calculations using the fields
|
181 | * available in {@link ChronoField}.
|
182 | * If the field is not supported a {@link DateTimeException} must be thrown.
|
183 | *
|
184 | * Implementations must not alter the specified temporal object.
|
185 | * Instead, an adjusted copy of the original must be returned.
|
186 | * This provides equivalent, safe behavior for immutable and mutable implementations.
|
187 | *
|
188 | * @param {!Temporal} temporal the temporal object to adjust.
|
189 | * @param {!number} newValue the new value of the field.
|
190 | * @return {Temporal} the adjusted temporal object.
|
191 | * @throws {DateTimeException} if the field cannot be set.
|
192 | */
|
193 | // eslint-disable-next-line no-unused-vars
|
194 | adjustInto(temporal, newValue) {
|
195 | abstractMethodFail('adjustInto');
|
196 | }
|
197 |
|
198 | /**
|
199 | * Checks if this field is supported by the temporal object.
|
200 | *
|
201 | * This determines whether the temporal accessor supports this field.
|
202 | * If this returns false, the the temporal cannot be queried for this field.
|
203 | *
|
204 | * There are two equivalent ways of using this method.
|
205 | * The first is to invoke this method directly.
|
206 | * The second is to use {@link TemporalAccessor#isSupported}:
|
207 | * <pre>
|
208 | * // these two lines are equivalent, but the second approach is recommended
|
209 | * temporal = thisField.isSupportedBy(temporal);
|
210 | * temporal = temporal.isSupported(thisField);
|
211 | * </pre>
|
212 | * It is recommended to use the second approach, `isSupported(temporal)`,
|
213 | * as it is a lot clearer to read in code.
|
214 | *
|
215 | * Implementations should determine whether they are supported using the fields
|
216 | * available in {@link ChronoField}.
|
217 | *
|
218 | * @param {!TemporalAccesor} temporal the temporal object to query.
|
219 | * @return {boolean} `true` if the date-time can be queried for this field, `false` if not.
|
220 | */
|
221 | // eslint-disable-next-line no-unused-vars
|
222 | isSupportedBy(temporal) {
|
223 | abstractMethodFail('isSupportedBy');
|
224 | }
|
225 |
|
226 | /**
|
227 | * @return {string}
|
228 | */
|
229 | displayName(/* TODO: locale */) {
|
230 | abstractMethodFail('displayName');
|
231 | }
|
232 |
|
233 | /**
|
234 | * @param {*} other
|
235 | * @returns {boolean}
|
236 | */
|
237 | // eslint-disable-next-line no-unused-vars
|
238 | equals(other) {
|
239 | abstractMethodFail('equals');
|
240 | }
|
241 |
|
242 | /**
|
243 | * @returns {string}
|
244 | */
|
245 | name() {
|
246 | abstractMethodFail('name');
|
247 | }
|
248 | }
|