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 }