71 import java.time.LocalTime; |
71 import java.time.LocalTime; |
72 import java.time.ZoneId; |
72 import java.time.ZoneId; |
73 import java.time.ZoneOffset; |
73 import java.time.ZoneOffset; |
74 import java.time.format.DateTimeFormatter; |
74 import java.time.format.DateTimeFormatter; |
75 import java.time.temporal.ChronoField; |
75 import java.time.temporal.ChronoField; |
76 import java.time.temporal.Queries; |
|
77 import java.time.temporal.Temporal; |
76 import java.time.temporal.Temporal; |
78 import java.time.temporal.TemporalAccessor; |
77 import java.time.temporal.TemporalAccessor; |
79 import java.time.temporal.TemporalAdjuster; |
78 import java.time.temporal.TemporalAdjuster; |
80 import java.time.temporal.TemporalAmount; |
79 import java.time.temporal.TemporalAmount; |
81 import java.time.temporal.TemporalField; |
80 import java.time.temporal.TemporalField; |
117 */ |
116 */ |
118 public interface ChronoLocalDateTime<D extends ChronoLocalDate<D>> |
117 public interface ChronoLocalDateTime<D extends ChronoLocalDate<D>> |
119 extends Temporal, TemporalAdjuster, Comparable<ChronoLocalDateTime<?>> { |
118 extends Temporal, TemporalAdjuster, Comparable<ChronoLocalDateTime<?>> { |
120 |
119 |
121 /** |
120 /** |
122 * Comparator for two {@code ChronoLocalDateTime} instances ignoring the chronology. |
121 * Gets a comparator that compares {@code ChronoLocalDateTime} in |
123 * <p> |
122 * time-line order ignoring the chronology. |
124 * This method differs from the comparison in {@link #compareTo} in that it |
123 * <p> |
125 * only compares the underlying date and not the chronology. |
124 * This comparator differs from the comparison in {@link #compareTo} in that it |
|
125 * only compares the underlying date-time and not the chronology. |
126 * This allows dates in different calendar systems to be compared based |
126 * This allows dates in different calendar systems to be compared based |
127 * on the time-line position. |
127 * on the position of the date-time on the local time-line. |
|
128 * The underlying comparison is equivalent to comparing the epoch-day and nano-of-day. |
128 * |
129 * |
129 * @see #isAfter |
130 * @see #isAfter |
130 * @see #isBefore |
131 * @see #isBefore |
131 * @see #isEqual |
132 * @see #isEqual |
132 */ |
133 */ |
133 Comparator<ChronoLocalDateTime<?>> DATE_TIME_COMPARATOR = |
134 static Comparator<ChronoLocalDateTime<?>> timeLineOrder() { |
134 new Comparator<ChronoLocalDateTime<?>>() { |
135 return Chronology.DATE_TIME_ORDER; |
135 @Override |
136 } |
136 public int compare(ChronoLocalDateTime<?> datetime1, ChronoLocalDateTime<?> datetime2) { |
137 |
137 int cmp = Long.compare(datetime1.toLocalDate().toEpochDay(), datetime2.toLocalDate().toEpochDay()); |
138 //----------------------------------------------------------------------- |
138 if (cmp == 0) { |
139 /** |
139 cmp = Long.compare(datetime1.toLocalTime().toNanoOfDay(), datetime2.toLocalTime().toNanoOfDay()); |
140 * Obtains an instance of {@code ChronoLocalDateTime} from a temporal object. |
140 } |
141 * <p> |
141 return cmp; |
142 * This obtains a local date-time based on the specified temporal. |
|
143 * A {@code TemporalAccessor} represents an arbitrary set of date and time information, |
|
144 * which this factory converts to an instance of {@code ChronoLocalDateTime}. |
|
145 * <p> |
|
146 * The conversion extracts and combines the chronology and the date-time |
|
147 * from the temporal object. The behavior is equivalent to using |
|
148 * {@link Chronology#localDateTime(TemporalAccessor)} with the extracted chronology. |
|
149 * Implementations are permitted to perform optimizations such as accessing |
|
150 * those fields that are equivalent to the relevant objects. |
|
151 * <p> |
|
152 * This method matches the signature of the functional interface {@link TemporalQuery} |
|
153 * allowing it to be used as a query via method reference, {@code ChronoLocalDateTime::from}. |
|
154 * |
|
155 * @param temporal the temporal object to convert, not null |
|
156 * @return the date-time, not null |
|
157 * @throws DateTimeException if unable to convert to a {@code ChronoLocalDateTime} |
|
158 * @see Chronology#localDateTime(TemporalAccessor) |
|
159 */ |
|
160 static ChronoLocalDateTime<?> from(TemporalAccessor temporal) { |
|
161 if (temporal instanceof ChronoLocalDateTime) { |
|
162 return (ChronoLocalDateTime<?>) temporal; |
142 } |
163 } |
143 }; |
164 Chronology chrono = temporal.query(TemporalQuery.chronology()); |
144 |
165 if (chrono == null) { |
|
166 throw new DateTimeException("Unable to obtain ChronoLocalDateTime from TemporalAccessor: " + temporal.getClass()); |
|
167 } |
|
168 return chrono.localDateTime(temporal); |
|
169 } |
|
170 |
|
171 //----------------------------------------------------------------------- |
145 /** |
172 /** |
146 * Gets the local date part of this date-time. |
173 * Gets the local date part of this date-time. |
147 * <p> |
174 * <p> |
148 * This returns a local date with the same year, month and day |
175 * This returns a local date with the same year, month and day |
149 * as this date-time. |
176 * as this date-time. |
161 * @return the time part of this date-time, not null |
188 * @return the time part of this date-time, not null |
162 */ |
189 */ |
163 LocalTime toLocalTime(); |
190 LocalTime toLocalTime(); |
164 |
191 |
165 @Override // Override to provide javadoc |
192 @Override // Override to provide javadoc |
166 public boolean isSupported(TemporalField field); |
193 boolean isSupported(TemporalField field); |
167 |
194 |
168 //----------------------------------------------------------------------- |
195 //----------------------------------------------------------------------- |
169 // override for covariant return type |
196 // override for covariant return type |
170 /** |
197 /** |
171 * {@inheritDoc} |
198 * {@inheritDoc} |
172 * @throws DateTimeException {@inheritDoc} |
199 * @throws DateTimeException {@inheritDoc} |
173 * @throws ArithmeticException {@inheritDoc} |
200 * @throws ArithmeticException {@inheritDoc} |
174 */ |
201 */ |
175 @Override |
202 @Override |
176 public default ChronoLocalDateTime<D> with(TemporalAdjuster adjuster) { |
203 default ChronoLocalDateTime<D> with(TemporalAdjuster adjuster) { |
177 return (ChronoLocalDateTime<D>)(toLocalDate().getChronology().ensureChronoLocalDateTime(Temporal.super.with(adjuster))); |
204 return (ChronoLocalDateTime<D>)(toLocalDate().getChronology().ensureChronoLocalDateTime(Temporal.super.with(adjuster))); |
178 } |
205 } |
179 |
206 |
180 /** |
207 /** |
181 * {@inheritDoc} |
208 * {@inheritDoc} |
207 * {@inheritDoc} |
234 * {@inheritDoc} |
208 * @throws DateTimeException {@inheritDoc} |
235 * @throws DateTimeException {@inheritDoc} |
209 * @throws ArithmeticException {@inheritDoc} |
236 * @throws ArithmeticException {@inheritDoc} |
210 */ |
237 */ |
211 @Override |
238 @Override |
212 public default ChronoLocalDateTime<D> minus(TemporalAmount amount) { |
239 default ChronoLocalDateTime<D> minus(TemporalAmount amount) { |
213 return (ChronoLocalDateTime<D>)(toLocalDate().getChronology().ensureChronoLocalDateTime(Temporal.super.minus(amount))); |
240 return (ChronoLocalDateTime<D>)(toLocalDate().getChronology().ensureChronoLocalDateTime(Temporal.super.minus(amount))); |
214 } |
241 } |
215 |
242 |
216 /** |
243 /** |
217 * {@inheritDoc} |
244 * {@inheritDoc} |
218 * @throws DateTimeException {@inheritDoc} |
245 * @throws DateTimeException {@inheritDoc} |
219 * @throws ArithmeticException {@inheritDoc} |
246 * @throws ArithmeticException {@inheritDoc} |
220 */ |
247 */ |
221 @Override |
248 @Override |
222 public default ChronoLocalDateTime<D> minus(long amountToSubtract, TemporalUnit unit) { |
249 default ChronoLocalDateTime<D> minus(long amountToSubtract, TemporalUnit unit) { |
223 return (ChronoLocalDateTime<D>)(toLocalDate().getChronology().ensureChronoLocalDateTime(Temporal.super.minus(amountToSubtract, unit))); |
250 return (ChronoLocalDateTime<D>)(toLocalDate().getChronology().ensureChronoLocalDateTime(Temporal.super.minus(amountToSubtract, unit))); |
224 } |
251 } |
225 |
252 |
226 //----------------------------------------------------------------------- |
253 //----------------------------------------------------------------------- |
227 /** |
254 /** |
242 * @throws DateTimeException if unable to query (defined by the query) |
269 * @throws DateTimeException if unable to query (defined by the query) |
243 * @throws ArithmeticException if numeric overflow occurs (defined by the query) |
270 * @throws ArithmeticException if numeric overflow occurs (defined by the query) |
244 */ |
271 */ |
245 @SuppressWarnings("unchecked") |
272 @SuppressWarnings("unchecked") |
246 @Override |
273 @Override |
247 public default <R> R query(TemporalQuery<R> query) { |
274 default <R> R query(TemporalQuery<R> query) { |
248 if (query == Queries.zoneId() || query == Queries.zone() || query == Queries.offset()) { |
275 if (query == TemporalQuery.zoneId() || query == TemporalQuery.zone() || query == TemporalQuery.offset()) { |
249 return null; |
276 return null; |
250 } else if (query == Queries.localTime()) { |
277 } else if (query == TemporalQuery.localTime()) { |
251 return (R) toLocalTime(); |
278 return (R) toLocalTime(); |
252 } else if (query == Queries.chronology()) { |
279 } else if (query == TemporalQuery.chronology()) { |
253 return (R) toLocalDate().getChronology(); |
280 return (R) toLocalDate().getChronology(); |
254 } else if (query == Queries.precision()) { |
281 } else if (query == TemporalQuery.precision()) { |
255 return (R) NANOS; |
282 return (R) NANOS; |
256 } |
283 } |
257 // inline TemporalAccessor.super.query(query) as an optimization |
284 // inline TemporalAccessor.super.query(query) as an optimization |
258 // non-JDK classes are not permitted to make this optimization |
285 // non-JDK classes are not permitted to make this optimization |
259 return query.queryFrom(this); |
286 return query.queryFrom(this); |
283 * @return the adjusted object, not null |
310 * @return the adjusted object, not null |
284 * @throws DateTimeException if unable to make the adjustment |
311 * @throws DateTimeException if unable to make the adjustment |
285 * @throws ArithmeticException if numeric overflow occurs |
312 * @throws ArithmeticException if numeric overflow occurs |
286 */ |
313 */ |
287 @Override |
314 @Override |
288 public default Temporal adjustInto(Temporal temporal) { |
315 default Temporal adjustInto(Temporal temporal) { |
289 return temporal |
316 return temporal |
290 .with(EPOCH_DAY, toLocalDate().toEpochDay()) |
317 .with(EPOCH_DAY, toLocalDate().toEpochDay()) |
291 .with(NANO_OF_DAY, toLocalTime().toNanoOfDay()); |
318 .with(NANO_OF_DAY, toLocalTime().toNanoOfDay()); |
|
319 } |
|
320 |
|
321 /** |
|
322 * Formats this date-time using the specified formatter. |
|
323 * <p> |
|
324 * This date-time will be passed to the formatter to produce a string. |
|
325 * <p> |
|
326 * The default implementation must behave as follows: |
|
327 * <pre> |
|
328 * return formatter.format(this); |
|
329 * </pre> |
|
330 * |
|
331 * @param formatter the formatter to use, not null |
|
332 * @return the formatted date-time string, not null |
|
333 * @throws DateTimeException if an error occurs during printing |
|
334 */ |
|
335 default String format(DateTimeFormatter formatter) { |
|
336 Objects.requireNonNull(formatter, "formatter"); |
|
337 return formatter.format(this); |
292 } |
338 } |
293 |
339 |
294 //----------------------------------------------------------------------- |
340 //----------------------------------------------------------------------- |
295 /** |
341 /** |
296 * Combines this time with a time-zone to create a {@code ChronoZonedDateTime}. |
342 * Combines this time with a time-zone to create a {@code ChronoZonedDateTime}. |
332 * second-of-day of the time. |
378 * second-of-day of the time. |
333 * |
379 * |
334 * @param offset the offset to use for the conversion, not null |
380 * @param offset the offset to use for the conversion, not null |
335 * @return an {@code Instant} representing the same instant, not null |
381 * @return an {@code Instant} representing the same instant, not null |
336 */ |
382 */ |
337 public default Instant toInstant(ZoneOffset offset) { |
383 default Instant toInstant(ZoneOffset offset) { |
338 return Instant.ofEpochSecond(toEpochSecond(offset), toLocalTime().getNano()); |
384 return Instant.ofEpochSecond(toEpochSecond(offset), toLocalTime().getNano()); |
339 } |
385 } |
340 |
386 |
341 /** |
387 /** |
342 * Converts this date-time to the number of seconds from the epoch |
388 * Converts this date-time to the number of seconds from the epoch |
350 * second-of-day of the time. |
396 * second-of-day of the time. |
351 * |
397 * |
352 * @param offset the offset to use for the conversion, not null |
398 * @param offset the offset to use for the conversion, not null |
353 * @return the number of seconds from the epoch of 1970-01-01T00:00:00Z |
399 * @return the number of seconds from the epoch of 1970-01-01T00:00:00Z |
354 */ |
400 */ |
355 public default long toEpochSecond(ZoneOffset offset) { |
401 default long toEpochSecond(ZoneOffset offset) { |
356 Objects.requireNonNull(offset, "offset"); |
402 Objects.requireNonNull(offset, "offset"); |
357 long epochDay = toLocalDate().toEpochDay(); |
403 long epochDay = toLocalDate().toEpochDay(); |
358 long secs = epochDay * 86400 + toLocalTime().toSecondOfDay(); |
404 long secs = epochDay * 86400 + toLocalTime().toSecondOfDay(); |
359 secs -= offset.getTotalSeconds(); |
405 secs -= offset.getTotalSeconds(); |
360 return secs; |
406 return secs; |
386 * |
432 * |
387 * @param other the other date-time to compare to, not null |
433 * @param other the other date-time to compare to, not null |
388 * @return the comparator value, negative if less, positive if greater |
434 * @return the comparator value, negative if less, positive if greater |
389 */ |
435 */ |
390 @Override |
436 @Override |
391 public default int compareTo(ChronoLocalDateTime<?> other) { |
437 default int compareTo(ChronoLocalDateTime<?> other) { |
392 int cmp = toLocalDate().compareTo(other.toLocalDate()); |
438 int cmp = toLocalDate().compareTo(other.toLocalDate()); |
393 if (cmp == 0) { |
439 if (cmp == 0) { |
394 cmp = toLocalTime().compareTo(other.toLocalTime()); |
440 cmp = toLocalTime().compareTo(other.toLocalTime()); |
395 if (cmp == 0) { |
441 if (cmp == 0) { |
396 cmp = toLocalDate().getChronology().compareTo(other.toLocalDate().getChronology()); |
442 cmp = toLocalDate().getChronology().compareTo(other.toLocalDate().getChronology()); |
411 * and nano-of-day. |
457 * and nano-of-day. |
412 * |
458 * |
413 * @param other the other date-time to compare to, not null |
459 * @param other the other date-time to compare to, not null |
414 * @return true if this is after the specified date-time |
460 * @return true if this is after the specified date-time |
415 */ |
461 */ |
416 public default boolean isAfter(ChronoLocalDateTime<?> other) { |
462 default boolean isAfter(ChronoLocalDateTime<?> other) { |
417 long thisEpDay = this.toLocalDate().toEpochDay(); |
463 long thisEpDay = this.toLocalDate().toEpochDay(); |
418 long otherEpDay = other.toLocalDate().toEpochDay(); |
464 long otherEpDay = other.toLocalDate().toEpochDay(); |
419 return thisEpDay > otherEpDay || |
465 return thisEpDay > otherEpDay || |
420 (thisEpDay == otherEpDay && this.toLocalTime().toNanoOfDay() > other.toLocalTime().toNanoOfDay()); |
466 (thisEpDay == otherEpDay && this.toLocalTime().toNanoOfDay() > other.toLocalTime().toNanoOfDay()); |
421 } |
467 } |
432 * and nano-of-day. |
478 * and nano-of-day. |
433 * |
479 * |
434 * @param other the other date-time to compare to, not null |
480 * @param other the other date-time to compare to, not null |
435 * @return true if this is before the specified date-time |
481 * @return true if this is before the specified date-time |
436 */ |
482 */ |
437 public default boolean isBefore(ChronoLocalDateTime<?> other) { |
483 default boolean isBefore(ChronoLocalDateTime<?> other) { |
438 long thisEpDay = this.toLocalDate().toEpochDay(); |
484 long thisEpDay = this.toLocalDate().toEpochDay(); |
439 long otherEpDay = other.toLocalDate().toEpochDay(); |
485 long otherEpDay = other.toLocalDate().toEpochDay(); |
440 return thisEpDay < otherEpDay || |
486 return thisEpDay < otherEpDay || |
441 (thisEpDay == otherEpDay && this.toLocalTime().toNanoOfDay() < other.toLocalTime().toNanoOfDay()); |
487 (thisEpDay == otherEpDay && this.toLocalTime().toNanoOfDay() < other.toLocalTime().toNanoOfDay()); |
442 } |
488 } |
453 * and nano-of-day. |
499 * and nano-of-day. |
454 * |
500 * |
455 * @param other the other date-time to compare to, not null |
501 * @param other the other date-time to compare to, not null |
456 * @return true if the underlying date-time is equal to the specified date-time on the timeline |
502 * @return true if the underlying date-time is equal to the specified date-time on the timeline |
457 */ |
503 */ |
458 public default boolean isEqual(ChronoLocalDateTime<?> other) { |
504 default boolean isEqual(ChronoLocalDateTime<?> other) { |
459 // Do the time check first, it is cheaper than computing EPOCH day. |
505 // Do the time check first, it is cheaper than computing EPOCH day. |
460 return this.toLocalTime().toNanoOfDay() == other.toLocalTime().toNanoOfDay() && |
506 return this.toLocalTime().toNanoOfDay() == other.toLocalTime().toNanoOfDay() && |
461 this.toLocalDate().toEpochDay() == other.toLocalDate().toEpochDay(); |
507 this.toLocalDate().toEpochDay() == other.toLocalDate().toEpochDay(); |
462 } |
508 } |
463 |
509 |
482 |
528 |
483 //----------------------------------------------------------------------- |
529 //----------------------------------------------------------------------- |
484 /** |
530 /** |
485 * Outputs this date-time as a {@code String}. |
531 * Outputs this date-time as a {@code String}. |
486 * <p> |
532 * <p> |
487 * The output will include the full local date-time and the chronology ID. |
533 * The output will include the full local date-time. |
488 * |
534 * |
489 * @return a string representation of this date-time, not null |
535 * @return a string representation of this date-time, not null |
490 */ |
536 */ |
491 @Override |
537 @Override |
492 String toString(); |
538 String toString(); |
493 |
539 |
494 /** |
|
495 * Outputs this date-time as a {@code String} using the formatter. |
|
496 * <p> |
|
497 * The default implementation must behave as follows: |
|
498 * <pre> |
|
499 * return formatter.format(this); |
|
500 * </pre> |
|
501 * |
|
502 * @param formatter the formatter to use, not null |
|
503 * @return the formatted date-time string, not null |
|
504 * @throws DateTimeException if an error occurs during printing |
|
505 */ |
|
506 public default String toString(DateTimeFormatter formatter) { |
|
507 Objects.requireNonNull(formatter, "formatter"); |
|
508 return formatter.format(this); |
|
509 } |
|
510 } |
540 } |