UNPKG

9.9 kBJavaScriptView Raw
1import { 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 */
26export 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}