1 /* |
|
2 * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. Oracle designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Oracle in the LICENSE file that accompanied this code. |
|
10 * |
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 * version 2 for more details (a copy is included in the LICENSE file that |
|
15 * accompanied this code). |
|
16 * |
|
17 * You should have received a copy of the GNU General Public License version |
|
18 * 2 along with this work; if not, write to the Free Software Foundation, |
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 * |
|
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
22 * or visit www.oracle.com if you need additional information or have any |
|
23 * questions. |
|
24 */ |
|
25 |
|
26 /* |
|
27 * This file is available under and governed by the GNU General Public |
|
28 * License version 2 only, as published by the Free Software Foundation. |
|
29 * However, the following notice accompanied the original version of this |
|
30 * file: |
|
31 * |
|
32 * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos |
|
33 * |
|
34 * All rights reserved. |
|
35 * |
|
36 * Redistribution and use in source and binary forms, with or without |
|
37 * modification, are permitted provided that the following conditions are met: |
|
38 * |
|
39 * * Redistributions of source code must retain the above copyright notice, |
|
40 * this list of conditions and the following disclaimer. |
|
41 * |
|
42 * * Redistributions in binary form must reproduce the above copyright notice, |
|
43 * this list of conditions and the following disclaimer in the documentation |
|
44 * and/or other materials provided with the distribution. |
|
45 * |
|
46 * * Neither the name of JSR-310 nor the names of its contributors |
|
47 * may be used to endorse or promote products derived from this software |
|
48 * without specific prior written permission. |
|
49 * |
|
50 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
51 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
52 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
53 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
|
54 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
|
55 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
|
56 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
|
57 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
|
58 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
|
59 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
|
60 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
61 */ |
|
62 package java.time.temporal; |
|
63 |
|
64 import static java.time.temporal.ChronoField.EPOCH_DAY; |
|
65 import static java.time.temporal.ChronoField.NANO_OF_DAY; |
|
66 import static java.time.temporal.ChronoUnit.NANOS; |
|
67 |
|
68 import java.time.DateTimeException; |
|
69 import java.time.Instant; |
|
70 import java.time.LocalDateTime; |
|
71 import java.time.LocalTime; |
|
72 import java.time.ZoneId; |
|
73 import java.time.ZoneOffset; |
|
74 import java.time.format.DateTimeFormatter; |
|
75 import java.time.zone.ZoneRules; |
|
76 import java.util.Comparator; |
|
77 import java.util.Objects; |
|
78 |
|
79 /** |
|
80 * A date-time without a time-zone in an arbitrary chronology, intended |
|
81 * for advanced globalization use cases. |
|
82 * <p> |
|
83 * <b>Most applications should declare method signatures, fields and variables |
|
84 * as {@link LocalDateTime}, not this interface.</b> |
|
85 * <p> |
|
86 * A {@code ChronoLocalDateTime} is the abstract representation of a local date-time |
|
87 * where the {@code Chrono chronology}, or calendar system, is pluggable. |
|
88 * The date-time is defined in terms of fields expressed by {@link TemporalField}, |
|
89 * where most common implementations are defined in {@link ChronoField}. |
|
90 * The chronology defines how the calendar system operates and the meaning of |
|
91 * the standard fields. |
|
92 * |
|
93 * <h3>When to use this interface</h3> |
|
94 * The design of the API encourages the use of {@code LocalDateTime} rather than this |
|
95 * interface, even in the case where the application needs to deal with multiple |
|
96 * calendar systems. The rationale for this is explored in detail in {@link ChronoLocalDate}. |
|
97 * <p> |
|
98 * Ensure that the discussion in {@code ChronoLocalDate} has been read and understood |
|
99 * before using this interface. |
|
100 * |
|
101 * <h3>Specification for implementors</h3> |
|
102 * This interface must be implemented with care to ensure other classes operate correctly. |
|
103 * All implementations that can be instantiated must be final, immutable and thread-safe. |
|
104 * Subclasses should be Serializable wherever possible. |
|
105 * |
|
106 * @param <C> the chronology of this date-time |
|
107 * @since 1.8 |
|
108 */ |
|
109 public interface ChronoLocalDateTime<C extends Chrono<C>> |
|
110 extends Temporal, TemporalAdjuster, Comparable<ChronoLocalDateTime<?>> { |
|
111 |
|
112 /** |
|
113 * Comparator for two {@code ChronoLocalDateTime} instances ignoring the chronology. |
|
114 * <p> |
|
115 * This method differs from the comparison in {@link #compareTo} in that it |
|
116 * only compares the underlying date and not the chronology. |
|
117 * This allows dates in different calendar systems to be compared based |
|
118 * on the time-line position. |
|
119 * |
|
120 * @see #isAfter |
|
121 * @see #isBefore |
|
122 * @see #isEqual |
|
123 */ |
|
124 Comparator<ChronoLocalDateTime<?>> DATE_TIME_COMPARATOR = |
|
125 new Comparator<ChronoLocalDateTime<?>>() { |
|
126 @Override |
|
127 public int compare(ChronoLocalDateTime<?> datetime1, ChronoLocalDateTime<?> datetime2) { |
|
128 int cmp = Long.compare(datetime1.getDate().toEpochDay(), datetime2.getDate().toEpochDay()); |
|
129 if (cmp == 0) { |
|
130 cmp = Long.compare(datetime1.getTime().toNanoOfDay(), datetime2.getTime().toNanoOfDay()); |
|
131 } |
|
132 return cmp; |
|
133 } |
|
134 }; |
|
135 |
|
136 /** |
|
137 * Gets the local date part of this date-time. |
|
138 * <p> |
|
139 * This returns a local date with the same year, month and day |
|
140 * as this date-time. |
|
141 * |
|
142 * @return the date part of this date-time, not null |
|
143 */ |
|
144 ChronoLocalDate<C> getDate() ; |
|
145 |
|
146 /** |
|
147 * Gets the local time part of this date-time. |
|
148 * <p> |
|
149 * This returns a local time with the same hour, minute, second and |
|
150 * nanosecond as this date-time. |
|
151 * |
|
152 * @return the time part of this date-time, not null |
|
153 */ |
|
154 LocalTime getTime(); |
|
155 |
|
156 |
|
157 //----------------------------------------------------------------------- |
|
158 // override for covariant return type |
|
159 /** |
|
160 * {@inheritDoc} |
|
161 * @throws DateTimeException {@inheritDoc} |
|
162 * @throws ArithmeticException {@inheritDoc} |
|
163 */ |
|
164 @Override |
|
165 public default ChronoLocalDateTime<C> with(TemporalAdjuster adjuster) { |
|
166 return getDate().getChrono().ensureChronoLocalDateTime(Temporal.super.with(adjuster)); |
|
167 } |
|
168 |
|
169 /** |
|
170 * {@inheritDoc} |
|
171 * @throws DateTimeException {@inheritDoc} |
|
172 * @throws ArithmeticException {@inheritDoc} |
|
173 */ |
|
174 @Override |
|
175 ChronoLocalDateTime<C> with(TemporalField field, long newValue); |
|
176 |
|
177 /** |
|
178 * {@inheritDoc} |
|
179 * @throws DateTimeException {@inheritDoc} |
|
180 * @throws ArithmeticException {@inheritDoc} |
|
181 */ |
|
182 @Override |
|
183 public default ChronoLocalDateTime<C> plus(TemporalAdder adder) { |
|
184 return getDate().getChrono().ensureChronoLocalDateTime(Temporal.super.plus(adder)); |
|
185 } |
|
186 |
|
187 /** |
|
188 * {@inheritDoc} |
|
189 * @throws DateTimeException {@inheritDoc} |
|
190 * @throws ArithmeticException {@inheritDoc} |
|
191 */ |
|
192 @Override |
|
193 ChronoLocalDateTime<C> plus(long amountToAdd, TemporalUnit unit); |
|
194 |
|
195 /** |
|
196 * {@inheritDoc} |
|
197 * @throws DateTimeException {@inheritDoc} |
|
198 * @throws ArithmeticException {@inheritDoc} |
|
199 */ |
|
200 @Override |
|
201 public default ChronoLocalDateTime<C> minus(TemporalSubtractor subtractor) { |
|
202 return getDate().getChrono().ensureChronoLocalDateTime(Temporal.super.minus(subtractor)); |
|
203 } |
|
204 |
|
205 /** |
|
206 * {@inheritDoc} |
|
207 * @throws DateTimeException {@inheritDoc} |
|
208 * @throws ArithmeticException {@inheritDoc} |
|
209 */ |
|
210 @Override |
|
211 public default ChronoLocalDateTime<C> minus(long amountToSubtract, TemporalUnit unit) { |
|
212 return getDate().getChrono().ensureChronoLocalDateTime(Temporal.super.minus(amountToSubtract, unit)); |
|
213 } |
|
214 |
|
215 //----------------------------------------------------------------------- |
|
216 /** |
|
217 * Queries this date-time using the specified query. |
|
218 * <p> |
|
219 * This queries this date-time using the specified query strategy object. |
|
220 * The {@code TemporalQuery} object defines the logic to be used to |
|
221 * obtain the result. Read the documentation of the query to understand |
|
222 * what the result of this method will be. |
|
223 * <p> |
|
224 * The result of this method is obtained by invoking the |
|
225 * {@link java.time.temporal.TemporalQuery#queryFrom(TemporalAccessor)} method on the |
|
226 * specified query passing {@code this} as the argument. |
|
227 * |
|
228 * @param <R> the type of the result |
|
229 * @param query the query to invoke, not null |
|
230 * @return the query result, null may be returned (defined by the query) |
|
231 * @throws DateTimeException if unable to query (defined by the query) |
|
232 * @throws ArithmeticException if numeric overflow occurs (defined by the query) |
|
233 */ |
|
234 @SuppressWarnings("unchecked") |
|
235 @Override |
|
236 public default <R> R query(TemporalQuery<R> query) { |
|
237 if (query == Queries.chrono()) { |
|
238 return (R) getDate().getChrono(); |
|
239 } |
|
240 if (query == Queries.precision()) { |
|
241 return (R) NANOS; |
|
242 } |
|
243 // inline TemporalAccessor.super.query(query) as an optimization |
|
244 if (query == Queries.zoneId() || query == Queries.zone() || query == Queries.offset()) { |
|
245 return null; |
|
246 } |
|
247 return query.queryFrom(this); |
|
248 } |
|
249 |
|
250 /** |
|
251 * Adjusts the specified temporal object to have the same date and time as this object. |
|
252 * <p> |
|
253 * This returns a temporal object of the same observable type as the input |
|
254 * with the date and time changed to be the same as this. |
|
255 * <p> |
|
256 * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)} |
|
257 * twice, passing {@link ChronoField#EPOCH_DAY} and |
|
258 * {@link ChronoField#NANO_OF_DAY} as the fields. |
|
259 * <p> |
|
260 * In most cases, it is clearer to reverse the calling pattern by using |
|
261 * {@link Temporal#with(TemporalAdjuster)}: |
|
262 * <pre> |
|
263 * // these two lines are equivalent, but the second approach is recommended |
|
264 * temporal = thisLocalDateTime.adjustInto(temporal); |
|
265 * temporal = temporal.with(thisLocalDateTime); |
|
266 * </pre> |
|
267 * <p> |
|
268 * This instance is immutable and unaffected by this method call. |
|
269 * |
|
270 * @param temporal the target object to be adjusted, not null |
|
271 * @return the adjusted object, not null |
|
272 * @throws DateTimeException if unable to make the adjustment |
|
273 * @throws ArithmeticException if numeric overflow occurs |
|
274 */ |
|
275 @Override |
|
276 public default Temporal adjustInto(Temporal temporal) { |
|
277 return temporal |
|
278 .with(EPOCH_DAY, getDate().toEpochDay()) |
|
279 .with(NANO_OF_DAY, getTime().toNanoOfDay()); |
|
280 } |
|
281 |
|
282 //----------------------------------------------------------------------- |
|
283 /** |
|
284 * Returns a zoned date-time formed from this date-time and the specified time-zone. |
|
285 * <p> |
|
286 * This creates a zoned date-time matching the input date-time as closely as possible. |
|
287 * Time-zone rules, such as daylight savings, mean that not every local date-time |
|
288 * is valid for the specified zone, thus the local date-time may be adjusted. |
|
289 * <p> |
|
290 * The local date-time is resolved to a single instant on the time-line. |
|
291 * This is achieved by finding a valid offset from UTC/Greenwich for the local |
|
292 * date-time as defined by the {@link ZoneRules rules} of the zone ID. |
|
293 *<p> |
|
294 * In most cases, there is only one valid offset for a local date-time. |
|
295 * In the case of an overlap, where clocks are set back, there are two valid offsets. |
|
296 * This method uses the earlier offset typically corresponding to "summer". |
|
297 * <p> |
|
298 * In the case of a gap, where clocks jump forward, there is no valid offset. |
|
299 * Instead, the local date-time is adjusted to be later by the length of the gap. |
|
300 * For a typical one hour daylight savings change, the local date-time will be |
|
301 * moved one hour later into the offset typically corresponding to "summer". |
|
302 * <p> |
|
303 * To obtain the later offset during an overlap, call |
|
304 * {@link ChronoZonedDateTime#withLaterOffsetAtOverlap()} on the result of this method. |
|
305 * <p> |
|
306 * This instance is immutable and unaffected by this method call. |
|
307 * |
|
308 * @param zone the time-zone to use, not null |
|
309 * @return the zoned date-time formed from this date-time, not null |
|
310 */ |
|
311 ChronoZonedDateTime<C> atZone(ZoneId zone); |
|
312 |
|
313 //----------------------------------------------------------------------- |
|
314 /** |
|
315 * Converts this date-time to an {@code Instant}. |
|
316 * <p> |
|
317 * This combines this local date-time and the specified offset to form |
|
318 * an {@code Instant}. |
|
319 * <p> |
|
320 * This default implementation calculates from the epoch-day of the date and the |
|
321 * second-of-day of the time. |
|
322 * |
|
323 * @param offset the offset to use for the conversion, not null |
|
324 * @return an {@code Instant} representing the same instant, not null |
|
325 */ |
|
326 public default Instant toInstant(ZoneOffset offset) { |
|
327 return Instant.ofEpochSecond(toEpochSecond(offset), getTime().getNano()); |
|
328 } |
|
329 |
|
330 /** |
|
331 * Converts this date-time to the number of seconds from the epoch |
|
332 * of 1970-01-01T00:00:00Z. |
|
333 * <p> |
|
334 * This combines this local date-time and the specified offset to calculate the |
|
335 * epoch-second value, which is the number of elapsed seconds from 1970-01-01T00:00:00Z. |
|
336 * Instants on the time-line after the epoch are positive, earlier are negative. |
|
337 * <p> |
|
338 * This default implementation calculates from the epoch-day of the date and the |
|
339 * second-of-day of the time. |
|
340 * |
|
341 * @param offset the offset to use for the conversion, not null |
|
342 * @return the number of seconds from the epoch of 1970-01-01T00:00:00Z |
|
343 */ |
|
344 public default long toEpochSecond(ZoneOffset offset) { |
|
345 Objects.requireNonNull(offset, "offset"); |
|
346 long epochDay = getDate().toEpochDay(); |
|
347 long secs = epochDay * 86400 + getTime().toSecondOfDay(); |
|
348 secs -= offset.getTotalSeconds(); |
|
349 return secs; |
|
350 } |
|
351 |
|
352 //----------------------------------------------------------------------- |
|
353 /** |
|
354 * Compares this date-time to another date-time, including the chronology. |
|
355 * <p> |
|
356 * The comparison is based first on the underlying time-line date-time, then |
|
357 * on the chronology. |
|
358 * It is "consistent with equals", as defined by {@link Comparable}. |
|
359 * <p> |
|
360 * For example, the following is the comparator order: |
|
361 * <ol> |
|
362 * <li>{@code 2012-12-03T12:00 (ISO)}</li> |
|
363 * <li>{@code 2012-12-04T12:00 (ISO)}</li> |
|
364 * <li>{@code 2555-12-04T12:00 (ThaiBuddhist)}</li> |
|
365 * <li>{@code 2012-12-05T12:00 (ISO)}</li> |
|
366 * </ol> |
|
367 * Values #2 and #3 represent the same date-time on the time-line. |
|
368 * When two values represent the same date-time, the chronology ID is compared to distinguish them. |
|
369 * This step is needed to make the ordering "consistent with equals". |
|
370 * <p> |
|
371 * If all the date-time objects being compared are in the same chronology, then the |
|
372 * additional chronology stage is not required and only the local date-time is used. |
|
373 * <p> |
|
374 * This default implementation performs the comparison defined above. |
|
375 * |
|
376 * @param other the other date-time to compare to, not null |
|
377 * @return the comparator value, negative if less, positive if greater |
|
378 */ |
|
379 @Override |
|
380 public default int compareTo(ChronoLocalDateTime<?> other) { |
|
381 int cmp = getDate().compareTo(other.getDate()); |
|
382 if (cmp == 0) { |
|
383 cmp = getTime().compareTo(other.getTime()); |
|
384 if (cmp == 0) { |
|
385 cmp = getDate().getChrono().compareTo(other.getDate().getChrono()); |
|
386 } |
|
387 } |
|
388 return cmp; |
|
389 } |
|
390 |
|
391 /** |
|
392 * Checks if this date-time is after the specified date-time ignoring the chronology. |
|
393 * <p> |
|
394 * This method differs from the comparison in {@link #compareTo} in that it |
|
395 * only compares the underlying date-time and not the chronology. |
|
396 * This allows dates in different calendar systems to be compared based |
|
397 * on the time-line position. |
|
398 * <p> |
|
399 * This default implementation performs the comparison based on the epoch-day |
|
400 * and nano-of-day. |
|
401 * |
|
402 * @param other the other date-time to compare to, not null |
|
403 * @return true if this is after the specified date-time |
|
404 */ |
|
405 public default boolean isAfter(ChronoLocalDateTime<?> other) { |
|
406 long thisEpDay = this.getDate().toEpochDay(); |
|
407 long otherEpDay = other.getDate().toEpochDay(); |
|
408 return thisEpDay > otherEpDay || |
|
409 (thisEpDay == otherEpDay && this.getTime().toNanoOfDay() > other.getTime().toNanoOfDay()); |
|
410 } |
|
411 |
|
412 /** |
|
413 * Checks if this date-time is before the specified date-time ignoring the chronology. |
|
414 * <p> |
|
415 * This method differs from the comparison in {@link #compareTo} in that it |
|
416 * only compares the underlying date-time and not the chronology. |
|
417 * This allows dates in different calendar systems to be compared based |
|
418 * on the time-line position. |
|
419 * <p> |
|
420 * This default implementation performs the comparison based on the epoch-day |
|
421 * and nano-of-day. |
|
422 * |
|
423 * @param other the other date-time to compare to, not null |
|
424 * @return true if this is before the specified date-time |
|
425 */ |
|
426 public default boolean isBefore(ChronoLocalDateTime<?> other) { |
|
427 long thisEpDay = this.getDate().toEpochDay(); |
|
428 long otherEpDay = other.getDate().toEpochDay(); |
|
429 return thisEpDay < otherEpDay || |
|
430 (thisEpDay == otherEpDay && this.getTime().toNanoOfDay() < other.getTime().toNanoOfDay()); |
|
431 } |
|
432 |
|
433 /** |
|
434 * Checks if this date-time is equal to the specified date-time ignoring the chronology. |
|
435 * <p> |
|
436 * This method differs from the comparison in {@link #compareTo} in that it |
|
437 * only compares the underlying date and time and not the chronology. |
|
438 * This allows date-times in different calendar systems to be compared based |
|
439 * on the time-line position. |
|
440 * <p> |
|
441 * This default implementation performs the comparison based on the epoch-day |
|
442 * and nano-of-day. |
|
443 * |
|
444 * @param other the other date-time to compare to, not null |
|
445 * @return true if the underlying date-time is equal to the specified date-time on the timeline |
|
446 */ |
|
447 public default boolean isEqual(ChronoLocalDateTime<?> other) { |
|
448 // Do the time check first, it is cheaper than computing EPOCH day. |
|
449 return this.getTime().toNanoOfDay() == other.getTime().toNanoOfDay() && |
|
450 this.getDate().toEpochDay() == other.getDate().toEpochDay(); |
|
451 } |
|
452 |
|
453 /** |
|
454 * Checks if this date-time is equal to another date-time, including the chronology. |
|
455 * <p> |
|
456 * Compares this date-time with another ensuring that the date-time and chronology are the same. |
|
457 * |
|
458 * @param obj the object to check, null returns false |
|
459 * @return true if this is equal to the other date |
|
460 */ |
|
461 @Override |
|
462 boolean equals(Object obj); |
|
463 |
|
464 /** |
|
465 * A hash code for this date-time. |
|
466 * |
|
467 * @return a suitable hash code |
|
468 */ |
|
469 @Override |
|
470 int hashCode(); |
|
471 |
|
472 //----------------------------------------------------------------------- |
|
473 /** |
|
474 * Outputs this date-time as a {@code String}. |
|
475 * <p> |
|
476 * The output will include the full local date-time and the chronology ID. |
|
477 * |
|
478 * @return a string representation of this date-time, not null |
|
479 */ |
|
480 @Override |
|
481 String toString(); |
|
482 |
|
483 /** |
|
484 * Outputs this date-time as a {@code String} using the formatter. |
|
485 * <p> |
|
486 * The default implementation must behave as follows: |
|
487 * <pre> |
|
488 * return formatter.print(this); |
|
489 * </pre> |
|
490 * |
|
491 * @param formatter the formatter to use, not null |
|
492 * @return the formatted date-time string, not null |
|
493 * @throws DateTimeException if an error occurs during printing |
|
494 */ |
|
495 public default String toString(DateTimeFormatter formatter) { |
|
496 Objects.requireNonNull(formatter, "formatter"); |
|
497 return formatter.print(this); |
|
498 } |
|
499 } |
|