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.chrono; 63 64 import static java.time.temporal.ChronoField.INSTANT_SECONDS; 65 import static java.time.temporal.ChronoField.OFFSET_SECONDS; 66 import static java.time.temporal.ChronoUnit.NANOS; 67 68 import java.time.DateTimeException; 69 import java.time.Instant; 70 import java.time.LocalTime; 71 import java.time.ZoneId; 72 import java.time.ZoneOffset; 73 import java.time.ZonedDateTime; 74 import java.time.format.DateTimeFormatter; 75 import java.time.temporal.ChronoField; 76 import java.time.temporal.Queries; 77 import java.time.temporal.Temporal; 78 import java.time.temporal.TemporalAccessor; 79 import java.time.temporal.TemporalAdjuster; 80 import java.time.temporal.TemporalAmount; 81 import java.time.temporal.TemporalField; 82 import java.time.temporal.TemporalQuery; 83 import java.time.temporal.TemporalUnit; 84 import java.time.temporal.ValueRange; 85 import java.util.Comparator; 86 import java.util.Objects; 87 88 /** 89 * A date-time with a time-zone in an arbitrary chronology, 90 * intended for advanced globalization use cases. 91 * <p> 92 * <b>Most applications should declare method signatures, fields and variables 93 * as {@link ZonedDateTime}, not this interface.</b> 94 * <p> 95 * A {@code ChronoZonedDateTime} is the abstract representation of an offset date-time 96 * where the {@code Chronology chronology}, or calendar system, is pluggable. 97 * The date-time is defined in terms of fields expressed by {@link TemporalField}, 98 * where most common implementations are defined in {@link ChronoField}. 99 * The chronology defines how the calendar system operates and the meaning of 100 * the standard fields. 101 * 102 * <h3>When to use this interface</h3> 103 * The design of the API encourages the use of {@code ZonedDateTime} rather than this 104 * interface, even in the case where the application needs to deal with multiple 105 * calendar systems. The rationale for this is explored in detail in {@link ChronoLocalDate}. 106 * <p> 107 * Ensure that the discussion in {@code ChronoLocalDate} has been read and understood 108 * before using this interface. 109 * 110 * <h3>Specification for implementors</h3> 111 * This interface must be implemented with care to ensure other classes operate correctly. 112 * All implementations that can be instantiated must be final, immutable and thread-safe. 113 * Subclasses should be Serializable wherever possible. 114 * 115 * @param <D> the concrete type for the date of this date-time 116 * @since 1.8 117 */ 118 public interface ChronoZonedDateTime<D extends ChronoLocalDate<D>> 119 extends Temporal, Comparable<ChronoZonedDateTime<?>> { 120 121 /** 122 * Comparator for two {@code ChronoZonedDateTime} instances ignoring the chronology. 123 * <p> 124 * This method differs from the comparison in {@link #compareTo} in that it 125 * only compares the underlying date and not the chronology. 126 * This allows dates in different calendar systems to be compared based 127 * on the time-line position. 128 * 129 * @see #isAfter 130 * @see #isBefore 131 * @see #isEqual 132 */ 133 Comparator<ChronoZonedDateTime<?>> INSTANT_COMPARATOR = new Comparator<ChronoZonedDateTime<?>>() { 134 @Override 135 public int compare(ChronoZonedDateTime<?> datetime1, ChronoZonedDateTime<?> datetime2) { 136 int cmp = Long.compare(datetime1.toEpochSecond(), datetime2.toEpochSecond()); 137 if (cmp == 0) { 138 cmp = Long.compare(datetime1.toLocalTime().toNanoOfDay(), datetime2.toLocalTime().toNanoOfDay()); 139 } 140 return cmp; 141 } 142 }; 143 144 @Override 145 public default ValueRange range(TemporalField field) { 146 if (field instanceof ChronoField) { 147 if (field == INSTANT_SECONDS || field == OFFSET_SECONDS) { 148 return field.range(); 149 } 150 return toLocalDateTime().range(field); 151 } 152 return field.rangeRefinedBy(this); 153 } 154 155 @Override 156 public default int get(TemporalField field) { 157 if (field instanceof ChronoField) { 158 switch ((ChronoField) field) { 159 case INSTANT_SECONDS: throw new DateTimeException("Field too large for an int: " + field); 160 case OFFSET_SECONDS: return getOffset().getTotalSeconds(); 161 } 162 return toLocalDateTime().get(field); 163 } 164 return Temporal.super.get(field); 165 } 166 167 @Override 168 public default long getLong(TemporalField field) { 169 if (field instanceof ChronoField) { 170 switch ((ChronoField) field) { 171 case INSTANT_SECONDS: return toEpochSecond(); 172 case OFFSET_SECONDS: return getOffset().getTotalSeconds(); 173 } 174 return toLocalDateTime().getLong(field); 175 } 176 return field.getFrom(this); 177 } 178 179 /** 180 * Gets the local date part of this date-time. 181 * <p> 182 * This returns a local date with the same year, month and day 183 * as this date-time. 184 * 185 * @return the date part of this date-time, not null 186 */ 187 public default D toLocalDate() { 188 return toLocalDateTime().toLocalDate(); 189 } 190 191 /** 192 * Gets the local time part of this date-time. 193 * <p> 194 * This returns a local time with the same hour, minute, second and 195 * nanosecond as this date-time. 196 * 197 * @return the time part of this date-time, not null 198 */ 199 public default LocalTime toLocalTime() { 200 return toLocalDateTime().toLocalTime(); 201 } 202 203 /** 204 * Gets the local date-time part of this date-time. 205 * <p> 206 * This returns a local date with the same year, month and day 207 * as this date-time. 208 * 209 * @return the local date-time part of this date-time, not null 210 */ 211 ChronoLocalDateTime<D> toLocalDateTime(); 212 213 /** 214 * Gets the zone offset, such as '+01:00'. 215 * <p> 216 * This is the offset of the local date-time from UTC/Greenwich. 217 * 218 * @return the zone offset, not null 219 */ 289 /** 290 * Returns a copy of this date-time with a different time-zone, 291 * retaining the instant. 292 * <p> 293 * This method changes the time-zone and retains the instant. 294 * This normally results in a change to the local date-time. 295 * <p> 296 * This method is based on retaining the same instant, thus gaps and overlaps 297 * in the local time-line have no effect on the result. 298 * <p> 299 * To change the offset while keeping the local time, 300 * use {@link #withZoneSameLocal(ZoneId)}. 301 * 302 * @param zone the time-zone to change to, not null 303 * @return a {@code ChronoZonedDateTime} based on this date-time with the requested zone, not null 304 * @throws DateTimeException if the result exceeds the supported date range 305 */ 306 ChronoZonedDateTime<D> withZoneSameInstant(ZoneId zone); 307 308 @Override // Override to provide javadoc 309 public boolean isSupported(TemporalField field); 310 311 //----------------------------------------------------------------------- 312 // override for covariant return type 313 /** 314 * {@inheritDoc} 315 * @throws DateTimeException {@inheritDoc} 316 * @throws ArithmeticException {@inheritDoc} 317 */ 318 @Override 319 public default ChronoZonedDateTime<D> with(TemporalAdjuster adjuster) { 320 return (ChronoZonedDateTime<D>)(toLocalDate().getChronology().ensureChronoZonedDateTime(Temporal.super.with(adjuster))); 321 } 322 323 /** 324 * {@inheritDoc} 325 * @throws DateTimeException {@inheritDoc} 326 * @throws ArithmeticException {@inheritDoc} 327 */ 328 @Override 329 ChronoZonedDateTime<D> with(TemporalField field, long newValue); 330 331 /** 332 * {@inheritDoc} 333 * @throws DateTimeException {@inheritDoc} 334 * @throws ArithmeticException {@inheritDoc} 335 */ 336 @Override 337 public default ChronoZonedDateTime<D> plus(TemporalAmount amount) { 338 return (ChronoZonedDateTime<D>)(toLocalDate().getChronology().ensureChronoZonedDateTime(Temporal.super.plus(amount))); 339 } 340 341 /** 342 * {@inheritDoc} 343 * @throws DateTimeException {@inheritDoc} 344 * @throws ArithmeticException {@inheritDoc} 345 */ 346 @Override 347 ChronoZonedDateTime<D> plus(long amountToAdd, TemporalUnit unit); 348 349 /** 350 * {@inheritDoc} 351 * @throws DateTimeException {@inheritDoc} 352 * @throws ArithmeticException {@inheritDoc} 353 */ 354 @Override 355 public default ChronoZonedDateTime<D> minus(TemporalAmount amount) { 356 return (ChronoZonedDateTime<D>)(toLocalDate().getChronology().ensureChronoZonedDateTime(Temporal.super.minus(amount))); 357 } 358 359 /** 360 * {@inheritDoc} 361 * @throws DateTimeException {@inheritDoc} 362 * @throws ArithmeticException {@inheritDoc} 363 */ 364 @Override 365 public default ChronoZonedDateTime<D> minus(long amountToSubtract, TemporalUnit unit) { 366 return (ChronoZonedDateTime<D>)(toLocalDate().getChronology().ensureChronoZonedDateTime(Temporal.super.minus(amountToSubtract, unit))); 367 } 368 369 //----------------------------------------------------------------------- 370 /** 371 * Queries this date-time using the specified query. 372 * <p> 373 * This queries this date-time using the specified query strategy object. 374 * The {@code TemporalQuery} object defines the logic to be used to 375 * obtain the result. Read the documentation of the query to understand 376 * what the result of this method will be. 377 * <p> 378 * The result of this method is obtained by invoking the 379 * {@link java.time.temporal.TemporalQuery#queryFrom(TemporalAccessor)} method on the 380 * specified query passing {@code this} as the argument. 381 * 382 * @param <R> the type of the result 383 * @param query the query to invoke, not null 384 * @return the query result, null may be returned (defined by the query) 385 * @throws DateTimeException if unable to query (defined by the query) 386 * @throws ArithmeticException if numeric overflow occurs (defined by the query) 387 */ 388 @SuppressWarnings("unchecked") 389 @Override 390 public default <R> R query(TemporalQuery<R> query) { 391 if (query == Queries.zone() || query == Queries.zoneId()) { 392 return (R) getZone(); 393 } else if (query == Queries.offset()) { 394 return (R) getOffset(); 395 } else if (query == Queries.localTime()) { 396 return (R) toLocalTime(); 397 } else if (query == Queries.chronology()) { 398 return (R) toLocalDate().getChronology(); 399 } else if (query == Queries.precision()) { 400 return (R) NANOS; 401 } 402 // inline TemporalAccessor.super.query(query) as an optimization 403 // non-JDK classes are not permitted to make this optimization 404 return query.queryFrom(this); 405 } 406 407 //----------------------------------------------------------------------- 408 /** 409 * Converts this date-time to an {@code Instant}. 410 * <p> 411 * This returns an {@code Instant} representing the same point on the 412 * time-line as this date-time. The calculation combines the 413 * {@linkplain #toLocalDateTime() local date-time} and 414 * {@linkplain #getOffset() offset}. 415 * 416 * @return an {@code Instant} representing the same instant, not null 417 */ 418 public default Instant toInstant() { 419 return Instant.ofEpochSecond(toEpochSecond(), toLocalTime().getNano()); 420 } 421 422 /** 423 * Converts this date-time to the number of seconds from the epoch 424 * of 1970-01-01T00:00:00Z. 425 * <p> 426 * This uses the {@linkplain #toLocalDateTime() local date-time} and 427 * {@linkplain #getOffset() offset} to calculate the epoch-second value, 428 * which is the number of elapsed seconds from 1970-01-01T00:00:00Z. 429 * Instants on the time-line after the epoch are positive, earlier are negative. 430 * 431 * @return the number of seconds from the epoch of 1970-01-01T00:00:00Z 432 */ 433 public default long toEpochSecond() { 434 long epochDay = toLocalDate().toEpochDay(); 435 long secs = epochDay * 86400 + toLocalTime().toSecondOfDay(); 436 secs -= getOffset().getTotalSeconds(); 437 return secs; 438 } 439 440 //----------------------------------------------------------------------- 441 /** 442 * Compares this date-time to another date-time, including the chronology. 443 * <p> 444 * The comparison is based first on the instant, then on the local date-time, 445 * then on the zone ID, then on the chronology. 446 * It is "consistent with equals", as defined by {@link Comparable}. 447 * <p> 448 * If all the date-time objects being compared are in the same chronology, then the 449 * additional chronology stage is not required. 450 * <p> 451 * This default implementation performs the comparison defined above. 452 * 453 * @param other the other date-time to compare to, not null 454 * @return the comparator value, negative if less, positive if greater 455 */ 456 @Override 457 public default int compareTo(ChronoZonedDateTime<?> other) { 458 int cmp = Long.compare(toEpochSecond(), other.toEpochSecond()); 459 if (cmp == 0) { 460 cmp = toLocalTime().getNano() - other.toLocalTime().getNano(); 461 if (cmp == 0) { 462 cmp = toLocalDateTime().compareTo(other.toLocalDateTime()); 463 if (cmp == 0) { 464 cmp = getZone().getId().compareTo(other.getZone().getId()); 465 if (cmp == 0) { 466 cmp = toLocalDate().getChronology().compareTo(other.toLocalDate().getChronology()); 467 } 468 } 469 } 470 } 471 return cmp; 472 } 473 474 /** 475 * Checks if the instant of this date-time is before that of the specified date-time. 476 * <p> 477 * This method differs from the comparison in {@link #compareTo} in that it 478 * only compares the instant of the date-time. This is equivalent to using 479 * {@code dateTime1.toInstant().isBefore(dateTime2.toInstant());}. 480 * <p> 481 * This default implementation performs the comparison based on the epoch-second 482 * and nano-of-second. 483 * 484 * @param other the other date-time to compare to, not null 485 * @return true if this point is before the specified date-time 486 */ 487 public default boolean isBefore(ChronoZonedDateTime<?> other) { 488 long thisEpochSec = toEpochSecond(); 489 long otherEpochSec = other.toEpochSecond(); 490 return thisEpochSec < otherEpochSec || 491 (thisEpochSec == otherEpochSec && toLocalTime().getNano() < other.toLocalTime().getNano()); 492 } 493 494 /** 495 * Checks if the instant of this date-time is after that of the specified date-time. 496 * <p> 497 * This method differs from the comparison in {@link #compareTo} in that it 498 * only compares the instant of the date-time. This is equivalent to using 499 * {@code dateTime1.toInstant().isAfter(dateTime2.toInstant());}. 500 * <p> 501 * This default implementation performs the comparison based on the epoch-second 502 * and nano-of-second. 503 * 504 * @param other the other date-time to compare to, not null 505 * @return true if this is after the specified date-time 506 */ 507 public default boolean isAfter(ChronoZonedDateTime<?> other) { 508 long thisEpochSec = toEpochSecond(); 509 long otherEpochSec = other.toEpochSecond(); 510 return thisEpochSec > otherEpochSec || 511 (thisEpochSec == otherEpochSec && toLocalTime().getNano() > other.toLocalTime().getNano()); 512 } 513 514 /** 515 * Checks if the instant of this date-time is equal to that of the specified date-time. 516 * <p> 517 * This method differs from the comparison in {@link #compareTo} and {@link #equals} 518 * in that it only compares the instant of the date-time. This is equivalent to using 519 * {@code dateTime1.toInstant().equals(dateTime2.toInstant());}. 520 * <p> 521 * This default implementation performs the comparison based on the epoch-second 522 * and nano-of-second. 523 * 524 * @param other the other date-time to compare to, not null 525 * @return true if the instant equals the instant of the specified date-time 526 */ 527 public default boolean isEqual(ChronoZonedDateTime<?> other) { 528 return toEpochSecond() == other.toEpochSecond() && 529 toLocalTime().getNano() == other.toLocalTime().getNano(); 530 } 531 532 //----------------------------------------------------------------------- 533 /** 534 * Checks if this date-time is equal to another date-time. 535 * <p> 536 * The comparison is based on the offset date-time and the zone. 537 * To compare for the same instant on the time-line, use {@link #compareTo}. 538 * Only objects of type {@code ChronoZonedDateTime} are compared, other types return false. 539 * 540 * @param obj the object to check, null returns false 541 * @return true if this is equal to the other date-time 542 */ 543 @Override 544 boolean equals(Object obj); 545 546 /** 547 * A hash code for this date-time. 548 * 549 * @return a suitable hash code 550 */ 551 @Override 552 int hashCode(); 553 554 //----------------------------------------------------------------------- 555 /** 556 * Outputs this date-time as a {@code String}. 557 * <p> 558 * The output will include the full zoned date-time and the chronology ID. 559 * 560 * @return a string representation of this date-time, not null 561 */ 562 @Override 563 String toString(); 564 565 /** 566 * Outputs this date-time as a {@code String} using the formatter. 567 * <p> 568 * The default implementation must behave as follows: 569 * <pre> 570 * return formatter.format(this); 571 * </pre> 572 * 573 * @param formatter the formatter to use, not null 574 * @return the formatted date-time string, not null 575 * @throws DateTimeException if an error occurs during printing 576 */ 577 public default String toString(DateTimeFormatter formatter) { 578 Objects.requireNonNull(formatter, "formatter"); 579 return formatter.format(this); 580 } 581 582 } | 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.chrono; 63 64 import static java.time.temporal.ChronoField.INSTANT_SECONDS; 65 import static java.time.temporal.ChronoField.OFFSET_SECONDS; 66 import static java.time.temporal.ChronoUnit.NANOS; 67 68 import java.time.DateTimeException; 69 import java.time.Instant; 70 import java.time.LocalTime; 71 import java.time.ZoneId; 72 import java.time.ZoneOffset; 73 import java.time.ZonedDateTime; 74 import java.time.format.DateTimeFormatter; 75 import java.time.temporal.ChronoField; 76 import java.time.temporal.Temporal; 77 import java.time.temporal.TemporalAccessor; 78 import java.time.temporal.TemporalAdjuster; 79 import java.time.temporal.TemporalAmount; 80 import java.time.temporal.TemporalField; 81 import java.time.temporal.TemporalQuery; 82 import java.time.temporal.TemporalUnit; 83 import java.time.temporal.UnsupportedTemporalTypeException; 84 import java.time.temporal.ValueRange; 85 import java.util.Comparator; 86 import java.util.Objects; 87 88 /** 89 * A date-time with a time-zone in an arbitrary chronology, 90 * intended for advanced globalization use cases. 91 * <p> 92 * <b>Most applications should declare method signatures, fields and variables 93 * as {@link ZonedDateTime}, not this interface.</b> 94 * <p> 95 * A {@code ChronoZonedDateTime} is the abstract representation of an offset date-time 96 * where the {@code Chronology chronology}, or calendar system, is pluggable. 97 * The date-time is defined in terms of fields expressed by {@link TemporalField}, 98 * where most common implementations are defined in {@link ChronoField}. 99 * The chronology defines how the calendar system operates and the meaning of 100 * the standard fields. 101 * 102 * <h3>When to use this interface</h3> 103 * The design of the API encourages the use of {@code ZonedDateTime} rather than this 104 * interface, even in the case where the application needs to deal with multiple 105 * calendar systems. The rationale for this is explored in detail in {@link ChronoLocalDate}. 106 * <p> 107 * Ensure that the discussion in {@code ChronoLocalDate} has been read and understood 108 * before using this interface. 109 * 110 * <h3>Specification for implementors</h3> 111 * This interface must be implemented with care to ensure other classes operate correctly. 112 * All implementations that can be instantiated must be final, immutable and thread-safe. 113 * Subclasses should be Serializable wherever possible. 114 * 115 * @param <D> the concrete type for the date of this date-time 116 * @since 1.8 117 */ 118 public interface ChronoZonedDateTime<D extends ChronoLocalDate<D>> 119 extends Temporal, Comparable<ChronoZonedDateTime<?>> { 120 121 /** 122 * Gets a comparator that compares {@code ChronoZonedDateTime} in 123 * time-line order ignoring the chronology. 124 * <p> 125 * This comparator differs from the comparison in {@link #compareTo} in that it 126 * only compares the underlying instant and not the chronology. 127 * This allows dates in different calendar systems to be compared based 128 * on the position of the date-time on the instant time-line. 129 * The underlying comparison is equivalent to comparing the epoch-second and nano-of-second. 130 * 131 * @see #isAfter 132 * @see #isBefore 133 * @see #isEqual 134 */ 135 static Comparator<ChronoZonedDateTime<?>> timeLineOrder() { 136 return Chronology.INSTANT_ORDER; 137 } 138 139 //----------------------------------------------------------------------- 140 /** 141 * Obtains an instance of {@code ChronoZonedDateTime} from a temporal object. 142 * <p> 143 * This creates a zoned date-time based on the specified temporal. 144 * A {@code TemporalAccessor} represents an arbitrary set of date and time information, 145 * which this factory converts to an instance of {@code ChronoZonedDateTime}. 146 * <p> 147 * The conversion extracts and combines the chronology, date, time and zone 148 * from the temporal object. The behavior is equivalent to using 149 * {@link Chronology#zonedDateTime(TemporalAccessor)} with the extracted chronology. 150 * Implementations are permitted to perform optimizations such as accessing 151 * those fields that are equivalent to the relevant objects. 152 * <p> 153 * This method matches the signature of the functional interface {@link TemporalQuery} 154 * allowing it to be used as a query via method reference, {@code ChronoZonedDateTime::from}. 155 * 156 * @param temporal the temporal objec t to convert, not null 157 * @return the date-time, not null 158 * @throws DateTimeException if unable to convert to a {@code ChronoZonedDateTime} 159 * @see Chronology#zonedDateTime(TemporalAccessor) 160 */ 161 static ChronoZonedDateTime<?> from(TemporalAccessor temporal) { 162 if (temporal instanceof ChronoZonedDateTime) { 163 return (ChronoZonedDateTime<?>) temporal; 164 } 165 Chronology chrono = temporal.query(TemporalQuery.chronology()); 166 if (chrono == null) { 167 throw new DateTimeException("Unable to obtain ChronoZonedDateTime from TemporalAccessor: " + temporal.getClass()); 168 } 169 return chrono.zonedDateTime(temporal); 170 } 171 172 //----------------------------------------------------------------------- 173 @Override 174 default ValueRange range(TemporalField field) { 175 if (field instanceof ChronoField) { 176 if (field == INSTANT_SECONDS || field == OFFSET_SECONDS) { 177 return field.range(); 178 } 179 return toLocalDateTime().range(field); 180 } 181 return field.rangeRefinedBy(this); 182 } 183 184 @Override 185 default int get(TemporalField field) { 186 if (field instanceof ChronoField) { 187 switch ((ChronoField) field) { 188 case INSTANT_SECONDS: 189 throw new UnsupportedTemporalTypeException("Invalid field 'InstantSeconds' for get() method, use getLong() instead"); 190 case OFFSET_SECONDS: 191 return getOffset().getTotalSeconds(); 192 } 193 return toLocalDateTime().get(field); 194 } 195 return Temporal.super.get(field); 196 } 197 198 @Override 199 default long getLong(TemporalField field) { 200 if (field instanceof ChronoField) { 201 switch ((ChronoField) field) { 202 case INSTANT_SECONDS: return toEpochSecond(); 203 case OFFSET_SECONDS: return getOffset().getTotalSeconds(); 204 } 205 return toLocalDateTime().getLong(field); 206 } 207 return field.getFrom(this); 208 } 209 210 /** 211 * Gets the local date part of this date-time. 212 * <p> 213 * This returns a local date with the same year, month and day 214 * as this date-time. 215 * 216 * @return the date part of this date-time, not null 217 */ 218 default D toLocalDate() { 219 return toLocalDateTime().toLocalDate(); 220 } 221 222 /** 223 * Gets the local time part of this date-time. 224 * <p> 225 * This returns a local time with the same hour, minute, second and 226 * nanosecond as this date-time. 227 * 228 * @return the time part of this date-time, not null 229 */ 230 default LocalTime toLocalTime() { 231 return toLocalDateTime().toLocalTime(); 232 } 233 234 /** 235 * Gets the local date-time part of this date-time. 236 * <p> 237 * This returns a local date with the same year, month and day 238 * as this date-time. 239 * 240 * @return the local date-time part of this date-time, not null 241 */ 242 ChronoLocalDateTime<D> toLocalDateTime(); 243 244 /** 245 * Gets the zone offset, such as '+01:00'. 246 * <p> 247 * This is the offset of the local date-time from UTC/Greenwich. 248 * 249 * @return the zone offset, not null 250 */ 320 /** 321 * Returns a copy of this date-time with a different time-zone, 322 * retaining the instant. 323 * <p> 324 * This method changes the time-zone and retains the instant. 325 * This normally results in a change to the local date-time. 326 * <p> 327 * This method is based on retaining the same instant, thus gaps and overlaps 328 * in the local time-line have no effect on the result. 329 * <p> 330 * To change the offset while keeping the local time, 331 * use {@link #withZoneSameLocal(ZoneId)}. 332 * 333 * @param zone the time-zone to change to, not null 334 * @return a {@code ChronoZonedDateTime} based on this date-time with the requested zone, not null 335 * @throws DateTimeException if the result exceeds the supported date range 336 */ 337 ChronoZonedDateTime<D> withZoneSameInstant(ZoneId zone); 338 339 @Override // Override to provide javadoc 340 boolean isSupported(TemporalField field); 341 342 //----------------------------------------------------------------------- 343 // override for covariant return type 344 /** 345 * {@inheritDoc} 346 * @throws DateTimeException {@inheritDoc} 347 * @throws ArithmeticException {@inheritDoc} 348 */ 349 @Override 350 default ChronoZonedDateTime<D> with(TemporalAdjuster adjuster) { 351 return (ChronoZonedDateTime<D>)(toLocalDate().getChronology().ensureChronoZonedDateTime(Temporal.super.with(adjuster))); 352 } 353 354 /** 355 * {@inheritDoc} 356 * @throws DateTimeException {@inheritDoc} 357 * @throws ArithmeticException {@inheritDoc} 358 */ 359 @Override 360 ChronoZonedDateTime<D> with(TemporalField field, long newValue); 361 362 /** 363 * {@inheritDoc} 364 * @throws DateTimeException {@inheritDoc} 365 * @throws ArithmeticException {@inheritDoc} 366 */ 367 @Override 368 default ChronoZonedDateTime<D> plus(TemporalAmount amount) { 369 return (ChronoZonedDateTime<D>)(toLocalDate().getChronology().ensureChronoZonedDateTime(Temporal.super.plus(amount))); 370 } 371 372 /** 373 * {@inheritDoc} 374 * @throws DateTimeException {@inheritDoc} 375 * @throws ArithmeticException {@inheritDoc} 376 */ 377 @Override 378 ChronoZonedDateTime<D> plus(long amountToAdd, TemporalUnit unit); 379 380 /** 381 * {@inheritDoc} 382 * @throws DateTimeException {@inheritDoc} 383 * @throws ArithmeticException {@inheritDoc} 384 */ 385 @Override 386 default ChronoZonedDateTime<D> minus(TemporalAmount amount) { 387 return (ChronoZonedDateTime<D>)(toLocalDate().getChronology().ensureChronoZonedDateTime(Temporal.super.minus(amount))); 388 } 389 390 /** 391 * {@inheritDoc} 392 * @throws DateTimeException {@inheritDoc} 393 * @throws ArithmeticException {@inheritDoc} 394 */ 395 @Override 396 default ChronoZonedDateTime<D> minus(long amountToSubtract, TemporalUnit unit) { 397 return (ChronoZonedDateTime<D>)(toLocalDate().getChronology().ensureChronoZonedDateTime(Temporal.super.minus(amountToSubtract, unit))); 398 } 399 400 //----------------------------------------------------------------------- 401 /** 402 * Queries this date-time using the specified query. 403 * <p> 404 * This queries this date-time using the specified query strategy object. 405 * The {@code TemporalQuery} object defines the logic to be used to 406 * obtain the result. Read the documentation of the query to understand 407 * what the result of this method will be. 408 * <p> 409 * The result of this method is obtained by invoking the 410 * {@link java.time.temporal.TemporalQuery#queryFrom(TemporalAccessor)} method on the 411 * specified query passing {@code this} as the argument. 412 * 413 * @param <R> the type of the result 414 * @param query the query to invoke, not null 415 * @return the query result, null may be returned (defined by the query) 416 * @throws DateTimeException if unable to query (defined by the query) 417 * @throws ArithmeticException if numeric overflow occurs (defined by the query) 418 */ 419 @SuppressWarnings("unchecked") 420 @Override 421 default <R> R query(TemporalQuery<R> query) { 422 if (query == TemporalQuery.zone() || query == TemporalQuery.zoneId()) { 423 return (R) getZone(); 424 } else if (query == TemporalQuery.offset()) { 425 return (R) getOffset(); 426 } else if (query == TemporalQuery.localTime()) { 427 return (R) toLocalTime(); 428 } else if (query == TemporalQuery.chronology()) { 429 return (R) toLocalDate().getChronology(); 430 } else if (query == TemporalQuery.precision()) { 431 return (R) NANOS; 432 } 433 // inline TemporalAccessor.super.query(query) as an optimization 434 // non-JDK classes are not permitted to make this optimization 435 return query.queryFrom(this); 436 } 437 438 /** 439 * Formats this date-time using the specified formatter. 440 * <p> 441 * This date-time will be passed to the formatter to produce a string. 442 * <p> 443 * The default implementation must behave as follows: 444 * <pre> 445 * return formatter.format(this); 446 * </pre> 447 * 448 * @param formatter the formatter to use, not null 449 * @return the formatted date-time string, not null 450 * @throws DateTimeException if an error occurs during printing 451 */ 452 default String format(DateTimeFormatter formatter) { 453 Objects.requireNonNull(formatter, "formatter"); 454 return formatter.format(this); 455 } 456 457 //----------------------------------------------------------------------- 458 /** 459 * Converts this date-time to an {@code Instant}. 460 * <p> 461 * This returns an {@code Instant} representing the same point on the 462 * time-line as this date-time. The calculation combines the 463 * {@linkplain #toLocalDateTime() local date-time} and 464 * {@linkplain #getOffset() offset}. 465 * 466 * @return an {@code Instant} representing the same instant, not null 467 */ 468 default Instant toInstant() { 469 return Instant.ofEpochSecond(toEpochSecond(), toLocalTime().getNano()); 470 } 471 472 /** 473 * Converts this date-time to the number of seconds from the epoch 474 * of 1970-01-01T00:00:00Z. 475 * <p> 476 * This uses the {@linkplain #toLocalDateTime() local date-time} and 477 * {@linkplain #getOffset() offset} to calculate the epoch-second value, 478 * which is the number of elapsed seconds from 1970-01-01T00:00:00Z. 479 * Instants on the time-line after the epoch are positive, earlier are negative. 480 * 481 * @return the number of seconds from the epoch of 1970-01-01T00:00:00Z 482 */ 483 default long toEpochSecond() { 484 long epochDay = toLocalDate().toEpochDay(); 485 long secs = epochDay * 86400 + toLocalTime().toSecondOfDay(); 486 secs -= getOffset().getTotalSeconds(); 487 return secs; 488 } 489 490 //----------------------------------------------------------------------- 491 /** 492 * Compares this date-time to another date-time, including the chronology. 493 * <p> 494 * The comparison is based first on the instant, then on the local date-time, 495 * then on the zone ID, then on the chronology. 496 * It is "consistent with equals", as defined by {@link Comparable}. 497 * <p> 498 * If all the date-time objects being compared are in the same chronology, then the 499 * additional chronology stage is not required. 500 * <p> 501 * This default implementation performs the comparison defined above. 502 * 503 * @param other the other date-time to compare to, not null 504 * @return the comparator value, negative if less, positive if greater 505 */ 506 @Override 507 default int compareTo(ChronoZonedDateTime<?> other) { 508 int cmp = Long.compare(toEpochSecond(), other.toEpochSecond()); 509 if (cmp == 0) { 510 cmp = toLocalTime().getNano() - other.toLocalTime().getNano(); 511 if (cmp == 0) { 512 cmp = toLocalDateTime().compareTo(other.toLocalDateTime()); 513 if (cmp == 0) { 514 cmp = getZone().getId().compareTo(other.getZone().getId()); 515 if (cmp == 0) { 516 cmp = toLocalDate().getChronology().compareTo(other.toLocalDate().getChronology()); 517 } 518 } 519 } 520 } 521 return cmp; 522 } 523 524 /** 525 * Checks if the instant of this date-time is before that of the specified date-time. 526 * <p> 527 * This method differs from the comparison in {@link #compareTo} in that it 528 * only compares the instant of the date-time. This is equivalent to using 529 * {@code dateTime1.toInstant().isBefore(dateTime2.toInstant());}. 530 * <p> 531 * This default implementation performs the comparison based on the epoch-second 532 * and nano-of-second. 533 * 534 * @param other the other date-time to compare to, not null 535 * @return true if this point is before the specified date-time 536 */ 537 default boolean isBefore(ChronoZonedDateTime<?> other) { 538 long thisEpochSec = toEpochSecond(); 539 long otherEpochSec = other.toEpochSecond(); 540 return thisEpochSec < otherEpochSec || 541 (thisEpochSec == otherEpochSec && toLocalTime().getNano() < other.toLocalTime().getNano()); 542 } 543 544 /** 545 * Checks if the instant of this date-time is after that of the specified date-time. 546 * <p> 547 * This method differs from the comparison in {@link #compareTo} in that it 548 * only compares the instant of the date-time. This is equivalent to using 549 * {@code dateTime1.toInstant().isAfter(dateTime2.toInstant());}. 550 * <p> 551 * This default implementation performs the comparison based on the epoch-second 552 * and nano-of-second. 553 * 554 * @param other the other date-time to compare to, not null 555 * @return true if this is after the specified date-time 556 */ 557 default boolean isAfter(ChronoZonedDateTime<?> other) { 558 long thisEpochSec = toEpochSecond(); 559 long otherEpochSec = other.toEpochSecond(); 560 return thisEpochSec > otherEpochSec || 561 (thisEpochSec == otherEpochSec && toLocalTime().getNano() > other.toLocalTime().getNano()); 562 } 563 564 /** 565 * Checks if the instant of this date-time is equal to that of the specified date-time. 566 * <p> 567 * This method differs from the comparison in {@link #compareTo} and {@link #equals} 568 * in that it only compares the instant of the date-time. This is equivalent to using 569 * {@code dateTime1.toInstant().equals(dateTime2.toInstant());}. 570 * <p> 571 * This default implementation performs the comparison based on the epoch-second 572 * and nano-of-second. 573 * 574 * @param other the other date-time to compare to, not null 575 * @return true if the instant equals the instant of the specified date-time 576 */ 577 default boolean isEqual(ChronoZonedDateTime<?> other) { 578 return toEpochSecond() == other.toEpochSecond() && 579 toLocalTime().getNano() == other.toLocalTime().getNano(); 580 } 581 582 //----------------------------------------------------------------------- 583 /** 584 * Checks if this date-time is equal to another date-time. 585 * <p> 586 * The comparison is based on the offset date-time and the zone. 587 * To compare for the same instant on the time-line, use {@link #compareTo}. 588 * Only objects of type {@code ChronoZonedDateTime} are compared, other types return false. 589 * 590 * @param obj the object to check, null returns false 591 * @return true if this is equal to the other date-time 592 */ 593 @Override 594 boolean equals(Object obj); 595 596 /** 597 * A hash code for this date-time. 598 * 599 * @return a suitable hash code 600 */ 601 @Override 602 int hashCode(); 603 604 //----------------------------------------------------------------------- 605 /** 606 * Outputs this date-time as a {@code String}. 607 * <p> 608 * The output will include the full zoned date-time. 609 * 610 * @return a string representation of this date-time, not null 611 */ 612 @Override 613 String toString(); 614 615 } |