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