1 /* 2 * Copyright (c) 2012, 2025, 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.EPOCH_DAY; 65 import static java.time.temporal.ChronoField.INSTANT_SECONDS; 66 import static java.time.temporal.ChronoField.NANO_OF_DAY; 67 import static java.time.temporal.ChronoField.OFFSET_SECONDS; 68 import static java.time.temporal.ChronoUnit.FOREVER; 69 import static java.time.temporal.ChronoUnit.NANOS; 70 71 import java.io.IOException; 72 import java.io.ObjectInput; 73 import java.io.ObjectOutput; 74 import java.io.InvalidObjectException; 75 import java.io.ObjectInputStream; 76 import java.io.Serializable; 77 import java.time.chrono.IsoChronology; 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.TemporalQueries; 88 import java.time.temporal.TemporalQuery; 89 import java.time.temporal.TemporalUnit; 90 import java.time.temporal.UnsupportedTemporalTypeException; 91 import java.time.temporal.ValueRange; 92 import java.time.zone.ZoneRules; 93 import java.util.Comparator; 94 import java.util.Objects; 95 96 import jdk.internal.util.DateTimeHelper; 97 98 /** 99 * A date-time with an offset from UTC/Greenwich in the ISO-8601 calendar system, 100 * such as {@code 2007-12-03T10:15:30+01:00}. 101 * <p> 102 * {@code OffsetDateTime} is an immutable representation of a date-time with an offset. 103 * This class stores all date and time fields, to a precision of nanoseconds, 104 * as well as the offset from UTC/Greenwich. For example, the value 105 * "2nd October 2007 at 13:45:30.123456789 +02:00" can be stored in an {@code OffsetDateTime}. 106 * <p> 107 * {@code OffsetDateTime}, {@link java.time.ZonedDateTime} and {@link java.time.Instant} all store an instant 108 * on the time-line to nanosecond precision. 109 * {@code Instant} is the simplest, simply representing the instant. 110 * {@code OffsetDateTime} adds to the instant the offset from UTC/Greenwich, which allows 111 * the local date-time to be obtained. 112 * {@code ZonedDateTime} adds full time-zone rules. 113 * <p> 114 * It is intended that {@code ZonedDateTime} or {@code Instant} is used to model data 115 * in simpler applications. This class may be used when modeling date-time concepts in 116 * more detail, or when communicating to a database or in a network protocol. 117 * <p> 118 * This is a <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a> 119 * class; programmers should treat instances that are {@linkplain #equals(Object) equal} 120 * as interchangeable and should not use instances for synchronization, mutexes, or 121 * with {@linkplain java.lang.ref.Reference object references}. 122 * 123 * <div class="preview-block"> 124 * <div class="preview-comment"> 125 * When preview features are enabled, {@code OffsetDateTime} is a {@linkplain Class#isValue value class}. 126 * Use of value class instances for synchronization, mutexes, or with 127 * {@linkplain java.lang.ref.Reference object references} result in 128 * {@link IdentityException}. 129 * </div> 130 * </div> 131 * 132 * @implSpec 133 * This class is immutable and thread-safe. 134 * 135 * @since 1.8 136 */ 137 @jdk.internal.ValueBased 138 @jdk.internal.MigratedValueClass 139 public final class OffsetDateTime 140 implements Temporal, TemporalAdjuster, Comparable<OffsetDateTime>, Serializable { 141 142 /** 143 * The minimum supported {@code OffsetDateTime}, '-999999999-01-01T00:00:00+18:00'. 144 * This is the local date-time of midnight at the start of the minimum date 145 * in the maximum offset (larger offsets are earlier on the time-line). 146 * This combines {@link LocalDateTime#MIN} and {@link ZoneOffset#MAX}. 147 * This could be used by an application as a "far past" date-time. 148 */ 149 public static final OffsetDateTime MIN = LocalDateTime.MIN.atOffset(ZoneOffset.MAX); 150 /** 151 * The maximum supported {@code OffsetDateTime}, '+999999999-12-31T23:59:59.999999999-18:00'. 152 * This is the local date-time just before midnight at the end of the maximum date 153 * in the minimum offset (larger negative offsets are later on the time-line). 154 * This combines {@link LocalDateTime#MAX} and {@link ZoneOffset#MIN}. 155 * This could be used by an application as a "far future" date-time. 156 */ 157 public static final OffsetDateTime MAX = LocalDateTime.MAX.atOffset(ZoneOffset.MIN); 158 159 /** 160 * Gets a comparator that compares two {@code OffsetDateTime} instances 161 * based solely on the instant. 162 * <p> 163 * This method differs from the comparison in {@link #compareTo} in that it 164 * only compares the underlying instant. 165 * 166 * @return a comparator that compares in time-line order 167 * 168 * @see #isAfter 169 * @see #isBefore 170 * @see #isEqual 171 */ 172 public static Comparator<OffsetDateTime> timeLineOrder() { 173 return OffsetDateTime::compareInstant; 174 } 175 176 /** 177 * Compares this {@code OffsetDateTime} to another date-time. 178 * The comparison is based on the instant. 179 * 180 * @param datetime1 the first date-time to compare, not null 181 * @param datetime2 the other date-time to compare to, not null 182 * @return the comparator value, that is less than zero if {@code datetime1} is before {@code datetime2}, 183 * zero if they are equal, greater than zero if {@code datetime1} is after {@code datetime2} 184 */ 185 private static int compareInstant(OffsetDateTime datetime1, OffsetDateTime datetime2) { 186 if (datetime1.getOffset().equals(datetime2.getOffset())) { 187 return datetime1.toLocalDateTime().compareTo(datetime2.toLocalDateTime()); 188 } 189 int cmp = Long.compare(datetime1.toEpochSecond(), datetime2.toEpochSecond()); 190 if (cmp == 0) { 191 cmp = datetime1.toLocalTime().getNano() - datetime2.toLocalTime().getNano(); 192 } 193 return cmp; 194 } 195 196 /** 197 * Serialization version. 198 */ 199 @java.io.Serial 200 private static final long serialVersionUID = 2287754244819255394L; 201 202 /** 203 * @serial The local date-time. 204 */ 205 private final LocalDateTime dateTime; 206 /** 207 * @serial The offset from UTC/Greenwich. 208 */ 209 private final ZoneOffset offset; 210 211 //----------------------------------------------------------------------- 212 /** 213 * Obtains the current date-time from the system clock in the default time-zone. 214 * <p> 215 * This will query the {@link Clock#systemDefaultZone() system clock} in the default 216 * time-zone to obtain the current date-time. 217 * The offset will be calculated from the time-zone in the clock. 218 * <p> 219 * Using this method will prevent the ability to use an alternate clock for testing 220 * because the clock is hard-coded. 221 * 222 * @return the current date-time using the system clock, not null 223 */ 224 public static OffsetDateTime now() { 225 return now(Clock.systemDefaultZone()); 226 } 227 228 /** 229 * Obtains the current date-time from the system clock in the specified time-zone. 230 * <p> 231 * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date-time. 232 * Specifying the time-zone avoids dependence on the default time-zone. 233 * The offset will be calculated from the specified time-zone. 234 * <p> 235 * Using this method will prevent the ability to use an alternate clock for testing 236 * because the clock is hard-coded. 237 * 238 * @param zone the zone ID to use, not null 239 * @return the current date-time using the system clock, not null 240 */ 241 public static OffsetDateTime now(ZoneId zone) { 242 return now(Clock.system(zone)); 243 } 244 245 /** 246 * Obtains the current date-time from the specified clock. 247 * <p> 248 * This will query the specified clock to obtain the current date-time. 249 * The offset will be calculated from the time-zone in the clock. 250 * <p> 251 * Using this method allows the use of an alternate clock for testing. 252 * The alternate clock may be introduced using {@link Clock dependency injection}. 253 * 254 * @param clock the clock to use, not null 255 * @return the current date-time, not null 256 */ 257 public static OffsetDateTime now(Clock clock) { 258 Objects.requireNonNull(clock, "clock"); 259 final Instant now = clock.instant(); // called once 260 return ofInstant(now, clock.getZone().getRules().getOffset(now)); 261 } 262 263 //----------------------------------------------------------------------- 264 /** 265 * Obtains an instance of {@code OffsetDateTime} from a date, time and offset. 266 * <p> 267 * This creates an offset date-time with the specified local date, time and offset. 268 * 269 * @param date the local date, not null 270 * @param time the local time, not null 271 * @param offset the zone offset, not null 272 * @return the offset date-time, not null 273 */ 274 public static OffsetDateTime of(LocalDate date, LocalTime time, ZoneOffset offset) { 275 LocalDateTime dt = LocalDateTime.of(date, time); 276 return new OffsetDateTime(dt, offset); 277 } 278 279 /** 280 * Obtains an instance of {@code OffsetDateTime} from a date-time and offset. 281 * <p> 282 * This creates an offset date-time with the specified local date-time and offset. 283 * 284 * @param dateTime the local date-time, not null 285 * @param offset the zone offset, not null 286 * @return the offset date-time, not null 287 */ 288 public static OffsetDateTime of(LocalDateTime dateTime, ZoneOffset offset) { 289 return new OffsetDateTime(dateTime, offset); 290 } 291 292 /** 293 * Obtains an instance of {@code OffsetDateTime} from a year, month, day, 294 * hour, minute, second, nanosecond and offset. 295 * <p> 296 * This creates an offset date-time with the seven specified fields. 297 * <p> 298 * This method exists primarily for writing test cases. 299 * Non test-code will typically use other methods to create an offset time. 300 * {@code LocalDateTime} has five additional convenience variants of the 301 * equivalent factory method taking fewer arguments. 302 * They are not provided here to reduce the footprint of the API. 303 * 304 * @param year the year to represent, from MIN_YEAR to MAX_YEAR 305 * @param month the month-of-year to represent, from 1 (January) to 12 (December) 306 * @param dayOfMonth the day-of-month to represent, from 1 to 31 307 * @param hour the hour-of-day to represent, from 0 to 23 308 * @param minute the minute-of-hour to represent, from 0 to 59 309 * @param second the second-of-minute to represent, from 0 to 59 310 * @param nanoOfSecond the nano-of-second to represent, from 0 to 999,999,999 311 * @param offset the zone offset, not null 312 * @return the offset date-time, not null 313 * @throws DateTimeException if the value of any field is out of range, or 314 * if the day-of-month is invalid for the month-year 315 */ 316 public static OffsetDateTime of( 317 int year, int month, int dayOfMonth, 318 int hour, int minute, int second, int nanoOfSecond, ZoneOffset offset) { 319 LocalDateTime dt = LocalDateTime.of(year, month, dayOfMonth, hour, minute, second, nanoOfSecond); 320 return new OffsetDateTime(dt, offset); 321 } 322 323 //----------------------------------------------------------------------- 324 /** 325 * Obtains an instance of {@code OffsetDateTime} from an {@code Instant} and zone ID. 326 * <p> 327 * This creates an offset date-time with the same instant as that specified. 328 * Finding the offset from UTC/Greenwich is simple as there is only one valid 329 * offset for each instant. 330 * 331 * @param instant the instant to create the date-time from, not null 332 * @param zone the time-zone, which may be an offset, not null 333 * @return the offset date-time, not null 334 * @throws DateTimeException if the result exceeds the supported range 335 */ 336 public static OffsetDateTime ofInstant(Instant instant, ZoneId zone) { 337 Objects.requireNonNull(instant, "instant"); 338 Objects.requireNonNull(zone, "zone"); 339 ZoneRules rules = zone.getRules(); 340 ZoneOffset offset = rules.getOffset(instant); 341 LocalDateTime ldt = LocalDateTime.ofEpochSecond(instant.getEpochSecond(), instant.getNano(), offset); 342 return new OffsetDateTime(ldt, offset); 343 } 344 345 //----------------------------------------------------------------------- 346 /** 347 * Obtains an instance of {@code OffsetDateTime} from a temporal object. 348 * <p> 349 * This obtains an offset date-time based on the specified temporal. 350 * A {@code TemporalAccessor} represents an arbitrary set of date and time information, 351 * which this factory converts to an instance of {@code OffsetDateTime}. 352 * <p> 353 * The conversion will first obtain a {@code ZoneOffset} from the temporal object. 354 * It will then try to obtain a {@code LocalDateTime}, falling back to an {@code Instant} if necessary. 355 * The result will be the combination of {@code ZoneOffset} with either 356 * with {@code LocalDateTime} or {@code Instant}. 357 * Implementations are permitted to perform optimizations such as accessing 358 * those fields that are equivalent to the relevant objects. 359 * <p> 360 * This method matches the signature of the functional interface {@link TemporalQuery} 361 * allowing it to be used as a query via method reference, {@code OffsetDateTime::from}. 362 * 363 * @param temporal the temporal object to convert, not null 364 * @return the offset date-time, not null 365 * @throws DateTimeException if unable to convert to an {@code OffsetDateTime} 366 */ 367 public static OffsetDateTime from(TemporalAccessor temporal) { 368 if (temporal instanceof OffsetDateTime) { 369 return (OffsetDateTime) temporal; 370 } 371 try { 372 ZoneOffset offset = ZoneOffset.from(temporal); 373 LocalDate date = temporal.query(TemporalQueries.localDate()); 374 LocalTime time = temporal.query(TemporalQueries.localTime()); 375 if (date != null && time != null) { 376 return OffsetDateTime.of(date, time, offset); 377 } else { 378 Instant instant = Instant.from(temporal); 379 return OffsetDateTime.ofInstant(instant, offset); 380 } 381 } catch (DateTimeException ex) { 382 throw new DateTimeException("Unable to obtain OffsetDateTime from TemporalAccessor: " + 383 temporal + " of type " + temporal.getClass().getName(), ex); 384 } 385 } 386 387 //----------------------------------------------------------------------- 388 /** 389 * Obtains an instance of {@code OffsetDateTime} from a text string 390 * such as {@code 2007-12-03T10:15:30+01:00}. 391 * <p> 392 * The string must represent a valid date-time and is parsed using 393 * {@link java.time.format.DateTimeFormatter#ISO_OFFSET_DATE_TIME}. 394 * 395 * @param text the text to parse such as "2007-12-03T10:15:30+01:00", not null 396 * @return the parsed offset date-time, not null 397 * @throws DateTimeParseException if the text cannot be parsed 398 */ 399 public static OffsetDateTime parse(CharSequence text) { 400 return parse(text, DateTimeFormatter.ISO_OFFSET_DATE_TIME); 401 } 402 403 /** 404 * Obtains an instance of {@code OffsetDateTime} from a text string using a specific formatter. 405 * <p> 406 * The text is parsed using the formatter, returning a date-time. 407 * 408 * @param text the text to parse, not null 409 * @param formatter the formatter to use, not null 410 * @return the parsed offset date-time, not null 411 * @throws DateTimeParseException if the text cannot be parsed 412 */ 413 public static OffsetDateTime parse(CharSequence text, DateTimeFormatter formatter) { 414 Objects.requireNonNull(formatter, "formatter"); 415 return formatter.parse(text, OffsetDateTime::from); 416 } 417 418 //----------------------------------------------------------------------- 419 /** 420 * Constructor. 421 * 422 * @param dateTime the local date-time, not null 423 * @param offset the zone offset, not null 424 */ 425 private OffsetDateTime(LocalDateTime dateTime, ZoneOffset offset) { 426 this.dateTime = Objects.requireNonNull(dateTime, "dateTime"); 427 this.offset = Objects.requireNonNull(offset, "offset"); 428 } 429 430 /** 431 * Returns a new date-time based on this one, returning {@code this} where possible. 432 * 433 * @param dateTime the date-time to create with, not null 434 * @param offset the zone offset to create with, not null 435 */ 436 private OffsetDateTime with(LocalDateTime dateTime, ZoneOffset offset) { 437 if (this.dateTime == dateTime && this.offset.equals(offset)) { 438 return this; 439 } 440 return new OffsetDateTime(dateTime, offset); 441 } 442 443 //----------------------------------------------------------------------- 444 /** 445 * Checks if the specified field is supported. 446 * <p> 447 * This checks if this date-time can be queried for the specified field. 448 * If false, then calling the {@link #range(TemporalField) range}, 449 * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)} 450 * methods will throw an exception. 451 * <p> 452 * If the field is a {@link ChronoField} then the query is implemented here. 453 * The supported fields are: 454 * <ul> 455 * <li>{@code NANO_OF_SECOND} 456 * <li>{@code NANO_OF_DAY} 457 * <li>{@code MICRO_OF_SECOND} 458 * <li>{@code MICRO_OF_DAY} 459 * <li>{@code MILLI_OF_SECOND} 460 * <li>{@code MILLI_OF_DAY} 461 * <li>{@code SECOND_OF_MINUTE} 462 * <li>{@code SECOND_OF_DAY} 463 * <li>{@code MINUTE_OF_HOUR} 464 * <li>{@code MINUTE_OF_DAY} 465 * <li>{@code HOUR_OF_AMPM} 466 * <li>{@code CLOCK_HOUR_OF_AMPM} 467 * <li>{@code HOUR_OF_DAY} 468 * <li>{@code CLOCK_HOUR_OF_DAY} 469 * <li>{@code AMPM_OF_DAY} 470 * <li>{@code DAY_OF_WEEK} 471 * <li>{@code ALIGNED_DAY_OF_WEEK_IN_MONTH} 472 * <li>{@code ALIGNED_DAY_OF_WEEK_IN_YEAR} 473 * <li>{@code DAY_OF_MONTH} 474 * <li>{@code DAY_OF_YEAR} 475 * <li>{@code EPOCH_DAY} 476 * <li>{@code ALIGNED_WEEK_OF_MONTH} 477 * <li>{@code ALIGNED_WEEK_OF_YEAR} 478 * <li>{@code MONTH_OF_YEAR} 479 * <li>{@code PROLEPTIC_MONTH} 480 * <li>{@code YEAR_OF_ERA} 481 * <li>{@code YEAR} 482 * <li>{@code ERA} 483 * <li>{@code INSTANT_SECONDS} 484 * <li>{@code OFFSET_SECONDS} 485 * </ul> 486 * All other {@code ChronoField} instances will return false. 487 * <p> 488 * If the field is not a {@code ChronoField}, then the result of this method 489 * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)} 490 * passing {@code this} as the argument. 491 * Whether the field is supported is determined by the field. 492 * 493 * @param field the field to check, null returns false 494 * @return true if the field is supported on this date-time, false if not 495 */ 496 @Override 497 public boolean isSupported(TemporalField field) { 498 return field instanceof ChronoField || (field != null && field.isSupportedBy(this)); 499 } 500 501 /** 502 * Checks if the specified unit is supported. 503 * <p> 504 * This checks if the specified unit can be added to, or subtracted from, this date-time. 505 * If false, then calling the {@link #plus(long, TemporalUnit)} and 506 * {@link #minus(long, TemporalUnit) minus} methods will throw an exception. 507 * <p> 508 * If the unit is a {@link ChronoUnit} then the query is implemented here. 509 * The supported units are: 510 * <ul> 511 * <li>{@code NANOS} 512 * <li>{@code MICROS} 513 * <li>{@code MILLIS} 514 * <li>{@code SECONDS} 515 * <li>{@code MINUTES} 516 * <li>{@code HOURS} 517 * <li>{@code HALF_DAYS} 518 * <li>{@code DAYS} 519 * <li>{@code WEEKS} 520 * <li>{@code MONTHS} 521 * <li>{@code YEARS} 522 * <li>{@code DECADES} 523 * <li>{@code CENTURIES} 524 * <li>{@code MILLENNIA} 525 * <li>{@code ERAS} 526 * </ul> 527 * All other {@code ChronoUnit} instances will return false. 528 * <p> 529 * If the unit is not a {@code ChronoUnit}, then the result of this method 530 * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)} 531 * passing {@code this} as the argument. 532 * Whether the unit is supported is determined by the unit. 533 * 534 * @param unit the unit to check, null returns false 535 * @return true if the unit can be added/subtracted, false if not 536 */ 537 @Override // override for Javadoc 538 public boolean isSupported(TemporalUnit unit) { 539 if (unit instanceof ChronoUnit) { 540 return unit != FOREVER; 541 } 542 return unit != null && unit.isSupportedBy(this); 543 } 544 545 //----------------------------------------------------------------------- 546 /** 547 * Gets the range of valid values for the specified field. 548 * <p> 549 * The range object expresses the minimum and maximum valid values for a field. 550 * This date-time is used to enhance the accuracy of the returned range. 551 * If it is not possible to return the range, because the field is not supported 552 * or for some other reason, an exception is thrown. 553 * <p> 554 * If the field is a {@link ChronoField} then the query is implemented here. 555 * The {@link #isSupported(TemporalField) supported fields} will return 556 * appropriate range instances. 557 * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}. 558 * <p> 559 * If the field is not a {@code ChronoField}, then the result of this method 560 * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)} 561 * passing {@code this} as the argument. 562 * Whether the range can be obtained is determined by the field. 563 * 564 * @param field the field to query the range for, not null 565 * @return the range of valid values for the field, not null 566 * @throws DateTimeException if the range for the field cannot be obtained 567 * @throws UnsupportedTemporalTypeException if the field is not supported 568 */ 569 @Override 570 public ValueRange range(TemporalField field) { 571 if (field instanceof ChronoField) { 572 if (field == INSTANT_SECONDS || field == OFFSET_SECONDS) { 573 return field.range(); 574 } 575 return dateTime.range(field); 576 } 577 return field.rangeRefinedBy(this); 578 } 579 580 /** 581 * Gets the value of the specified field from this date-time as an {@code int}. 582 * <p> 583 * This queries this date-time for the value of the specified field. 584 * The returned value will always be within the valid range of values for the field. 585 * If it is not possible to return the value, because the field is not supported 586 * or for some other reason, an exception is thrown. 587 * <p> 588 * If the field is a {@link ChronoField} then the query is implemented here. 589 * The {@link #isSupported(TemporalField) supported fields} will return valid 590 * values based on this date-time, except {@code NANO_OF_DAY}, {@code MICRO_OF_DAY}, 591 * {@code EPOCH_DAY}, {@code PROLEPTIC_MONTH} and {@code INSTANT_SECONDS} which are too 592 * large to fit in an {@code int} and throw an {@code UnsupportedTemporalTypeException}. 593 * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}. 594 * <p> 595 * If the field is not a {@code ChronoField}, then the result of this method 596 * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} 597 * passing {@code this} as the argument. Whether the value can be obtained, 598 * and what the value represents, is determined by the field. 599 * 600 * @param field the field to get, not null 601 * @return the value for the field 602 * @throws DateTimeException if a value for the field cannot be obtained or 603 * the value is outside the range of valid values for the field 604 * @throws UnsupportedTemporalTypeException if the field is not supported or 605 * the range of values exceeds an {@code int} 606 * @throws ArithmeticException if numeric overflow occurs 607 */ 608 @Override 609 public int get(TemporalField field) { 610 if (field instanceof ChronoField chronoField) { 611 return switch (chronoField) { 612 case INSTANT_SECONDS -> throw new UnsupportedTemporalTypeException("Invalid field " + 613 "'InstantSeconds' for get() method, use getLong() instead"); 614 case OFFSET_SECONDS -> getOffset().getTotalSeconds(); 615 default -> dateTime.get(field); 616 }; 617 } 618 return Temporal.super.get(field); 619 } 620 621 /** 622 * Gets the value of the specified field from this date-time as a {@code long}. 623 * <p> 624 * This queries this date-time for the value of the specified field. 625 * If it is not possible to return the value, because the field is not supported 626 * or for some other reason, an exception is thrown. 627 * <p> 628 * If the field is a {@link ChronoField} then the query is implemented here. 629 * The {@link #isSupported(TemporalField) supported fields} will return valid 630 * values based on this date-time. 631 * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}. 632 * <p> 633 * If the field is not a {@code ChronoField}, then the result of this method 634 * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} 635 * passing {@code this} as the argument. Whether the value can be obtained, 636 * and what the value represents, is determined by the field. 637 * 638 * @param field the field to get, not null 639 * @return the value for the field 640 * @throws DateTimeException if a value for the field cannot be obtained 641 * @throws UnsupportedTemporalTypeException if the field is not supported 642 * @throws ArithmeticException if numeric overflow occurs 643 */ 644 @Override 645 public long getLong(TemporalField field) { 646 if (field instanceof ChronoField chronoField) { 647 return switch (chronoField) { 648 case INSTANT_SECONDS -> toEpochSecond(); 649 case OFFSET_SECONDS -> getOffset().getTotalSeconds(); 650 default -> dateTime.getLong(field); 651 }; 652 } 653 return field.getFrom(this); 654 } 655 656 //----------------------------------------------------------------------- 657 /** 658 * Gets the zone offset, such as '+01:00'. 659 * <p> 660 * This is the offset of the local date-time from UTC/Greenwich. 661 * 662 * @return the zone offset, not null 663 */ 664 public ZoneOffset getOffset() { 665 return offset; 666 } 667 668 /** 669 * Returns a copy of this {@code OffsetDateTime} with the specified offset ensuring 670 * that the result has the same local date-time. 671 * <p> 672 * This method returns an object with the same {@code LocalDateTime} and the specified {@code ZoneOffset}. 673 * No calculation is needed or performed. 674 * For example, if this time represents {@code 2007-12-03T10:30+02:00} and the offset specified is 675 * {@code +03:00}, then this method will return {@code 2007-12-03T10:30+03:00}. 676 * <p> 677 * To take into account the difference between the offsets, and adjust the time fields, 678 * use {@link #withOffsetSameInstant}. 679 * <p> 680 * This instance is immutable and unaffected by this method call. 681 * 682 * @param offset the zone offset to change to, not null 683 * @return an {@code OffsetDateTime} based on this date-time with the requested offset, not null 684 */ 685 public OffsetDateTime withOffsetSameLocal(ZoneOffset offset) { 686 return with(dateTime, offset); 687 } 688 689 /** 690 * Returns a copy of this {@code OffsetDateTime} with the specified offset ensuring 691 * that the result is at the same instant. 692 * <p> 693 * This method returns an object with the specified {@code ZoneOffset} and a {@code LocalDateTime} 694 * adjusted by the difference between the two offsets. 695 * This will result in the old and new objects representing the same instant. 696 * This is useful for finding the local time in a different offset. 697 * For example, if this time represents {@code 2007-12-03T10:30+02:00} and the offset specified is 698 * {@code +03:00}, then this method will return {@code 2007-12-03T11:30+03:00}. 699 * <p> 700 * To change the offset without adjusting the local time use {@link #withOffsetSameLocal}. 701 * <p> 702 * This instance is immutable and unaffected by this method call. 703 * 704 * @param offset the zone offset to change to, not null 705 * @return an {@code OffsetDateTime} based on this date-time with the requested offset, not null 706 * @throws DateTimeException if the result exceeds the supported date range 707 */ 708 public OffsetDateTime withOffsetSameInstant(ZoneOffset offset) { 709 if (offset.equals(this.offset)) { 710 return this; 711 } 712 int difference = offset.getTotalSeconds() - this.offset.getTotalSeconds(); 713 LocalDateTime adjusted = dateTime.plusSeconds(difference); 714 return new OffsetDateTime(adjusted, offset); 715 } 716 717 //----------------------------------------------------------------------- 718 /** 719 * Gets the {@code LocalDateTime} part of this date-time. 720 * <p> 721 * This returns a {@code LocalDateTime} with the same year, month, day and time 722 * as this date-time. 723 * 724 * @return the local date-time part of this date-time, not null 725 */ 726 public LocalDateTime toLocalDateTime() { 727 return dateTime; 728 } 729 730 //----------------------------------------------------------------------- 731 /** 732 * Gets the {@code LocalDate} part of this date-time. 733 * <p> 734 * This returns a {@code LocalDate} with the same year, month and day 735 * as this date-time. 736 * 737 * @return the date part of this date-time, not null 738 */ 739 public LocalDate toLocalDate() { 740 return dateTime.toLocalDate(); 741 } 742 743 /** 744 * Gets the year field. 745 * <p> 746 * This method returns the primitive {@code int} value for the year. 747 * <p> 748 * The year returned by this method is proleptic as per {@code get(YEAR)}. 749 * To obtain the year-of-era, use {@code get(YEAR_OF_ERA)}. 750 * 751 * @return the year, from MIN_YEAR to MAX_YEAR 752 */ 753 public int getYear() { 754 return dateTime.getYear(); 755 } 756 757 /** 758 * Gets the month-of-year field from 1 to 12. 759 * <p> 760 * This method returns the month as an {@code int} from 1 to 12. 761 * Application code is frequently clearer if the enum {@link Month} 762 * is used by calling {@link #getMonth()}. 763 * 764 * @return the month-of-year, from 1 to 12 765 * @see #getMonth() 766 */ 767 public int getMonthValue() { 768 return dateTime.getMonthValue(); 769 } 770 771 /** 772 * Gets the month-of-year field using the {@code Month} enum. 773 * <p> 774 * This method returns the enum {@link Month} for the month. 775 * This avoids confusion as to what {@code int} values mean. 776 * If you need access to the primitive {@code int} value then the enum 777 * provides the {@link Month#getValue() int value}. 778 * 779 * @return the month-of-year, not null 780 * @see #getMonthValue() 781 */ 782 public Month getMonth() { 783 return dateTime.getMonth(); 784 } 785 786 /** 787 * Gets the day-of-month field. 788 * <p> 789 * This method returns the primitive {@code int} value for the day-of-month. 790 * 791 * @return the day-of-month, from 1 to 31 792 */ 793 public int getDayOfMonth() { 794 return dateTime.getDayOfMonth(); 795 } 796 797 /** 798 * Gets the day-of-year field. 799 * <p> 800 * This method returns the primitive {@code int} value for the day-of-year. 801 * 802 * @return the day-of-year, from 1 to 365, or 366 in a leap year 803 */ 804 public int getDayOfYear() { 805 return dateTime.getDayOfYear(); 806 } 807 808 /** 809 * Gets the day-of-week field, which is an enum {@code DayOfWeek}. 810 * <p> 811 * This method returns the enum {@link DayOfWeek} for the day-of-week. 812 * This avoids confusion as to what {@code int} values mean. 813 * If you need access to the primitive {@code int} value then the enum 814 * provides the {@link DayOfWeek#getValue() int value}. 815 * <p> 816 * Additional information can be obtained from the {@code DayOfWeek}. 817 * This includes textual names of the values. 818 * 819 * @return the day-of-week, not null 820 */ 821 public DayOfWeek getDayOfWeek() { 822 return dateTime.getDayOfWeek(); 823 } 824 825 //----------------------------------------------------------------------- 826 /** 827 * Gets the {@code LocalTime} part of this date-time. 828 * <p> 829 * This returns a {@code LocalTime} with the same hour, minute, second and 830 * nanosecond as this date-time. 831 * 832 * @return the time part of this date-time, not null 833 */ 834 public LocalTime toLocalTime() { 835 return dateTime.toLocalTime(); 836 } 837 838 /** 839 * Gets the hour-of-day field. 840 * 841 * @return the hour-of-day, from 0 to 23 842 */ 843 public int getHour() { 844 return dateTime.getHour(); 845 } 846 847 /** 848 * Gets the minute-of-hour field. 849 * 850 * @return the minute-of-hour, from 0 to 59 851 */ 852 public int getMinute() { 853 return dateTime.getMinute(); 854 } 855 856 /** 857 * Gets the second-of-minute field. 858 * 859 * @return the second-of-minute, from 0 to 59 860 */ 861 public int getSecond() { 862 return dateTime.getSecond(); 863 } 864 865 /** 866 * Gets the nano-of-second field. 867 * 868 * @return the nano-of-second, from 0 to 999,999,999 869 */ 870 public int getNano() { 871 return dateTime.getNano(); 872 } 873 874 //----------------------------------------------------------------------- 875 /** 876 * Returns an adjusted copy of this date-time. 877 * <p> 878 * This returns an {@code OffsetDateTime}, based on this one, with the date-time adjusted. 879 * The adjustment takes place using the specified adjuster strategy object. 880 * Read the documentation of the adjuster to understand what adjustment will be made. 881 * <p> 882 * A simple adjuster might simply set the one of the fields, such as the year field. 883 * A more complex adjuster might set the date to the last day of the month. 884 * A selection of common adjustments is provided in 885 * {@link java.time.temporal.TemporalAdjusters TemporalAdjusters}. 886 * These include finding the "last day of the month" and "next Wednesday". 887 * Key date-time classes also implement the {@code TemporalAdjuster} interface, 888 * such as {@link Month} and {@link java.time.MonthDay MonthDay}. 889 * The adjuster is responsible for handling special cases, such as the varying 890 * lengths of month and leap years. 891 * <p> 892 * For example this code returns a date on the last day of July: 893 * <pre> 894 * import static java.time.Month.*; 895 * import static java.time.temporal.TemporalAdjusters.*; 896 * 897 * result = offsetDateTime.with(JULY).with(lastDayOfMonth()); 898 * </pre> 899 * <p> 900 * The classes {@link LocalDate}, {@link LocalTime} and {@link ZoneOffset} implement 901 * {@code TemporalAdjuster}, thus this method can be used to change the date, time or offset: 902 * <pre> 903 * result = offsetDateTime.with(date); 904 * result = offsetDateTime.with(time); 905 * result = offsetDateTime.with(offset); 906 * </pre> 907 * <p> 908 * The result of this method is obtained by invoking the 909 * {@link TemporalAdjuster#adjustInto(Temporal)} method on the 910 * specified adjuster passing {@code this} as the argument. 911 * <p> 912 * This instance is immutable and unaffected by this method call. 913 * 914 * @param adjuster the adjuster to use, not null 915 * @return an {@code OffsetDateTime} based on {@code this} with the adjustment made, not null 916 * @throws DateTimeException if the adjustment cannot be made 917 * @throws ArithmeticException if numeric overflow occurs 918 */ 919 @Override 920 public OffsetDateTime with(TemporalAdjuster adjuster) { 921 // optimizations 922 if (adjuster instanceof LocalDate || adjuster instanceof LocalTime || adjuster instanceof LocalDateTime) { 923 return with(dateTime.with(adjuster), offset); 924 } else if (adjuster instanceof Instant) { 925 return ofInstant((Instant) adjuster, offset); 926 } else if (adjuster instanceof ZoneOffset) { 927 return with(dateTime, (ZoneOffset) adjuster); 928 } else if (adjuster instanceof OffsetDateTime) { 929 return (OffsetDateTime) adjuster; 930 } 931 return (OffsetDateTime) adjuster.adjustInto(this); 932 } 933 934 /** 935 * Returns a copy of this date-time with the specified field set to a new value. 936 * <p> 937 * This returns an {@code OffsetDateTime}, based on this one, with the value 938 * for the specified field changed. 939 * This can be used to change any supported field, such as the year, month or day-of-month. 940 * If it is not possible to set the value, because the field is not supported or for 941 * some other reason, an exception is thrown. 942 * <p> 943 * In some cases, changing the specified field can cause the resulting date-time to become invalid, 944 * such as changing the month from 31st January to February would make the day-of-month invalid. 945 * In cases like this, the field is responsible for resolving the date. Typically it will choose 946 * the previous valid date, which would be the last valid day of February in this example. 947 * <p> 948 * If the field is a {@link ChronoField} then the adjustment is implemented here. 949 * <p> 950 * The {@code INSTANT_SECONDS} field will return a date-time with the specified instant. 951 * The offset and nano-of-second are unchanged. 952 * If the new instant value is outside the valid range then a {@code DateTimeException} will be thrown. 953 * <p> 954 * The {@code OFFSET_SECONDS} field will return a date-time with the specified offset. 955 * The local date-time is unaltered. If the new offset value is outside the valid range 956 * then a {@code DateTimeException} will be thrown. 957 * <p> 958 * The other {@link #isSupported(TemporalField) supported fields} will behave as per 959 * the matching method on {@link LocalDateTime#with(TemporalField, long) LocalDateTime}. 960 * In this case, the offset is not part of the calculation and will be unchanged. 961 * <p> 962 * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}. 963 * <p> 964 * If the field is not a {@code ChronoField}, then the result of this method 965 * is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)} 966 * passing {@code this} as the argument. In this case, the field determines 967 * whether and how to adjust the instant. 968 * <p> 969 * This instance is immutable and unaffected by this method call. 970 * 971 * @param field the field to set in the result, not null 972 * @param newValue the new value of the field in the result 973 * @return an {@code OffsetDateTime} based on {@code this} with the specified field set, not null 974 * @throws DateTimeException if the field cannot be set 975 * @throws UnsupportedTemporalTypeException if the field is not supported 976 * @throws ArithmeticException if numeric overflow occurs 977 */ 978 @Override 979 public OffsetDateTime with(TemporalField field, long newValue) { 980 if (field instanceof ChronoField chronoField) { 981 return switch (chronoField) { 982 case INSTANT_SECONDS -> ofInstant(Instant.ofEpochSecond(newValue, getNano()), offset); 983 case OFFSET_SECONDS -> 984 with(dateTime, ZoneOffset.ofTotalSeconds(chronoField.checkValidIntValue(newValue))); 985 default -> with(dateTime.with(field, newValue), offset); 986 }; 987 } 988 return field.adjustInto(this, newValue); 989 } 990 991 //----------------------------------------------------------------------- 992 /** 993 * Returns a copy of this {@code OffsetDateTime} with the year altered. 994 * <p> 995 * The time and offset do not affect the calculation and will be the same in the result. 996 * If the day-of-month is invalid for the year, it will be changed to the last valid day of the month. 997 * <p> 998 * This instance is immutable and unaffected by this method call. 999 * 1000 * @param year the year to set in the result, from MIN_YEAR to MAX_YEAR 1001 * @return an {@code OffsetDateTime} based on this date-time with the requested year, not null 1002 * @throws DateTimeException if the year value is invalid 1003 */ 1004 public OffsetDateTime withYear(int year) { 1005 return with(dateTime.withYear(year), offset); 1006 } 1007 1008 /** 1009 * Returns a copy of this {@code OffsetDateTime} with the month-of-year altered. 1010 * <p> 1011 * The time and offset do not affect the calculation and will be the same in the result. 1012 * If the day-of-month is invalid for the year, it will be changed to the last valid day of the month. 1013 * <p> 1014 * This instance is immutable and unaffected by this method call. 1015 * 1016 * @param month the month-of-year to set in the result, from 1 (January) to 12 (December) 1017 * @return an {@code OffsetDateTime} based on this date-time with the requested month, not null 1018 * @throws DateTimeException if the month-of-year value is invalid 1019 */ 1020 public OffsetDateTime withMonth(int month) { 1021 return with(dateTime.withMonth(month), offset); 1022 } 1023 1024 /** 1025 * Returns a copy of this {@code OffsetDateTime} with the day-of-month altered. 1026 * <p> 1027 * If the resulting {@code OffsetDateTime} is invalid, an exception is thrown. 1028 * The time and offset do not affect the calculation and will be the same in the result. 1029 * <p> 1030 * This instance is immutable and unaffected by this method call. 1031 * 1032 * @param dayOfMonth the day-of-month to set in the result, from 1 to 28-31 1033 * @return an {@code OffsetDateTime} based on this date-time with the requested day, not null 1034 * @throws DateTimeException if the day-of-month value is invalid, 1035 * or if the day-of-month is invalid for the month-year 1036 */ 1037 public OffsetDateTime withDayOfMonth(int dayOfMonth) { 1038 return with(dateTime.withDayOfMonth(dayOfMonth), offset); 1039 } 1040 1041 /** 1042 * Returns a copy of this {@code OffsetDateTime} with the day-of-year altered. 1043 * <p> 1044 * The time and offset do not affect the calculation and will be the same in the result. 1045 * If the resulting {@code OffsetDateTime} is invalid, an exception is thrown. 1046 * <p> 1047 * This instance is immutable and unaffected by this method call. 1048 * 1049 * @param dayOfYear the day-of-year to set in the result, from 1 to 365-366 1050 * @return an {@code OffsetDateTime} based on this date with the requested day, not null 1051 * @throws DateTimeException if the day-of-year value is invalid, 1052 * or if the day-of-year is invalid for the year 1053 */ 1054 public OffsetDateTime withDayOfYear(int dayOfYear) { 1055 return with(dateTime.withDayOfYear(dayOfYear), offset); 1056 } 1057 1058 //----------------------------------------------------------------------- 1059 /** 1060 * Returns a copy of this {@code OffsetDateTime} with the hour-of-day altered. 1061 * <p> 1062 * The date and offset do not affect the calculation and will be the same in the result. 1063 * <p> 1064 * This instance is immutable and unaffected by this method call. 1065 * 1066 * @param hour the hour-of-day to set in the result, from 0 to 23 1067 * @return an {@code OffsetDateTime} based on this date-time with the requested hour, not null 1068 * @throws DateTimeException if the hour value is invalid 1069 */ 1070 public OffsetDateTime withHour(int hour) { 1071 return with(dateTime.withHour(hour), offset); 1072 } 1073 1074 /** 1075 * Returns a copy of this {@code OffsetDateTime} with the minute-of-hour altered. 1076 * <p> 1077 * The date and offset do not affect the calculation and will be the same in the result. 1078 * <p> 1079 * This instance is immutable and unaffected by this method call. 1080 * 1081 * @param minute the minute-of-hour to set in the result, from 0 to 59 1082 * @return an {@code OffsetDateTime} based on this date-time with the requested minute, not null 1083 * @throws DateTimeException if the minute value is invalid 1084 */ 1085 public OffsetDateTime withMinute(int minute) { 1086 return with(dateTime.withMinute(minute), offset); 1087 } 1088 1089 /** 1090 * Returns a copy of this {@code OffsetDateTime} with the second-of-minute altered. 1091 * <p> 1092 * The date and offset do not affect the calculation and will be the same in the result. 1093 * <p> 1094 * This instance is immutable and unaffected by this method call. 1095 * 1096 * @param second the second-of-minute to set in the result, from 0 to 59 1097 * @return an {@code OffsetDateTime} based on this date-time with the requested second, not null 1098 * @throws DateTimeException if the second value is invalid 1099 */ 1100 public OffsetDateTime withSecond(int second) { 1101 return with(dateTime.withSecond(second), offset); 1102 } 1103 1104 /** 1105 * Returns a copy of this {@code OffsetDateTime} with the nano-of-second altered. 1106 * <p> 1107 * The date and offset do not affect the calculation and will be the same in the result. 1108 * <p> 1109 * This instance is immutable and unaffected by this method call. 1110 * 1111 * @param nanoOfSecond the nano-of-second to set in the result, from 0 to 999,999,999 1112 * @return an {@code OffsetDateTime} based on this date-time with the requested nanosecond, not null 1113 * @throws DateTimeException if the nano value is invalid 1114 */ 1115 public OffsetDateTime withNano(int nanoOfSecond) { 1116 return with(dateTime.withNano(nanoOfSecond), offset); 1117 } 1118 1119 //----------------------------------------------------------------------- 1120 /** 1121 * Returns a copy of this {@code OffsetDateTime} with the time truncated. 1122 * <p> 1123 * Truncation returns a copy of the original date-time with fields 1124 * smaller than the specified unit set to zero. 1125 * For example, truncating with the {@link ChronoUnit#MINUTES minutes} unit 1126 * will set the second-of-minute and nano-of-second field to zero. 1127 * <p> 1128 * The unit must have a {@linkplain TemporalUnit#getDuration() duration} 1129 * that divides into the length of a standard day without remainder. 1130 * This includes all supplied time units on {@link ChronoUnit} and 1131 * {@link ChronoUnit#DAYS DAYS}. Other units throw an exception. 1132 * <p> 1133 * The offset does not affect the calculation and will be the same in the result. 1134 * <p> 1135 * This instance is immutable and unaffected by this method call. 1136 * 1137 * @param unit the unit to truncate to, not null 1138 * @return an {@code OffsetDateTime} based on this date-time with the time truncated, not null 1139 * @throws DateTimeException if unable to truncate 1140 * @throws UnsupportedTemporalTypeException if the unit is not supported 1141 */ 1142 public OffsetDateTime truncatedTo(TemporalUnit unit) { 1143 return with(dateTime.truncatedTo(unit), offset); 1144 } 1145 1146 //----------------------------------------------------------------------- 1147 /** 1148 * Returns a copy of this date-time with the specified amount added. 1149 * <p> 1150 * This returns an {@code OffsetDateTime}, based on this one, with the specified amount added. 1151 * The amount is typically {@link Period} or {@link Duration} but may be 1152 * any other type implementing the {@link TemporalAmount} interface. 1153 * <p> 1154 * The calculation is delegated to the amount object by calling 1155 * {@link TemporalAmount#addTo(Temporal)}. The amount implementation is free 1156 * to implement the addition in any way it wishes, however it typically 1157 * calls back to {@link #plus(long, TemporalUnit)}. Consult the documentation 1158 * of the amount implementation to determine if it can be successfully added. 1159 * <p> 1160 * This instance is immutable and unaffected by this method call. 1161 * 1162 * @param amountToAdd the amount to add, not null 1163 * @return an {@code OffsetDateTime} based on this date-time with the addition made, not null 1164 * @throws DateTimeException if the addition cannot be made 1165 * @throws ArithmeticException if numeric overflow occurs 1166 */ 1167 @Override 1168 public OffsetDateTime plus(TemporalAmount amountToAdd) { 1169 return (OffsetDateTime) amountToAdd.addTo(this); 1170 } 1171 1172 /** 1173 * Returns a copy of this date-time with the specified amount added. 1174 * <p> 1175 * This returns an {@code OffsetDateTime}, based on this one, with the amount 1176 * in terms of the unit added. If it is not possible to add the amount, because the 1177 * unit is not supported or for some other reason, an exception is thrown. 1178 * <p> 1179 * If the field is a {@link ChronoUnit} then the addition is implemented by 1180 * {@link LocalDateTime#plus(long, TemporalUnit)}. 1181 * The offset is not part of the calculation and will be unchanged in the result. 1182 * <p> 1183 * If the field is not a {@code ChronoUnit}, then the result of this method 1184 * is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)} 1185 * passing {@code this} as the argument. In this case, the unit determines 1186 * whether and how to perform the addition. 1187 * <p> 1188 * This instance is immutable and unaffected by this method call. 1189 * 1190 * @param amountToAdd the amount of the unit to add to the result, may be negative 1191 * @param unit the unit of the amount to add, not null 1192 * @return an {@code OffsetDateTime} based on this date-time with the specified amount added, not null 1193 * @throws DateTimeException if the addition cannot be made 1194 * @throws UnsupportedTemporalTypeException if the unit is not supported 1195 * @throws ArithmeticException if numeric overflow occurs 1196 */ 1197 @Override 1198 public OffsetDateTime plus(long amountToAdd, TemporalUnit unit) { 1199 if (unit instanceof ChronoUnit) { 1200 return with(dateTime.plus(amountToAdd, unit), offset); 1201 } 1202 return unit.addTo(this, amountToAdd); 1203 } 1204 1205 //----------------------------------------------------------------------- 1206 /** 1207 * Returns a copy of this {@code OffsetDateTime} with the specified number of years added. 1208 * <p> 1209 * This method adds the specified amount to the years field in three steps: 1210 * <ol> 1211 * <li>Add the input years to the year field</li> 1212 * <li>Check if the resulting date would be invalid</li> 1213 * <li>Adjust the day-of-month to the last valid day if necessary</li> 1214 * </ol> 1215 * <p> 1216 * For example, 2008-02-29 (leap year) plus one year would result in the 1217 * invalid date 2009-02-29 (standard year). Instead of returning an invalid 1218 * result, the last valid day of the month, 2009-02-28, is selected instead. 1219 * <p> 1220 * This instance is immutable and unaffected by this method call. 1221 * 1222 * @param years the years to add, may be negative 1223 * @return an {@code OffsetDateTime} based on this date-time with the years added, not null 1224 * @throws DateTimeException if the result exceeds the supported date range 1225 */ 1226 public OffsetDateTime plusYears(long years) { 1227 return with(dateTime.plusYears(years), offset); 1228 } 1229 1230 /** 1231 * Returns a copy of this {@code OffsetDateTime} with the specified number of months added. 1232 * <p> 1233 * This method adds the specified amount to the months field in three steps: 1234 * <ol> 1235 * <li>Add the input months to the month-of-year field</li> 1236 * <li>Check if the resulting date would be invalid</li> 1237 * <li>Adjust the day-of-month to the last valid day if necessary</li> 1238 * </ol> 1239 * <p> 1240 * For example, 2007-03-31 plus one month would result in the invalid date 1241 * 2007-04-31. Instead of returning an invalid result, the last valid day 1242 * of the month, 2007-04-30, is selected instead. 1243 * <p> 1244 * This instance is immutable and unaffected by this method call. 1245 * 1246 * @param months the months to add, may be negative 1247 * @return an {@code OffsetDateTime} based on this date-time with the months added, not null 1248 * @throws DateTimeException if the result exceeds the supported date range 1249 */ 1250 public OffsetDateTime plusMonths(long months) { 1251 return with(dateTime.plusMonths(months), offset); 1252 } 1253 1254 /** 1255 * Returns a copy of this OffsetDateTime with the specified number of weeks added. 1256 * <p> 1257 * This method adds the specified amount in weeks to the days field incrementing 1258 * the month and year fields as necessary to ensure the result remains valid. 1259 * The result is only invalid if the maximum/minimum year is exceeded. 1260 * <p> 1261 * For example, 2008-12-31 plus one week would result in 2009-01-07. 1262 * <p> 1263 * This instance is immutable and unaffected by this method call. 1264 * 1265 * @param weeks the weeks to add, may be negative 1266 * @return an {@code OffsetDateTime} based on this date-time with the weeks added, not null 1267 * @throws DateTimeException if the result exceeds the supported date range 1268 */ 1269 public OffsetDateTime plusWeeks(long weeks) { 1270 return with(dateTime.plusWeeks(weeks), offset); 1271 } 1272 1273 /** 1274 * Returns a copy of this OffsetDateTime with the specified number of days added. 1275 * <p> 1276 * This method adds the specified amount to the days field incrementing the 1277 * month and year fields as necessary to ensure the result remains valid. 1278 * The result is only invalid if the maximum/minimum year is exceeded. 1279 * <p> 1280 * For example, 2008-12-31 plus one day would result in 2009-01-01. 1281 * <p> 1282 * This instance is immutable and unaffected by this method call. 1283 * 1284 * @param days the days to add, may be negative 1285 * @return an {@code OffsetDateTime} based on this date-time with the days added, not null 1286 * @throws DateTimeException if the result exceeds the supported date range 1287 */ 1288 public OffsetDateTime plusDays(long days) { 1289 return with(dateTime.plusDays(days), offset); 1290 } 1291 1292 /** 1293 * Returns a copy of this {@code OffsetDateTime} with the specified number of hours added. 1294 * <p> 1295 * This instance is immutable and unaffected by this method call. 1296 * 1297 * @param hours the hours to add, may be negative 1298 * @return an {@code OffsetDateTime} based on this date-time with the hours added, not null 1299 * @throws DateTimeException if the result exceeds the supported date range 1300 */ 1301 public OffsetDateTime plusHours(long hours) { 1302 return with(dateTime.plusHours(hours), offset); 1303 } 1304 1305 /** 1306 * Returns a copy of this {@code OffsetDateTime} with the specified number of minutes added. 1307 * <p> 1308 * This instance is immutable and unaffected by this method call. 1309 * 1310 * @param minutes the minutes to add, may be negative 1311 * @return an {@code OffsetDateTime} based on this date-time with the minutes added, not null 1312 * @throws DateTimeException if the result exceeds the supported date range 1313 */ 1314 public OffsetDateTime plusMinutes(long minutes) { 1315 return with(dateTime.plusMinutes(minutes), offset); 1316 } 1317 1318 /** 1319 * Returns a copy of this {@code OffsetDateTime} with the specified number of seconds added. 1320 * <p> 1321 * This instance is immutable and unaffected by this method call. 1322 * 1323 * @param seconds the seconds to add, may be negative 1324 * @return an {@code OffsetDateTime} based on this date-time with the seconds added, not null 1325 * @throws DateTimeException if the result exceeds the supported date range 1326 */ 1327 public OffsetDateTime plusSeconds(long seconds) { 1328 return with(dateTime.plusSeconds(seconds), offset); 1329 } 1330 1331 /** 1332 * Returns a copy of this {@code OffsetDateTime} with the specified number of nanoseconds added. 1333 * <p> 1334 * This instance is immutable and unaffected by this method call. 1335 * 1336 * @param nanos the nanos to add, may be negative 1337 * @return an {@code OffsetDateTime} based on this date-time with the nanoseconds added, not null 1338 * @throws DateTimeException if the unit cannot be added to this type 1339 */ 1340 public OffsetDateTime plusNanos(long nanos) { 1341 return with(dateTime.plusNanos(nanos), offset); 1342 } 1343 1344 //----------------------------------------------------------------------- 1345 /** 1346 * Returns a copy of this date-time with the specified amount subtracted. 1347 * <p> 1348 * This returns an {@code OffsetDateTime}, based on this one, with the specified amount subtracted. 1349 * The amount is typically {@link Period} or {@link Duration} but may be 1350 * any other type implementing the {@link TemporalAmount} interface. 1351 * <p> 1352 * The calculation is delegated to the amount object by calling 1353 * {@link TemporalAmount#subtractFrom(Temporal)}. The amount implementation is free 1354 * to implement the subtraction in any way it wishes, however it typically 1355 * calls back to {@link #minus(long, TemporalUnit)}. Consult the documentation 1356 * of the amount implementation to determine if it can be successfully subtracted. 1357 * <p> 1358 * This instance is immutable and unaffected by this method call. 1359 * 1360 * @param amountToSubtract the amount to subtract, not null 1361 * @return an {@code OffsetDateTime} based on this date-time with the subtraction made, not null 1362 * @throws DateTimeException if the subtraction cannot be made 1363 * @throws ArithmeticException if numeric overflow occurs 1364 */ 1365 @Override 1366 public OffsetDateTime minus(TemporalAmount amountToSubtract) { 1367 return (OffsetDateTime) amountToSubtract.subtractFrom(this); 1368 } 1369 1370 /** 1371 * Returns a copy of this date-time with the specified amount subtracted. 1372 * <p> 1373 * This returns an {@code OffsetDateTime}, based on this one, with the amount 1374 * in terms of the unit subtracted. If it is not possible to subtract the amount, 1375 * because the unit is not supported or for some other reason, an exception is thrown. 1376 * <p> 1377 * This method is equivalent to {@link #plus(long, TemporalUnit)} with the amount negated. 1378 * See that method for a full description of how addition, and thus subtraction, works. 1379 * <p> 1380 * This instance is immutable and unaffected by this method call. 1381 * 1382 * @param amountToSubtract the amount of the unit to subtract from the result, may be negative 1383 * @param unit the unit of the amount to subtract, not null 1384 * @return an {@code OffsetDateTime} based on this date-time with the specified amount subtracted, not null 1385 * @throws DateTimeException if the subtraction cannot be made 1386 * @throws UnsupportedTemporalTypeException if the unit is not supported 1387 * @throws ArithmeticException if numeric overflow occurs 1388 */ 1389 @Override 1390 public OffsetDateTime minus(long amountToSubtract, TemporalUnit unit) { 1391 return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit)); 1392 } 1393 1394 //----------------------------------------------------------------------- 1395 /** 1396 * Returns a copy of this {@code OffsetDateTime} with the specified number of years subtracted. 1397 * <p> 1398 * This method subtracts the specified amount from the years field in three steps: 1399 * <ol> 1400 * <li>Subtract the input years from the year field</li> 1401 * <li>Check if the resulting date would be invalid</li> 1402 * <li>Adjust the day-of-month to the last valid day if necessary</li> 1403 * </ol> 1404 * <p> 1405 * For example, 2008-02-29 (leap year) minus one year would result in the 1406 * invalid date 2007-02-29 (standard year). Instead of returning an invalid 1407 * result, the last valid day of the month, 2007-02-28, is selected instead. 1408 * <p> 1409 * This instance is immutable and unaffected by this method call. 1410 * 1411 * @param years the years to subtract, may be negative 1412 * @return an {@code OffsetDateTime} based on this date-time with the years subtracted, not null 1413 * @throws DateTimeException if the result exceeds the supported date range 1414 */ 1415 public OffsetDateTime minusYears(long years) { 1416 return (years == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-years)); 1417 } 1418 1419 /** 1420 * Returns a copy of this {@code OffsetDateTime} with the specified number of months subtracted. 1421 * <p> 1422 * This method subtracts the specified amount from the months field in three steps: 1423 * <ol> 1424 * <li>Subtract the input months from the month-of-year field</li> 1425 * <li>Check if the resulting date would be invalid</li> 1426 * <li>Adjust the day-of-month to the last valid day if necessary</li> 1427 * </ol> 1428 * <p> 1429 * For example, 2007-03-31 minus one month would result in the invalid date 1430 * 2007-02-31. Instead of returning an invalid result, the last valid day 1431 * of the month, 2007-02-28, is selected instead. 1432 * <p> 1433 * This instance is immutable and unaffected by this method call. 1434 * 1435 * @param months the months to subtract, may be negative 1436 * @return an {@code OffsetDateTime} based on this date-time with the months subtracted, not null 1437 * @throws DateTimeException if the result exceeds the supported date range 1438 */ 1439 public OffsetDateTime minusMonths(long months) { 1440 return (months == Long.MIN_VALUE ? plusMonths(Long.MAX_VALUE).plusMonths(1) : plusMonths(-months)); 1441 } 1442 1443 /** 1444 * Returns a copy of this {@code OffsetDateTime} with the specified number of weeks subtracted. 1445 * <p> 1446 * This method subtracts the specified amount in weeks from the days field decrementing 1447 * the month and year fields as necessary to ensure the result remains valid. 1448 * The result is only invalid if the maximum/minimum year is exceeded. 1449 * <p> 1450 * For example, 2009-01-07 minus one week would result in 2008-12-31. 1451 * <p> 1452 * This instance is immutable and unaffected by this method call. 1453 * 1454 * @param weeks the weeks to subtract, may be negative 1455 * @return an {@code OffsetDateTime} based on this date-time with the weeks subtracted, not null 1456 * @throws DateTimeException if the result exceeds the supported date range 1457 */ 1458 public OffsetDateTime minusWeeks(long weeks) { 1459 return (weeks == Long.MIN_VALUE ? plusWeeks(Long.MAX_VALUE).plusWeeks(1) : plusWeeks(-weeks)); 1460 } 1461 1462 /** 1463 * Returns a copy of this {@code OffsetDateTime} with the specified number of days subtracted. 1464 * <p> 1465 * This method subtracts the specified amount from the days field decrementing the 1466 * month and year fields as necessary to ensure the result remains valid. 1467 * The result is only invalid if the maximum/minimum year is exceeded. 1468 * <p> 1469 * For example, 2009-01-01 minus one day would result in 2008-12-31. 1470 * <p> 1471 * This instance is immutable and unaffected by this method call. 1472 * 1473 * @param days the days to subtract, may be negative 1474 * @return an {@code OffsetDateTime} based on this date-time with the days subtracted, not null 1475 * @throws DateTimeException if the result exceeds the supported date range 1476 */ 1477 public OffsetDateTime minusDays(long days) { 1478 return (days == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-days)); 1479 } 1480 1481 /** 1482 * Returns a copy of this {@code OffsetDateTime} with the specified number of hours subtracted. 1483 * <p> 1484 * This instance is immutable and unaffected by this method call. 1485 * 1486 * @param hours the hours to subtract, may be negative 1487 * @return an {@code OffsetDateTime} based on this date-time with the hours subtracted, not null 1488 * @throws DateTimeException if the result exceeds the supported date range 1489 */ 1490 public OffsetDateTime minusHours(long hours) { 1491 return (hours == Long.MIN_VALUE ? plusHours(Long.MAX_VALUE).plusHours(1) : plusHours(-hours)); 1492 } 1493 1494 /** 1495 * Returns a copy of this {@code OffsetDateTime} with the specified number of minutes subtracted. 1496 * <p> 1497 * This instance is immutable and unaffected by this method call. 1498 * 1499 * @param minutes the minutes to subtract, may be negative 1500 * @return an {@code OffsetDateTime} based on this date-time with the minutes subtracted, not null 1501 * @throws DateTimeException if the result exceeds the supported date range 1502 */ 1503 public OffsetDateTime minusMinutes(long minutes) { 1504 return (minutes == Long.MIN_VALUE ? plusMinutes(Long.MAX_VALUE).plusMinutes(1) : plusMinutes(-minutes)); 1505 } 1506 1507 /** 1508 * Returns a copy of this {@code OffsetDateTime} with the specified number of seconds subtracted. 1509 * <p> 1510 * This instance is immutable and unaffected by this method call. 1511 * 1512 * @param seconds the seconds to subtract, may be negative 1513 * @return an {@code OffsetDateTime} based on this date-time with the seconds subtracted, not null 1514 * @throws DateTimeException if the result exceeds the supported date range 1515 */ 1516 public OffsetDateTime minusSeconds(long seconds) { 1517 return (seconds == Long.MIN_VALUE ? plusSeconds(Long.MAX_VALUE).plusSeconds(1) : plusSeconds(-seconds)); 1518 } 1519 1520 /** 1521 * Returns a copy of this {@code OffsetDateTime} with the specified number of nanoseconds subtracted. 1522 * <p> 1523 * This instance is immutable and unaffected by this method call. 1524 * 1525 * @param nanos the nanos to subtract, may be negative 1526 * @return an {@code OffsetDateTime} based on this date-time with the nanoseconds subtracted, not null 1527 * @throws DateTimeException if the result exceeds the supported date range 1528 */ 1529 public OffsetDateTime minusNanos(long nanos) { 1530 return (nanos == Long.MIN_VALUE ? plusNanos(Long.MAX_VALUE).plusNanos(1) : plusNanos(-nanos)); 1531 } 1532 1533 //----------------------------------------------------------------------- 1534 /** 1535 * Queries this date-time using the specified query. 1536 * <p> 1537 * This queries this date-time using the specified query strategy object. 1538 * The {@code TemporalQuery} object defines the logic to be used to 1539 * obtain the result. Read the documentation of the query to understand 1540 * what the result of this method will be. 1541 * <p> 1542 * The result of this method is obtained by invoking the 1543 * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the 1544 * specified query passing {@code this} as the argument. 1545 * 1546 * @param <R> the type of the result 1547 * @param query the query to invoke, not null 1548 * @return the query result, null may be returned (defined by the query) 1549 * @throws DateTimeException if unable to query (defined by the query) 1550 * @throws ArithmeticException if numeric overflow occurs (defined by the query) 1551 */ 1552 @SuppressWarnings("unchecked") 1553 @Override 1554 public <R> R query(TemporalQuery<R> query) { 1555 if (query == TemporalQueries.offset() || query == TemporalQueries.zone()) { 1556 return (R) getOffset(); 1557 } else if (query == TemporalQueries.zoneId()) { 1558 return null; 1559 } else if (query == TemporalQueries.localDate()) { 1560 return (R) toLocalDate(); 1561 } else if (query == TemporalQueries.localTime()) { 1562 return (R) toLocalTime(); 1563 } else if (query == TemporalQueries.chronology()) { 1564 return (R) IsoChronology.INSTANCE; 1565 } else if (query == TemporalQueries.precision()) { 1566 return (R) NANOS; 1567 } 1568 // inline TemporalAccessor.super.query(query) as an optimization 1569 // non-JDK classes are not permitted to make this optimization 1570 return query.queryFrom(this); 1571 } 1572 1573 /** 1574 * Adjusts the specified temporal object to have the same offset, date 1575 * and time as this object. 1576 * <p> 1577 * This returns a temporal object of the same observable type as the input 1578 * with the offset, date and time changed to be the same as this. 1579 * <p> 1580 * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)} 1581 * three times, passing {@link ChronoField#EPOCH_DAY}, 1582 * {@link ChronoField#NANO_OF_DAY} and {@link ChronoField#OFFSET_SECONDS} as the fields. 1583 * <p> 1584 * In most cases, it is clearer to reverse the calling pattern by using 1585 * {@link Temporal#with(TemporalAdjuster)}: 1586 * <pre> 1587 * // these two lines are equivalent, but the second approach is recommended 1588 * temporal = thisOffsetDateTime.adjustInto(temporal); 1589 * temporal = temporal.with(thisOffsetDateTime); 1590 * </pre> 1591 * <p> 1592 * This instance is immutable and unaffected by this method call. 1593 * 1594 * @param temporal the target object to be adjusted, not null 1595 * @return the adjusted object, not null 1596 * @throws DateTimeException if unable to make the adjustment 1597 * @throws ArithmeticException if numeric overflow occurs 1598 */ 1599 @Override 1600 public Temporal adjustInto(Temporal temporal) { 1601 // OffsetDateTime is treated as three separate fields, not an instant 1602 // this produces the most consistent set of results overall 1603 // the offset is set after the date and time, as it is typically a small 1604 // tweak to the result, with ZonedDateTime frequently ignoring the offset 1605 return temporal 1606 .with(EPOCH_DAY, toLocalDate().toEpochDay()) 1607 .with(NANO_OF_DAY, toLocalTime().toNanoOfDay()) 1608 .with(OFFSET_SECONDS, getOffset().getTotalSeconds()); 1609 } 1610 1611 /** 1612 * Calculates the amount of time until another date-time in terms of the specified unit. 1613 * <p> 1614 * This calculates the amount of time between two {@code OffsetDateTime} 1615 * objects in terms of a single {@code TemporalUnit}. 1616 * The start and end points are {@code this} and the specified date-time. 1617 * The result will be negative if the end is before the start. 1618 * For example, the amount in days between two date-times can be calculated 1619 * using {@code startDateTime.until(endDateTime, DAYS)}. 1620 * <p> 1621 * The {@code Temporal} passed to this method is converted to a 1622 * {@code OffsetDateTime} using {@link #from(TemporalAccessor)}. 1623 * If the offset differs between the two date-times, the specified 1624 * end date-time is normalized to have the same offset as this date-time. 1625 * <p> 1626 * The calculation returns a whole number, representing the number of 1627 * complete units between the two date-times. 1628 * For example, the amount in months between 2012-06-15T00:00Z and 2012-08-14T23:59Z 1629 * will only be one month as it is one minute short of two months. 1630 * <p> 1631 * There are two equivalent ways of using this method. 1632 * The first is to invoke this method. 1633 * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}: 1634 * <pre> 1635 * // these two lines are equivalent 1636 * amount = start.until(end, MONTHS); 1637 * amount = MONTHS.between(start, end); 1638 * </pre> 1639 * The choice should be made based on which makes the code more readable. 1640 * <p> 1641 * The calculation is implemented in this method for {@link ChronoUnit}. 1642 * The units {@code NANOS}, {@code MICROS}, {@code MILLIS}, {@code SECONDS}, 1643 * {@code MINUTES}, {@code HOURS} and {@code HALF_DAYS}, {@code DAYS}, 1644 * {@code WEEKS}, {@code MONTHS}, {@code YEARS}, {@code DECADES}, 1645 * {@code CENTURIES}, {@code MILLENNIA} and {@code ERAS} are supported. 1646 * Other {@code ChronoUnit} values will throw an exception. 1647 * <p> 1648 * If the unit is not a {@code ChronoUnit}, then the result of this method 1649 * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)} 1650 * passing {@code this} as the first argument and the converted input temporal 1651 * as the second argument. 1652 * <p> 1653 * This instance is immutable and unaffected by this method call. 1654 * 1655 * @param endExclusive the end date, exclusive, which is converted to an {@code OffsetDateTime}, not null 1656 * @param unit the unit to measure the amount in, not null 1657 * @return the amount of time between this date-time and the end date-time 1658 * @throws DateTimeException if the amount cannot be calculated, or the end 1659 * temporal cannot be converted to an {@code OffsetDateTime} 1660 * @throws UnsupportedTemporalTypeException if the unit is not supported 1661 * @throws ArithmeticException if numeric overflow occurs 1662 */ 1663 @Override 1664 public long until(Temporal endExclusive, TemporalUnit unit) { 1665 OffsetDateTime end = OffsetDateTime.from(endExclusive); 1666 if (unit instanceof ChronoUnit) { 1667 OffsetDateTime start = this; 1668 try { 1669 end = end.withOffsetSameInstant(offset); 1670 } catch (DateTimeException ex) { 1671 // end may be out of valid range. Adjust to end's offset. 1672 start = withOffsetSameInstant(end.offset); 1673 } 1674 return start.dateTime.until(end.dateTime, unit); 1675 } 1676 return unit.between(this, end); 1677 } 1678 1679 /** 1680 * Formats this date-time using the specified formatter. 1681 * <p> 1682 * This date-time will be passed to the formatter to produce a string. 1683 * 1684 * @param formatter the formatter to use, not null 1685 * @return the formatted date-time string, not null 1686 * @throws DateTimeException if an error occurs during printing 1687 */ 1688 public String format(DateTimeFormatter formatter) { 1689 Objects.requireNonNull(formatter, "formatter"); 1690 return formatter.format(this); 1691 } 1692 1693 //----------------------------------------------------------------------- 1694 /** 1695 * Combines this date-time with a time-zone to create a {@code ZonedDateTime} 1696 * ensuring that the result has the same instant. 1697 * <p> 1698 * This returns a {@code ZonedDateTime} formed from this date-time and the specified time-zone. 1699 * This conversion will ignore the visible local date-time and use the underlying instant instead. 1700 * This avoids any problems with local time-line gaps or overlaps. 1701 * The result might have different values for fields such as hour, minute an even day. 1702 * <p> 1703 * To attempt to retain the values of the fields, use {@link #atZoneSimilarLocal(ZoneId)}. 1704 * To use the offset as the zone ID, use {@link #toZonedDateTime()}. 1705 * 1706 * @param zone the time-zone to use, not null 1707 * @return the zoned date-time formed from this date-time, not null 1708 */ 1709 public ZonedDateTime atZoneSameInstant(ZoneId zone) { 1710 return ZonedDateTime.ofInstant(dateTime, offset, zone); 1711 } 1712 1713 /** 1714 * Combines this date-time with a time-zone to create a {@code ZonedDateTime} 1715 * trying to keep the same local date and time. 1716 * <p> 1717 * This returns a {@code ZonedDateTime} formed from this date-time and the specified time-zone. 1718 * Where possible, the result will have the same local date-time as this object. 1719 * <p> 1720 * Time-zone rules, such as daylight savings, mean that not every time on the 1721 * local time-line exists. If the local date-time is in a gap or overlap according to 1722 * the rules then a resolver is used to determine the resultant local time and offset. 1723 * This method uses {@link ZonedDateTime#ofLocal(LocalDateTime, ZoneId, ZoneOffset)} 1724 * to retain the offset from this instance if possible. 1725 * <p> 1726 * Finer control over gaps and overlaps is available in two ways. 1727 * If you simply want to use the later offset at overlaps then call 1728 * {@link ZonedDateTime#withLaterOffsetAtOverlap()} immediately after this method. 1729 * <p> 1730 * To create a zoned date-time at the same instant irrespective of the local time-line, 1731 * use {@link #atZoneSameInstant(ZoneId)}. 1732 * To use the offset as the zone ID, use {@link #toZonedDateTime()}. 1733 * 1734 * @param zone the time-zone to use, not null 1735 * @return the zoned date-time formed from this date and the earliest valid time for the zone, not null 1736 */ 1737 public ZonedDateTime atZoneSimilarLocal(ZoneId zone) { 1738 return ZonedDateTime.ofLocal(dateTime, zone, offset); 1739 } 1740 1741 //----------------------------------------------------------------------- 1742 /** 1743 * Converts this date-time to an {@code OffsetTime}. 1744 * <p> 1745 * This returns an offset time with the same local time and offset. 1746 * 1747 * @return an OffsetTime representing the time and offset, not null 1748 */ 1749 public OffsetTime toOffsetTime() { 1750 return OffsetTime.of(dateTime.toLocalTime(), offset); 1751 } 1752 1753 /** 1754 * Converts this date-time to a {@code ZonedDateTime} using the offset as the zone ID. 1755 * <p> 1756 * This creates the simplest possible {@code ZonedDateTime} using the offset 1757 * as the zone ID. 1758 * <p> 1759 * To control the time-zone used, see {@link #atZoneSameInstant(ZoneId)} and 1760 * {@link #atZoneSimilarLocal(ZoneId)}. 1761 * 1762 * @return a zoned date-time representing the same local date-time and offset, not null 1763 */ 1764 public ZonedDateTime toZonedDateTime() { 1765 return ZonedDateTime.of(dateTime, offset); 1766 } 1767 1768 /** 1769 * Converts this date-time to an {@code Instant}. 1770 * <p> 1771 * This returns an {@code Instant} representing the same point on the 1772 * time-line as this date-time. 1773 * 1774 * @return an {@code Instant} representing the same instant, not null 1775 */ 1776 public Instant toInstant() { 1777 return dateTime.toInstant(offset); 1778 } 1779 1780 /** 1781 * Converts this date-time to the number of seconds from the epoch of 1970-01-01T00:00:00Z. 1782 * <p> 1783 * This allows this date-time to be converted to a value of the 1784 * {@link ChronoField#INSTANT_SECONDS epoch-seconds} field. This is primarily 1785 * intended for low-level conversions rather than general application usage. 1786 * 1787 * @return the number of seconds from the epoch of 1970-01-01T00:00:00Z 1788 */ 1789 public long toEpochSecond() { 1790 return dateTime.toEpochSecond(offset); 1791 } 1792 1793 //----------------------------------------------------------------------- 1794 /** 1795 * Compares this date-time to another date-time. 1796 * <p> 1797 * The comparison is based on the instant then on the local date-time. 1798 * It is "consistent with equals", as defined by {@link Comparable}. 1799 * <p> 1800 * For example, the following is the comparator order: 1801 * <ol> 1802 * <li>{@code 2008-12-03T10:30+01:00}</li> 1803 * <li>{@code 2008-12-03T11:00+01:00}</li> 1804 * <li>{@code 2008-12-03T12:00+02:00}</li> 1805 * <li>{@code 2008-12-03T11:30+01:00}</li> 1806 * <li>{@code 2008-12-03T12:00+01:00}</li> 1807 * <li>{@code 2008-12-03T12:30+01:00}</li> 1808 * </ol> 1809 * Values #2 and #3 represent the same instant on the time-line. 1810 * When two values represent the same instant, the local date-time is compared 1811 * to distinguish them. This step is needed to make the ordering 1812 * consistent with {@code equals()}. 1813 * 1814 * @param other the other date-time to compare to, not null 1815 * @return the comparator value, that is the comparison with the {@code other}'s instant, if they are not equal; 1816 * and if equal to the {@code other}'s instant, the comparison of the {@code other}'s local date-time 1817 * @see #isBefore 1818 * @see #isAfter 1819 */ 1820 @Override 1821 public int compareTo(OffsetDateTime other) { 1822 int cmp = getOffset().compareTo(other.getOffset()); 1823 if (cmp != 0) { 1824 cmp = Long.compare(toEpochSecond(), other.toEpochSecond()); 1825 if (cmp == 0) { 1826 cmp = toLocalTime().getNano() - other.toLocalTime().getNano(); 1827 } 1828 } 1829 if (cmp == 0) { 1830 cmp = toLocalDateTime().compareTo(other.toLocalDateTime()); 1831 } 1832 return cmp; 1833 } 1834 1835 //----------------------------------------------------------------------- 1836 /** 1837 * Checks if the instant of this date-time is after that of the specified date-time. 1838 * <p> 1839 * This method differs from the comparison in {@link #compareTo} and {@link #equals} in that it 1840 * only compares the instant of the date-time. This is equivalent to using 1841 * {@code dateTime1.toInstant().isAfter(dateTime2.toInstant());}. 1842 * 1843 * @param other the other date-time to compare to, not null 1844 * @return true if this is after the instant of the specified date-time 1845 */ 1846 public boolean isAfter(OffsetDateTime other) { 1847 long thisEpochSec = toEpochSecond(); 1848 long otherEpochSec = other.toEpochSecond(); 1849 return thisEpochSec > otherEpochSec || 1850 (thisEpochSec == otherEpochSec && toLocalTime().getNano() > other.toLocalTime().getNano()); 1851 } 1852 1853 /** 1854 * Checks if the instant of this date-time is before that of the specified date-time. 1855 * <p> 1856 * This method differs from the comparison in {@link #compareTo} in that it 1857 * only compares the instant of the date-time. This is equivalent to using 1858 * {@code dateTime1.toInstant().isBefore(dateTime2.toInstant());}. 1859 * 1860 * @param other the other date-time to compare to, not null 1861 * @return true if this is before the instant of the specified date-time 1862 */ 1863 public boolean isBefore(OffsetDateTime other) { 1864 long thisEpochSec = toEpochSecond(); 1865 long otherEpochSec = other.toEpochSecond(); 1866 return thisEpochSec < otherEpochSec || 1867 (thisEpochSec == otherEpochSec && toLocalTime().getNano() < other.toLocalTime().getNano()); 1868 } 1869 1870 /** 1871 * Checks if the instant of this date-time is equal to that of the specified date-time. 1872 * <p> 1873 * This method differs from the comparison in {@link #compareTo} and {@link #equals} 1874 * in that it only compares the instant of the date-time. This is equivalent to using 1875 * {@code dateTime1.toInstant().equals(dateTime2.toInstant());}. 1876 * 1877 * @param other the other date-time to compare to, not null 1878 * @return true if the instant equals the instant of the specified date-time 1879 */ 1880 public boolean isEqual(OffsetDateTime other) { 1881 return toEpochSecond() == other.toEpochSecond() && 1882 toLocalTime().getNano() == other.toLocalTime().getNano(); 1883 } 1884 1885 //----------------------------------------------------------------------- 1886 /** 1887 * Checks if this date-time is equal to another date-time. 1888 * <p> 1889 * The comparison is based on the local date-time and the offset. 1890 * To compare for the same instant on the time-line, use {@link #isEqual}. 1891 * Only objects of type {@code OffsetDateTime} are compared, other types return false. 1892 * 1893 * @param obj the object to check, null returns false 1894 * @return true if this is equal to the other date-time 1895 */ 1896 @Override 1897 public boolean equals(Object obj) { 1898 if (this == obj) { 1899 return true; 1900 } 1901 return (obj instanceof OffsetDateTime other) 1902 && dateTime.equals(other.dateTime) 1903 && offset.equals(other.offset); 1904 } 1905 1906 /** 1907 * A hash code for this date-time. 1908 * 1909 * @return a suitable hash code 1910 */ 1911 @Override 1912 public int hashCode() { 1913 return dateTime.hashCode() ^ offset.hashCode(); 1914 } 1915 1916 //----------------------------------------------------------------------- 1917 /** 1918 * Outputs this date-time as a {@code String}, such as {@code 2007-12-03T10:15:30+01:00}. 1919 * <p> 1920 * The output will be one of the following formats: 1921 * <ul> 1922 * <li>{@code uuuu-MM-dd'T'HH:mmXXXXX}</li> 1923 * <li>{@code uuuu-MM-dd'T'HH:mm:ssXXXXX}</li> 1924 * <li>{@code uuuu-MM-dd'T'HH:mm:ss.SSSXXXXX}</li> 1925 * <li>{@code uuuu-MM-dd'T'HH:mm:ss.SSSSSSXXXXX}</li> 1926 * <li>{@code uuuu-MM-dd'T'HH:mm:ss.SSSSSSSSSXXXXX}</li> 1927 * </ul> 1928 * The format used will be the shortest that outputs the full value of 1929 * the time where the omitted parts are implied to be zero. The output 1930 * is compatible with ISO 8601 if the seconds in the offset are zero. 1931 * 1932 * @return a string representation of this date-time, not null 1933 */ 1934 @Override 1935 public String toString() { 1936 var offsetStr = offset.toString(); 1937 var buf = new StringBuilder(29 + offsetStr.length()); 1938 DateTimeHelper.formatTo(buf, dateTime); 1939 return buf.append(offsetStr).toString(); 1940 } 1941 1942 //----------------------------------------------------------------------- 1943 /** 1944 * Writes the object using a 1945 * <a href="{@docRoot}/serialized-form.html#java.time.Ser">dedicated serialized form</a>. 1946 * @serialData 1947 * <pre> 1948 * out.writeByte(10); // identifies an OffsetDateTime 1949 * // the <a href="{@docRoot}/serialized-form.html#java.time.LocalDateTime">datetime</a> excluding the one byte header 1950 * // the <a href="{@docRoot}/serialized-form.html#java.time.ZoneOffset">offset</a> excluding the one byte header 1951 * </pre> 1952 * 1953 * @return the instance of {@code Ser}, not null 1954 */ 1955 @java.io.Serial 1956 private Object writeReplace() { 1957 return new Ser(Ser.OFFSET_DATE_TIME_TYPE, this); 1958 } 1959 1960 /** 1961 * Defend against malicious streams. 1962 * 1963 * @param s the stream to read 1964 * @throws InvalidObjectException always 1965 */ 1966 @java.io.Serial 1967 private void readObject(ObjectInputStream s) throws InvalidObjectException { 1968 throw new InvalidObjectException("Deserialization via serialization delegate"); 1969 } 1970 1971 void writeExternal(ObjectOutput out) throws IOException { 1972 dateTime.writeExternal(out); 1973 offset.writeExternal(out); 1974 } 1975 1976 static OffsetDateTime readExternal(ObjectInput in) throws IOException, ClassNotFoundException { 1977 LocalDateTime dateTime = LocalDateTime.readExternal(in); 1978 ZoneOffset offset = ZoneOffset.readExternal(in); 1979 return OffsetDateTime.of(dateTime, offset); 1980 } 1981 1982 }