1 /* 2 * Copyright (c) 2012, 2024, 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.temporal.ChronoField.HOUR_OF_DAY; 65 import static java.time.temporal.ChronoField.MICRO_OF_DAY; 66 import static java.time.temporal.ChronoField.MINUTE_OF_HOUR; 67 import static java.time.temporal.ChronoField.NANO_OF_DAY; 68 import static java.time.temporal.ChronoField.NANO_OF_SECOND; 69 import static java.time.temporal.ChronoField.SECOND_OF_DAY; 70 import static java.time.temporal.ChronoField.SECOND_OF_MINUTE; 71 import static java.time.temporal.ChronoUnit.NANOS; 72 73 import java.io.DataInput; 74 import java.io.DataOutput; 75 import java.io.IOException; 76 import java.io.InvalidObjectException; 77 import java.io.ObjectInputStream; 78 import java.io.Serializable; 79 import java.time.format.DateTimeFormatter; 80 import java.time.format.DateTimeParseException; 81 import java.time.temporal.ChronoField; 82 import java.time.temporal.ChronoUnit; 83 import java.time.temporal.Temporal; 84 import java.time.temporal.TemporalAccessor; 85 import java.time.temporal.TemporalAdjuster; 86 import java.time.temporal.TemporalAmount; 87 import java.time.temporal.TemporalField; 88 import java.time.temporal.TemporalQueries; 89 import java.time.temporal.TemporalQuery; 90 import java.time.temporal.TemporalUnit; 91 import java.time.temporal.UnsupportedTemporalTypeException; 92 import java.time.temporal.ValueRange; 93 import java.util.Objects; 94 95 import jdk.internal.util.DecimalDigits; 96 97 /** 98 * A time without a time-zone in the ISO-8601 calendar system, 99 * such as {@code 10:15:30}. 100 * <p> 101 * {@code LocalTime} is an immutable date-time object that represents a time, 102 * often viewed as hour-minute-second. 103 * Time is represented to nanosecond precision. 104 * For example, the value "13:45.30.123456789" can be stored in a {@code LocalTime}. 105 * <p> 106 * This class does not store or represent a date or time-zone. 107 * Instead, it is a description of the local time as seen on a wall clock. 108 * It cannot represent an instant on the time-line without additional information 109 * such as an offset or time-zone. 110 * <p> 111 * The ISO-8601 calendar system is the modern civil calendar system used today 112 * in most of the world. This API assumes that all calendar systems use the same 113 * representation, this class, for time-of-day. 114 * <p> 115 * This is a <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a> 116 * class; programmers should treat instances that are 117 * {@linkplain #equals(Object) equal} as interchangeable and should not 118 * use instances for synchronization, or unpredictable behavior may 119 * occur. For example, in a future release, synchronization may fail. 120 * The {@code equals} method should be used for comparisons. 121 * 122 * @implSpec 123 * This class is immutable and thread-safe. 124 * 125 * @since 1.8 126 */ 127 @jdk.internal.ValueBased 128 @jdk.internal.MigratedValueClass 129 public final class LocalTime 130 implements Temporal, TemporalAdjuster, Comparable<LocalTime>, Serializable { 131 132 /** 133 * The minimum supported {@code LocalTime}, '00:00'. 134 * This is the time of midnight at the start of the day. 135 */ 136 public static final LocalTime MIN; 137 /** 138 * The maximum supported {@code LocalTime}, '23:59:59.999999999'. 139 * This is the time just before midnight at the end of the day. 140 */ 141 public static final LocalTime MAX; 142 /** 143 * The time of midnight at the start of the day, '00:00'. 144 */ 145 public static final LocalTime MIDNIGHT; 146 /** 147 * The time of noon in the middle of the day, '12:00'. 148 */ 149 public static final LocalTime NOON; 150 /** 151 * Constants for the local time of each hour. 152 */ 153 private static final LocalTime[] HOURS = new LocalTime[24]; 154 static { 155 for (int i = 0; i < HOURS.length; i++) { 156 HOURS[i] = new LocalTime(i, 0, 0, 0); 157 } 158 MIDNIGHT = HOURS[0]; 159 NOON = HOURS[12]; 160 MIN = HOURS[0]; 161 MAX = new LocalTime(23, 59, 59, 999_999_999); 162 } 163 164 /** 165 * Hours per day. 166 */ 167 static final int HOURS_PER_DAY = 24; 168 /** 169 * Minutes per hour. 170 */ 171 static final int MINUTES_PER_HOUR = 60; 172 /** 173 * Minutes per day. 174 */ 175 static final int MINUTES_PER_DAY = MINUTES_PER_HOUR * HOURS_PER_DAY; 176 /** 177 * Seconds per minute. 178 */ 179 static final int SECONDS_PER_MINUTE = 60; 180 /** 181 * Seconds per hour. 182 */ 183 static final int SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR; 184 /** 185 * Seconds per day. 186 */ 187 static final int SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY; 188 /** 189 * Milliseconds per second. 190 */ 191 static final long MILLIS_PER_SECOND = 1000L; 192 /** 193 * Milliseconds per day. 194 */ 195 static final long MILLIS_PER_DAY = MILLIS_PER_SECOND * SECONDS_PER_DAY; 196 /** 197 * Microseconds per second. 198 */ 199 static final long MICROS_PER_SECOND = 1000_000L; 200 /** 201 * Microseconds per day. 202 */ 203 static final long MICROS_PER_DAY = MICROS_PER_SECOND * SECONDS_PER_DAY; 204 /** 205 * Nanos per millisecond. 206 */ 207 static final long NANOS_PER_MILLI = 1000_000L; 208 /** 209 * Nanos per second. 210 */ 211 static final long NANOS_PER_SECOND = 1000_000_000L; 212 /** 213 * Nanos per minute. 214 */ 215 static final long NANOS_PER_MINUTE = NANOS_PER_SECOND * SECONDS_PER_MINUTE; 216 /** 217 * Nanos per hour. 218 */ 219 static final long NANOS_PER_HOUR = NANOS_PER_MINUTE * MINUTES_PER_HOUR; 220 /** 221 * Nanos per day. 222 */ 223 static final long NANOS_PER_DAY = NANOS_PER_HOUR * HOURS_PER_DAY; 224 225 /** 226 * Serialization version. 227 */ 228 @java.io.Serial 229 private static final long serialVersionUID = 6414437269572265201L; 230 231 /** 232 * The hour. 233 */ 234 private final byte hour; 235 /** 236 * The minute. 237 */ 238 private final byte minute; 239 /** 240 * The second. 241 */ 242 private final byte second; 243 /** 244 * The nanosecond. 245 */ 246 private final int nano; 247 248 //----------------------------------------------------------------------- 249 /** 250 * Obtains the current time from the system clock in the default time-zone. 251 * <p> 252 * This will query the {@link Clock#systemDefaultZone() system clock} in the default 253 * time-zone to obtain the current time. 254 * <p> 255 * Using this method will prevent the ability to use an alternate clock for testing 256 * because the clock is hard-coded. 257 * 258 * @return the current time using the system clock and default time-zone, not null 259 */ 260 public static LocalTime now() { 261 return now(Clock.systemDefaultZone()); 262 } 263 264 /** 265 * Obtains the current time from the system clock in the specified time-zone. 266 * <p> 267 * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current time. 268 * Specifying the time-zone avoids dependence on the default time-zone. 269 * <p> 270 * Using this method will prevent the ability to use an alternate clock for testing 271 * because the clock is hard-coded. 272 * 273 * @param zone the zone ID to use, not null 274 * @return the current time using the system clock, not null 275 */ 276 public static LocalTime now(ZoneId zone) { 277 return now(Clock.system(zone)); 278 } 279 280 /** 281 * Obtains the current time from the specified clock. 282 * <p> 283 * This will query the specified clock to obtain the current time. 284 * Using this method allows the use of an alternate clock for testing. 285 * The alternate clock may be introduced using {@link Clock dependency injection}. 286 * 287 * @param clock the clock to use, not null 288 * @return the current time, not null 289 */ 290 public static LocalTime now(Clock clock) { 291 Objects.requireNonNull(clock, "clock"); 292 final Instant now = clock.instant(); // called once 293 return ofInstant(now, clock.getZone()); 294 } 295 296 //----------------------------------------------------------------------- 297 /** 298 * Obtains an instance of {@code LocalTime} from an hour and minute. 299 * <p> 300 * This returns a {@code LocalTime} with the specified hour and minute. 301 * The second and nanosecond fields will be set to zero. 302 * 303 * @param hour the hour-of-day to represent, from 0 to 23 304 * @param minute the minute-of-hour to represent, from 0 to 59 305 * @return the local time, not null 306 * @throws DateTimeException if the value of any field is out of range 307 */ 308 public static LocalTime of(int hour, int minute) { 309 HOUR_OF_DAY.checkValidValue(hour); 310 if (minute == 0) { 311 return HOURS[hour]; // for performance 312 } 313 MINUTE_OF_HOUR.checkValidValue(minute); 314 return new LocalTime(hour, minute, 0, 0); 315 } 316 317 /** 318 * Obtains an instance of {@code LocalTime} from an hour, minute and second. 319 * <p> 320 * This returns a {@code LocalTime} with the specified hour, minute and second. 321 * The nanosecond field will be set to zero. 322 * 323 * @param hour the hour-of-day to represent, from 0 to 23 324 * @param minute the minute-of-hour to represent, from 0 to 59 325 * @param second the second-of-minute to represent, from 0 to 59 326 * @return the local time, not null 327 * @throws DateTimeException if the value of any field is out of range 328 */ 329 public static LocalTime of(int hour, int minute, int second) { 330 HOUR_OF_DAY.checkValidValue(hour); 331 if ((minute | second) == 0) { 332 return HOURS[hour]; // for performance 333 } 334 MINUTE_OF_HOUR.checkValidValue(minute); 335 SECOND_OF_MINUTE.checkValidValue(second); 336 return new LocalTime(hour, minute, second, 0); 337 } 338 339 /** 340 * Obtains an instance of {@code LocalTime} from an hour, minute, second and nanosecond. 341 * <p> 342 * This returns a {@code LocalTime} with the specified hour, minute, second and nanosecond. 343 * 344 * @param hour the hour-of-day to represent, from 0 to 23 345 * @param minute the minute-of-hour to represent, from 0 to 59 346 * @param second the second-of-minute to represent, from 0 to 59 347 * @param nanoOfSecond the nano-of-second to represent, from 0 to 999,999,999 348 * @return the local time, not null 349 * @throws DateTimeException if the value of any field is out of range 350 */ 351 public static LocalTime of(int hour, int minute, int second, int nanoOfSecond) { 352 HOUR_OF_DAY.checkValidValue(hour); 353 MINUTE_OF_HOUR.checkValidValue(minute); 354 SECOND_OF_MINUTE.checkValidValue(second); 355 NANO_OF_SECOND.checkValidValue(nanoOfSecond); 356 return create(hour, minute, second, nanoOfSecond); 357 } 358 359 /** 360 * Obtains an instance of {@code LocalTime} from an {@code Instant} and zone ID. 361 * <p> 362 * This creates a local time based on the specified instant. 363 * First, the offset from UTC/Greenwich is obtained using the zone ID and instant, 364 * which is simple as there is only one valid offset for each instant. 365 * Then, the instant and offset are used to calculate the local time. 366 * 367 * @param instant the instant to create the time from, not null 368 * @param zone the time-zone, which may be an offset, not null 369 * @return the local time, not null 370 * @since 9 371 */ 372 public static LocalTime ofInstant(Instant instant, ZoneId zone) { 373 Objects.requireNonNull(instant, "instant"); 374 Objects.requireNonNull(zone, "zone"); 375 ZoneOffset offset = zone.getRules().getOffset(instant); 376 long localSecond = instant.getEpochSecond() + offset.getTotalSeconds(); 377 int secsOfDay = Math.floorMod(localSecond, SECONDS_PER_DAY); 378 return ofNanoOfDay(secsOfDay * NANOS_PER_SECOND + instant.getNano()); 379 } 380 381 //----------------------------------------------------------------------- 382 /** 383 * Obtains an instance of {@code LocalTime} from a second-of-day value. 384 * <p> 385 * This returns a {@code LocalTime} with the specified second-of-day. 386 * The nanosecond field will be set to zero. 387 * 388 * @param secondOfDay the second-of-day, from {@code 0} to {@code 24 * 60 * 60 - 1} 389 * @return the local time, not null 390 * @throws DateTimeException if the second-of-day value is invalid 391 */ 392 public static LocalTime ofSecondOfDay(long secondOfDay) { 393 SECOND_OF_DAY.checkValidValue(secondOfDay); 394 int hours = (int) (secondOfDay / SECONDS_PER_HOUR); 395 secondOfDay -= hours * SECONDS_PER_HOUR; 396 int minutes = (int) (secondOfDay / SECONDS_PER_MINUTE); 397 secondOfDay -= minutes * SECONDS_PER_MINUTE; 398 return create(hours, minutes, (int) secondOfDay, 0); 399 } 400 401 /** 402 * Obtains an instance of {@code LocalTime} from a nanos-of-day value. 403 * <p> 404 * This returns a {@code LocalTime} with the specified nanosecond-of-day. 405 * 406 * @param nanoOfDay the nano of day, from {@code 0} to {@code 24 * 60 * 60 * 1,000,000,000 - 1} 407 * @return the local time, not null 408 * @throws DateTimeException if the nanos of day value is invalid 409 */ 410 public static LocalTime ofNanoOfDay(long nanoOfDay) { 411 NANO_OF_DAY.checkValidValue(nanoOfDay); 412 int hours = (int) (nanoOfDay / NANOS_PER_HOUR); 413 nanoOfDay -= hours * NANOS_PER_HOUR; 414 int minutes = (int) (nanoOfDay / NANOS_PER_MINUTE); 415 nanoOfDay -= minutes * NANOS_PER_MINUTE; 416 int seconds = (int) (nanoOfDay / NANOS_PER_SECOND); 417 nanoOfDay -= seconds * NANOS_PER_SECOND; 418 return create(hours, minutes, seconds, (int) nanoOfDay); 419 } 420 421 //----------------------------------------------------------------------- 422 /** 423 * Obtains an instance of {@code LocalTime} from a temporal object. 424 * <p> 425 * This obtains a local time based on the specified temporal. 426 * A {@code TemporalAccessor} represents an arbitrary set of date and time information, 427 * which this factory converts to an instance of {@code LocalTime}. 428 * <p> 429 * The conversion uses the {@link TemporalQueries#localTime()} query, which relies 430 * on extracting the {@link ChronoField#NANO_OF_DAY NANO_OF_DAY} field. 431 * <p> 432 * This method matches the signature of the functional interface {@link TemporalQuery} 433 * allowing it to be used as a query via method reference, {@code LocalTime::from}. 434 * 435 * @param temporal the temporal object to convert, not null 436 * @return the local time, not null 437 * @throws DateTimeException if unable to convert to a {@code LocalTime} 438 */ 439 public static LocalTime from(TemporalAccessor temporal) { 440 Objects.requireNonNull(temporal, "temporal"); 441 LocalTime time = temporal.query(TemporalQueries.localTime()); 442 if (time == null) { 443 throw new DateTimeException("Unable to obtain LocalTime from TemporalAccessor: " + 444 temporal + " of type " + temporal.getClass().getName()); 445 } 446 return time; 447 } 448 449 //----------------------------------------------------------------------- 450 /** 451 * Obtains an instance of {@code LocalTime} from a text string such as {@code 10:15}. 452 * <p> 453 * The string must represent a valid time and is parsed using 454 * {@link java.time.format.DateTimeFormatter#ISO_LOCAL_TIME}. 455 * 456 * @param text the text to parse such as "10:15:30", not null 457 * @return the parsed local time, not null 458 * @throws DateTimeParseException if the text cannot be parsed 459 */ 460 public static LocalTime parse(CharSequence text) { 461 return parse(text, DateTimeFormatter.ISO_LOCAL_TIME); 462 } 463 464 /** 465 * Obtains an instance of {@code LocalTime} from a text string using a specific formatter. 466 * <p> 467 * The text is parsed using the formatter, returning a time. 468 * 469 * @param text the text to parse, not null 470 * @param formatter the formatter to use, not null 471 * @return the parsed local time, not null 472 * @throws DateTimeParseException if the text cannot be parsed 473 */ 474 public static LocalTime parse(CharSequence text, DateTimeFormatter formatter) { 475 Objects.requireNonNull(formatter, "formatter"); 476 return formatter.parse(text, LocalTime::from); 477 } 478 479 //----------------------------------------------------------------------- 480 /** 481 * Creates a local time from the hour, minute, second and nanosecond fields. 482 * <p> 483 * This factory may return a cached value, but applications must not rely on this. 484 * 485 * @param hour the hour-of-day to represent, validated from 0 to 23 486 * @param minute the minute-of-hour to represent, validated from 0 to 59 487 * @param second the second-of-minute to represent, validated from 0 to 59 488 * @param nanoOfSecond the nano-of-second to represent, validated from 0 to 999,999,999 489 * @return the local time, not null 490 */ 491 private static LocalTime create(int hour, int minute, int second, int nanoOfSecond) { 492 if ((minute | second | nanoOfSecond) == 0) { 493 return HOURS[hour]; 494 } 495 return new LocalTime(hour, minute, second, nanoOfSecond); 496 } 497 498 /** 499 * Constructor, previously validated. 500 * 501 * @param hour the hour-of-day to represent, validated from 0 to 23 502 * @param minute the minute-of-hour to represent, validated from 0 to 59 503 * @param second the second-of-minute to represent, validated from 0 to 59 504 * @param nanoOfSecond the nano-of-second to represent, validated from 0 to 999,999,999 505 */ 506 private LocalTime(int hour, int minute, int second, int nanoOfSecond) { 507 this.hour = (byte) hour; 508 this.minute = (byte) minute; 509 this.second = (byte) second; 510 this.nano = nanoOfSecond; 511 } 512 513 //----------------------------------------------------------------------- 514 /** 515 * Checks if the specified field is supported. 516 * <p> 517 * This checks if this time can be queried for the specified field. 518 * If false, then calling the {@link #range(TemporalField) range}, 519 * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)} 520 * methods will throw an exception. 521 * <p> 522 * If the field is a {@link ChronoField} then the query is implemented here. 523 * The supported fields are: 524 * <ul> 525 * <li>{@code NANO_OF_SECOND} 526 * <li>{@code NANO_OF_DAY} 527 * <li>{@code MICRO_OF_SECOND} 528 * <li>{@code MICRO_OF_DAY} 529 * <li>{@code MILLI_OF_SECOND} 530 * <li>{@code MILLI_OF_DAY} 531 * <li>{@code SECOND_OF_MINUTE} 532 * <li>{@code SECOND_OF_DAY} 533 * <li>{@code MINUTE_OF_HOUR} 534 * <li>{@code MINUTE_OF_DAY} 535 * <li>{@code HOUR_OF_AMPM} 536 * <li>{@code CLOCK_HOUR_OF_AMPM} 537 * <li>{@code HOUR_OF_DAY} 538 * <li>{@code CLOCK_HOUR_OF_DAY} 539 * <li>{@code AMPM_OF_DAY} 540 * </ul> 541 * All other {@code ChronoField} instances will return false. 542 * <p> 543 * If the field is not a {@code ChronoField}, then the result of this method 544 * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)} 545 * passing {@code this} as the argument. 546 * Whether the field is supported is determined by the field. 547 * 548 * @param field the field to check, null returns false 549 * @return true if the field is supported on this time, false if not 550 */ 551 @Override 552 public boolean isSupported(TemporalField field) { 553 if (field instanceof ChronoField) { 554 return field.isTimeBased(); 555 } 556 return field != null && field.isSupportedBy(this); 557 } 558 559 /** 560 * Checks if the specified unit is supported. 561 * <p> 562 * This checks if the specified unit can be added to, or subtracted from, this time. 563 * If false, then calling the {@link #plus(long, TemporalUnit)} and 564 * {@link #minus(long, TemporalUnit) minus} methods will throw an exception. 565 * <p> 566 * If the unit is a {@link ChronoUnit} then the query is implemented here. 567 * The supported units are: 568 * <ul> 569 * <li>{@code NANOS} 570 * <li>{@code MICROS} 571 * <li>{@code MILLIS} 572 * <li>{@code SECONDS} 573 * <li>{@code MINUTES} 574 * <li>{@code HOURS} 575 * <li>{@code HALF_DAYS} 576 * </ul> 577 * All other {@code ChronoUnit} instances will return false. 578 * <p> 579 * If the unit is not a {@code ChronoUnit}, then the result of this method 580 * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)} 581 * passing {@code this} as the argument. 582 * Whether the unit is supported is determined by the unit. 583 * 584 * @param unit the unit to check, null returns false 585 * @return true if the unit can be added/subtracted, false if not 586 */ 587 @Override // override for Javadoc 588 public boolean isSupported(TemporalUnit unit) { 589 if (unit instanceof ChronoUnit) { 590 return unit.isTimeBased(); 591 } 592 return unit != null && unit.isSupportedBy(this); 593 } 594 595 //----------------------------------------------------------------------- 596 /** 597 * Gets the range of valid values for the specified field. 598 * <p> 599 * The range object expresses the minimum and maximum valid values for a field. 600 * This time is used to enhance the accuracy of the returned range. 601 * If it is not possible to return the range, because the field is not supported 602 * or for some other reason, an exception is thrown. 603 * <p> 604 * If the field is a {@link ChronoField} then the query is implemented here. 605 * The {@link #isSupported(TemporalField) supported fields} will return 606 * appropriate range instances. 607 * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}. 608 * <p> 609 * If the field is not a {@code ChronoField}, then the result of this method 610 * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)} 611 * passing {@code this} as the argument. 612 * Whether the range can be obtained is determined by the field. 613 * 614 * @param field the field to query the range for, not null 615 * @return the range of valid values for the field, not null 616 * @throws DateTimeException if the range for the field cannot be obtained 617 * @throws UnsupportedTemporalTypeException if the field is not supported 618 */ 619 @Override // override for Javadoc 620 public ValueRange range(TemporalField field) { 621 return Temporal.super.range(field); 622 } 623 624 /** 625 * Gets the value of the specified field from this time as an {@code int}. 626 * <p> 627 * This queries this time for the value of the specified field. 628 * The returned value will always be within the valid range of values for the field. 629 * If it is not possible to return the value, because the field is not supported 630 * or for some other reason, an exception is thrown. 631 * <p> 632 * If the field is a {@link ChronoField} then the query is implemented here. 633 * The {@link #isSupported(TemporalField) supported fields} will return valid 634 * values based on this time, except {@code NANO_OF_DAY} and {@code MICRO_OF_DAY} 635 * which are too large to fit in an {@code int} and throw an {@code UnsupportedTemporalTypeException}. 636 * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}. 637 * <p> 638 * If the field is not a {@code ChronoField}, then the result of this method 639 * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} 640 * passing {@code this} as the argument. Whether the value can be obtained, 641 * and what the value represents, is determined by the field. 642 * 643 * @param field the field to get, not null 644 * @return the value for the field 645 * @throws DateTimeException if a value for the field cannot be obtained or 646 * the value is outside the range of valid values for the field 647 * @throws UnsupportedTemporalTypeException if the field is not supported or 648 * the range of values exceeds an {@code int} 649 * @throws ArithmeticException if numeric overflow occurs 650 */ 651 @Override // override for Javadoc and performance 652 public int get(TemporalField field) { 653 if (field instanceof ChronoField) { 654 return get0(field); 655 } 656 return Temporal.super.get(field); 657 } 658 659 /** 660 * Gets the value of the specified field from this time as a {@code long}. 661 * <p> 662 * This queries this time for the value of the specified field. 663 * If it is not possible to return the value, because the field is not supported 664 * or for some other reason, an exception is thrown. 665 * <p> 666 * If the field is a {@link ChronoField} then the query is implemented here. 667 * The {@link #isSupported(TemporalField) supported fields} will return valid 668 * values based on this time. 669 * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}. 670 * <p> 671 * If the field is not a {@code ChronoField}, then the result of this method 672 * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} 673 * passing {@code this} as the argument. Whether the value can be obtained, 674 * and what the value represents, is determined by the field. 675 * 676 * @param field the field to get, not null 677 * @return the value for the field 678 * @throws DateTimeException if a value for the field cannot be obtained 679 * @throws UnsupportedTemporalTypeException if the field is not supported 680 * @throws ArithmeticException if numeric overflow occurs 681 */ 682 @Override 683 public long getLong(TemporalField field) { 684 if (field instanceof ChronoField) { 685 if (field == NANO_OF_DAY) { 686 return toNanoOfDay(); 687 } 688 if (field == MICRO_OF_DAY) { 689 return toNanoOfDay() / 1000; 690 } 691 return get0(field); 692 } 693 return field.getFrom(this); 694 } 695 696 private int get0(TemporalField field) { 697 return switch ((ChronoField) field) { 698 case NANO_OF_SECOND -> nano; 699 case NANO_OF_DAY -> throw new UnsupportedTemporalTypeException("Invalid field 'NanoOfDay' for get() method, use getLong() instead"); 700 case MICRO_OF_SECOND -> nano / 1000; 701 case MICRO_OF_DAY -> throw new UnsupportedTemporalTypeException("Invalid field 'MicroOfDay' for get() method, use getLong() instead"); 702 case MILLI_OF_SECOND -> nano / 1000_000; 703 case MILLI_OF_DAY -> (int) (toNanoOfDay() / 1000_000); 704 case SECOND_OF_MINUTE -> second; 705 case SECOND_OF_DAY -> toSecondOfDay(); 706 case MINUTE_OF_HOUR -> minute; 707 case MINUTE_OF_DAY -> hour * 60 + minute; 708 case HOUR_OF_AMPM -> hour % 12; 709 case CLOCK_HOUR_OF_AMPM -> { int ham = hour % 12; yield ham % 12 == 0 ? 12 : ham; } 710 case HOUR_OF_DAY -> hour; 711 case CLOCK_HOUR_OF_DAY -> (hour == 0 ? 24 : hour); 712 case AMPM_OF_DAY -> hour / 12; 713 default -> throw new UnsupportedTemporalTypeException("Unsupported field: " + field); 714 }; 715 } 716 717 //----------------------------------------------------------------------- 718 /** 719 * Gets the hour-of-day field. 720 * 721 * @return the hour-of-day, from 0 to 23 722 */ 723 public int getHour() { 724 return hour; 725 } 726 727 /** 728 * Gets the minute-of-hour field. 729 * 730 * @return the minute-of-hour, from 0 to 59 731 */ 732 public int getMinute() { 733 return minute; 734 } 735 736 /** 737 * Gets the second-of-minute field. 738 * 739 * @return the second-of-minute, from 0 to 59 740 */ 741 public int getSecond() { 742 return second; 743 } 744 745 /** 746 * Gets the nano-of-second field. 747 * 748 * @return the nano-of-second, from 0 to 999,999,999 749 */ 750 public int getNano() { 751 return nano; 752 } 753 754 //----------------------------------------------------------------------- 755 /** 756 * Returns an adjusted copy of this time. 757 * <p> 758 * This returns a {@code LocalTime}, based on this one, with the time adjusted. 759 * The adjustment takes place using the specified adjuster strategy object. 760 * Read the documentation of the adjuster to understand what adjustment will be made. 761 * <p> 762 * A simple adjuster might simply set the one of the fields, such as the hour field. 763 * A more complex adjuster might set the time to the last hour of the day. 764 * <p> 765 * The result of this method is obtained by invoking the 766 * {@link TemporalAdjuster#adjustInto(Temporal)} method on the 767 * specified adjuster passing {@code this} as the argument. 768 * <p> 769 * This instance is immutable and unaffected by this method call. 770 * 771 * @param adjuster the adjuster to use, not null 772 * @return a {@code LocalTime} based on {@code this} with the adjustment made, not null 773 * @throws DateTimeException if the adjustment cannot be made 774 * @throws ArithmeticException if numeric overflow occurs 775 */ 776 @Override 777 public LocalTime with(TemporalAdjuster adjuster) { 778 // optimizations 779 if (adjuster instanceof LocalTime) { 780 return (LocalTime) adjuster; 781 } 782 return (LocalTime) adjuster.adjustInto(this); 783 } 784 785 /** 786 * Returns a copy of this time with the specified field set to a new value. 787 * <p> 788 * This returns a {@code LocalTime}, based on this one, with the value 789 * for the specified field changed. 790 * This can be used to change any supported field, such as the hour, minute or second. 791 * If it is not possible to set the value, because the field is not supported or for 792 * some other reason, an exception is thrown. 793 * <p> 794 * If the field is a {@link ChronoField} then the adjustment is implemented here. 795 * The supported fields behave as follows: 796 * <ul> 797 * <li>{@code NANO_OF_SECOND} - 798 * Returns a {@code LocalTime} with the specified nano-of-second. 799 * The hour, minute and second will be unchanged. 800 * <li>{@code NANO_OF_DAY} - 801 * Returns a {@code LocalTime} with the specified nano-of-day. 802 * This completely replaces the time and is equivalent to {@link #ofNanoOfDay(long)}. 803 * <li>{@code MICRO_OF_SECOND} - 804 * Returns a {@code LocalTime} with the nano-of-second replaced by the specified 805 * micro-of-second multiplied by 1,000. 806 * The hour, minute and second will be unchanged. 807 * <li>{@code MICRO_OF_DAY} - 808 * Returns a {@code LocalTime} with the specified micro-of-day. 809 * This completely replaces the time and is equivalent to using {@link #ofNanoOfDay(long)} 810 * with the micro-of-day multiplied by 1,000. 811 * <li>{@code MILLI_OF_SECOND} - 812 * Returns a {@code LocalTime} with the nano-of-second replaced by the specified 813 * milli-of-second multiplied by 1,000,000. 814 * The hour, minute and second will be unchanged. 815 * <li>{@code MILLI_OF_DAY} - 816 * Returns a {@code LocalTime} with the specified milli-of-day. 817 * This completely replaces the time and is equivalent to using {@link #ofNanoOfDay(long)} 818 * with the milli-of-day multiplied by 1,000,000. 819 * <li>{@code SECOND_OF_MINUTE} - 820 * Returns a {@code LocalTime} with the specified second-of-minute. 821 * The hour, minute and nano-of-second will be unchanged. 822 * <li>{@code SECOND_OF_DAY} - 823 * Returns a {@code LocalTime} with the specified second-of-day. 824 * The nano-of-second will be unchanged. 825 * <li>{@code MINUTE_OF_HOUR} - 826 * Returns a {@code LocalTime} with the specified minute-of-hour. 827 * The hour, second-of-minute and nano-of-second will be unchanged. 828 * <li>{@code MINUTE_OF_DAY} - 829 * Returns a {@code LocalTime} with the specified minute-of-day. 830 * The second-of-minute and nano-of-second will be unchanged. 831 * <li>{@code HOUR_OF_AMPM} - 832 * Returns a {@code LocalTime} with the specified hour-of-am-pm. 833 * The AM/PM, minute-of-hour, second-of-minute and nano-of-second will be unchanged. 834 * <li>{@code CLOCK_HOUR_OF_AMPM} - 835 * Returns a {@code LocalTime} with the specified clock-hour-of-am-pm. 836 * The AM/PM, minute-of-hour, second-of-minute and nano-of-second will be unchanged. 837 * <li>{@code HOUR_OF_DAY} - 838 * Returns a {@code LocalTime} with the specified hour-of-day. 839 * The minute-of-hour, second-of-minute and nano-of-second will be unchanged. 840 * <li>{@code CLOCK_HOUR_OF_DAY} - 841 * Returns a {@code LocalTime} with the specified clock-hour-of-day. 842 * The minute-of-hour, second-of-minute and nano-of-second will be unchanged. 843 * <li>{@code AMPM_OF_DAY} - 844 * Returns a {@code LocalTime} with the specified AM/PM. 845 * The hour-of-am-pm, minute-of-hour, second-of-minute and nano-of-second will be unchanged. 846 * </ul> 847 * <p> 848 * In all cases, if the new value is outside the valid range of values for the field 849 * then a {@code DateTimeException} will be thrown. 850 * <p> 851 * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}. 852 * <p> 853 * If the field is not a {@code ChronoField}, then the result of this method 854 * is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)} 855 * passing {@code this} as the argument. In this case, the field determines 856 * whether and how to adjust the instant. 857 * <p> 858 * This instance is immutable and unaffected by this method call. 859 * 860 * @param field the field to set in the result, not null 861 * @param newValue the new value of the field in the result 862 * @return a {@code LocalTime} based on {@code this} with the specified field set, not null 863 * @throws DateTimeException if the field cannot be set 864 * @throws UnsupportedTemporalTypeException if the field is not supported 865 * @throws ArithmeticException if numeric overflow occurs 866 */ 867 @Override 868 public LocalTime with(TemporalField field, long newValue) { 869 if (field instanceof ChronoField chronoField) { 870 chronoField.checkValidValue(newValue); 871 return switch (chronoField) { 872 case NANO_OF_SECOND -> withNano((int) newValue); 873 case NANO_OF_DAY -> LocalTime.ofNanoOfDay(newValue); 874 case MICRO_OF_SECOND -> withNano((int) newValue * 1000); 875 case MICRO_OF_DAY -> LocalTime.ofNanoOfDay(newValue * 1000); 876 case MILLI_OF_SECOND -> withNano((int) newValue * 1000_000); 877 case MILLI_OF_DAY -> LocalTime.ofNanoOfDay(newValue * 1000_000); 878 case SECOND_OF_MINUTE -> withSecond((int) newValue); 879 case SECOND_OF_DAY -> plusSeconds(newValue - toSecondOfDay()); 880 case MINUTE_OF_HOUR -> withMinute((int) newValue); 881 case MINUTE_OF_DAY -> plusMinutes(newValue - (hour * 60 + minute)); 882 case HOUR_OF_AMPM -> plusHours(newValue - (hour % 12)); 883 case CLOCK_HOUR_OF_AMPM -> plusHours((newValue == 12 ? 0 : newValue) - (hour % 12)); 884 case HOUR_OF_DAY -> withHour((int) newValue); 885 case CLOCK_HOUR_OF_DAY -> withHour((int) (newValue == 24 ? 0 : newValue)); 886 case AMPM_OF_DAY -> plusHours((newValue - (hour / 12)) * 12); 887 default -> throw new UnsupportedTemporalTypeException("Unsupported field: " + field); 888 }; 889 } 890 return field.adjustInto(this, newValue); 891 } 892 893 //----------------------------------------------------------------------- 894 /** 895 * Returns a copy of this {@code LocalTime} with the hour-of-day altered. 896 * <p> 897 * This instance is immutable and unaffected by this method call. 898 * 899 * @param hour the hour-of-day to set in the result, from 0 to 23 900 * @return a {@code LocalTime} based on this time with the requested hour, not null 901 * @throws DateTimeException if the hour value is invalid 902 */ 903 public LocalTime withHour(int hour) { 904 if (this.hour == hour) { 905 return this; 906 } 907 HOUR_OF_DAY.checkValidValue(hour); 908 return create(hour, minute, second, nano); 909 } 910 911 /** 912 * Returns a copy of this {@code LocalTime} with the minute-of-hour altered. 913 * <p> 914 * This instance is immutable and unaffected by this method call. 915 * 916 * @param minute the minute-of-hour to set in the result, from 0 to 59 917 * @return a {@code LocalTime} based on this time with the requested minute, not null 918 * @throws DateTimeException if the minute value is invalid 919 */ 920 public LocalTime withMinute(int minute) { 921 if (this.minute == minute) { 922 return this; 923 } 924 MINUTE_OF_HOUR.checkValidValue(minute); 925 return create(hour, minute, second, nano); 926 } 927 928 /** 929 * Returns a copy of this {@code LocalTime} with the second-of-minute altered. 930 * <p> 931 * This instance is immutable and unaffected by this method call. 932 * 933 * @param second the second-of-minute to set in the result, from 0 to 59 934 * @return a {@code LocalTime} based on this time with the requested second, not null 935 * @throws DateTimeException if the second value is invalid 936 */ 937 public LocalTime withSecond(int second) { 938 if (this.second == second) { 939 return this; 940 } 941 SECOND_OF_MINUTE.checkValidValue(second); 942 return create(hour, minute, second, nano); 943 } 944 945 /** 946 * Returns a copy of this {@code LocalTime} with the nano-of-second altered. 947 * <p> 948 * This instance is immutable and unaffected by this method call. 949 * 950 * @param nanoOfSecond the nano-of-second to set in the result, from 0 to 999,999,999 951 * @return a {@code LocalTime} based on this time with the requested nanosecond, not null 952 * @throws DateTimeException if the nanos value is invalid 953 */ 954 public LocalTime withNano(int nanoOfSecond) { 955 if (this.nano == nanoOfSecond) { 956 return this; 957 } 958 NANO_OF_SECOND.checkValidValue(nanoOfSecond); 959 return create(hour, minute, second, nanoOfSecond); 960 } 961 962 //----------------------------------------------------------------------- 963 /** 964 * Returns a copy of this {@code LocalTime} with the time truncated. 965 * <p> 966 * Truncation returns a copy of the original time with fields 967 * smaller than the specified unit set to zero. 968 * For example, truncating with the {@link ChronoUnit#MINUTES minutes} unit 969 * will set the second-of-minute and nano-of-second field to zero. 970 * <p> 971 * The unit must have a {@linkplain TemporalUnit#getDuration() duration} 972 * that divides into the length of a standard day without remainder. 973 * This includes all supplied time units on {@link ChronoUnit} and 974 * {@link ChronoUnit#DAYS DAYS}. Other units throw an exception. 975 * <p> 976 * This instance is immutable and unaffected by this method call. 977 * 978 * @param unit the unit to truncate to, not null 979 * @return a {@code LocalTime} based on this time with the time truncated, not null 980 * @throws DateTimeException if unable to truncate 981 * @throws UnsupportedTemporalTypeException if the unit is not supported 982 */ 983 public LocalTime truncatedTo(TemporalUnit unit) { 984 if (unit == ChronoUnit.NANOS) { 985 return this; 986 } 987 Duration unitDur = unit.getDuration(); 988 if (unitDur.getSeconds() > SECONDS_PER_DAY) { 989 throw new UnsupportedTemporalTypeException("Unit is too large to be used for truncation"); 990 } 991 long dur = unitDur.toNanos(); 992 if ((NANOS_PER_DAY % dur) != 0) { 993 throw new UnsupportedTemporalTypeException("Unit must divide into a standard day without remainder"); 994 } 995 long nod = toNanoOfDay(); 996 return ofNanoOfDay((nod / dur) * dur); 997 } 998 999 //----------------------------------------------------------------------- 1000 /** 1001 * Returns a copy of this time with the specified amount added. 1002 * <p> 1003 * This returns a {@code LocalTime}, based on this one, with the specified amount added. 1004 * The amount is typically {@link Duration} but may be any other type implementing 1005 * the {@link TemporalAmount} interface. 1006 * <p> 1007 * The calculation is delegated to the amount object by calling 1008 * {@link TemporalAmount#addTo(Temporal)}. The amount implementation is free 1009 * to implement the addition in any way it wishes, however it typically 1010 * calls back to {@link #plus(long, TemporalUnit)}. Consult the documentation 1011 * of the amount implementation to determine if it can be successfully added. 1012 * <p> 1013 * This instance is immutable and unaffected by this method call. 1014 * 1015 * @param amountToAdd the amount to add, not null 1016 * @return a {@code LocalTime} based on this time with the addition made, not null 1017 * @throws DateTimeException if the addition cannot be made 1018 * @throws ArithmeticException if numeric overflow occurs 1019 */ 1020 @Override 1021 public LocalTime plus(TemporalAmount amountToAdd) { 1022 return (LocalTime) amountToAdd.addTo(this); 1023 } 1024 1025 /** 1026 * Returns a copy of this time with the specified amount added. 1027 * <p> 1028 * This returns a {@code LocalTime}, based on this one, with the amount 1029 * in terms of the unit added. If it is not possible to add the amount, because the 1030 * unit is not supported or for some other reason, an exception is thrown. 1031 * <p> 1032 * If the field is a {@link ChronoUnit} then the addition is implemented here. 1033 * The supported fields behave as follows: 1034 * <ul> 1035 * <li>{@code NANOS} - 1036 * Returns a {@code LocalTime} with the specified number of nanoseconds added. 1037 * This is equivalent to {@link #plusNanos(long)}. 1038 * <li>{@code MICROS} - 1039 * Returns a {@code LocalTime} with the specified number of microseconds added. 1040 * This is equivalent to {@link #plusNanos(long)} with the amount 1041 * multiplied by 1,000. 1042 * <li>{@code MILLIS} - 1043 * Returns a {@code LocalTime} with the specified number of milliseconds added. 1044 * This is equivalent to {@link #plusNanos(long)} with the amount 1045 * multiplied by 1,000,000. 1046 * <li>{@code SECONDS} - 1047 * Returns a {@code LocalTime} with the specified number of seconds added. 1048 * This is equivalent to {@link #plusSeconds(long)}. 1049 * <li>{@code MINUTES} - 1050 * Returns a {@code LocalTime} with the specified number of minutes added. 1051 * This is equivalent to {@link #plusMinutes(long)}. 1052 * <li>{@code HOURS} - 1053 * Returns a {@code LocalTime} with the specified number of hours added. 1054 * This is equivalent to {@link #plusHours(long)}. 1055 * <li>{@code HALF_DAYS} - 1056 * Returns a {@code LocalTime} with the specified number of half-days added. 1057 * This is equivalent to {@link #plusHours(long)} with the amount 1058 * multiplied by 12. 1059 * </ul> 1060 * <p> 1061 * All other {@code ChronoUnit} instances will throw an {@code UnsupportedTemporalTypeException}. 1062 * <p> 1063 * If the field is not a {@code ChronoUnit}, then the result of this method 1064 * is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)} 1065 * passing {@code this} as the argument. In this case, the unit determines 1066 * whether and how to perform the addition. 1067 * <p> 1068 * This instance is immutable and unaffected by this method call. 1069 * 1070 * @param amountToAdd the amount of the unit to add to the result, may be negative 1071 * @param unit the unit of the amount to add, not null 1072 * @return a {@code LocalTime} based on this time with the specified amount added, not null 1073 * @throws DateTimeException if the addition cannot be made 1074 * @throws UnsupportedTemporalTypeException if the unit is not supported 1075 * @throws ArithmeticException if numeric overflow occurs 1076 */ 1077 @Override 1078 public LocalTime plus(long amountToAdd, TemporalUnit unit) { 1079 if (unit instanceof ChronoUnit chronoUnit) { 1080 return switch (chronoUnit) { 1081 case NANOS -> plusNanos(amountToAdd); 1082 case MICROS -> plusNanos((amountToAdd % MICROS_PER_DAY) * 1000); 1083 case MILLIS -> plusNanos((amountToAdd % MILLIS_PER_DAY) * 1000_000); 1084 case SECONDS -> plusSeconds(amountToAdd); 1085 case MINUTES -> plusMinutes(amountToAdd); 1086 case HOURS -> plusHours(amountToAdd); 1087 case HALF_DAYS -> plusHours((amountToAdd % 2) * 12); 1088 default -> throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); 1089 }; 1090 } 1091 return unit.addTo(this, amountToAdd); 1092 } 1093 1094 //----------------------------------------------------------------------- 1095 /** 1096 * Returns a copy of this {@code LocalTime} with the specified number of hours added. 1097 * <p> 1098 * This adds the specified number of hours to this time, returning a new time. 1099 * The calculation wraps around midnight. 1100 * <p> 1101 * This instance is immutable and unaffected by this method call. 1102 * 1103 * @param hoursToAdd the hours to add, may be negative 1104 * @return a {@code LocalTime} based on this time with the hours added, not null 1105 */ 1106 public LocalTime plusHours(long hoursToAdd) { 1107 if (hoursToAdd == 0) { 1108 return this; 1109 } 1110 int newHour = ((int) (hoursToAdd % HOURS_PER_DAY) + hour + HOURS_PER_DAY) % HOURS_PER_DAY; 1111 return create(newHour, minute, second, nano); 1112 } 1113 1114 /** 1115 * Returns a copy of this {@code LocalTime} with the specified number of minutes added. 1116 * <p> 1117 * This adds the specified number of minutes to this time, returning a new time. 1118 * The calculation wraps around midnight. 1119 * <p> 1120 * This instance is immutable and unaffected by this method call. 1121 * 1122 * @param minutesToAdd the minutes to add, may be negative 1123 * @return a {@code LocalTime} based on this time with the minutes added, not null 1124 */ 1125 public LocalTime plusMinutes(long minutesToAdd) { 1126 if (minutesToAdd == 0) { 1127 return this; 1128 } 1129 int mofd = hour * MINUTES_PER_HOUR + minute; 1130 int newMofd = ((int) (minutesToAdd % MINUTES_PER_DAY) + mofd + MINUTES_PER_DAY) % MINUTES_PER_DAY; 1131 if (mofd == newMofd) { 1132 return this; 1133 } 1134 int newHour = newMofd / MINUTES_PER_HOUR; 1135 int newMinute = newMofd % MINUTES_PER_HOUR; 1136 return create(newHour, newMinute, second, nano); 1137 } 1138 1139 /** 1140 * Returns a copy of this {@code LocalTime} with the specified number of seconds added. 1141 * <p> 1142 * This adds the specified number of seconds to this time, returning a new time. 1143 * The calculation wraps around midnight. 1144 * <p> 1145 * This instance is immutable and unaffected by this method call. 1146 * 1147 * @param secondstoAdd the seconds to add, may be negative 1148 * @return a {@code LocalTime} based on this time with the seconds added, not null 1149 */ 1150 public LocalTime plusSeconds(long secondstoAdd) { 1151 if (secondstoAdd == 0) { 1152 return this; 1153 } 1154 int sofd = hour * SECONDS_PER_HOUR + 1155 minute * SECONDS_PER_MINUTE + second; 1156 int newSofd = ((int) (secondstoAdd % SECONDS_PER_DAY) + sofd + SECONDS_PER_DAY) % SECONDS_PER_DAY; 1157 if (sofd == newSofd) { 1158 return this; 1159 } 1160 int newHour = newSofd / SECONDS_PER_HOUR; 1161 int newMinute = (newSofd / SECONDS_PER_MINUTE) % MINUTES_PER_HOUR; 1162 int newSecond = newSofd % SECONDS_PER_MINUTE; 1163 return create(newHour, newMinute, newSecond, nano); 1164 } 1165 1166 /** 1167 * Returns a copy of this {@code LocalTime} with the specified number of nanoseconds added. 1168 * <p> 1169 * This adds the specified number of nanoseconds to this time, returning a new time. 1170 * The calculation wraps around midnight. 1171 * <p> 1172 * This instance is immutable and unaffected by this method call. 1173 * 1174 * @param nanosToAdd the nanos to add, may be negative 1175 * @return a {@code LocalTime} based on this time with the nanoseconds added, not null 1176 */ 1177 public LocalTime plusNanos(long nanosToAdd) { 1178 if (nanosToAdd == 0) { 1179 return this; 1180 } 1181 long nofd = toNanoOfDay(); 1182 long newNofd = ((nanosToAdd % NANOS_PER_DAY) + nofd + NANOS_PER_DAY) % NANOS_PER_DAY; 1183 if (nofd == newNofd) { 1184 return this; 1185 } 1186 int newHour = (int) (newNofd / NANOS_PER_HOUR); 1187 int newMinute = (int) ((newNofd / NANOS_PER_MINUTE) % MINUTES_PER_HOUR); 1188 int newSecond = (int) ((newNofd / NANOS_PER_SECOND) % SECONDS_PER_MINUTE); 1189 int newNano = (int) (newNofd % NANOS_PER_SECOND); 1190 return create(newHour, newMinute, newSecond, newNano); 1191 } 1192 1193 //----------------------------------------------------------------------- 1194 /** 1195 * Returns a copy of this time with the specified amount subtracted. 1196 * <p> 1197 * This returns a {@code LocalTime}, based on this one, with the specified amount subtracted. 1198 * The amount is typically {@link Duration} but may be any other type implementing 1199 * the {@link TemporalAmount} interface. 1200 * <p> 1201 * The calculation is delegated to the amount object by calling 1202 * {@link TemporalAmount#subtractFrom(Temporal)}. The amount implementation is free 1203 * to implement the subtraction in any way it wishes, however it typically 1204 * calls back to {@link #minus(long, TemporalUnit)}. Consult the documentation 1205 * of the amount implementation to determine if it can be successfully subtracted. 1206 * <p> 1207 * This instance is immutable and unaffected by this method call. 1208 * 1209 * @param amountToSubtract the amount to subtract, not null 1210 * @return a {@code LocalTime} based on this time with the subtraction made, not null 1211 * @throws DateTimeException if the subtraction cannot be made 1212 * @throws ArithmeticException if numeric overflow occurs 1213 */ 1214 @Override 1215 public LocalTime minus(TemporalAmount amountToSubtract) { 1216 return (LocalTime) amountToSubtract.subtractFrom(this); 1217 } 1218 1219 /** 1220 * Returns a copy of this time with the specified amount subtracted. 1221 * <p> 1222 * This returns a {@code LocalTime}, based on this one, with the amount 1223 * in terms of the unit subtracted. If it is not possible to subtract the amount, 1224 * because the unit is not supported or for some other reason, an exception is thrown. 1225 * <p> 1226 * This method is equivalent to {@link #plus(long, TemporalUnit)} with the amount negated. 1227 * See that method for a full description of how addition, and thus subtraction, works. 1228 * <p> 1229 * This instance is immutable and unaffected by this method call. 1230 * 1231 * @param amountToSubtract the amount of the unit to subtract from the result, may be negative 1232 * @param unit the unit of the amount to subtract, not null 1233 * @return a {@code LocalTime} based on this time with the specified amount subtracted, not null 1234 * @throws DateTimeException if the subtraction cannot be made 1235 * @throws UnsupportedTemporalTypeException if the unit is not supported 1236 * @throws ArithmeticException if numeric overflow occurs 1237 */ 1238 @Override 1239 public LocalTime minus(long amountToSubtract, TemporalUnit unit) { 1240 return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit)); 1241 } 1242 1243 //----------------------------------------------------------------------- 1244 /** 1245 * Returns a copy of this {@code LocalTime} with the specified number of hours subtracted. 1246 * <p> 1247 * This subtracts the specified number of hours from this time, returning a new time. 1248 * The calculation wraps around midnight. 1249 * <p> 1250 * This instance is immutable and unaffected by this method call. 1251 * 1252 * @param hoursToSubtract the hours to subtract, may be negative 1253 * @return a {@code LocalTime} based on this time with the hours subtracted, not null 1254 */ 1255 public LocalTime minusHours(long hoursToSubtract) { 1256 return plusHours(-(hoursToSubtract % HOURS_PER_DAY)); 1257 } 1258 1259 /** 1260 * Returns a copy of this {@code LocalTime} with the specified number of minutes subtracted. 1261 * <p> 1262 * This subtracts the specified number of minutes from this time, returning a new time. 1263 * The calculation wraps around midnight. 1264 * <p> 1265 * This instance is immutable and unaffected by this method call. 1266 * 1267 * @param minutesToSubtract the minutes to subtract, may be negative 1268 * @return a {@code LocalTime} based on this time with the minutes subtracted, not null 1269 */ 1270 public LocalTime minusMinutes(long minutesToSubtract) { 1271 return plusMinutes(-(minutesToSubtract % MINUTES_PER_DAY)); 1272 } 1273 1274 /** 1275 * Returns a copy of this {@code LocalTime} with the specified number of seconds subtracted. 1276 * <p> 1277 * This subtracts the specified number of seconds from this time, returning a new time. 1278 * The calculation wraps around midnight. 1279 * <p> 1280 * This instance is immutable and unaffected by this method call. 1281 * 1282 * @param secondsToSubtract the seconds to subtract, may be negative 1283 * @return a {@code LocalTime} based on this time with the seconds subtracted, not null 1284 */ 1285 public LocalTime minusSeconds(long secondsToSubtract) { 1286 return plusSeconds(-(secondsToSubtract % SECONDS_PER_DAY)); 1287 } 1288 1289 /** 1290 * Returns a copy of this {@code LocalTime} with the specified number of nanoseconds subtracted. 1291 * <p> 1292 * This subtracts the specified number of nanoseconds from this time, returning a new time. 1293 * The calculation wraps around midnight. 1294 * <p> 1295 * This instance is immutable and unaffected by this method call. 1296 * 1297 * @param nanosToSubtract the nanos to subtract, may be negative 1298 * @return a {@code LocalTime} based on this time with the nanoseconds subtracted, not null 1299 */ 1300 public LocalTime minusNanos(long nanosToSubtract) { 1301 return plusNanos(-(nanosToSubtract % NANOS_PER_DAY)); 1302 } 1303 1304 //----------------------------------------------------------------------- 1305 /** 1306 * Queries this time using the specified query. 1307 * <p> 1308 * This queries this time using the specified query strategy object. 1309 * The {@code TemporalQuery} object defines the logic to be used to 1310 * obtain the result. Read the documentation of the query to understand 1311 * what the result of this method will be. 1312 * <p> 1313 * The result of this method is obtained by invoking the 1314 * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the 1315 * specified query passing {@code this} as the argument. 1316 * 1317 * @param <R> the type of the result 1318 * @param query the query to invoke, not null 1319 * @return the query result, null may be returned (defined by the query) 1320 * @throws DateTimeException if unable to query (defined by the query) 1321 * @throws ArithmeticException if numeric overflow occurs (defined by the query) 1322 */ 1323 @SuppressWarnings("unchecked") 1324 @Override 1325 public <R> R query(TemporalQuery<R> query) { 1326 if (query == TemporalQueries.chronology() || query == TemporalQueries.zoneId() || 1327 query == TemporalQueries.zone() || query == TemporalQueries.offset()) { 1328 return null; 1329 } else if (query == TemporalQueries.localTime()) { 1330 return (R) this; 1331 } else if (query == TemporalQueries.localDate()) { 1332 return null; 1333 } else if (query == TemporalQueries.precision()) { 1334 return (R) NANOS; 1335 } 1336 // inline TemporalAccessor.super.query(query) as an optimization 1337 // non-JDK classes are not permitted to make this optimization 1338 return query.queryFrom(this); 1339 } 1340 1341 /** 1342 * Adjusts the specified temporal object to have the same time as this object. 1343 * <p> 1344 * This returns a temporal object of the same observable type as the input 1345 * with the time changed to be the same as this. 1346 * <p> 1347 * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)} 1348 * passing {@link ChronoField#NANO_OF_DAY} as the field. 1349 * <p> 1350 * In most cases, it is clearer to reverse the calling pattern by using 1351 * {@link Temporal#with(TemporalAdjuster)}: 1352 * <pre> 1353 * // these two lines are equivalent, but the second approach is recommended 1354 * temporal = thisLocalTime.adjustInto(temporal); 1355 * temporal = temporal.with(thisLocalTime); 1356 * </pre> 1357 * <p> 1358 * This instance is immutable and unaffected by this method call. 1359 * 1360 * @param temporal the target object to be adjusted, not null 1361 * @return the adjusted object, not null 1362 * @throws DateTimeException if unable to make the adjustment 1363 * @throws ArithmeticException if numeric overflow occurs 1364 */ 1365 @Override 1366 public Temporal adjustInto(Temporal temporal) { 1367 return temporal.with(NANO_OF_DAY, toNanoOfDay()); 1368 } 1369 1370 /** 1371 * Calculates the amount of time until another time in terms of the specified unit. 1372 * <p> 1373 * This calculates the amount of time between two {@code LocalTime} 1374 * objects in terms of a single {@code TemporalUnit}. 1375 * The start and end points are {@code this} and the specified time. 1376 * The result will be negative if the end is before the start. 1377 * The {@code Temporal} passed to this method is converted to a 1378 * {@code LocalTime} using {@link #from(TemporalAccessor)}. 1379 * For example, the amount in hours between two times can be calculated 1380 * using {@code startTime.until(endTime, HOURS)}. 1381 * <p> 1382 * The calculation returns a whole number, representing the number of 1383 * complete units between the two times. 1384 * For example, the amount in hours between 11:30 and 13:29 will only 1385 * be one hour as it is one minute short of two hours. 1386 * <p> 1387 * There are two equivalent ways of using this method. 1388 * The first is to invoke this method. 1389 * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}: 1390 * <pre> 1391 * // these two lines are equivalent 1392 * amount = start.until(end, MINUTES); 1393 * amount = MINUTES.between(start, end); 1394 * </pre> 1395 * The choice should be made based on which makes the code more readable. 1396 * <p> 1397 * The calculation is implemented in this method for {@link ChronoUnit}. 1398 * The units {@code NANOS}, {@code MICROS}, {@code MILLIS}, {@code SECONDS}, 1399 * {@code MINUTES}, {@code HOURS} and {@code HALF_DAYS} are supported. 1400 * Other {@code ChronoUnit} values will throw an exception. 1401 * <p> 1402 * If the unit is not a {@code ChronoUnit}, then the result of this method 1403 * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} 1404 * passing {@code this} as the first argument and the converted input temporal 1405 * as the second argument. 1406 * <p> 1407 * This instance is immutable and unaffected by this method call. 1408 * 1409 * @param endExclusive the end time, exclusive, which is converted to a {@code LocalTime}, not null 1410 * @param unit the unit to measure the amount in, not null 1411 * @return the amount of time between this time and the end time 1412 * @throws DateTimeException if the amount cannot be calculated, or the end 1413 * temporal cannot be converted to a {@code LocalTime} 1414 * @throws UnsupportedTemporalTypeException if the unit is not supported 1415 * @throws ArithmeticException if numeric overflow occurs 1416 */ 1417 @Override 1418 public long until(Temporal endExclusive, TemporalUnit unit) { 1419 LocalTime end = LocalTime.from(endExclusive); 1420 if (unit instanceof ChronoUnit chronoUnit) { 1421 long nanosUntil = end.toNanoOfDay() - toNanoOfDay(); // no overflow 1422 return switch (chronoUnit) { 1423 case NANOS -> nanosUntil; 1424 case MICROS -> nanosUntil / 1000; 1425 case MILLIS -> nanosUntil / 1000_000; 1426 case SECONDS -> nanosUntil / NANOS_PER_SECOND; 1427 case MINUTES -> nanosUntil / NANOS_PER_MINUTE; 1428 case HOURS -> nanosUntil / NANOS_PER_HOUR; 1429 case HALF_DAYS -> nanosUntil / (12 * NANOS_PER_HOUR); 1430 default -> throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); 1431 }; 1432 } 1433 return unit.between(this, end); 1434 } 1435 1436 /** 1437 * Formats this time using the specified formatter. 1438 * <p> 1439 * This time will be passed to the formatter to produce a string. 1440 * 1441 * @param formatter the formatter to use, not null 1442 * @return the formatted time string, not null 1443 * @throws DateTimeException if an error occurs during printing 1444 */ 1445 public String format(DateTimeFormatter formatter) { 1446 Objects.requireNonNull(formatter, "formatter"); 1447 return formatter.format(this); 1448 } 1449 1450 //----------------------------------------------------------------------- 1451 /** 1452 * Combines this time with a date to create a {@code LocalDateTime}. 1453 * <p> 1454 * This returns a {@code LocalDateTime} formed from this time at the specified date. 1455 * All possible combinations of date and time are valid. 1456 * 1457 * @param date the date to combine with, not null 1458 * @return the local date-time formed from this time and the specified date, not null 1459 */ 1460 public LocalDateTime atDate(LocalDate date) { 1461 return LocalDateTime.of(date, this); 1462 } 1463 1464 /** 1465 * Combines this time with an offset to create an {@code OffsetTime}. 1466 * <p> 1467 * This returns an {@code OffsetTime} formed from this time at the specified offset. 1468 * All possible combinations of time and offset are valid. 1469 * 1470 * @param offset the offset to combine with, not null 1471 * @return the offset time formed from this time and the specified offset, not null 1472 */ 1473 public OffsetTime atOffset(ZoneOffset offset) { 1474 return OffsetTime.of(this, offset); 1475 } 1476 1477 //----------------------------------------------------------------------- 1478 /** 1479 * Extracts the time as seconds of day, 1480 * from {@code 0} to {@code 24 * 60 * 60 - 1}. 1481 * 1482 * @return the second-of-day equivalent to this time 1483 */ 1484 public int toSecondOfDay() { 1485 int total = hour * SECONDS_PER_HOUR; 1486 total += minute * SECONDS_PER_MINUTE; 1487 total += second; 1488 return total; 1489 } 1490 1491 /** 1492 * Extracts the time as nanos of day, 1493 * from {@code 0} to {@code 24 * 60 * 60 * 1,000,000,000 - 1}. 1494 * 1495 * @return the nano of day equivalent to this time 1496 */ 1497 public long toNanoOfDay() { 1498 long total = hour * NANOS_PER_HOUR; 1499 total += minute * NANOS_PER_MINUTE; 1500 total += second * NANOS_PER_SECOND; 1501 total += nano; 1502 return total; 1503 } 1504 1505 /** 1506 * Converts this {@code LocalTime} to the number of seconds since the epoch 1507 * of 1970-01-01T00:00:00Z. 1508 * <p> 1509 * This combines this local time with the specified date and 1510 * offset to calculate the epoch-second value, which is the 1511 * number of elapsed seconds from 1970-01-01T00:00:00Z. 1512 * Instants on the time-line after the epoch are positive, earlier 1513 * are negative. 1514 * 1515 * @param date the local date, not null 1516 * @param offset the zone offset, not null 1517 * @return the number of seconds since the epoch of 1970-01-01T00:00:00Z, may be negative 1518 * @since 9 1519 */ 1520 public long toEpochSecond(LocalDate date, ZoneOffset offset) { 1521 Objects.requireNonNull(date, "date"); 1522 Objects.requireNonNull(offset, "offset"); 1523 long epochDay = date.toEpochDay(); 1524 long secs = epochDay * 86400 + toSecondOfDay(); 1525 secs -= offset.getTotalSeconds(); 1526 return secs; 1527 } 1528 1529 //----------------------------------------------------------------------- 1530 /** 1531 * Compares this time to another time. 1532 * <p> 1533 * The comparison is based on the time-line position of the local times within a day. 1534 * It is "consistent with equals", as defined by {@link Comparable}. 1535 * 1536 * @param other the other time to compare to, not null 1537 * @return the comparator value, that is less than zero if this is before {@code other}, 1538 * zero if they are equal, or greater than zero if this is after {@code other} 1539 * @see #isBefore 1540 * @see #isAfter 1541 */ 1542 @Override 1543 public int compareTo(LocalTime other) { 1544 int cmp = Integer.compare(hour, other.hour); 1545 if (cmp == 0) { 1546 cmp = Integer.compare(minute, other.minute); 1547 if (cmp == 0) { 1548 cmp = Integer.compare(second, other.second); 1549 if (cmp == 0) { 1550 cmp = Integer.compare(nano, other.nano); 1551 } 1552 } 1553 } 1554 return cmp; 1555 } 1556 1557 /** 1558 * Checks if this time is after the specified time. 1559 * <p> 1560 * The comparison is based on the time-line position of the time within a day. 1561 * 1562 * @param other the other time to compare to, not null 1563 * @return true if this is after the specified time 1564 */ 1565 public boolean isAfter(LocalTime other) { 1566 return compareTo(other) > 0; 1567 } 1568 1569 /** 1570 * Checks if this time is before the specified time. 1571 * <p> 1572 * The comparison is based on the time-line position of the time within a day. 1573 * 1574 * @param other the other time to compare to, not null 1575 * @return true if this point is before the specified time 1576 */ 1577 public boolean isBefore(LocalTime other) { 1578 return compareTo(other) < 0; 1579 } 1580 1581 //----------------------------------------------------------------------- 1582 /** 1583 * Checks if this time is equal to another time. 1584 * <p> 1585 * The comparison is based on the time-line position of the time within a day. 1586 * <p> 1587 * Only objects of type {@code LocalTime} are compared, other types return false. 1588 * To compare the date of two {@code TemporalAccessor} instances, use 1589 * {@link ChronoField#NANO_OF_DAY} as a comparator. 1590 * 1591 * @param obj the object to check, null returns false 1592 * @return true if this is equal to the other time 1593 */ 1594 @Override 1595 public boolean equals(Object obj) { 1596 if (this == obj) { 1597 return true; 1598 } 1599 return (obj instanceof LocalTime other) 1600 && hour == other.hour 1601 && minute == other.minute 1602 && second == other.second 1603 && nano == other.nano; 1604 } 1605 1606 /** 1607 * A hash code for this time. 1608 * 1609 * @return a suitable hash code 1610 */ 1611 @Override 1612 public int hashCode() { 1613 return Long.hashCode(toNanoOfDay()); 1614 } 1615 1616 //----------------------------------------------------------------------- 1617 /** 1618 * Outputs this time as a {@code String}, such as {@code 10:15}. 1619 * <p> 1620 * The output will be one of the following ISO-8601 formats: 1621 * <ul> 1622 * <li>{@code HH:mm}</li> 1623 * <li>{@code HH:mm:ss}</li> 1624 * <li>{@code HH:mm:ss.SSS}</li> 1625 * <li>{@code HH:mm:ss.SSSSSS}</li> 1626 * <li>{@code HH:mm:ss.SSSSSSSSS}</li> 1627 * </ul> 1628 * The format used will be the shortest that outputs the full value of 1629 * the time where the omitted parts are implied to be zero. 1630 * 1631 * @return a string representation of this time, not null 1632 */ 1633 @Override 1634 public String toString() { 1635 var buf = new StringBuilder(18); 1636 formatTo(buf); 1637 return buf.toString(); 1638 } 1639 1640 /** 1641 * Prints the toString result to the given buf, avoiding extra string allocations. 1642 * Requires extra capacity of 18 to avoid StringBuilder reallocation. 1643 */ 1644 void formatTo(StringBuilder buf) { 1645 int hourValue = hour; 1646 int minuteValue = minute; 1647 int secondValue = second; 1648 int nanoValue = nano; 1649 buf.append(hourValue < 10 ? "0" : "").append(hourValue) 1650 .append(minuteValue < 10 ? ":0" : ":").append(minuteValue); 1651 if (secondValue > 0 || nanoValue > 0) { 1652 buf.append(secondValue < 10 ? ":0" : ":").append(secondValue); 1653 if (nanoValue > 0) { 1654 buf.append('.'); 1655 int zeros = 9 - DecimalDigits.stringSize(nanoValue); 1656 if (zeros > 0) { 1657 buf.repeat('0', zeros); 1658 } 1659 int digits; 1660 if (nanoValue % 1_000_000 == 0) { 1661 digits = nanoValue / 1_000_000; 1662 } else if (nanoValue % 1000 == 0) { 1663 digits = nanoValue / 1000; 1664 } else { 1665 digits = nanoValue; 1666 } 1667 buf.append(digits); 1668 } 1669 } 1670 } 1671 1672 //----------------------------------------------------------------------- 1673 /** 1674 * Writes the object using a 1675 * <a href="{@docRoot}/serialized-form.html#java.time.Ser">dedicated serialized form</a>. 1676 * @serialData 1677 * A twos-complement value indicates the remaining values are not in the stream 1678 * and should be set to zero. 1679 * <pre> 1680 * out.writeByte(4); // identifies a LocalTime 1681 * if (nano == 0) { 1682 * if (second == 0) { 1683 * if (minute == 0) { 1684 * out.writeByte(~hour); 1685 * } else { 1686 * out.writeByte(hour); 1687 * out.writeByte(~minute); 1688 * } 1689 * } else { 1690 * out.writeByte(hour); 1691 * out.writeByte(minute); 1692 * out.writeByte(~second); 1693 * } 1694 * } else { 1695 * out.writeByte(hour); 1696 * out.writeByte(minute); 1697 * out.writeByte(second); 1698 * out.writeInt(nano); 1699 * } 1700 * </pre> 1701 * 1702 * @return the instance of {@code Ser}, not null 1703 */ 1704 @java.io.Serial 1705 private Object writeReplace() { 1706 return new Ser(Ser.LOCAL_TIME_TYPE, this); 1707 } 1708 1709 /** 1710 * Defend against malicious streams. 1711 * 1712 * @param s the stream to read 1713 * @throws InvalidObjectException always 1714 */ 1715 @java.io.Serial 1716 private void readObject(ObjectInputStream s) throws InvalidObjectException { 1717 throw new InvalidObjectException("Deserialization via serialization delegate"); 1718 } 1719 1720 void writeExternal(DataOutput out) throws IOException { 1721 if (nano == 0) { 1722 if (second == 0) { 1723 if (minute == 0) { 1724 out.writeByte(~hour); 1725 } else { 1726 out.writeByte(hour); 1727 out.writeByte(~minute); 1728 } 1729 } else { 1730 out.writeByte(hour); 1731 out.writeByte(minute); 1732 out.writeByte(~second); 1733 } 1734 } else { 1735 out.writeByte(hour); 1736 out.writeByte(minute); 1737 out.writeByte(second); 1738 out.writeInt(nano); 1739 } 1740 } 1741 1742 static LocalTime readExternal(DataInput in) throws IOException { 1743 int hour = in.readByte(); 1744 int minute = 0; 1745 int second = 0; 1746 int nano = 0; 1747 if (hour < 0) { 1748 hour = ~hour; 1749 } else { 1750 minute = in.readByte(); 1751 if (minute < 0) { 1752 minute = ~minute; 1753 } else { 1754 second = in.readByte(); 1755 if (second < 0) { 1756 second = ~second; 1757 } else { 1758 nano = in.readInt(); 1759 } 1760 } 1761 } 1762 return LocalTime.of(hour, minute, second, nano); 1763 } 1764 1765 }