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; 63 64 import static java.time.LocalTime.NANOS_PER_HOUR; 65 import static java.time.LocalTime.NANOS_PER_MINUTE; 66 import static java.time.LocalTime.NANOS_PER_SECOND; 67 import static java.time.LocalTime.SECONDS_PER_DAY; 68 import static java.time.temporal.ChronoField.NANO_OF_DAY; 69 import static java.time.temporal.ChronoField.OFFSET_SECONDS; 70 import static java.time.temporal.ChronoUnit.NANOS; 71 72 import java.io.IOException; 73 import java.io.InvalidObjectException; 74 import java.io.ObjectInput; 75 import java.io.ObjectOutput; 76 import java.io.ObjectStreamException; 77 import java.io.Serializable; 78 import java.time.format.DateTimeFormatter; 79 import java.time.format.DateTimeParseException; 80 import java.time.temporal.ChronoField; 81 import java.time.temporal.ChronoUnit; 82 import java.time.temporal.Temporal; 83 import java.time.temporal.TemporalAccessor; 84 import java.time.temporal.TemporalAdjuster; 85 import java.time.temporal.TemporalAmount; 86 import java.time.temporal.TemporalField; 87 import java.time.temporal.TemporalQuery; 88 import java.time.temporal.TemporalUnit; 89 import java.time.temporal.UnsupportedTemporalTypeException; 90 import java.time.temporal.ValueRange; 91 import java.time.zone.ZoneRules; 92 import java.util.Objects; 93 94 /** 95 * A time with an offset from UTC/Greenwich in the ISO-8601 calendar system, 96 * such as {@code 10:15:30+01:00}. 97 * <p> 98 * {@code OffsetTime} is an immutable date-time object that represents a time, often 99 * viewed as hour-minute-second-offset. 100 * This class stores all time fields, to a precision of nanoseconds, 101 * as well as a zone offset. 102 * For example, the value "13:45.30.123456789+02:00" can be stored 103 * in an {@code OffsetTime}. 104 * 105 * <h3>Specification for implementors</h3> 106 * This class is immutable and thread-safe. 107 * 108 * @since 1.8 109 */ 110 public final class OffsetTime 111 implements Temporal, TemporalAdjuster, Comparable<OffsetTime>, Serializable { 112 113 /** 114 * The minimum supported {@code OffsetTime}, '00:00:00+18:00'. 115 * This is the time of midnight at the start of the day in the maximum offset 116 * (larger offsets are earlier on the time-line). 117 * This combines {@link LocalTime#MIN} and {@link ZoneOffset#MAX}. 118 * This could be used by an application as a "far past" date. 119 */ 120 public static final OffsetTime MIN = LocalTime.MIN.atOffset(ZoneOffset.MAX); 121 /** 122 * The maximum supported {@code OffsetTime}, '23:59:59.999999999-18:00'. 123 * This is the time just before midnight at the end of the day in the minimum offset 124 * (larger negative offsets are later on the time-line). 125 * This combines {@link LocalTime#MAX} and {@link ZoneOffset#MIN}. 126 * This could be used by an application as a "far future" date. 127 */ 128 public static final OffsetTime MAX = LocalTime.MAX.atOffset(ZoneOffset.MIN); 129 130 /** 131 * Serialization version. 132 */ 133 private static final long serialVersionUID = 7264499704384272492L; 134 135 /** 136 * The local date-time. 137 */ 138 private final LocalTime time; 139 /** 140 * The offset from UTC/Greenwich. 141 */ 142 private final ZoneOffset offset; 143 144 //----------------------------------------------------------------------- 145 /** 146 * Obtains the current time from the system clock in the default time-zone. 147 * <p> 148 * This will query the {@link java.time.Clock#systemDefaultZone() system clock} in the default 149 * time-zone to obtain the current time. 150 * The offset will be calculated from the time-zone in the clock. 151 * <p> 152 * Using this method will prevent the ability to use an alternate clock for testing 153 * because the clock is hard-coded. 154 * 155 * @return the current time using the system clock, not null 156 */ 157 public static OffsetTime now() { 158 return now(Clock.systemDefaultZone()); 159 } 160 161 /** 162 * Obtains the current time from the system clock in the specified time-zone. 163 * <p> 164 * This will query the {@link Clock#system(java.time.ZoneId) system clock} to obtain the current time. 165 * Specifying the time-zone avoids dependence on the default time-zone. 166 * The offset will be calculated from the specified time-zone. 167 * <p> 168 * Using this method will prevent the ability to use an alternate clock for testing 169 * because the clock is hard-coded. 170 * 171 * @param zone the zone ID to use, not null 172 * @return the current time using the system clock, not null 173 */ 174 public static OffsetTime now(ZoneId zone) { 175 return now(Clock.system(zone)); 176 } 177 178 /** 179 * Obtains the current time from the specified clock. 180 * <p> 181 * This will query the specified clock to obtain the current time. 182 * The offset will be calculated from the time-zone in the clock. 183 * <p> 184 * Using this method allows the use of an alternate clock for testing. 185 * The alternate clock may be introduced using {@link Clock dependency injection}. 186 * 187 * @param clock the clock to use, not null 188 * @return the current time, not null 189 */ 190 public static OffsetTime now(Clock clock) { 191 Objects.requireNonNull(clock, "clock"); 192 final Instant now = clock.instant(); // called once 193 return ofInstant(now, clock.getZone().getRules().getOffset(now)); 194 } 195 196 //----------------------------------------------------------------------- 197 /** 198 * Obtains an instance of {@code OffsetTime} from a local time and an offset. 199 * 200 * @param time the local time, not null 201 * @param offset the zone offset, not null 202 * @return the offset time, not null 203 */ 204 public static OffsetTime of(LocalTime time, ZoneOffset offset) { 205 return new OffsetTime(time, offset); 206 } 207 208 /** 209 * Obtains an instance of {@code OffsetTime} from an hour, minute, second and nanosecond. 210 * <p> 211 * This creates an offset time with the four specified fields. 212 * <p> 213 * This method exists primarily for writing test cases. 214 * Non test-code will typically use other methods to create an offset time. 215 * {@code LocalTime} has two additional convenience variants of the 216 * equivalent factory method taking fewer arguments. 217 * They are not provided here to reduce the footprint of the API. 218 * 219 * @param hour the hour-of-day to represent, from 0 to 23 220 * @param minute the minute-of-hour to represent, from 0 to 59 221 * @param second the second-of-minute to represent, from 0 to 59 222 * @param nanoOfSecond the nano-of-second to represent, from 0 to 999,999,999 223 * @param offset the zone offset, not null 224 * @return the offset time, not null 225 * @throws DateTimeException if the value of any field is out of range 226 */ 227 public static OffsetTime of(int hour, int minute, int second, int nanoOfSecond, ZoneOffset offset) { 228 return new OffsetTime(LocalTime.of(hour, minute, second, nanoOfSecond), offset); 229 } 230 231 //----------------------------------------------------------------------- 232 /** 233 * Obtains an instance of {@code OffsetTime} from an {@code Instant} and zone ID. 234 * <p> 235 * This creates an offset time with the same instant as that specified. 236 * Finding the offset from UTC/Greenwich is simple as there is only one valid 237 * offset for each instant. 238 * <p> 239 * The date component of the instant is dropped during the conversion. 240 * This means that the conversion can never fail due to the instant being 241 * out of the valid range of dates. 242 * 243 * @param instant the instant to create the time from, not null 244 * @param zone the time-zone, which may be an offset, not null 245 * @return the offset time, not null 246 */ 247 public static OffsetTime ofInstant(Instant instant, ZoneId zone) { 248 Objects.requireNonNull(instant, "instant"); 249 Objects.requireNonNull(zone, "zone"); 250 ZoneRules rules = zone.getRules(); 251 ZoneOffset offset = rules.getOffset(instant); 252 long localSecond = instant.getEpochSecond() + offset.getTotalSeconds(); // overflow caught later 253 int secsOfDay = (int) Math.floorMod(localSecond, SECONDS_PER_DAY); 254 LocalTime time = LocalTime.ofNanoOfDay(secsOfDay * NANOS_PER_SECOND + instant.getNano()); 255 return new OffsetTime(time, offset); 256 } 257 258 //----------------------------------------------------------------------- 259 /** 260 * Obtains an instance of {@code OffsetTime} from a temporal object. 261 * <p> 262 * This obtains an offset time based on the specified temporal. 263 * A {@code TemporalAccessor} represents an arbitrary set of date and time information, 264 * which this factory converts to an instance of {@code OffsetTime}. 265 * <p> 266 * The conversion extracts and combines the {@code ZoneOffset} and the 267 * {@code LocalTime} from the temporal object. 268 * Implementations are permitted to perform optimizations such as accessing 269 * those fields that are equivalent to the relevant objects. 270 * <p> 271 * This method matches the signature of the functional interface {@link TemporalQuery} 272 * allowing it to be used in queries via method reference, {@code OffsetTime::from}. 273 * 274 * @param temporal the temporal object to convert, not null 275 * @return the offset time, not null 276 * @throws DateTimeException if unable to convert to an {@code OffsetTime} 277 */ 278 public static OffsetTime from(TemporalAccessor temporal) { 279 if (temporal instanceof OffsetTime) { 280 return (OffsetTime) temporal; 281 } 282 try { 283 LocalTime time = LocalTime.from(temporal); 284 ZoneOffset offset = ZoneOffset.from(temporal); 285 return new OffsetTime(time, offset); 286 } catch (DateTimeException ex) { 287 throw new DateTimeException("Unable to obtain OffsetTime from TemporalAccessor: " + temporal.getClass(), ex); 288 } 289 } 290 291 //----------------------------------------------------------------------- 292 /** 293 * Obtains an instance of {@code OffsetTime} from a text string such as {@code 10:15:30+01:00}. 294 * <p> 295 * The string must represent a valid time and is parsed using 296 * {@link java.time.format.DateTimeFormatter#ISO_OFFSET_TIME}. 297 * 298 * @param text the text to parse such as "10:15:30+01:00", not null 299 * @return the parsed local time, not null 300 * @throws DateTimeParseException if the text cannot be parsed 301 */ 302 public static OffsetTime parse(CharSequence text) { 303 return parse(text, DateTimeFormatter.ISO_OFFSET_TIME); 304 } 305 306 /** 307 * Obtains an instance of {@code OffsetTime} from a text string using a specific formatter. 308 * <p> 309 * The text is parsed using the formatter, returning a time. 310 * 311 * @param text the text to parse, not null 312 * @param formatter the formatter to use, not null 313 * @return the parsed offset time, not null 314 * @throws DateTimeParseException if the text cannot be parsed 315 */ 316 public static OffsetTime parse(CharSequence text, DateTimeFormatter formatter) { 317 Objects.requireNonNull(formatter, "formatter"); 318 return formatter.parse(text, OffsetTime::from); 319 } 320 321 //----------------------------------------------------------------------- 322 /** 323 * Constructor. 324 * 325 * @param time the local time, not null 326 * @param offset the zone offset, not null 327 */ 328 private OffsetTime(LocalTime time, ZoneOffset offset) { 329 this.time = Objects.requireNonNull(time, "time"); 330 this.offset = Objects.requireNonNull(offset, "offset"); 331 } 332 333 /** 334 * Returns a new time based on this one, returning {@code this} where possible. 335 * 336 * @param time the time to create with, not null 337 * @param offset the zone offset to create with, not null 338 */ 339 private OffsetTime with(LocalTime time, ZoneOffset offset) { 340 if (this.time == time && this.offset.equals(offset)) { 341 return this; 342 } 343 return new OffsetTime(time, offset); 344 } 345 346 //----------------------------------------------------------------------- 347 /** 348 * Checks if the specified field is supported. 349 * <p> 350 * This checks if this time can be queried for the specified field. 351 * If false, then calling the {@link #range(TemporalField) range} and 352 * {@link #get(TemporalField) get} methods will throw an exception. 353 * <p> 354 * If the field is a {@link ChronoField} then the query is implemented here. 355 * The supported fields are: 356 * <ul> 357 * <li>{@code NANO_OF_SECOND} 358 * <li>{@code NANO_OF_DAY} 359 * <li>{@code MICRO_OF_SECOND} 360 * <li>{@code MICRO_OF_DAY} 361 * <li>{@code MILLI_OF_SECOND} 362 * <li>{@code MILLI_OF_DAY} 363 * <li>{@code SECOND_OF_MINUTE} 364 * <li>{@code SECOND_OF_DAY} 365 * <li>{@code MINUTE_OF_HOUR} 366 * <li>{@code MINUTE_OF_DAY} 367 * <li>{@code HOUR_OF_AMPM} 368 * <li>{@code CLOCK_HOUR_OF_AMPM} 369 * <li>{@code HOUR_OF_DAY} 370 * <li>{@code CLOCK_HOUR_OF_DAY} 371 * <li>{@code AMPM_OF_DAY} 372 * <li>{@code OFFSET_SECONDS} 373 * </ul> 374 * All other {@code ChronoField} instances will return false. 375 * <p> 376 * If the field is not a {@code ChronoField}, then the result of this method 377 * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)} 378 * passing {@code this} as the argument. 379 * Whether the field is supported is determined by the field. 380 * 381 * @param field the field to check, null returns false 382 * @return true if the field is supported on this time, false if not 383 */ 384 @Override 385 public boolean isSupported(TemporalField field) { 386 if (field instanceof ChronoField) { 387 return field.isTimeBased() || field == OFFSET_SECONDS; 388 } 389 return field != null && field.isSupportedBy(this); 390 } 391 392 /** 393 * Gets the range of valid values for the specified field. 394 * <p> 395 * The range object expresses the minimum and maximum valid values for a field. 396 * This time is used to enhance the accuracy of the returned range. 397 * If it is not possible to return the range, because the field is not supported 398 * or for some other reason, an exception is thrown. 399 * <p> 400 * If the field is a {@link ChronoField} then the query is implemented here. 401 * The {@link #isSupported(TemporalField) supported fields} will return 402 * appropriate range instances. 403 * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}. 404 * <p> 405 * If the field is not a {@code ChronoField}, then the result of this method 406 * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)} 407 * passing {@code this} as the argument. 408 * Whether the range can be obtained is determined by the field. 409 * 410 * @param field the field to query the range for, not null 411 * @return the range of valid values for the field, not null 412 * @throws DateTimeException if the range for the field cannot be obtained 413 * @throws UnsupportedTemporalTypeException if the field is not supported 414 */ 415 @Override 416 public ValueRange range(TemporalField field) { 417 if (field instanceof ChronoField) { 418 if (field == OFFSET_SECONDS) { 419 return field.range(); 420 } 421 return time.range(field); 422 } 423 return field.rangeRefinedBy(this); 424 } 425 426 /** 427 * Gets the value of the specified field from this time as an {@code int}. 428 * <p> 429 * This queries this time for the value for the specified field. 430 * The returned value will always be within the valid range of values for the field. 431 * If it is not possible to return the value, because the field is not supported 432 * or for some other reason, an exception is thrown. 433 * <p> 434 * If the field is a {@link ChronoField} then the query is implemented here. 435 * The {@link #isSupported(TemporalField) supported fields} will return valid 436 * values based on this time, except {@code NANO_OF_DAY} and {@code MICRO_OF_DAY} 437 * which are too large to fit in an {@code int} and throw a {@code DateTimeException}. 438 * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}. 439 * <p> 440 * If the field is not a {@code ChronoField}, then the result of this method 441 * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} 442 * passing {@code this} as the argument. Whether the value can be obtained, 443 * and what the value represents, is determined by the field. 444 * 445 * @param field the field to get, not null 446 * @return the value for the field 447 * @throws DateTimeException if a value for the field cannot be obtained or 448 * the value is outside the range of valid values for the field 449 * @throws UnsupportedTemporalTypeException if the field is not supported or 450 * the range of values exceeds an {@code int} 451 * @throws ArithmeticException if numeric overflow occurs 452 */ 453 @Override // override for Javadoc 454 public int get(TemporalField field) { 455 return Temporal.super.get(field); 456 } 457 458 /** 459 * Gets the value of the specified field from this time as a {@code long}. 460 * <p> 461 * This queries this time for the value for the specified field. 462 * If it is not possible to return the value, because the field is not supported 463 * or for some other reason, an exception is thrown. 464 * <p> 465 * If the field is a {@link ChronoField} then the query is implemented here. 466 * The {@link #isSupported(TemporalField) supported fields} will return valid 467 * values based on this time. 468 * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}. 469 * <p> 470 * If the field is not a {@code ChronoField}, then the result of this method 471 * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} 472 * passing {@code this} as the argument. Whether the value can be obtained, 473 * and what the value represents, is determined by the field. 474 * 475 * @param field the field to get, not null 476 * @return the value for the field 477 * @throws DateTimeException if a value for the field cannot be obtained 478 * @throws UnsupportedTemporalTypeException if the field is not supported 479 * @throws ArithmeticException if numeric overflow occurs 480 */ 481 @Override 482 public long getLong(TemporalField field) { 483 if (field instanceof ChronoField) { 484 if (field == OFFSET_SECONDS) { 485 return offset.getTotalSeconds(); 486 } 487 return time.getLong(field); 488 } 489 return field.getFrom(this); 490 } 491 492 //----------------------------------------------------------------------- 493 /** 494 * Gets the zone offset, such as '+01:00'. 495 * <p> 496 * This is the offset of the local time from UTC/Greenwich. 497 * 498 * @return the zone offset, not null 499 */ 500 public ZoneOffset getOffset() { 501 return offset; 502 } 503 504 /** 505 * Returns a copy of this {@code OffsetTime} with the specified offset ensuring 506 * that the result has the same local time. 507 * <p> 508 * This method returns an object with the same {@code LocalTime} and the specified {@code ZoneOffset}. 509 * No calculation is needed or performed. 510 * For example, if this time represents {@code 10:30+02:00} and the offset specified is 511 * {@code +03:00}, then this method will return {@code 10:30+03:00}. 512 * <p> 513 * To take into account the difference between the offsets, and adjust the time fields, 514 * use {@link #withOffsetSameInstant}. 515 * <p> 516 * This instance is immutable and unaffected by this method call. 517 * 518 * @param offset the zone offset to change to, not null 519 * @return an {@code OffsetTime} based on this time with the requested offset, not null 520 */ 521 public OffsetTime withOffsetSameLocal(ZoneOffset offset) { 522 return offset != null && offset.equals(this.offset) ? this : new OffsetTime(time, offset); 523 } 524 525 /** 526 * Returns a copy of this {@code OffsetTime} with the specified offset ensuring 527 * that the result is at the same instant on an implied day. 528 * <p> 529 * This method returns an object with the specified {@code ZoneOffset} and a {@code LocalTime} 530 * adjusted by the difference between the two offsets. 531 * This will result in the old and new objects representing the same instant an an implied day. 532 * This is useful for finding the local time in a different offset. 533 * For example, if this time represents {@code 10:30+02:00} and the offset specified is 534 * {@code +03:00}, then this method will return {@code 11:30+03:00}. 535 * <p> 536 * To change the offset without adjusting the local time use {@link #withOffsetSameLocal}. 537 * <p> 538 * This instance is immutable and unaffected by this method call. 539 * 540 * @param offset the zone offset to change to, not null 541 * @return an {@code OffsetTime} based on this time with the requested offset, not null 542 */ 543 public OffsetTime withOffsetSameInstant(ZoneOffset offset) { 544 if (offset.equals(this.offset)) { 545 return this; 546 } 547 int difference = offset.getTotalSeconds() - this.offset.getTotalSeconds(); 548 LocalTime adjusted = time.plusSeconds(difference); 549 return new OffsetTime(adjusted, offset); 550 } 551 552 //----------------------------------------------------------------------- 553 /** 554 * Gets the {@code LocalTime} part of this date-time. 555 * <p> 556 * This returns a {@code LocalTime} with the same hour, minute, second and 557 * nanosecond as this date-time. 558 * 559 * @return the time part of this date-time, not null 560 */ 561 public LocalTime toLocalTime() { 562 return time; 563 } 564 565 //----------------------------------------------------------------------- 566 /** 567 * Gets the hour-of-day field. 568 * 569 * @return the hour-of-day, from 0 to 23 570 */ 571 public int getHour() { 572 return time.getHour(); 573 } 574 575 /** 576 * Gets the minute-of-hour field. 577 * 578 * @return the minute-of-hour, from 0 to 59 579 */ 580 public int getMinute() { 581 return time.getMinute(); 582 } 583 584 /** 585 * Gets the second-of-minute field. 586 * 587 * @return the second-of-minute, from 0 to 59 588 */ 589 public int getSecond() { 590 return time.getSecond(); 591 } 592 593 /** 594 * Gets the nano-of-second field. 595 * 596 * @return the nano-of-second, from 0 to 999,999,999 597 */ 598 public int getNano() { 599 return time.getNano(); 600 } 601 602 //----------------------------------------------------------------------- 603 /** 604 * Returns an adjusted copy of this time. 605 * <p> 606 * This returns an {@code OffsetTime}, based on this one, with the time adjusted. 607 * The adjustment takes place using the specified adjuster strategy object. 608 * Read the documentation of the adjuster to understand what adjustment will be made. 609 * <p> 610 * A simple adjuster might simply set the one of the fields, such as the hour field. 611 * A more complex adjuster might set the time to the last hour of the day. 612 * <p> 613 * The classes {@link LocalTime} and {@link ZoneOffset} implement {@code TemporalAdjuster}, 614 * thus this method can be used to change the time or offset: 615 * <pre> 616 * result = offsetTime.with(time); 617 * result = offsetTime.with(offset); 618 * </pre> 619 * <p> 620 * The result of this method is obtained by invoking the 621 * {@link TemporalAdjuster#adjustInto(Temporal)} method on the 622 * specified adjuster passing {@code this} as the argument. 623 * <p> 624 * This instance is immutable and unaffected by this method call. 625 * 626 * @param adjuster the adjuster to use, not null 627 * @return an {@code OffsetTime} based on {@code this} with the adjustment made, not null 628 * @throws DateTimeException if the adjustment cannot be made 629 * @throws ArithmeticException if numeric overflow occurs 630 */ 631 @Override 632 public OffsetTime with(TemporalAdjuster adjuster) { 633 // optimizations 634 if (adjuster instanceof LocalTime) { 635 return with((LocalTime) adjuster, offset); 636 } else if (adjuster instanceof ZoneOffset) { 637 return with(time, (ZoneOffset) adjuster); 638 } else if (adjuster instanceof OffsetTime) { 639 return (OffsetTime) adjuster; 640 } 641 return (OffsetTime) adjuster.adjustInto(this); 642 } 643 644 /** 645 * Returns a copy of this time with the specified field set to a new value. 646 * <p> 647 * This returns an {@code OffsetTime}, based on this one, with the value 648 * for the specified field changed. 649 * This can be used to change any supported field, such as the hour, minute or second. 650 * If it is not possible to set the value, because the field is not supported or for 651 * some other reason, an exception is thrown. 652 * <p> 653 * If the field is a {@link ChronoField} then the adjustment is implemented here. 654 * <p> 655 * The {@code OFFSET_SECONDS} field will return a time with the specified offset. 656 * The local time is unaltered. If the new offset value is outside the valid range 657 * then a {@code DateTimeException} will be thrown. 658 * <p> 659 * The other {@link #isSupported(TemporalField) supported fields} will behave as per 660 * the matching method on {@link LocalTime#with(TemporalField, long)} LocalTime}. 661 * In this case, the offset is not part of the calculation and will be unchanged. 662 * <p> 663 * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}. 664 * <p> 665 * If the field is not a {@code ChronoField}, then the result of this method 666 * is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)} 667 * passing {@code this} as the argument. In this case, the field determines 668 * whether and how to adjust the instant. 669 * <p> 670 * This instance is immutable and unaffected by this method call. 671 * 672 * @param field the field to set in the result, not null 673 * @param newValue the new value of the field in the result 674 * @return an {@code OffsetTime} based on {@code this} with the specified field set, not null 675 * @throws DateTimeException if the field cannot be set 676 * @throws UnsupportedTemporalTypeException if the field is not supported 677 * @throws ArithmeticException if numeric overflow occurs 678 */ 679 @Override 680 public OffsetTime with(TemporalField field, long newValue) { 681 if (field instanceof ChronoField) { 682 if (field == OFFSET_SECONDS) { 683 ChronoField f = (ChronoField) field; 684 return with(time, ZoneOffset.ofTotalSeconds(f.checkValidIntValue(newValue))); 685 } 686 return with(time.with(field, newValue), offset); 687 } 688 return field.adjustInto(this, newValue); 689 } 690 691 //----------------------------------------------------------------------- 692 /** 693 * Returns a copy of this {@code OffsetTime} with the hour-of-day value altered. 694 * <p> 695 * The offset does not affect the calculation and will be the same in the result. 696 * <p> 697 * This instance is immutable and unaffected by this method call. 698 * 699 * @param hour the hour-of-day to set in the result, from 0 to 23 700 * @return an {@code OffsetTime} based on this time with the requested hour, not null 701 * @throws DateTimeException if the hour value is invalid 702 */ 703 public OffsetTime withHour(int hour) { 704 return with(time.withHour(hour), offset); 705 } 706 707 /** 708 * Returns a copy of this {@code OffsetTime} with the minute-of-hour value altered. 709 * <p> 710 * The offset does not affect the calculation and will be the same in the result. 711 * <p> 712 * This instance is immutable and unaffected by this method call. 713 * 714 * @param minute the minute-of-hour to set in the result, from 0 to 59 715 * @return an {@code OffsetTime} based on this time with the requested minute, not null 716 * @throws DateTimeException if the minute value is invalid 717 */ 718 public OffsetTime withMinute(int minute) { 719 return with(time.withMinute(minute), offset); 720 } 721 722 /** 723 * Returns a copy of this {@code OffsetTime} with the second-of-minute value altered. 724 * <p> 725 * The offset does not affect the calculation and will be the same in the result. 726 * <p> 727 * This instance is immutable and unaffected by this method call. 728 * 729 * @param second the second-of-minute to set in the result, from 0 to 59 730 * @return an {@code OffsetTime} based on this time with the requested second, not null 731 * @throws DateTimeException if the second value is invalid 732 */ 733 public OffsetTime withSecond(int second) { 734 return with(time.withSecond(second), offset); 735 } 736 737 /** 738 * Returns a copy of this {@code OffsetTime} with the nano-of-second value altered. 739 * <p> 740 * The offset does not affect the calculation and will be the same in the result. 741 * <p> 742 * This instance is immutable and unaffected by this method call. 743 * 744 * @param nanoOfSecond the nano-of-second to set in the result, from 0 to 999,999,999 745 * @return an {@code OffsetTime} based on this time with the requested nanosecond, not null 746 * @throws DateTimeException if the nanos value is invalid 747 */ 748 public OffsetTime withNano(int nanoOfSecond) { 749 return with(time.withNano(nanoOfSecond), offset); 750 } 751 752 //----------------------------------------------------------------------- 753 /** 754 * Returns a copy of this {@code OffsetTime} with the time truncated. 755 * <p> 756 * Truncation returns a copy of the original time with fields 757 * smaller than the specified unit set to zero. 758 * For example, truncating with the {@link ChronoUnit#MINUTES minutes} unit 759 * will set the second-of-minute and nano-of-second field to zero. 760 * <p> 761 * The unit must have a {@linkplain TemporalUnit#getDuration() duration} 762 * that divides into the length of a standard day without remainder. 763 * This includes all supplied time units on {@link ChronoUnit} and 764 * {@link ChronoUnit#DAYS DAYS}. Other units throw an exception. 765 * <p> 766 * The offset does not affect the calculation and will be the same in the result. 767 * <p> 768 * This instance is immutable and unaffected by this method call. 769 * 770 * @param unit the unit to truncate to, not null 771 * @return an {@code OffsetTime} based on this time with the time truncated, not null 772 * @throws DateTimeException if unable to truncate 773 * @throws UnsupportedTemporalTypeException if the unit is not supported 774 */ 775 public OffsetTime truncatedTo(TemporalUnit unit) { 776 return with(time.truncatedTo(unit), offset); 777 } 778 779 //----------------------------------------------------------------------- 780 /** 781 * Returns a copy of this time with the specified amount added. 782 * <p> 783 * This returns an {@code OffsetTime}, based on this one, with the specified amount added. 784 * The amount is typically {@link Duration} but may be any other type implementing 785 * the {@link TemporalAmount} interface. 786 * <p> 787 * The calculation is delegated to the amount object by calling 788 * {@link TemporalAmount#addTo(Temporal)}. The amount implementation is free 789 * to implement the addition in any way it wishes, however it typically 790 * calls back to {@link #plus(long, TemporalUnit)}. Consult the documentation 791 * of the amount implementation to determine if it can be successfully added. 792 * <p> 793 * This instance is immutable and unaffected by this method call. 794 * 795 * @param amountToAdd the amount to add, not null 796 * @return an {@code OffsetTime} based on this time with the addition made, not null 797 * @throws DateTimeException if the addition cannot be made 798 * @throws ArithmeticException if numeric overflow occurs 799 */ 800 @Override 801 public OffsetTime plus(TemporalAmount amountToAdd) { 802 return (OffsetTime) amountToAdd.addTo(this); 803 } 804 805 /** 806 * Returns a copy of this time with the specified amount added. 807 * <p> 808 * This returns an {@code OffsetTime}, based on this one, with the amount 809 * in terms of the unit added. If it is not possible to add the amount, because the 810 * unit is not supported or for some other reason, an exception is thrown. 811 * <p> 812 * If the field is a {@link ChronoUnit} then the addition is implemented by 813 * {@link LocalTime#plus(long, TemporalUnit)}. 814 * The offset is not part of the calculation and will be unchanged in the result. 815 * <p> 816 * If the field is not a {@code ChronoUnit}, then the result of this method 817 * is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)} 818 * passing {@code this} as the argument. In this case, the unit determines 819 * whether and how to perform the addition. 820 * <p> 821 * This instance is immutable and unaffected by this method call. 822 * 823 * @param amountToAdd the amount of the unit to add to the result, may be negative 824 * @param unit the unit of the amount to add, not null 825 * @return an {@code OffsetTime} based on this time with the specified amount added, not null 826 * @throws DateTimeException if the addition cannot be made 827 * @throws UnsupportedTemporalTypeException if the unit is not supported 828 * @throws ArithmeticException if numeric overflow occurs 829 */ 830 @Override 831 public OffsetTime plus(long amountToAdd, TemporalUnit unit) { 832 if (unit instanceof ChronoUnit) { 833 return with(time.plus(amountToAdd, unit), offset); 834 } 835 return unit.addTo(this, amountToAdd); 836 } 837 838 //----------------------------------------------------------------------- 839 /** 840 * Returns a copy of this {@code OffsetTime} with the specified period in hours added. 841 * <p> 842 * This adds the specified number of hours to this time, returning a new time. 843 * The calculation wraps around midnight. 844 * <p> 845 * This instance is immutable and unaffected by this method call. 846 * 847 * @param hours the hours to add, may be negative 848 * @return an {@code OffsetTime} based on this time with the hours added, not null 849 */ 850 public OffsetTime plusHours(long hours) { 851 return with(time.plusHours(hours), offset); 852 } 853 854 /** 855 * Returns a copy of this {@code OffsetTime} with the specified period in minutes added. 856 * <p> 857 * This adds the specified number of minutes to this time, returning a new time. 858 * The calculation wraps around midnight. 859 * <p> 860 * This instance is immutable and unaffected by this method call. 861 * 862 * @param minutes the minutes to add, may be negative 863 * @return an {@code OffsetTime} based on this time with the minutes added, not null 864 */ 865 public OffsetTime plusMinutes(long minutes) { 866 return with(time.plusMinutes(minutes), offset); 867 } 868 869 /** 870 * Returns a copy of this {@code OffsetTime} with the specified period in seconds added. 871 * <p> 872 * This adds the specified number of seconds to this time, returning a new time. 873 * The calculation wraps around midnight. 874 * <p> 875 * This instance is immutable and unaffected by this method call. 876 * 877 * @param seconds the seconds to add, may be negative 878 * @return an {@code OffsetTime} based on this time with the seconds added, not null 879 */ 880 public OffsetTime plusSeconds(long seconds) { 881 return with(time.plusSeconds(seconds), offset); 882 } 883 884 /** 885 * Returns a copy of this {@code OffsetTime} with the specified period in nanoseconds added. 886 * <p> 887 * This adds the specified number of nanoseconds to this time, returning a new time. 888 * The calculation wraps around midnight. 889 * <p> 890 * This instance is immutable and unaffected by this method call. 891 * 892 * @param nanos the nanos to add, may be negative 893 * @return an {@code OffsetTime} based on this time with the nanoseconds added, not null 894 */ 895 public OffsetTime plusNanos(long nanos) { 896 return with(time.plusNanos(nanos), offset); 897 } 898 899 //----------------------------------------------------------------------- 900 /** 901 * Returns a copy of this time with the specified amount subtracted. 902 * <p> 903 * This returns an {@code OffsetTime}, based on this one, with the specified amount subtracted. 904 * The amount is typically {@link Duration} but may be any other type implementing 905 * the {@link TemporalAmount} interface. 906 * <p> 907 * The calculation is delegated to the amount object by calling 908 * {@link TemporalAmount#subtractFrom(Temporal)}. The amount implementation is free 909 * to implement the subtraction in any way it wishes, however it typically 910 * calls back to {@link #minus(long, TemporalUnit)}. Consult the documentation 911 * of the amount implementation to determine if it can be successfully subtracted. 912 * <p> 913 * This instance is immutable and unaffected by this method call. 914 * 915 * @param amountToSubtract the amount to subtract, not null 916 * @return an {@code OffsetTime} based on this time with the subtraction made, not null 917 * @throws DateTimeException if the subtraction cannot be made 918 * @throws ArithmeticException if numeric overflow occurs 919 */ 920 @Override 921 public OffsetTime minus(TemporalAmount amountToSubtract) { 922 return (OffsetTime) amountToSubtract.subtractFrom(this); 923 } 924 925 /** 926 * Returns a copy of this time with the specified amount subtracted. 927 * <p> 928 * This returns an {@code OffsetTime}, based on this one, with the amount 929 * in terms of the unit subtracted. If it is not possible to subtract the amount, 930 * because the unit is not supported or for some other reason, an exception is thrown. 931 * <p> 932 * This method is equivalent to {@link #plus(long, TemporalUnit)} with the amount negated. 933 * See that method for a full description of how addition, and thus subtraction, works. 934 * <p> 935 * This instance is immutable and unaffected by this method call. 936 * 937 * @param amountToSubtract the amount of the unit to subtract from the result, may be negative 938 * @param unit the unit of the amount to subtract, not null 939 * @return an {@code OffsetTime} based on this time with the specified amount subtracted, not null 940 * @throws DateTimeException if the subtraction cannot be made 941 * @throws UnsupportedTemporalTypeException if the unit is not supported 942 * @throws ArithmeticException if numeric overflow occurs 943 */ 944 @Override 945 public OffsetTime minus(long amountToSubtract, TemporalUnit unit) { 946 return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit)); 947 } 948 949 //----------------------------------------------------------------------- 950 /** 951 * Returns a copy of this {@code OffsetTime} with the specified period in hours subtracted. 952 * <p> 953 * This subtracts the specified number of hours from this time, returning a new time. 954 * The calculation wraps around midnight. 955 * <p> 956 * This instance is immutable and unaffected by this method call. 957 * 958 * @param hours the hours to subtract, may be negative 959 * @return an {@code OffsetTime} based on this time with the hours subtracted, not null 960 */ 961 public OffsetTime minusHours(long hours) { 962 return with(time.minusHours(hours), offset); 963 } 964 965 /** 966 * Returns a copy of this {@code OffsetTime} with the specified period in minutes subtracted. 967 * <p> 968 * This subtracts the specified number of minutes from this time, returning a new time. 969 * The calculation wraps around midnight. 970 * <p> 971 * This instance is immutable and unaffected by this method call. 972 * 973 * @param minutes the minutes to subtract, may be negative 974 * @return an {@code OffsetTime} based on this time with the minutes subtracted, not null 975 */ 976 public OffsetTime minusMinutes(long minutes) { 977 return with(time.minusMinutes(minutes), offset); 978 } 979 980 /** 981 * Returns a copy of this {@code OffsetTime} with the specified period in seconds subtracted. 982 * <p> 983 * This subtracts the specified number of seconds from this time, returning a new time. 984 * The calculation wraps around midnight. 985 * <p> 986 * This instance is immutable and unaffected by this method call. 987 * 988 * @param seconds the seconds to subtract, may be negative 989 * @return an {@code OffsetTime} based on this time with the seconds subtracted, not null 990 */ 991 public OffsetTime minusSeconds(long seconds) { 992 return with(time.minusSeconds(seconds), offset); 993 } 994 995 /** 996 * Returns a copy of this {@code OffsetTime} with the specified period in nanoseconds subtracted. 997 * <p> 998 * This subtracts the specified number of nanoseconds from this time, returning a new time. 999 * The calculation wraps around midnight. 1000 * <p> 1001 * This instance is immutable and unaffected by this method call. 1002 * 1003 * @param nanos the nanos to subtract, may be negative 1004 * @return an {@code OffsetTime} based on this time with the nanoseconds subtracted, not null 1005 */ 1006 public OffsetTime minusNanos(long nanos) { 1007 return with(time.minusNanos(nanos), offset); 1008 } 1009 1010 //----------------------------------------------------------------------- 1011 /** 1012 * Queries this time using the specified query. 1013 * <p> 1014 * This queries this time using the specified query strategy object. 1015 * The {@code TemporalQuery} object defines the logic to be used to 1016 * obtain the result. Read the documentation of the query to understand 1017 * what the result of this method will be. 1018 * <p> 1019 * The result of this method is obtained by invoking the 1020 * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the 1021 * specified query passing {@code this} as the argument. 1022 * 1023 * @param <R> the type of the result 1024 * @param query the query to invoke, not null 1025 * @return the query result, null may be returned (defined by the query) 1026 * @throws DateTimeException if unable to query (defined by the query) 1027 * @throws ArithmeticException if numeric overflow occurs (defined by the query) 1028 */ 1029 @SuppressWarnings("unchecked") 1030 @Override 1031 public <R> R query(TemporalQuery<R> query) { 1032 if (query == TemporalQuery.offset() || query == TemporalQuery.zone()) { 1033 return (R) offset; 1034 } else if (query == TemporalQuery.zoneId() | query == TemporalQuery.chronology() || query == TemporalQuery.localDate()) { 1035 return null; 1036 } else if (query == TemporalQuery.localTime()) { 1037 return (R) time; 1038 } else if (query == TemporalQuery.precision()) { 1039 return (R) NANOS; 1040 } 1041 // inline TemporalAccessor.super.query(query) as an optimization 1042 // non-JDK classes are not permitted to make this optimization 1043 return query.queryFrom(this); 1044 } 1045 1046 /** 1047 * Adjusts the specified temporal object to have the same offset and time 1048 * as this object. 1049 * <p> 1050 * This returns a temporal object of the same observable type as the input 1051 * with the offset and time changed to be the same as this. 1052 * <p> 1053 * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)} 1054 * twice, passing {@link ChronoField#NANO_OF_DAY} and 1055 * {@link ChronoField#OFFSET_SECONDS} as the fields. 1056 * <p> 1057 * In most cases, it is clearer to reverse the calling pattern by using 1058 * {@link Temporal#with(TemporalAdjuster)}: 1059 * <pre> 1060 * // these two lines are equivalent, but the second approach is recommended 1061 * temporal = thisOffsetTime.adjustInto(temporal); 1062 * temporal = temporal.with(thisOffsetTime); 1063 * </pre> 1064 * <p> 1065 * This instance is immutable and unaffected by this method call. 1066 * 1067 * @param temporal the target object to be adjusted, not null 1068 * @return the adjusted object, not null 1069 * @throws DateTimeException if unable to make the adjustment 1070 * @throws ArithmeticException if numeric overflow occurs 1071 */ 1072 @Override 1073 public Temporal adjustInto(Temporal temporal) { 1074 return temporal 1075 .with(NANO_OF_DAY, time.toNanoOfDay()) 1076 .with(OFFSET_SECONDS, offset.getTotalSeconds()); 1077 } 1078 1079 /** 1080 * Calculates the period between this time and another time in 1081 * terms of the specified unit. 1082 * <p> 1083 * This calculates the period between two times in terms of a single unit. 1084 * The start and end points are {@code this} and the specified time. 1085 * The result will be negative if the end is before the start. 1086 * For example, the period in hours between two times can be calculated 1087 * using {@code startTime.periodUntil(endTime, HOURS)}. 1088 * <p> 1089 * The {@code Temporal} passed to this method must be an {@code OffsetTime}. 1090 * If the offset differs between the two times, then the specified 1091 * end time is normalized to have the same offset as this time. 1092 * <p> 1093 * The calculation returns a whole number, representing the number of 1094 * complete units between the two times. 1095 * For example, the period in hours between 11:30Z and 13:29Z will only 1096 * be one hour as it is one minute short of two hours. 1097 * <p> 1098 * There are two equivalent ways of using this method. 1099 * The first is to invoke this method. 1100 * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}: 1101 * <pre> 1102 * // these two lines are equivalent 1103 * amount = start.periodUntil(end, MINUTES); 1104 * amount = MINUTES.between(start, end); 1105 * </pre> 1106 * The choice should be made based on which makes the code more readable. 1107 * <p> 1108 * The calculation is implemented in this method for {@link ChronoUnit}. 1109 * The units {@code NANOS}, {@code MICROS}, {@code MILLIS}, {@code SECONDS}, 1110 * {@code MINUTES}, {@code HOURS} and {@code HALF_DAYS} are supported. 1111 * Other {@code ChronoUnit} values will throw an exception. 1112 * <p> 1113 * If the unit is not a {@code ChronoUnit}, then the result of this method 1114 * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} 1115 * passing {@code this} as the first argument and the input temporal as 1116 * the second argument. 1117 * <p> 1118 * This instance is immutable and unaffected by this method call. 1119 * 1120 * @param endTime the end time, which must be an {@code OffsetTime}, not null 1121 * @param unit the unit to measure the period in, not null 1122 * @return the amount of the period between this time and the end time 1123 * @throws DateTimeException if the period cannot be calculated 1124 * @throws UnsupportedTemporalTypeException if the unit is not supported 1125 * @throws ArithmeticException if numeric overflow occurs 1126 */ 1127 @Override 1128 public long periodUntil(Temporal endTime, TemporalUnit unit) { 1129 if (endTime instanceof OffsetTime == false) { 1130 Objects.requireNonNull(endTime, "endTime"); 1131 throw new DateTimeException("Unable to calculate period between objects of two different types"); 1132 } 1133 if (unit instanceof ChronoUnit) { 1134 OffsetTime end = (OffsetTime) endTime; 1135 long nanosUntil = end.toEpochNano() - toEpochNano(); // no overflow 1136 switch ((ChronoUnit) unit) { 1137 case NANOS: return nanosUntil; 1138 case MICROS: return nanosUntil / 1000; 1139 case MILLIS: return nanosUntil / 1000_000; 1140 case SECONDS: return nanosUntil / NANOS_PER_SECOND; 1141 case MINUTES: return nanosUntil / NANOS_PER_MINUTE; 1142 case HOURS: return nanosUntil / NANOS_PER_HOUR; 1143 case HALF_DAYS: return nanosUntil / (12 * NANOS_PER_HOUR); 1144 } 1145 throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName()); 1146 } 1147 return unit.between(this, endTime); 1148 } 1149 1150 /** 1151 * Formats this time using the specified formatter. 1152 * <p> 1153 * This time will be passed to the formatter to produce a string. 1154 * 1155 * @param formatter the formatter to use, not null 1156 * @return the formatted time string, not null 1157 * @throws DateTimeException if an error occurs during printing 1158 */ 1159 public String format(DateTimeFormatter formatter) { 1160 Objects.requireNonNull(formatter, "formatter"); 1161 return formatter.format(this); 1162 } 1163 1164 //----------------------------------------------------------------------- 1165 /** 1166 * Combines this time with a date to create an {@code OffsetDateTime}. 1167 * <p> 1168 * This returns an {@code OffsetDateTime} formed from this time and the specified date. 1169 * All possible combinations of date and time are valid. 1170 * 1171 * @param date the date to combine with, not null 1172 * @return the offset date-time formed from this time and the specified date, not null 1173 */ 1174 public OffsetDateTime atDate(LocalDate date) { 1175 return OffsetDateTime.of(date, time, offset); 1176 } 1177 1178 //----------------------------------------------------------------------- 1179 /** 1180 * Converts this time to epoch nanos based on 1970-01-01Z. 1181 * 1182 * @return the epoch nanos value 1183 */ 1184 private long toEpochNano() { 1185 long nod = time.toNanoOfDay(); 1186 long offsetNanos = offset.getTotalSeconds() * NANOS_PER_SECOND; 1187 return nod - offsetNanos; 1188 } 1189 1190 //----------------------------------------------------------------------- 1191 /** 1192 * Compares this {@code OffsetTime} to another time. 1193 * <p> 1194 * The comparison is based first on the UTC equivalent instant, then on the local time. 1195 * It is "consistent with equals", as defined by {@link Comparable}. 1196 * <p> 1197 * For example, the following is the comparator order: 1198 * <ol> 1199 * <li>{@code 10:30+01:00}</li> 1200 * <li>{@code 11:00+01:00}</li> 1201 * <li>{@code 12:00+02:00}</li> 1202 * <li>{@code 11:30+01:00}</li> 1203 * <li>{@code 12:00+01:00}</li> 1204 * <li>{@code 12:30+01:00}</li> 1205 * </ol> 1206 * Values #2 and #3 represent the same instant on the time-line. 1207 * When two values represent the same instant, the local time is compared 1208 * to distinguish them. This step is needed to make the ordering 1209 * consistent with {@code equals()}. 1210 * <p> 1211 * To compare the underlying local time of two {@code TemporalAccessor} instances, 1212 * use {@link ChronoField#NANO_OF_DAY} as a comparator. 1213 * 1214 * @param other the other time to compare to, not null 1215 * @return the comparator value, negative if less, positive if greater 1216 * @throws NullPointerException if {@code other} is null 1217 */ 1218 @Override 1219 public int compareTo(OffsetTime other) { 1220 if (offset.equals(other.offset)) { 1221 return time.compareTo(other.time); 1222 } 1223 int compare = Long.compare(toEpochNano(), other.toEpochNano()); 1224 if (compare == 0) { 1225 compare = time.compareTo(other.time); 1226 } 1227 return compare; 1228 } 1229 1230 //----------------------------------------------------------------------- 1231 /** 1232 * Checks if the instant of this {@code OffsetTime} is after that of the 1233 * specified time applying both times to a common date. 1234 * <p> 1235 * This method differs from the comparison in {@link #compareTo} in that it 1236 * only compares the instant of the time. This is equivalent to converting both 1237 * times to an instant using the same date and comparing the instants. 1238 * 1239 * @param other the other time to compare to, not null 1240 * @return true if this is after the instant of the specified time 1241 */ 1242 public boolean isAfter(OffsetTime other) { 1243 return toEpochNano() > other.toEpochNano(); 1244 } 1245 1246 /** 1247 * Checks if the instant of this {@code OffsetTime} is before that of the 1248 * specified time applying both times to a common date. 1249 * <p> 1250 * This method differs from the comparison in {@link #compareTo} in that it 1251 * only compares the instant of the time. This is equivalent to converting both 1252 * times to an instant using the same date and comparing the instants. 1253 * 1254 * @param other the other time to compare to, not null 1255 * @return true if this is before the instant of the specified time 1256 */ 1257 public boolean isBefore(OffsetTime other) { 1258 return toEpochNano() < other.toEpochNano(); 1259 } 1260 1261 /** 1262 * Checks if the instant of this {@code OffsetTime} is equal to that of the 1263 * specified time applying both times to a common date. 1264 * <p> 1265 * This method differs from the comparison in {@link #compareTo} and {@link #equals} 1266 * in that it only compares the instant of the time. This is equivalent to converting both 1267 * times to an instant using the same date and comparing the instants. 1268 * 1269 * @param other the other time to compare to, not null 1270 * @return true if this is equal to the instant of the specified time 1271 */ 1272 public boolean isEqual(OffsetTime other) { 1273 return toEpochNano() == other.toEpochNano(); 1274 } 1275 1276 //----------------------------------------------------------------------- 1277 /** 1278 * Checks if this time is equal to another time. 1279 * <p> 1280 * The comparison is based on the local-time and the offset. 1281 * To compare for the same instant on the time-line, use {@link #isEqual(OffsetTime)}. 1282 * <p> 1283 * Only objects of type {@code OffsetTime} are compared, other types return false. 1284 * To compare the underlying local time of two {@code TemporalAccessor} instances, 1285 * use {@link ChronoField#NANO_OF_DAY} as a comparator. 1286 * 1287 * @param obj the object to check, null returns false 1288 * @return true if this is equal to the other time 1289 */ 1290 @Override 1291 public boolean equals(Object obj) { 1292 if (this == obj) { 1293 return true; 1294 } 1295 if (obj instanceof OffsetTime) { 1296 OffsetTime other = (OffsetTime) obj; 1297 return time.equals(other.time) && offset.equals(other.offset); 1298 } 1299 return false; 1300 } 1301 1302 /** 1303 * A hash code for this time. 1304 * 1305 * @return a suitable hash code 1306 */ 1307 @Override 1308 public int hashCode() { 1309 return time.hashCode() ^ offset.hashCode(); 1310 } 1311 1312 //----------------------------------------------------------------------- 1313 /** 1314 * Outputs this time as a {@code String}, such as {@code 10:15:30+01:00}. 1315 * <p> 1316 * The output will be one of the following ISO-8601 formats: 1317 * <p><ul> 1318 * <li>{@code HH:mmXXXXX}</li> 1319 * <li>{@code HH:mm:ssXXXXX}</li> 1320 * <li>{@code HH:mm:ss.SSSXXXXX}</li> 1321 * <li>{@code HH:mm:ss.SSSSSSXXXXX}</li> 1322 * <li>{@code HH:mm:ss.SSSSSSSSSXXXXX}</li> 1323 * </ul><p> 1324 * The format used will be the shortest that outputs the full value of 1325 * the time where the omitted parts are implied to be zero. 1326 * 1327 * @return a string representation of this time, not null 1328 */ 1329 @Override 1330 public String toString() { 1331 return time.toString() + offset.toString(); 1332 } 1333 1334 //----------------------------------------------------------------------- 1335 /** 1336 * Writes the object using a 1337 * <a href="../../../serialized-form.html#java.time.temporal.Ser">dedicated serialized form</a>. 1338 * <pre> 1339 * out.writeByte(9); // identifies this as a OffsetTime 1340 * out.writeObject(time); 1341 * out.writeObject(offset); 1342 * </pre> 1343 * 1344 * @return the instance of {@code Ser}, not null 1345 */ 1346 private Object writeReplace() { 1347 return new Ser(Ser.OFFSET_TIME_TYPE, this); 1348 } 1349 1350 /** 1351 * Defend against malicious streams. 1352 * @return never 1353 * @throws InvalidObjectException always 1354 */ 1355 private Object readResolve() throws ObjectStreamException { 1356 throw new InvalidObjectException("Deserialization via serialization delegate"); 1357 } 1358 1359 void writeExternal(ObjectOutput out) throws IOException { 1360 out.writeObject(time); 1361 out.writeObject(offset); 1362 } 1363 1364 static OffsetTime readExternal(ObjectInput in) throws IOException, ClassNotFoundException { 1365 LocalTime time = (LocalTime) in.readObject(); 1366 ZoneOffset offset = (ZoneOffset) in.readObject(); 1367 return OffsetTime.of(time, offset); 1368 } 1369 1370 }