Path: blob/master/src/java.base/share/classes/java/time/ZonedDateTime.java
41152 views
/*1* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425/*26* This file is available under and governed by the GNU General Public27* License version 2 only, as published by the Free Software Foundation.28* However, the following notice accompanied the original version of this29* file:30*31* Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos32*33* All rights reserved.34*35* Redistribution and use in source and binary forms, with or without36* modification, are permitted provided that the following conditions are met:37*38* * Redistributions of source code must retain the above copyright notice,39* this list of conditions and the following disclaimer.40*41* * Redistributions in binary form must reproduce the above copyright notice,42* this list of conditions and the following disclaimer in the documentation43* and/or other materials provided with the distribution.44*45* * Neither the name of JSR-310 nor the names of its contributors46* may be used to endorse or promote products derived from this software47* without specific prior written permission.48*49* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS50* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT51* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR52* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR53* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,54* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,55* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR56* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF57* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING58* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS59* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.60*/61package java.time;6263import static java.time.temporal.ChronoField.INSTANT_SECONDS;64import static java.time.temporal.ChronoField.NANO_OF_SECOND;65import static java.time.temporal.ChronoField.OFFSET_SECONDS;6667import java.io.DataOutput;68import java.io.IOException;69import java.io.ObjectInput;70import java.io.InvalidObjectException;71import java.io.ObjectInputStream;72import java.io.Serializable;73import java.time.chrono.ChronoZonedDateTime;74import java.time.format.DateTimeFormatter;75import java.time.format.DateTimeParseException;76import java.time.temporal.ChronoField;77import java.time.temporal.ChronoUnit;78import java.time.temporal.Temporal;79import java.time.temporal.TemporalAccessor;80import java.time.temporal.TemporalAdjuster;81import java.time.temporal.TemporalAmount;82import java.time.temporal.TemporalField;83import java.time.temporal.TemporalQueries;84import java.time.temporal.TemporalQuery;85import java.time.temporal.TemporalUnit;86import java.time.temporal.UnsupportedTemporalTypeException;87import java.time.temporal.ValueRange;88import java.time.zone.ZoneOffsetTransition;89import java.time.zone.ZoneRules;90import java.util.List;91import java.util.Objects;9293/**94* A date-time with a time-zone in the ISO-8601 calendar system,95* such as {@code 2007-12-03T10:15:30+01:00 Europe/Paris}.96* <p>97* {@code ZonedDateTime} is an immutable representation of a date-time with a time-zone.98* This class stores all date and time fields, to a precision of nanoseconds,99* and a time-zone, with a zone offset used to handle ambiguous local date-times.100* For example, the value101* "2nd October 2007 at 13:45.30.123456789 +02:00 in the Europe/Paris time-zone"102* can be stored in a {@code ZonedDateTime}.103* <p>104* This class handles conversion from the local time-line of {@code LocalDateTime}105* to the instant time-line of {@code Instant}.106* The difference between the two time-lines is the offset from UTC/Greenwich,107* represented by a {@code ZoneOffset}.108* <p>109* Converting between the two time-lines involves calculating the offset using the110* {@link ZoneRules rules} accessed from the {@code ZoneId}.111* Obtaining the offset for an instant is simple, as there is exactly one valid112* offset for each instant. By contrast, obtaining the offset for a local date-time113* is not straightforward. There are three cases:114* <ul>115* <li>Normal, with one valid offset. For the vast majority of the year, the normal116* case applies, where there is a single valid offset for the local date-time.</li>117* <li>Gap, with zero valid offsets. This is when clocks jump forward typically118* due to the spring daylight savings change from "winter" to "summer".119* In a gap there are local date-time values with no valid offset.</li>120* <li>Overlap, with two valid offsets. This is when clocks are set back typically121* due to the autumn daylight savings change from "summer" to "winter".122* In an overlap there are local date-time values with two valid offsets.</li>123* </ul>124* <p>125* Any method that converts directly or implicitly from a local date-time to an126* instant by obtaining the offset has the potential to be complicated.127* <p>128* For Gaps, the general strategy is that if the local date-time falls in the129* middle of a Gap, then the resulting zoned date-time will have a local date-time130* shifted forwards by the length of the Gap, resulting in a date-time in the later131* offset, typically "summer" time.132* <p>133* For Overlaps, the general strategy is that if the local date-time falls in the134* middle of an Overlap, then the previous offset will be retained. If there is no135* previous offset, or the previous offset is invalid, then the earlier offset is136* used, typically "summer" time.. Two additional methods,137* {@link #withEarlierOffsetAtOverlap()} and {@link #withLaterOffsetAtOverlap()},138* help manage the case of an overlap.139* <p>140* In terms of design, this class should be viewed primarily as the combination141* of a {@code LocalDateTime} and a {@code ZoneId}. The {@code ZoneOffset} is142* a vital, but secondary, piece of information, used to ensure that the class143* represents an instant, especially during a daylight savings overlap.144* <p>145* This is a <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>146* class; programmers should treat instances that are147* {@linkplain #equals(Object) equal} as interchangeable and should not148* use instances for synchronization, or unpredictable behavior may149* occur. For example, in a future release, synchronization may fail.150* The {@code equals} method should be used for comparisons.151*152* @implSpec153* A {@code ZonedDateTime} holds state equivalent to three separate objects,154* a {@code LocalDateTime}, a {@code ZoneId} and the resolved {@code ZoneOffset}.155* The offset and local date-time are used to define an instant when necessary.156* The zone ID is used to obtain the rules for how and when the offset changes.157* The offset cannot be freely set, as the zone controls which offsets are valid.158* <p>159* This class is immutable and thread-safe.160*161* @since 1.8162*/163@jdk.internal.ValueBased164public final class ZonedDateTime165implements Temporal, ChronoZonedDateTime<LocalDate>, Serializable {166167/**168* Serialization version.169*/170@java.io.Serial171private static final long serialVersionUID = -6260982410461394882L;172173/**174* The local date-time.175*/176private final LocalDateTime dateTime;177/**178* The offset from UTC/Greenwich.179*/180private final ZoneOffset offset;181/**182* The time-zone.183*/184private final ZoneId zone;185186//-----------------------------------------------------------------------187/**188* Obtains the current date-time from the system clock in the default time-zone.189* <p>190* This will query the {@link Clock#systemDefaultZone() system clock} in the default191* time-zone to obtain the current date-time.192* The zone and offset will be set based on the time-zone in the clock.193* <p>194* Using this method will prevent the ability to use an alternate clock for testing195* because the clock is hard-coded.196*197* @return the current date-time using the system clock, not null198*/199public static ZonedDateTime now() {200return now(Clock.systemDefaultZone());201}202203/**204* Obtains the current date-time from the system clock in the specified time-zone.205* <p>206* This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date-time.207* Specifying the time-zone avoids dependence on the default time-zone.208* The offset will be calculated from the specified time-zone.209* <p>210* Using this method will prevent the ability to use an alternate clock for testing211* because the clock is hard-coded.212*213* @param zone the zone ID to use, not null214* @return the current date-time using the system clock, not null215*/216public static ZonedDateTime now(ZoneId zone) {217return now(Clock.system(zone));218}219220/**221* Obtains the current date-time from the specified clock.222* <p>223* This will query the specified clock to obtain the current date-time.224* The zone and offset will be set based on the time-zone in the clock.225* <p>226* Using this method allows the use of an alternate clock for testing.227* The alternate clock may be introduced using {@link Clock dependency injection}.228*229* @param clock the clock to use, not null230* @return the current date-time, not null231*/232public static ZonedDateTime now(Clock clock) {233Objects.requireNonNull(clock, "clock");234final Instant now = clock.instant(); // called once235return ofInstant(now, clock.getZone());236}237238//-----------------------------------------------------------------------239/**240* Obtains an instance of {@code ZonedDateTime} from a local date and time.241* <p>242* This creates a zoned date-time matching the input local date and time as closely as possible.243* Time-zone rules, such as daylight savings, mean that not every local date-time244* is valid for the specified zone, thus the local date-time may be adjusted.245* <p>246* The local date time and first combined to form a local date-time.247* The local date-time is then resolved to a single instant on the time-line.248* This is achieved by finding a valid offset from UTC/Greenwich for the local249* date-time as defined by the {@link ZoneRules rules} of the zone ID.250*<p>251* In most cases, there is only one valid offset for a local date-time.252* In the case of an overlap, when clocks are set back, there are two valid offsets.253* This method uses the earlier offset typically corresponding to "summer".254* <p>255* In the case of a gap, when clocks jump forward, there is no valid offset.256* Instead, the local date-time is adjusted to be later by the length of the gap.257* For a typical one hour daylight savings change, the local date-time will be258* moved one hour later into the offset typically corresponding to "summer".259*260* @param date the local date, not null261* @param time the local time, not null262* @param zone the time-zone, not null263* @return the offset date-time, not null264*/265public static ZonedDateTime of(LocalDate date, LocalTime time, ZoneId zone) {266return of(LocalDateTime.of(date, time), zone);267}268269/**270* Obtains an instance of {@code ZonedDateTime} from a local date-time.271* <p>272* This creates a zoned date-time matching the input local date-time as closely as possible.273* Time-zone rules, such as daylight savings, mean that not every local date-time274* is valid for the specified zone, thus the local date-time may be adjusted.275* <p>276* The local date-time is resolved to a single instant on the time-line.277* This is achieved by finding a valid offset from UTC/Greenwich for the local278* date-time as defined by the {@link ZoneRules rules} of the zone ID.279*<p>280* In most cases, there is only one valid offset for a local date-time.281* In the case of an overlap, when clocks are set back, there are two valid offsets.282* This method uses the earlier offset typically corresponding to "summer".283* <p>284* In the case of a gap, when clocks jump forward, there is no valid offset.285* Instead, the local date-time is adjusted to be later by the length of the gap.286* For a typical one hour daylight savings change, the local date-time will be287* moved one hour later into the offset typically corresponding to "summer".288*289* @param localDateTime the local date-time, not null290* @param zone the time-zone, not null291* @return the zoned date-time, not null292*/293public static ZonedDateTime of(LocalDateTime localDateTime, ZoneId zone) {294return ofLocal(localDateTime, zone, null);295}296297/**298* Obtains an instance of {@code ZonedDateTime} from a year, month, day,299* hour, minute, second, nanosecond and time-zone.300* <p>301* This creates a zoned date-time matching the local date-time of the seven302* specified fields as closely as possible.303* Time-zone rules, such as daylight savings, mean that not every local date-time304* is valid for the specified zone, thus the local date-time may be adjusted.305* <p>306* The local date-time is resolved to a single instant on the time-line.307* This is achieved by finding a valid offset from UTC/Greenwich for the local308* date-time as defined by the {@link ZoneRules rules} of the zone ID.309*<p>310* In most cases, there is only one valid offset for a local date-time.311* In the case of an overlap, when clocks are set back, there are two valid offsets.312* This method uses the earlier offset typically corresponding to "summer".313* <p>314* In the case of a gap, when clocks jump forward, there is no valid offset.315* Instead, the local date-time is adjusted to be later by the length of the gap.316* For a typical one hour daylight savings change, the local date-time will be317* moved one hour later into the offset typically corresponding to "summer".318* <p>319* This method exists primarily for writing test cases.320* Non test-code will typically use other methods to create an offset time.321* {@code LocalDateTime} has five additional convenience variants of the322* equivalent factory method taking fewer arguments.323* They are not provided here to reduce the footprint of the API.324*325* @param year the year to represent, from MIN_YEAR to MAX_YEAR326* @param month the month-of-year to represent, from 1 (January) to 12 (December)327* @param dayOfMonth the day-of-month to represent, from 1 to 31328* @param hour the hour-of-day to represent, from 0 to 23329* @param minute the minute-of-hour to represent, from 0 to 59330* @param second the second-of-minute to represent, from 0 to 59331* @param nanoOfSecond the nano-of-second to represent, from 0 to 999,999,999332* @param zone the time-zone, not null333* @return the offset date-time, not null334* @throws DateTimeException if the value of any field is out of range, or335* if the day-of-month is invalid for the month-year336*/337public static ZonedDateTime of(338int year, int month, int dayOfMonth,339int hour, int minute, int second, int nanoOfSecond, ZoneId zone) {340LocalDateTime dt = LocalDateTime.of(year, month, dayOfMonth, hour, minute, second, nanoOfSecond);341return ofLocal(dt, zone, null);342}343344/**345* Obtains an instance of {@code ZonedDateTime} from a local date-time346* using the preferred offset if possible.347* <p>348* The local date-time is resolved to a single instant on the time-line.349* This is achieved by finding a valid offset from UTC/Greenwich for the local350* date-time as defined by the {@link ZoneRules rules} of the zone ID.351*<p>352* In most cases, there is only one valid offset for a local date-time.353* In the case of an overlap, where clocks are set back, there are two valid offsets.354* If the preferred offset is one of the valid offsets then it is used.355* Otherwise the earlier valid offset is used, typically corresponding to "summer".356* <p>357* In the case of a gap, where clocks jump forward, there is no valid offset.358* Instead, the local date-time is adjusted to be later by the length of the gap.359* For a typical one hour daylight savings change, the local date-time will be360* moved one hour later into the offset typically corresponding to "summer".361*362* @param localDateTime the local date-time, not null363* @param zone the time-zone, not null364* @param preferredOffset the zone offset, null if no preference365* @return the zoned date-time, not null366*/367public static ZonedDateTime ofLocal(LocalDateTime localDateTime, ZoneId zone, ZoneOffset preferredOffset) {368Objects.requireNonNull(localDateTime, "localDateTime");369Objects.requireNonNull(zone, "zone");370if (zone instanceof ZoneOffset) {371return new ZonedDateTime(localDateTime, (ZoneOffset) zone, zone);372}373ZoneRules rules = zone.getRules();374List<ZoneOffset> validOffsets = rules.getValidOffsets(localDateTime);375ZoneOffset offset;376if (validOffsets.size() == 1) {377offset = validOffsets.get(0);378} else if (validOffsets.size() == 0) {379ZoneOffsetTransition trans = rules.getTransition(localDateTime);380localDateTime = localDateTime.plusSeconds(trans.getDuration().getSeconds());381offset = trans.getOffsetAfter();382} else {383if (preferredOffset != null && validOffsets.contains(preferredOffset)) {384offset = preferredOffset;385} else {386offset = Objects.requireNonNull(validOffsets.get(0), "offset"); // protect against bad ZoneRules387}388}389return new ZonedDateTime(localDateTime, offset, zone);390}391392//-----------------------------------------------------------------------393/**394* Obtains an instance of {@code ZonedDateTime} from an {@code Instant}.395* <p>396* This creates a zoned date-time with the same instant as that specified.397* Calling {@link #toInstant()} will return an instant equal to the one used here.398* <p>399* Converting an instant to a zoned date-time is simple as there is only one valid400* offset for each instant.401*402* @param instant the instant to create the date-time from, not null403* @param zone the time-zone, not null404* @return the zoned date-time, not null405* @throws DateTimeException if the result exceeds the supported range406*/407public static ZonedDateTime ofInstant(Instant instant, ZoneId zone) {408Objects.requireNonNull(instant, "instant");409Objects.requireNonNull(zone, "zone");410return create(instant.getEpochSecond(), instant.getNano(), zone);411}412413/**414* Obtains an instance of {@code ZonedDateTime} from the instant formed by combining415* the local date-time and offset.416* <p>417* This creates a zoned date-time by {@link LocalDateTime#toInstant(ZoneOffset) combining}418* the {@code LocalDateTime} and {@code ZoneOffset}.419* This combination uniquely specifies an instant without ambiguity.420* <p>421* Converting an instant to a zoned date-time is simple as there is only one valid422* offset for each instant. If the valid offset is different to the offset specified,423* then the date-time and offset of the zoned date-time will differ from those specified.424* <p>425* If the {@code ZoneId} to be used is a {@code ZoneOffset}, this method is equivalent426* to {@link #of(LocalDateTime, ZoneId)}.427*428* @param localDateTime the local date-time, not null429* @param offset the zone offset, not null430* @param zone the time-zone, not null431* @return the zoned date-time, not null432*/433public static ZonedDateTime ofInstant(LocalDateTime localDateTime, ZoneOffset offset, ZoneId zone) {434Objects.requireNonNull(localDateTime, "localDateTime");435Objects.requireNonNull(offset, "offset");436Objects.requireNonNull(zone, "zone");437if (zone.getRules().isValidOffset(localDateTime, offset)) {438return new ZonedDateTime(localDateTime, offset, zone);439}440return create(localDateTime.toEpochSecond(offset), localDateTime.getNano(), zone);441}442443/**444* Obtains an instance of {@code ZonedDateTime} using seconds from the445* epoch of 1970-01-01T00:00:00Z.446*447* @param epochSecond the number of seconds from the epoch of 1970-01-01T00:00:00Z448* @param nanoOfSecond the nanosecond within the second, from 0 to 999,999,999449* @param zone the time-zone, not null450* @return the zoned date-time, not null451* @throws DateTimeException if the result exceeds the supported range452*/453private static ZonedDateTime create(long epochSecond, int nanoOfSecond, ZoneId zone) {454ZoneRules rules = zone.getRules();455Instant instant = Instant.ofEpochSecond(epochSecond, nanoOfSecond); // TODO: rules should be queryable by epochSeconds456ZoneOffset offset = rules.getOffset(instant);457LocalDateTime ldt = LocalDateTime.ofEpochSecond(epochSecond, nanoOfSecond, offset);458return new ZonedDateTime(ldt, offset, zone);459}460461//-----------------------------------------------------------------------462/**463* Obtains an instance of {@code ZonedDateTime} strictly validating the464* combination of local date-time, offset and zone ID.465* <p>466* This creates a zoned date-time ensuring that the offset is valid for the467* local date-time according to the rules of the specified zone.468* If the offset is invalid, an exception is thrown.469*470* @param localDateTime the local date-time, not null471* @param offset the zone offset, not null472* @param zone the time-zone, not null473* @return the zoned date-time, not null474* @throws DateTimeException if the combination of arguments is invalid475*/476public static ZonedDateTime ofStrict(LocalDateTime localDateTime, ZoneOffset offset, ZoneId zone) {477Objects.requireNonNull(localDateTime, "localDateTime");478Objects.requireNonNull(offset, "offset");479Objects.requireNonNull(zone, "zone");480ZoneRules rules = zone.getRules();481if (rules.isValidOffset(localDateTime, offset) == false) {482ZoneOffsetTransition trans = rules.getTransition(localDateTime);483if (trans != null && trans.isGap()) {484// error message says daylight savings for simplicity485// even though there are other kinds of gaps486throw new DateTimeException("LocalDateTime '" + localDateTime +487"' does not exist in zone '" + zone +488"' due to a gap in the local time-line, typically caused by daylight savings");489}490throw new DateTimeException("ZoneOffset '" + offset + "' is not valid for LocalDateTime '" +491localDateTime + "' in zone '" + zone + "'");492}493return new ZonedDateTime(localDateTime, offset, zone);494}495496/**497* Obtains an instance of {@code ZonedDateTime} leniently, for advanced use cases,498* allowing any combination of local date-time, offset and zone ID.499* <p>500* This creates a zoned date-time with no checks other than no nulls.501* This means that the resulting zoned date-time may have an offset that is in conflict502* with the zone ID.503* <p>504* This method is intended for advanced use cases.505* For example, consider the case where a zoned date-time with valid fields is created506* and then stored in a database or serialization-based store. At some later point,507* the object is then re-loaded. However, between those points in time, the government508* that defined the time-zone has changed the rules, such that the originally stored509* local date-time now does not occur. This method can be used to create the object510* in an "invalid" state, despite the change in rules.511*512* @param localDateTime the local date-time, not null513* @param offset the zone offset, not null514* @param zone the time-zone, not null515* @return the zoned date-time, not null516*/517private static ZonedDateTime ofLenient(LocalDateTime localDateTime, ZoneOffset offset, ZoneId zone) {518Objects.requireNonNull(localDateTime, "localDateTime");519Objects.requireNonNull(offset, "offset");520Objects.requireNonNull(zone, "zone");521if (zone instanceof ZoneOffset && offset.equals(zone) == false) {522throw new IllegalArgumentException("ZoneId must match ZoneOffset");523}524return new ZonedDateTime(localDateTime, offset, zone);525}526527//-----------------------------------------------------------------------528/**529* Obtains an instance of {@code ZonedDateTime} from a temporal object.530* <p>531* This obtains a zoned date-time based on the specified temporal.532* A {@code TemporalAccessor} represents an arbitrary set of date and time information,533* which this factory converts to an instance of {@code ZonedDateTime}.534* <p>535* The conversion will first obtain a {@code ZoneId} from the temporal object,536* falling back to a {@code ZoneOffset} if necessary. It will then try to obtain537* an {@code Instant}, falling back to a {@code LocalDateTime} if necessary.538* The result will be either the combination of {@code ZoneId} or {@code ZoneOffset}539* with {@code Instant} or {@code LocalDateTime}.540* Implementations are permitted to perform optimizations such as accessing541* those fields that are equivalent to the relevant objects.542* <p>543* This method matches the signature of the functional interface {@link TemporalQuery}544* allowing it to be used as a query via method reference, {@code ZonedDateTime::from}.545*546* @param temporal the temporal object to convert, not null547* @return the zoned date-time, not null548* @throws DateTimeException if unable to convert to an {@code ZonedDateTime}549*/550public static ZonedDateTime from(TemporalAccessor temporal) {551if (temporal instanceof ZonedDateTime) {552return (ZonedDateTime) temporal;553}554try {555ZoneId zone = ZoneId.from(temporal);556if (temporal.isSupported(INSTANT_SECONDS)) {557long epochSecond = temporal.getLong(INSTANT_SECONDS);558int nanoOfSecond = temporal.get(NANO_OF_SECOND);559return create(epochSecond, nanoOfSecond, zone);560} else {561LocalDate date = LocalDate.from(temporal);562LocalTime time = LocalTime.from(temporal);563return of(date, time, zone);564}565} catch (DateTimeException ex) {566throw new DateTimeException("Unable to obtain ZonedDateTime from TemporalAccessor: " +567temporal + " of type " + temporal.getClass().getName(), ex);568}569}570571//-----------------------------------------------------------------------572/**573* Obtains an instance of {@code ZonedDateTime} from a text string such as574* {@code 2007-12-03T10:15:30+01:00[Europe/Paris]}.575* <p>576* The string must represent a valid date-time and is parsed using577* {@link java.time.format.DateTimeFormatter#ISO_ZONED_DATE_TIME}.578*579* @param text the text to parse such as "2007-12-03T10:15:30+01:00[Europe/Paris]", not null580* @return the parsed zoned date-time, not null581* @throws DateTimeParseException if the text cannot be parsed582*/583public static ZonedDateTime parse(CharSequence text) {584return parse(text, DateTimeFormatter.ISO_ZONED_DATE_TIME);585}586587/**588* Obtains an instance of {@code ZonedDateTime} from a text string using a specific formatter.589* <p>590* The text is parsed using the formatter, returning a date-time.591*592* @param text the text to parse, not null593* @param formatter the formatter to use, not null594* @return the parsed zoned date-time, not null595* @throws DateTimeParseException if the text cannot be parsed596*/597public static ZonedDateTime parse(CharSequence text, DateTimeFormatter formatter) {598Objects.requireNonNull(formatter, "formatter");599return formatter.parse(text, ZonedDateTime::from);600}601602//-----------------------------------------------------------------------603/**604* Constructor.605*606* @param dateTime the date-time, validated as not null607* @param offset the zone offset, validated as not null608* @param zone the time-zone, validated as not null609*/610private ZonedDateTime(LocalDateTime dateTime, ZoneOffset offset, ZoneId zone) {611this.dateTime = dateTime;612this.offset = offset;613this.zone = zone;614}615616/**617* Resolves the new local date-time using this zone ID, retaining the offset if possible.618*619* @param newDateTime the new local date-time, not null620* @return the zoned date-time, not null621*/622private ZonedDateTime resolveLocal(LocalDateTime newDateTime) {623return ofLocal(newDateTime, zone, offset);624}625626/**627* Resolves the new local date-time using the offset to identify the instant.628*629* @param newDateTime the new local date-time, not null630* @return the zoned date-time, not null631*/632private ZonedDateTime resolveInstant(LocalDateTime newDateTime) {633return ofInstant(newDateTime, offset, zone);634}635636/**637* Resolves the offset into this zoned date-time for the with methods.638* <p>639* This typically ignores the offset, unless it can be used to switch offset in a DST overlap.640*641* @param offset the offset, not null642* @return the zoned date-time, not null643*/644private ZonedDateTime resolveOffset(ZoneOffset offset) {645if (offset.equals(this.offset) == false && zone.getRules().isValidOffset(dateTime, offset)) {646return new ZonedDateTime(dateTime, offset, zone);647}648return this;649}650651//-----------------------------------------------------------------------652/**653* Checks if the specified field is supported.654* <p>655* This checks if this date-time can be queried for the specified field.656* If false, then calling the {@link #range(TemporalField) range},657* {@link #get(TemporalField) get} and {@link #with(TemporalField, long)}658* methods will throw an exception.659* <p>660* If the field is a {@link ChronoField} then the query is implemented here.661* The supported fields are:662* <ul>663* <li>{@code NANO_OF_SECOND}664* <li>{@code NANO_OF_DAY}665* <li>{@code MICRO_OF_SECOND}666* <li>{@code MICRO_OF_DAY}667* <li>{@code MILLI_OF_SECOND}668* <li>{@code MILLI_OF_DAY}669* <li>{@code SECOND_OF_MINUTE}670* <li>{@code SECOND_OF_DAY}671* <li>{@code MINUTE_OF_HOUR}672* <li>{@code MINUTE_OF_DAY}673* <li>{@code HOUR_OF_AMPM}674* <li>{@code CLOCK_HOUR_OF_AMPM}675* <li>{@code HOUR_OF_DAY}676* <li>{@code CLOCK_HOUR_OF_DAY}677* <li>{@code AMPM_OF_DAY}678* <li>{@code DAY_OF_WEEK}679* <li>{@code ALIGNED_DAY_OF_WEEK_IN_MONTH}680* <li>{@code ALIGNED_DAY_OF_WEEK_IN_YEAR}681* <li>{@code DAY_OF_MONTH}682* <li>{@code DAY_OF_YEAR}683* <li>{@code EPOCH_DAY}684* <li>{@code ALIGNED_WEEK_OF_MONTH}685* <li>{@code ALIGNED_WEEK_OF_YEAR}686* <li>{@code MONTH_OF_YEAR}687* <li>{@code PROLEPTIC_MONTH}688* <li>{@code YEAR_OF_ERA}689* <li>{@code YEAR}690* <li>{@code ERA}691* <li>{@code INSTANT_SECONDS}692* <li>{@code OFFSET_SECONDS}693* </ul>694* All other {@code ChronoField} instances will return false.695* <p>696* If the field is not a {@code ChronoField}, then the result of this method697* is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}698* passing {@code this} as the argument.699* Whether the field is supported is determined by the field.700*701* @param field the field to check, null returns false702* @return true if the field is supported on this date-time, false if not703*/704@Override705public boolean isSupported(TemporalField field) {706return field instanceof ChronoField || (field != null && field.isSupportedBy(this));707}708709/**710* Checks if the specified unit is supported.711* <p>712* This checks if the specified unit can be added to, or subtracted from, this date-time.713* If false, then calling the {@link #plus(long, TemporalUnit)} and714* {@link #minus(long, TemporalUnit) minus} methods will throw an exception.715* <p>716* If the unit is a {@link ChronoUnit} then the query is implemented here.717* The supported units are:718* <ul>719* <li>{@code NANOS}720* <li>{@code MICROS}721* <li>{@code MILLIS}722* <li>{@code SECONDS}723* <li>{@code MINUTES}724* <li>{@code HOURS}725* <li>{@code HALF_DAYS}726* <li>{@code DAYS}727* <li>{@code WEEKS}728* <li>{@code MONTHS}729* <li>{@code YEARS}730* <li>{@code DECADES}731* <li>{@code CENTURIES}732* <li>{@code MILLENNIA}733* <li>{@code ERAS}734* </ul>735* All other {@code ChronoUnit} instances will return false.736* <p>737* If the unit is not a {@code ChronoUnit}, then the result of this method738* is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)}739* passing {@code this} as the argument.740* Whether the unit is supported is determined by the unit.741*742* @param unit the unit to check, null returns false743* @return true if the unit can be added/subtracted, false if not744*/745@Override // override for Javadoc746public boolean isSupported(TemporalUnit unit) {747return ChronoZonedDateTime.super.isSupported(unit);748}749750//-----------------------------------------------------------------------751/**752* Gets the range of valid values for the specified field.753* <p>754* The range object expresses the minimum and maximum valid values for a field.755* This date-time is used to enhance the accuracy of the returned range.756* If it is not possible to return the range, because the field is not supported757* or for some other reason, an exception is thrown.758* <p>759* If the field is a {@link ChronoField} then the query is implemented here.760* The {@link #isSupported(TemporalField) supported fields} will return761* appropriate range instances.762* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.763* <p>764* If the field is not a {@code ChronoField}, then the result of this method765* is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}766* passing {@code this} as the argument.767* Whether the range can be obtained is determined by the field.768*769* @param field the field to query the range for, not null770* @return the range of valid values for the field, not null771* @throws DateTimeException if the range for the field cannot be obtained772* @throws UnsupportedTemporalTypeException if the field is not supported773*/774@Override775public ValueRange range(TemporalField field) {776if (field instanceof ChronoField) {777if (field == INSTANT_SECONDS || field == OFFSET_SECONDS) {778return field.range();779}780return dateTime.range(field);781}782return field.rangeRefinedBy(this);783}784785/**786* Gets the value of the specified field from this date-time as an {@code int}.787* <p>788* This queries this date-time for the value of the specified field.789* The returned value will always be within the valid range of values for the field.790* If it is not possible to return the value, because the field is not supported791* or for some other reason, an exception is thrown.792* <p>793* If the field is a {@link ChronoField} then the query is implemented here.794* The {@link #isSupported(TemporalField) supported fields} will return valid795* values based on this date-time, except {@code NANO_OF_DAY}, {@code MICRO_OF_DAY},796* {@code EPOCH_DAY}, {@code PROLEPTIC_MONTH} and {@code INSTANT_SECONDS} which are too797* large to fit in an {@code int} and throw an {@code UnsupportedTemporalTypeException}.798* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.799* <p>800* If the field is not a {@code ChronoField}, then the result of this method801* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}802* passing {@code this} as the argument. Whether the value can be obtained,803* and what the value represents, is determined by the field.804*805* @param field the field to get, not null806* @return the value for the field807* @throws DateTimeException if a value for the field cannot be obtained or808* the value is outside the range of valid values for the field809* @throws UnsupportedTemporalTypeException if the field is not supported or810* the range of values exceeds an {@code int}811* @throws ArithmeticException if numeric overflow occurs812*/813@Override // override for Javadoc and performance814public int get(TemporalField field) {815if (field instanceof ChronoField chronoField) {816switch (chronoField) {817case INSTANT_SECONDS:818throw new UnsupportedTemporalTypeException("Invalid field 'InstantSeconds' for get() method, use getLong() instead");819case OFFSET_SECONDS:820return getOffset().getTotalSeconds();821}822return dateTime.get(field);823}824return ChronoZonedDateTime.super.get(field);825}826827/**828* Gets the value of the specified field from this date-time as a {@code long}.829* <p>830* This queries this date-time for the value of the specified field.831* If it is not possible to return the value, because the field is not supported832* or for some other reason, an exception is thrown.833* <p>834* If the field is a {@link ChronoField} then the query is implemented here.835* The {@link #isSupported(TemporalField) supported fields} will return valid836* values based on this date-time.837* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.838* <p>839* If the field is not a {@code ChronoField}, then the result of this method840* is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}841* passing {@code this} as the argument. Whether the value can be obtained,842* and what the value represents, is determined by the field.843*844* @param field the field to get, not null845* @return the value for the field846* @throws DateTimeException if a value for the field cannot be obtained847* @throws UnsupportedTemporalTypeException if the field is not supported848* @throws ArithmeticException if numeric overflow occurs849*/850@Override851public long getLong(TemporalField field) {852if (field instanceof ChronoField chronoField) {853switch (chronoField) {854case INSTANT_SECONDS: return toEpochSecond();855case OFFSET_SECONDS: return getOffset().getTotalSeconds();856}857return dateTime.getLong(field);858}859return field.getFrom(this);860}861862//-----------------------------------------------------------------------863/**864* Gets the zone offset, such as '+01:00'.865* <p>866* This is the offset of the local date-time from UTC/Greenwich.867*868* @return the zone offset, not null869*/870@Override871public ZoneOffset getOffset() {872return offset;873}874875/**876* Returns a copy of this date-time changing the zone offset to the877* earlier of the two valid offsets at a local time-line overlap.878* <p>879* This method only has any effect when the local time-line overlaps, such as880* at an autumn daylight savings cutover. In this scenario, there are two881* valid offsets for the local date-time. Calling this method will return882* a zoned date-time with the earlier of the two selected.883* <p>884* If this method is called when it is not an overlap, {@code this}885* is returned.886* <p>887* This instance is immutable and unaffected by this method call.888*889* @return a {@code ZonedDateTime} based on this date-time with the earlier offset, not null890*/891@Override892public ZonedDateTime withEarlierOffsetAtOverlap() {893ZoneOffsetTransition trans = getZone().getRules().getTransition(dateTime);894if (trans != null && trans.isOverlap()) {895ZoneOffset earlierOffset = trans.getOffsetBefore();896if (earlierOffset.equals(offset) == false) {897return new ZonedDateTime(dateTime, earlierOffset, zone);898}899}900return this;901}902903/**904* Returns a copy of this date-time changing the zone offset to the905* later of the two valid offsets at a local time-line overlap.906* <p>907* This method only has any effect when the local time-line overlaps, such as908* at an autumn daylight savings cutover. In this scenario, there are two909* valid offsets for the local date-time. Calling this method will return910* a zoned date-time with the later of the two selected.911* <p>912* If this method is called when it is not an overlap, {@code this}913* is returned.914* <p>915* This instance is immutable and unaffected by this method call.916*917* @return a {@code ZonedDateTime} based on this date-time with the later offset, not null918*/919@Override920public ZonedDateTime withLaterOffsetAtOverlap() {921ZoneOffsetTransition trans = getZone().getRules().getTransition(toLocalDateTime());922if (trans != null) {923ZoneOffset laterOffset = trans.getOffsetAfter();924if (laterOffset.equals(offset) == false) {925return new ZonedDateTime(dateTime, laterOffset, zone);926}927}928return this;929}930931//-----------------------------------------------------------------------932/**933* Gets the time-zone, such as 'Europe/Paris'.934* <p>935* This returns the zone ID. This identifies the time-zone {@link ZoneRules rules}936* that determine when and how the offset from UTC/Greenwich changes.937* <p>938* The zone ID may be same as the {@linkplain #getOffset() offset}.939* If this is true, then any future calculations, such as addition or subtraction,940* have no complex edge cases due to time-zone rules.941* See also {@link #withFixedOffsetZone()}.942*943* @return the time-zone, not null944*/945@Override946public ZoneId getZone() {947return zone;948}949950/**951* Returns a copy of this date-time with a different time-zone,952* retaining the local date-time if possible.953* <p>954* This method changes the time-zone and retains the local date-time.955* The local date-time is only changed if it is invalid for the new zone,956* determined using the same approach as957* {@link #ofLocal(LocalDateTime, ZoneId, ZoneOffset)}.958* <p>959* To change the zone and adjust the local date-time,960* use {@link #withZoneSameInstant(ZoneId)}.961* <p>962* This instance is immutable and unaffected by this method call.963*964* @param zone the time-zone to change to, not null965* @return a {@code ZonedDateTime} based on this date-time with the requested zone, not null966*/967@Override968public ZonedDateTime withZoneSameLocal(ZoneId zone) {969Objects.requireNonNull(zone, "zone");970return this.zone.equals(zone) ? this : ofLocal(dateTime, zone, offset);971}972973/**974* Returns a copy of this date-time with a different time-zone,975* retaining the instant.976* <p>977* This method changes the time-zone and retains the instant.978* This normally results in a change to the local date-time.979* <p>980* This method is based on retaining the same instant, thus gaps and overlaps981* in the local time-line have no effect on the result.982* <p>983* To change the offset while keeping the local time,984* use {@link #withZoneSameLocal(ZoneId)}.985*986* @param zone the time-zone to change to, not null987* @return a {@code ZonedDateTime} based on this date-time with the requested zone, not null988* @throws DateTimeException if the result exceeds the supported date range989*/990@Override991public ZonedDateTime withZoneSameInstant(ZoneId zone) {992Objects.requireNonNull(zone, "zone");993return this.zone.equals(zone) ? this :994create(dateTime.toEpochSecond(offset), dateTime.getNano(), zone);995}996997/**998* Returns a copy of this date-time with the zone ID set to the offset.999* <p>1000* This returns a zoned date-time where the zone ID is the same as {@link #getOffset()}.1001* The local date-time, offset and instant of the result will be the same as in this date-time.1002* <p>1003* Setting the date-time to a fixed single offset means that any future1004* calculations, such as addition or subtraction, have no complex edge cases1005* due to time-zone rules.1006* This might also be useful when sending a zoned date-time across a network,1007* as most protocols, such as ISO-8601, only handle offsets,1008* and not region-based zone IDs.1009* <p>1010* This is equivalent to {@code ZonedDateTime.of(zdt.toLocalDateTime(), zdt.getOffset())}.1011*1012* @return a {@code ZonedDateTime} with the zone ID set to the offset, not null1013*/1014public ZonedDateTime withFixedOffsetZone() {1015return this.zone.equals(offset) ? this : new ZonedDateTime(dateTime, offset, offset);1016}10171018//-----------------------------------------------------------------------1019/**1020* Gets the {@code LocalDateTime} part of this date-time.1021* <p>1022* This returns a {@code LocalDateTime} with the same year, month, day and time1023* as this date-time.1024*1025* @return the local date-time part of this date-time, not null1026*/1027@Override // override for return type1028public LocalDateTime toLocalDateTime() {1029return dateTime;1030}10311032//-----------------------------------------------------------------------1033/**1034* Gets the {@code LocalDate} part of this date-time.1035* <p>1036* This returns a {@code LocalDate} with the same year, month and day1037* as this date-time.1038*1039* @return the date part of this date-time, not null1040*/1041@Override // override for return type1042public LocalDate toLocalDate() {1043return dateTime.toLocalDate();1044}10451046/**1047* Gets the year field.1048* <p>1049* This method returns the primitive {@code int} value for the year.1050* <p>1051* The year returned by this method is proleptic as per {@code get(YEAR)}.1052* To obtain the year-of-era, use {@code get(YEAR_OF_ERA)}.1053*1054* @return the year, from MIN_YEAR to MAX_YEAR1055*/1056public int getYear() {1057return dateTime.getYear();1058}10591060/**1061* Gets the month-of-year field from 1 to 12.1062* <p>1063* This method returns the month as an {@code int} from 1 to 12.1064* Application code is frequently clearer if the enum {@link Month}1065* is used by calling {@link #getMonth()}.1066*1067* @return the month-of-year, from 1 to 121068* @see #getMonth()1069*/1070public int getMonthValue() {1071return dateTime.getMonthValue();1072}10731074/**1075* Gets the month-of-year field using the {@code Month} enum.1076* <p>1077* This method returns the enum {@link Month} for the month.1078* This avoids confusion as to what {@code int} values mean.1079* If you need access to the primitive {@code int} value then the enum1080* provides the {@link Month#getValue() int value}.1081*1082* @return the month-of-year, not null1083* @see #getMonthValue()1084*/1085public Month getMonth() {1086return dateTime.getMonth();1087}10881089/**1090* Gets the day-of-month field.1091* <p>1092* This method returns the primitive {@code int} value for the day-of-month.1093*1094* @return the day-of-month, from 1 to 311095*/1096public int getDayOfMonth() {1097return dateTime.getDayOfMonth();1098}10991100/**1101* Gets the day-of-year field.1102* <p>1103* This method returns the primitive {@code int} value for the day-of-year.1104*1105* @return the day-of-year, from 1 to 365, or 366 in a leap year1106*/1107public int getDayOfYear() {1108return dateTime.getDayOfYear();1109}11101111/**1112* Gets the day-of-week field, which is an enum {@code DayOfWeek}.1113* <p>1114* This method returns the enum {@link DayOfWeek} for the day-of-week.1115* This avoids confusion as to what {@code int} values mean.1116* If you need access to the primitive {@code int} value then the enum1117* provides the {@link DayOfWeek#getValue() int value}.1118* <p>1119* Additional information can be obtained from the {@code DayOfWeek}.1120* This includes textual names of the values.1121*1122* @return the day-of-week, not null1123*/1124public DayOfWeek getDayOfWeek() {1125return dateTime.getDayOfWeek();1126}11271128//-----------------------------------------------------------------------1129/**1130* Gets the {@code LocalTime} part of this date-time.1131* <p>1132* This returns a {@code LocalTime} with the same hour, minute, second and1133* nanosecond as this date-time.1134*1135* @return the time part of this date-time, not null1136*/1137@Override // override for Javadoc and performance1138public LocalTime toLocalTime() {1139return dateTime.toLocalTime();1140}11411142/**1143* Gets the hour-of-day field.1144*1145* @return the hour-of-day, from 0 to 231146*/1147public int getHour() {1148return dateTime.getHour();1149}11501151/**1152* Gets the minute-of-hour field.1153*1154* @return the minute-of-hour, from 0 to 591155*/1156public int getMinute() {1157return dateTime.getMinute();1158}11591160/**1161* Gets the second-of-minute field.1162*1163* @return the second-of-minute, from 0 to 591164*/1165public int getSecond() {1166return dateTime.getSecond();1167}11681169/**1170* Gets the nano-of-second field.1171*1172* @return the nano-of-second, from 0 to 999,999,9991173*/1174public int getNano() {1175return dateTime.getNano();1176}11771178//-----------------------------------------------------------------------1179/**1180* Returns an adjusted copy of this date-time.1181* <p>1182* This returns a {@code ZonedDateTime}, based on this one, with the date-time adjusted.1183* The adjustment takes place using the specified adjuster strategy object.1184* Read the documentation of the adjuster to understand what adjustment will be made.1185* <p>1186* A simple adjuster might simply set the one of the fields, such as the year field.1187* A more complex adjuster might set the date to the last day of the month.1188* A selection of common adjustments is provided in1189* {@link java.time.temporal.TemporalAdjusters TemporalAdjusters}.1190* These include finding the "last day of the month" and "next Wednesday".1191* Key date-time classes also implement the {@code TemporalAdjuster} interface,1192* such as {@link Month} and {@link java.time.MonthDay MonthDay}.1193* The adjuster is responsible for handling special cases, such as the varying1194* lengths of month and leap years.1195* <p>1196* For example this code returns a date on the last day of July:1197* <pre>1198* import static java.time.Month.*;1199* import static java.time.temporal.TemporalAdjusters.*;1200*1201* result = zonedDateTime.with(JULY).with(lastDayOfMonth());1202* </pre>1203* <p>1204* The classes {@link LocalDate} and {@link LocalTime} implement {@code TemporalAdjuster},1205* thus this method can be used to change the date, time or offset:1206* <pre>1207* result = zonedDateTime.with(date);1208* result = zonedDateTime.with(time);1209* </pre>1210* <p>1211* {@link ZoneOffset} also implements {@code TemporalAdjuster} however using it1212* as an argument typically has no effect. The offset of a {@code ZonedDateTime} is1213* controlled primarily by the time-zone. As such, changing the offset does not generally1214* make sense, because there is only one valid offset for the local date-time and zone.1215* If the zoned date-time is in a daylight savings overlap, then the offset is used1216* to switch between the two valid offsets. In all other cases, the offset is ignored.1217* <p>1218* The result of this method is obtained by invoking the1219* {@link TemporalAdjuster#adjustInto(Temporal)} method on the1220* specified adjuster passing {@code this} as the argument.1221* <p>1222* This instance is immutable and unaffected by this method call.1223*1224* @param adjuster the adjuster to use, not null1225* @return a {@code ZonedDateTime} based on {@code this} with the adjustment made, not null1226* @throws DateTimeException if the adjustment cannot be made1227* @throws ArithmeticException if numeric overflow occurs1228*/1229@Override1230public ZonedDateTime with(TemporalAdjuster adjuster) {1231// optimizations1232if (adjuster instanceof LocalDate) {1233return resolveLocal(LocalDateTime.of((LocalDate) adjuster, dateTime.toLocalTime()));1234} else if (adjuster instanceof LocalTime) {1235return resolveLocal(LocalDateTime.of(dateTime.toLocalDate(), (LocalTime) adjuster));1236} else if (adjuster instanceof LocalDateTime) {1237return resolveLocal((LocalDateTime) adjuster);1238} else if (adjuster instanceof OffsetDateTime odt) {1239return ofLocal(odt.toLocalDateTime(), zone, odt.getOffset());1240} else if (adjuster instanceof Instant instant) {1241return create(instant.getEpochSecond(), instant.getNano(), zone);1242} else if (adjuster instanceof ZoneOffset) {1243return resolveOffset((ZoneOffset) adjuster);1244}1245return (ZonedDateTime) adjuster.adjustInto(this);1246}12471248/**1249* Returns a copy of this date-time with the specified field set to a new value.1250* <p>1251* This returns a {@code ZonedDateTime}, based on this one, with the value1252* for the specified field changed.1253* This can be used to change any supported field, such as the year, month or day-of-month.1254* If it is not possible to set the value, because the field is not supported or for1255* some other reason, an exception is thrown.1256* <p>1257* In some cases, changing the specified field can cause the resulting date-time to become invalid,1258* such as changing the month from 31st January to February would make the day-of-month invalid.1259* In cases like this, the field is responsible for resolving the date. Typically it will choose1260* the previous valid date, which would be the last valid day of February in this example.1261* <p>1262* If the field is a {@link ChronoField} then the adjustment is implemented here.1263* <p>1264* The {@code INSTANT_SECONDS} field will return a date-time with the specified instant.1265* The zone and nano-of-second are unchanged.1266* The result will have an offset derived from the new instant and original zone.1267* If the new instant value is outside the valid range then a {@code DateTimeException} will be thrown.1268* <p>1269* The {@code OFFSET_SECONDS} field will typically be ignored.1270* The offset of a {@code ZonedDateTime} is controlled primarily by the time-zone.1271* As such, changing the offset does not generally make sense, because there is only1272* one valid offset for the local date-time and zone.1273* If the zoned date-time is in a daylight savings overlap, then the offset is used1274* to switch between the two valid offsets. In all other cases, the offset is ignored.1275* If the new offset value is outside the valid range then a {@code DateTimeException} will be thrown.1276* <p>1277* The other {@link #isSupported(TemporalField) supported fields} will behave as per1278* the matching method on {@link LocalDateTime#with(TemporalField, long) LocalDateTime}.1279* The zone is not part of the calculation and will be unchanged.1280* When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,1281* then the offset will be retained if possible, otherwise the earlier offset will be used.1282* If in a gap, the local date-time will be adjusted forward by the length of the gap.1283* <p>1284* All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.1285* <p>1286* If the field is not a {@code ChronoField}, then the result of this method1287* is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)}1288* passing {@code this} as the argument. In this case, the field determines1289* whether and how to adjust the instant.1290* <p>1291* This instance is immutable and unaffected by this method call.1292*1293* @param field the field to set in the result, not null1294* @param newValue the new value of the field in the result1295* @return a {@code ZonedDateTime} based on {@code this} with the specified field set, not null1296* @throws DateTimeException if the field cannot be set1297* @throws UnsupportedTemporalTypeException if the field is not supported1298* @throws ArithmeticException if numeric overflow occurs1299*/1300@Override1301public ZonedDateTime with(TemporalField field, long newValue) {1302if (field instanceof ChronoField chronoField) {1303switch (chronoField) {1304case INSTANT_SECONDS:1305return create(newValue, getNano(), zone);1306case OFFSET_SECONDS:1307ZoneOffset offset = ZoneOffset.ofTotalSeconds(chronoField.checkValidIntValue(newValue));1308return resolveOffset(offset);1309}1310return resolveLocal(dateTime.with(field, newValue));1311}1312return field.adjustInto(this, newValue);1313}13141315//-----------------------------------------------------------------------1316/**1317* Returns a copy of this {@code ZonedDateTime} with the year altered.1318* <p>1319* This operates on the local time-line,1320* {@link LocalDateTime#withYear(int) changing the year} of the local date-time.1321* This is then converted back to a {@code ZonedDateTime}, using the zone ID1322* to obtain the offset.1323* <p>1324* When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,1325* then the offset will be retained if possible, otherwise the earlier offset will be used.1326* If in a gap, the local date-time will be adjusted forward by the length of the gap.1327* <p>1328* This instance is immutable and unaffected by this method call.1329*1330* @param year the year to set in the result, from MIN_YEAR to MAX_YEAR1331* @return a {@code ZonedDateTime} based on this date-time with the requested year, not null1332* @throws DateTimeException if the year value is invalid1333*/1334public ZonedDateTime withYear(int year) {1335return resolveLocal(dateTime.withYear(year));1336}13371338/**1339* Returns a copy of this {@code ZonedDateTime} with the month-of-year altered.1340* <p>1341* This operates on the local time-line,1342* {@link LocalDateTime#withMonth(int) changing the month} of the local date-time.1343* This is then converted back to a {@code ZonedDateTime}, using the zone ID1344* to obtain the offset.1345* <p>1346* When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,1347* then the offset will be retained if possible, otherwise the earlier offset will be used.1348* If in a gap, the local date-time will be adjusted forward by the length of the gap.1349* <p>1350* This instance is immutable and unaffected by this method call.1351*1352* @param month the month-of-year to set in the result, from 1 (January) to 12 (December)1353* @return a {@code ZonedDateTime} based on this date-time with the requested month, not null1354* @throws DateTimeException if the month-of-year value is invalid1355*/1356public ZonedDateTime withMonth(int month) {1357return resolveLocal(dateTime.withMonth(month));1358}13591360/**1361* Returns a copy of this {@code ZonedDateTime} with the day-of-month altered.1362* <p>1363* This operates on the local time-line,1364* {@link LocalDateTime#withDayOfMonth(int) changing the day-of-month} of the local date-time.1365* This is then converted back to a {@code ZonedDateTime}, using the zone ID1366* to obtain the offset.1367* <p>1368* When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,1369* then the offset will be retained if possible, otherwise the earlier offset will be used.1370* If in a gap, the local date-time will be adjusted forward by the length of the gap.1371* <p>1372* This instance is immutable and unaffected by this method call.1373*1374* @param dayOfMonth the day-of-month to set in the result, from 1 to 28-311375* @return a {@code ZonedDateTime} based on this date-time with the requested day, not null1376* @throws DateTimeException if the day-of-month value is invalid,1377* or if the day-of-month is invalid for the month-year1378*/1379public ZonedDateTime withDayOfMonth(int dayOfMonth) {1380return resolveLocal(dateTime.withDayOfMonth(dayOfMonth));1381}13821383/**1384* Returns a copy of this {@code ZonedDateTime} with the day-of-year altered.1385* <p>1386* This operates on the local time-line,1387* {@link LocalDateTime#withDayOfYear(int) changing the day-of-year} of the local date-time.1388* This is then converted back to a {@code ZonedDateTime}, using the zone ID1389* to obtain the offset.1390* <p>1391* When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,1392* then the offset will be retained if possible, otherwise the earlier offset will be used.1393* If in a gap, the local date-time will be adjusted forward by the length of the gap.1394* <p>1395* This instance is immutable and unaffected by this method call.1396*1397* @param dayOfYear the day-of-year to set in the result, from 1 to 365-3661398* @return a {@code ZonedDateTime} based on this date with the requested day, not null1399* @throws DateTimeException if the day-of-year value is invalid,1400* or if the day-of-year is invalid for the year1401*/1402public ZonedDateTime withDayOfYear(int dayOfYear) {1403return resolveLocal(dateTime.withDayOfYear(dayOfYear));1404}14051406//-----------------------------------------------------------------------1407/**1408* Returns a copy of this {@code ZonedDateTime} with the hour-of-day altered.1409* <p>1410* This operates on the local time-line,1411* {@linkplain LocalDateTime#withHour(int) changing the time} of the local date-time.1412* This is then converted back to a {@code ZonedDateTime}, using the zone ID1413* to obtain the offset.1414* <p>1415* When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,1416* then the offset will be retained if possible, otherwise the earlier offset will be used.1417* If in a gap, the local date-time will be adjusted forward by the length of the gap.1418* <p>1419* This instance is immutable and unaffected by this method call.1420*1421* @param hour the hour-of-day to set in the result, from 0 to 231422* @return a {@code ZonedDateTime} based on this date-time with the requested hour, not null1423* @throws DateTimeException if the hour value is invalid1424*/1425public ZonedDateTime withHour(int hour) {1426return resolveLocal(dateTime.withHour(hour));1427}14281429/**1430* Returns a copy of this {@code ZonedDateTime} with the minute-of-hour altered.1431* <p>1432* This operates on the local time-line,1433* {@linkplain LocalDateTime#withMinute(int) changing the time} of the local date-time.1434* This is then converted back to a {@code ZonedDateTime}, using the zone ID1435* to obtain the offset.1436* <p>1437* When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,1438* then the offset will be retained if possible, otherwise the earlier offset will be used.1439* If in a gap, the local date-time will be adjusted forward by the length of the gap.1440* <p>1441* This instance is immutable and unaffected by this method call.1442*1443* @param minute the minute-of-hour to set in the result, from 0 to 591444* @return a {@code ZonedDateTime} based on this date-time with the requested minute, not null1445* @throws DateTimeException if the minute value is invalid1446*/1447public ZonedDateTime withMinute(int minute) {1448return resolveLocal(dateTime.withMinute(minute));1449}14501451/**1452* Returns a copy of this {@code ZonedDateTime} with the second-of-minute altered.1453* <p>1454* This operates on the local time-line,1455* {@linkplain LocalDateTime#withSecond(int) changing the time} of the local date-time.1456* This is then converted back to a {@code ZonedDateTime}, using the zone ID1457* to obtain the offset.1458* <p>1459* When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,1460* then the offset will be retained if possible, otherwise the earlier offset will be used.1461* If in a gap, the local date-time will be adjusted forward by the length of the gap.1462* <p>1463* This instance is immutable and unaffected by this method call.1464*1465* @param second the second-of-minute to set in the result, from 0 to 591466* @return a {@code ZonedDateTime} based on this date-time with the requested second, not null1467* @throws DateTimeException if the second value is invalid1468*/1469public ZonedDateTime withSecond(int second) {1470return resolveLocal(dateTime.withSecond(second));1471}14721473/**1474* Returns a copy of this {@code ZonedDateTime} with the nano-of-second altered.1475* <p>1476* This operates on the local time-line,1477* {@linkplain LocalDateTime#withNano(int) changing the time} of the local date-time.1478* This is then converted back to a {@code ZonedDateTime}, using the zone ID1479* to obtain the offset.1480* <p>1481* When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,1482* then the offset will be retained if possible, otherwise the earlier offset will be used.1483* If in a gap, the local date-time will be adjusted forward by the length of the gap.1484* <p>1485* This instance is immutable and unaffected by this method call.1486*1487* @param nanoOfSecond the nano-of-second to set in the result, from 0 to 999,999,9991488* @return a {@code ZonedDateTime} based on this date-time with the requested nanosecond, not null1489* @throws DateTimeException if the nano value is invalid1490*/1491public ZonedDateTime withNano(int nanoOfSecond) {1492return resolveLocal(dateTime.withNano(nanoOfSecond));1493}14941495//-----------------------------------------------------------------------1496/**1497* Returns a copy of this {@code ZonedDateTime} with the time truncated.1498* <p>1499* Truncation returns a copy of the original date-time with fields1500* smaller than the specified unit set to zero.1501* For example, truncating with the {@link ChronoUnit#MINUTES minutes} unit1502* will set the second-of-minute and nano-of-second field to zero.1503* <p>1504* The unit must have a {@linkplain TemporalUnit#getDuration() duration}1505* that divides into the length of a standard day without remainder.1506* This includes all supplied time units on {@link ChronoUnit} and1507* {@link ChronoUnit#DAYS DAYS}. Other units throw an exception.1508* <p>1509* This operates on the local time-line,1510* {@link LocalDateTime#truncatedTo(TemporalUnit) truncating}1511* the underlying local date-time. This is then converted back to a1512* {@code ZonedDateTime}, using the zone ID to obtain the offset.1513* <p>1514* When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,1515* then the offset will be retained if possible, otherwise the earlier offset will be used.1516* If in a gap, the local date-time will be adjusted forward by the length of the gap.1517* <p>1518* This instance is immutable and unaffected by this method call.1519*1520* @param unit the unit to truncate to, not null1521* @return a {@code ZonedDateTime} based on this date-time with the time truncated, not null1522* @throws DateTimeException if unable to truncate1523* @throws UnsupportedTemporalTypeException if the unit is not supported1524*/1525public ZonedDateTime truncatedTo(TemporalUnit unit) {1526return resolveLocal(dateTime.truncatedTo(unit));1527}15281529//-----------------------------------------------------------------------1530/**1531* Returns a copy of this date-time with the specified amount added.1532* <p>1533* This returns a {@code ZonedDateTime}, based on this one, with the specified amount added.1534* The amount is typically {@link Period} or {@link Duration} but may be1535* any other type implementing the {@link TemporalAmount} interface.1536* <p>1537* The calculation is delegated to the amount object by calling1538* {@link TemporalAmount#addTo(Temporal)}. The amount implementation is free1539* to implement the addition in any way it wishes, however it typically1540* calls back to {@link #plus(long, TemporalUnit)}. Consult the documentation1541* of the amount implementation to determine if it can be successfully added.1542* <p>1543* This instance is immutable and unaffected by this method call.1544*1545* @param amountToAdd the amount to add, not null1546* @return a {@code ZonedDateTime} based on this date-time with the addition made, not null1547* @throws DateTimeException if the addition cannot be made1548* @throws ArithmeticException if numeric overflow occurs1549*/1550@Override1551public ZonedDateTime plus(TemporalAmount amountToAdd) {1552if (amountToAdd instanceof Period periodToAdd) {1553return resolveLocal(dateTime.plus(periodToAdd));1554}1555Objects.requireNonNull(amountToAdd, "amountToAdd");1556return (ZonedDateTime) amountToAdd.addTo(this);1557}15581559/**1560* Returns a copy of this date-time with the specified amount added.1561* <p>1562* This returns a {@code ZonedDateTime}, based on this one, with the amount1563* in terms of the unit added. If it is not possible to add the amount, because the1564* unit is not supported or for some other reason, an exception is thrown.1565* <p>1566* If the field is a {@link ChronoUnit} then the addition is implemented here.1567* The zone is not part of the calculation and will be unchanged in the result.1568* The calculation for date and time units differ.1569* <p>1570* Date units operate on the local time-line.1571* The period is first added to the local date-time, then converted back1572* to a zoned date-time using the zone ID.1573* The conversion uses {@link #ofLocal(LocalDateTime, ZoneId, ZoneOffset)}1574* with the offset before the addition.1575* <p>1576* Time units operate on the instant time-line.1577* The period is first added to the local date-time, then converted back to1578* a zoned date-time using the zone ID.1579* The conversion uses {@link #ofInstant(LocalDateTime, ZoneOffset, ZoneId)}1580* with the offset before the addition.1581* <p>1582* If the field is not a {@code ChronoUnit}, then the result of this method1583* is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)}1584* passing {@code this} as the argument. In this case, the unit determines1585* whether and how to perform the addition.1586* <p>1587* This instance is immutable and unaffected by this method call.1588*1589* @param amountToAdd the amount of the unit to add to the result, may be negative1590* @param unit the unit of the amount to add, not null1591* @return a {@code ZonedDateTime} based on this date-time with the specified amount added, not null1592* @throws DateTimeException if the addition cannot be made1593* @throws UnsupportedTemporalTypeException if the unit is not supported1594* @throws ArithmeticException if numeric overflow occurs1595*/1596@Override1597public ZonedDateTime plus(long amountToAdd, TemporalUnit unit) {1598if (unit instanceof ChronoUnit) {1599if (unit.isDateBased()) {1600return resolveLocal(dateTime.plus(amountToAdd, unit));1601} else {1602return resolveInstant(dateTime.plus(amountToAdd, unit));1603}1604}1605return unit.addTo(this, amountToAdd);1606}16071608//-----------------------------------------------------------------------1609/**1610* Returns a copy of this {@code ZonedDateTime} with the specified number of years added.1611* <p>1612* This operates on the local time-line,1613* {@link LocalDateTime#plusYears(long) adding years} to the local date-time.1614* This is then converted back to a {@code ZonedDateTime}, using the zone ID1615* to obtain the offset.1616* <p>1617* When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,1618* then the offset will be retained if possible, otherwise the earlier offset will be used.1619* If in a gap, the local date-time will be adjusted forward by the length of the gap.1620* <p>1621* This instance is immutable and unaffected by this method call.1622*1623* @param years the years to add, may be negative1624* @return a {@code ZonedDateTime} based on this date-time with the years added, not null1625* @throws DateTimeException if the result exceeds the supported date range1626*/1627public ZonedDateTime plusYears(long years) {1628return resolveLocal(dateTime.plusYears(years));1629}16301631/**1632* Returns a copy of this {@code ZonedDateTime} with the specified number of months added.1633* <p>1634* This operates on the local time-line,1635* {@link LocalDateTime#plusMonths(long) adding months} to the local date-time.1636* This is then converted back to a {@code ZonedDateTime}, using the zone ID1637* to obtain the offset.1638* <p>1639* When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,1640* then the offset will be retained if possible, otherwise the earlier offset will be used.1641* If in a gap, the local date-time will be adjusted forward by the length of the gap.1642* <p>1643* This instance is immutable and unaffected by this method call.1644*1645* @param months the months to add, may be negative1646* @return a {@code ZonedDateTime} based on this date-time with the months added, not null1647* @throws DateTimeException if the result exceeds the supported date range1648*/1649public ZonedDateTime plusMonths(long months) {1650return resolveLocal(dateTime.plusMonths(months));1651}16521653/**1654* Returns a copy of this {@code ZonedDateTime} with the specified number of weeks added.1655* <p>1656* This operates on the local time-line,1657* {@link LocalDateTime#plusWeeks(long) adding weeks} to the local date-time.1658* This is then converted back to a {@code ZonedDateTime}, using the zone ID1659* to obtain the offset.1660* <p>1661* When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,1662* then the offset will be retained if possible, otherwise the earlier offset will be used.1663* If in a gap, the local date-time will be adjusted forward by the length of the gap.1664* <p>1665* This instance is immutable and unaffected by this method call.1666*1667* @param weeks the weeks to add, may be negative1668* @return a {@code ZonedDateTime} based on this date-time with the weeks added, not null1669* @throws DateTimeException if the result exceeds the supported date range1670*/1671public ZonedDateTime plusWeeks(long weeks) {1672return resolveLocal(dateTime.plusWeeks(weeks));1673}16741675/**1676* Returns a copy of this {@code ZonedDateTime} with the specified number of days added.1677* <p>1678* This operates on the local time-line,1679* {@link LocalDateTime#plusDays(long) adding days} to the local date-time.1680* This is then converted back to a {@code ZonedDateTime}, using the zone ID1681* to obtain the offset.1682* <p>1683* When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,1684* then the offset will be retained if possible, otherwise the earlier offset will be used.1685* If in a gap, the local date-time will be adjusted forward by the length of the gap.1686* <p>1687* This instance is immutable and unaffected by this method call.1688*1689* @param days the days to add, may be negative1690* @return a {@code ZonedDateTime} based on this date-time with the days added, not null1691* @throws DateTimeException if the result exceeds the supported date range1692*/1693public ZonedDateTime plusDays(long days) {1694return resolveLocal(dateTime.plusDays(days));1695}16961697//-----------------------------------------------------------------------1698/**1699* Returns a copy of this {@code ZonedDateTime} with the specified number of hours added.1700* <p>1701* This operates on the instant time-line, such that adding one hour will1702* always be a duration of one hour later.1703* This may cause the local date-time to change by an amount other than one hour.1704* Note that this is a different approach to that used by days, months and years,1705* thus adding one day is not the same as adding 24 hours.1706* <p>1707* For example, consider a time-zone, such as 'Europe/Paris', where the1708* Autumn DST cutover means that the local times 02:00 to 02:59 occur twice1709* changing from offset +02:00 in summer to +01:00 in winter.1710* <ul>1711* <li>Adding one hour to 01:30+02:00 will result in 02:30+02:001712* (both in summer time)1713* <li>Adding one hour to 02:30+02:00 will result in 02:30+01:001714* (moving from summer to winter time)1715* <li>Adding one hour to 02:30+01:00 will result in 03:30+01:001716* (both in winter time)1717* <li>Adding three hours to 01:30+02:00 will result in 03:30+01:001718* (moving from summer to winter time)1719* </ul>1720* <p>1721* This instance is immutable and unaffected by this method call.1722*1723* @param hours the hours to add, may be negative1724* @return a {@code ZonedDateTime} based on this date-time with the hours added, not null1725* @throws DateTimeException if the result exceeds the supported date range1726*/1727public ZonedDateTime plusHours(long hours) {1728return resolveInstant(dateTime.plusHours(hours));1729}17301731/**1732* Returns a copy of this {@code ZonedDateTime} with the specified number of minutes added.1733* <p>1734* This operates on the instant time-line, such that adding one minute will1735* always be a duration of one minute later.1736* This may cause the local date-time to change by an amount other than one minute.1737* Note that this is a different approach to that used by days, months and years.1738* <p>1739* This instance is immutable and unaffected by this method call.1740*1741* @param minutes the minutes to add, may be negative1742* @return a {@code ZonedDateTime} based on this date-time with the minutes added, not null1743* @throws DateTimeException if the result exceeds the supported date range1744*/1745public ZonedDateTime plusMinutes(long minutes) {1746return resolveInstant(dateTime.plusMinutes(minutes));1747}17481749/**1750* Returns a copy of this {@code ZonedDateTime} with the specified number of seconds added.1751* <p>1752* This operates on the instant time-line, such that adding one second will1753* always be a duration of one second later.1754* This may cause the local date-time to change by an amount other than one second.1755* Note that this is a different approach to that used by days, months and years.1756* <p>1757* This instance is immutable and unaffected by this method call.1758*1759* @param seconds the seconds to add, may be negative1760* @return a {@code ZonedDateTime} based on this date-time with the seconds added, not null1761* @throws DateTimeException if the result exceeds the supported date range1762*/1763public ZonedDateTime plusSeconds(long seconds) {1764return resolveInstant(dateTime.plusSeconds(seconds));1765}17661767/**1768* Returns a copy of this {@code ZonedDateTime} with the specified number of nanoseconds added.1769* <p>1770* This operates on the instant time-line, such that adding one nano will1771* always be a duration of one nano later.1772* This may cause the local date-time to change by an amount other than one nano.1773* Note that this is a different approach to that used by days, months and years.1774* <p>1775* This instance is immutable and unaffected by this method call.1776*1777* @param nanos the nanos to add, may be negative1778* @return a {@code ZonedDateTime} based on this date-time with the nanoseconds added, not null1779* @throws DateTimeException if the result exceeds the supported date range1780*/1781public ZonedDateTime plusNanos(long nanos) {1782return resolveInstant(dateTime.plusNanos(nanos));1783}17841785//-----------------------------------------------------------------------1786/**1787* Returns a copy of this date-time with the specified amount subtracted.1788* <p>1789* This returns a {@code ZonedDateTime}, based on this one, with the specified amount subtracted.1790* The amount is typically {@link Period} or {@link Duration} but may be1791* any other type implementing the {@link TemporalAmount} interface.1792* <p>1793* The calculation is delegated to the amount object by calling1794* {@link TemporalAmount#subtractFrom(Temporal)}. The amount implementation is free1795* to implement the subtraction in any way it wishes, however it typically1796* calls back to {@link #minus(long, TemporalUnit)}. Consult the documentation1797* of the amount implementation to determine if it can be successfully subtracted.1798* <p>1799* This instance is immutable and unaffected by this method call.1800*1801* @param amountToSubtract the amount to subtract, not null1802* @return a {@code ZonedDateTime} based on this date-time with the subtraction made, not null1803* @throws DateTimeException if the subtraction cannot be made1804* @throws ArithmeticException if numeric overflow occurs1805*/1806@Override1807public ZonedDateTime minus(TemporalAmount amountToSubtract) {1808if (amountToSubtract instanceof Period periodToSubtract) {1809return resolveLocal(dateTime.minus(periodToSubtract));1810}1811Objects.requireNonNull(amountToSubtract, "amountToSubtract");1812return (ZonedDateTime) amountToSubtract.subtractFrom(this);1813}18141815/**1816* Returns a copy of this date-time with the specified amount subtracted.1817* <p>1818* This returns a {@code ZonedDateTime}, based on this one, with the amount1819* in terms of the unit subtracted. If it is not possible to subtract the amount,1820* because the unit is not supported or for some other reason, an exception is thrown.1821* <p>1822* The calculation for date and time units differ.1823* <p>1824* Date units operate on the local time-line.1825* The period is first subtracted from the local date-time, then converted back1826* to a zoned date-time using the zone ID.1827* The conversion uses {@link #ofLocal(LocalDateTime, ZoneId, ZoneOffset)}1828* with the offset before the subtraction.1829* <p>1830* Time units operate on the instant time-line.1831* The period is first subtracted from the local date-time, then converted back to1832* a zoned date-time using the zone ID.1833* The conversion uses {@link #ofInstant(LocalDateTime, ZoneOffset, ZoneId)}1834* with the offset before the subtraction.1835* <p>1836* This method is equivalent to {@link #plus(long, TemporalUnit)} with the amount negated.1837* See that method for a full description of how addition, and thus subtraction, works.1838* <p>1839* This instance is immutable and unaffected by this method call.1840*1841* @param amountToSubtract the amount of the unit to subtract from the result, may be negative1842* @param unit the unit of the amount to subtract, not null1843* @return a {@code ZonedDateTime} based on this date-time with the specified amount subtracted, not null1844* @throws DateTimeException if the subtraction cannot be made1845* @throws UnsupportedTemporalTypeException if the unit is not supported1846* @throws ArithmeticException if numeric overflow occurs1847*/1848@Override1849public ZonedDateTime minus(long amountToSubtract, TemporalUnit unit) {1850return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit));1851}18521853//-----------------------------------------------------------------------1854/**1855* Returns a copy of this {@code ZonedDateTime} with the specified number of years subtracted.1856* <p>1857* This operates on the local time-line,1858* {@link LocalDateTime#minusYears(long) subtracting years} to the local date-time.1859* This is then converted back to a {@code ZonedDateTime}, using the zone ID1860* to obtain the offset.1861* <p>1862* When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,1863* then the offset will be retained if possible, otherwise the earlier offset will be used.1864* If in a gap, the local date-time will be adjusted forward by the length of the gap.1865* <p>1866* This instance is immutable and unaffected by this method call.1867*1868* @param years the years to subtract, may be negative1869* @return a {@code ZonedDateTime} based on this date-time with the years subtracted, not null1870* @throws DateTimeException if the result exceeds the supported date range1871*/1872public ZonedDateTime minusYears(long years) {1873return (years == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-years));1874}18751876/**1877* Returns a copy of this {@code ZonedDateTime} with the specified number of months subtracted.1878* <p>1879* This operates on the local time-line,1880* {@link LocalDateTime#minusMonths(long) subtracting months} to the local date-time.1881* This is then converted back to a {@code ZonedDateTime}, using the zone ID1882* to obtain the offset.1883* <p>1884* When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,1885* then the offset will be retained if possible, otherwise the earlier offset will be used.1886* If in a gap, the local date-time will be adjusted forward by the length of the gap.1887* <p>1888* This instance is immutable and unaffected by this method call.1889*1890* @param months the months to subtract, may be negative1891* @return a {@code ZonedDateTime} based on this date-time with the months subtracted, not null1892* @throws DateTimeException if the result exceeds the supported date range1893*/1894public ZonedDateTime minusMonths(long months) {1895return (months == Long.MIN_VALUE ? plusMonths(Long.MAX_VALUE).plusMonths(1) : plusMonths(-months));1896}18971898/**1899* Returns a copy of this {@code ZonedDateTime} with the specified number of weeks subtracted.1900* <p>1901* This operates on the local time-line,1902* {@link LocalDateTime#minusWeeks(long) subtracting weeks} to the local date-time.1903* This is then converted back to a {@code ZonedDateTime}, using the zone ID1904* to obtain the offset.1905* <p>1906* When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,1907* then the offset will be retained if possible, otherwise the earlier offset will be used.1908* If in a gap, the local date-time will be adjusted forward by the length of the gap.1909* <p>1910* This instance is immutable and unaffected by this method call.1911*1912* @param weeks the weeks to subtract, may be negative1913* @return a {@code ZonedDateTime} based on this date-time with the weeks subtracted, not null1914* @throws DateTimeException if the result exceeds the supported date range1915*/1916public ZonedDateTime minusWeeks(long weeks) {1917return (weeks == Long.MIN_VALUE ? plusWeeks(Long.MAX_VALUE).plusWeeks(1) : plusWeeks(-weeks));1918}19191920/**1921* Returns a copy of this {@code ZonedDateTime} with the specified number of days subtracted.1922* <p>1923* This operates on the local time-line,1924* {@link LocalDateTime#minusDays(long) subtracting days} to the local date-time.1925* This is then converted back to a {@code ZonedDateTime}, using the zone ID1926* to obtain the offset.1927* <p>1928* When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,1929* then the offset will be retained if possible, otherwise the earlier offset will be used.1930* If in a gap, the local date-time will be adjusted forward by the length of the gap.1931* <p>1932* This instance is immutable and unaffected by this method call.1933*1934* @param days the days to subtract, may be negative1935* @return a {@code ZonedDateTime} based on this date-time with the days subtracted, not null1936* @throws DateTimeException if the result exceeds the supported date range1937*/1938public ZonedDateTime minusDays(long days) {1939return (days == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-days));1940}19411942//-----------------------------------------------------------------------1943/**1944* Returns a copy of this {@code ZonedDateTime} with the specified number of hours subtracted.1945* <p>1946* This operates on the instant time-line, such that subtracting one hour will1947* always be a duration of one hour earlier.1948* This may cause the local date-time to change by an amount other than one hour.1949* Note that this is a different approach to that used by days, months and years,1950* thus subtracting one day is not the same as adding 24 hours.1951* <p>1952* For example, consider a time-zone, such as 'Europe/Paris', where the1953* Autumn DST cutover means that the local times 02:00 to 02:59 occur twice1954* changing from offset +02:00 in summer to +01:00 in winter.1955* <ul>1956* <li>Subtracting one hour from 03:30+01:00 will result in 02:30+01:001957* (both in winter time)1958* <li>Subtracting one hour from 02:30+01:00 will result in 02:30+02:001959* (moving from winter to summer time)1960* <li>Subtracting one hour from 02:30+02:00 will result in 01:30+02:001961* (both in summer time)1962* <li>Subtracting three hours from 03:30+01:00 will result in 01:30+02:001963* (moving from winter to summer time)1964* </ul>1965* <p>1966* This instance is immutable and unaffected by this method call.1967*1968* @param hours the hours to subtract, may be negative1969* @return a {@code ZonedDateTime} based on this date-time with the hours subtracted, not null1970* @throws DateTimeException if the result exceeds the supported date range1971*/1972public ZonedDateTime minusHours(long hours) {1973return (hours == Long.MIN_VALUE ? plusHours(Long.MAX_VALUE).plusHours(1) : plusHours(-hours));1974}19751976/**1977* Returns a copy of this {@code ZonedDateTime} with the specified number of minutes subtracted.1978* <p>1979* This operates on the instant time-line, such that subtracting one minute will1980* always be a duration of one minute earlier.1981* This may cause the local date-time to change by an amount other than one minute.1982* Note that this is a different approach to that used by days, months and years.1983* <p>1984* This instance is immutable and unaffected by this method call.1985*1986* @param minutes the minutes to subtract, may be negative1987* @return a {@code ZonedDateTime} based on this date-time with the minutes subtracted, not null1988* @throws DateTimeException if the result exceeds the supported date range1989*/1990public ZonedDateTime minusMinutes(long minutes) {1991return (minutes == Long.MIN_VALUE ? plusMinutes(Long.MAX_VALUE).plusMinutes(1) : plusMinutes(-minutes));1992}19931994/**1995* Returns a copy of this {@code ZonedDateTime} with the specified number of seconds subtracted.1996* <p>1997* This operates on the instant time-line, such that subtracting one second will1998* always be a duration of one second earlier.1999* This may cause the local date-time to change by an amount other than one second.2000* Note that this is a different approach to that used by days, months and years.2001* <p>2002* This instance is immutable and unaffected by this method call.2003*2004* @param seconds the seconds to subtract, may be negative2005* @return a {@code ZonedDateTime} based on this date-time with the seconds subtracted, not null2006* @throws DateTimeException if the result exceeds the supported date range2007*/2008public ZonedDateTime minusSeconds(long seconds) {2009return (seconds == Long.MIN_VALUE ? plusSeconds(Long.MAX_VALUE).plusSeconds(1) : plusSeconds(-seconds));2010}20112012/**2013* Returns a copy of this {@code ZonedDateTime} with the specified number of nanoseconds subtracted.2014* <p>2015* This operates on the instant time-line, such that subtracting one nano will2016* always be a duration of one nano earlier.2017* This may cause the local date-time to change by an amount other than one nano.2018* Note that this is a different approach to that used by days, months and years.2019* <p>2020* This instance is immutable and unaffected by this method call.2021*2022* @param nanos the nanos to subtract, may be negative2023* @return a {@code ZonedDateTime} based on this date-time with the nanoseconds subtracted, not null2024* @throws DateTimeException if the result exceeds the supported date range2025*/2026public ZonedDateTime minusNanos(long nanos) {2027return (nanos == Long.MIN_VALUE ? plusNanos(Long.MAX_VALUE).plusNanos(1) : plusNanos(-nanos));2028}20292030//-----------------------------------------------------------------------2031/**2032* Queries this date-time using the specified query.2033* <p>2034* This queries this date-time using the specified query strategy object.2035* The {@code TemporalQuery} object defines the logic to be used to2036* obtain the result. Read the documentation of the query to understand2037* what the result of this method will be.2038* <p>2039* The result of this method is obtained by invoking the2040* {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the2041* specified query passing {@code this} as the argument.2042*2043* @param <R> the type of the result2044* @param query the query to invoke, not null2045* @return the query result, null may be returned (defined by the query)2046* @throws DateTimeException if unable to query (defined by the query)2047* @throws ArithmeticException if numeric overflow occurs (defined by the query)2048*/2049@SuppressWarnings("unchecked")2050@Override // override for Javadoc2051public <R> R query(TemporalQuery<R> query) {2052if (query == TemporalQueries.localDate()) {2053return (R) toLocalDate();2054}2055return ChronoZonedDateTime.super.query(query);2056}20572058/**2059* Calculates the amount of time until another date-time in terms of the specified unit.2060* <p>2061* This calculates the amount of time between two {@code ZonedDateTime}2062* objects in terms of a single {@code TemporalUnit}.2063* The start and end points are {@code this} and the specified date-time.2064* The result will be negative if the end is before the start.2065* For example, the amount in days between two date-times can be calculated2066* using {@code startDateTime.until(endDateTime, DAYS)}.2067* <p>2068* The {@code Temporal} passed to this method is converted to a2069* {@code ZonedDateTime} using {@link #from(TemporalAccessor)}.2070* If the time-zone differs between the two zoned date-times, the specified2071* end date-time is normalized to have the same zone as this date-time.2072* <p>2073* The calculation returns a whole number, representing the number of2074* complete units between the two date-times.2075* For example, the amount in months between 2012-06-15T00:00Z and 2012-08-14T23:59Z2076* will only be one month as it is one minute short of two months.2077* <p>2078* There are two equivalent ways of using this method.2079* The first is to invoke this method.2080* The second is to use {@link TemporalUnit#between(Temporal, Temporal)}:2081* <pre>2082* // these two lines are equivalent2083* amount = start.until(end, MONTHS);2084* amount = MONTHS.between(start, end);2085* </pre>2086* The choice should be made based on which makes the code more readable.2087* <p>2088* The calculation is implemented in this method for {@link ChronoUnit}.2089* The units {@code NANOS}, {@code MICROS}, {@code MILLIS}, {@code SECONDS},2090* {@code MINUTES}, {@code HOURS} and {@code HALF_DAYS}, {@code DAYS},2091* {@code WEEKS}, {@code MONTHS}, {@code YEARS}, {@code DECADES},2092* {@code CENTURIES}, {@code MILLENNIA} and {@code ERAS} are supported.2093* Other {@code ChronoUnit} values will throw an exception.2094* <p>2095* The calculation for date and time units differ.2096* <p>2097* Date units operate on the local time-line, using the local date-time.2098* For example, the period from noon on day 1 to noon the following day2099* in days will always be counted as exactly one day, irrespective of whether2100* there was a daylight savings change or not.2101* <p>2102* Time units operate on the instant time-line.2103* The calculation effectively converts both zoned date-times to instants2104* and then calculates the period between the instants.2105* For example, the period from noon on day 1 to noon the following day2106* in hours may be 23, 24 or 25 hours (or some other amount) depending on2107* whether there was a daylight savings change or not.2108* <p>2109* If the unit is not a {@code ChronoUnit}, then the result of this method2110* is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}2111* passing {@code this} as the first argument and the converted input temporal2112* as the second argument.2113* <p>2114* This instance is immutable and unaffected by this method call.2115*2116* @param endExclusive the end date, exclusive, which is converted to a {@code ZonedDateTime}, not null2117* @param unit the unit to measure the amount in, not null2118* @return the amount of time between this date-time and the end date-time2119* @throws DateTimeException if the amount cannot be calculated, or the end2120* temporal cannot be converted to a {@code ZonedDateTime}2121* @throws UnsupportedTemporalTypeException if the unit is not supported2122* @throws ArithmeticException if numeric overflow occurs2123*/2124@Override2125public long until(Temporal endExclusive, TemporalUnit unit) {2126ZonedDateTime end = ZonedDateTime.from(endExclusive);2127if (unit instanceof ChronoUnit) {2128ZonedDateTime start = this;2129try {2130end = end.withZoneSameInstant(zone);2131} catch (DateTimeException ex) {2132// end may be out of valid range. Adjust to end's zone.2133start = withZoneSameInstant(end.zone);2134}2135if (unit.isDateBased()) {2136return start.dateTime.until(end.dateTime, unit);2137} else {2138return start.toOffsetDateTime().until(end.toOffsetDateTime(), unit);2139}2140}2141return unit.between(this, end);2142}21432144/**2145* Formats this date-time using the specified formatter.2146* <p>2147* This date-time will be passed to the formatter to produce a string.2148*2149* @param formatter the formatter to use, not null2150* @return the formatted date-time string, not null2151* @throws DateTimeException if an error occurs during printing2152*/2153@Override // override for Javadoc and performance2154public String format(DateTimeFormatter formatter) {2155Objects.requireNonNull(formatter, "formatter");2156return formatter.format(this);2157}21582159//-----------------------------------------------------------------------2160/**2161* Converts this date-time to an {@code OffsetDateTime}.2162* <p>2163* This creates an offset date-time using the local date-time and offset.2164* The zone ID is ignored.2165*2166* @return an offset date-time representing the same local date-time and offset, not null2167*/2168public OffsetDateTime toOffsetDateTime() {2169return OffsetDateTime.of(dateTime, offset);2170}21712172//-----------------------------------------------------------------------2173/**2174* Checks if this date-time is equal to another date-time.2175* <p>2176* The comparison is based on the offset date-time and the zone.2177* Only objects of type {@code ZonedDateTime} are compared, other types return false.2178*2179* @param obj the object to check, null returns false2180* @return true if this is equal to the other date-time2181*/2182@Override2183public boolean equals(Object obj) {2184if (this == obj) {2185return true;2186}2187return obj instanceof ZonedDateTime other2188&& dateTime.equals(other.dateTime)2189&& offset.equals(other.offset)2190&& zone.equals(other.zone);2191}21922193/**2194* A hash code for this date-time.2195*2196* @return a suitable hash code2197*/2198@Override2199public int hashCode() {2200return dateTime.hashCode() ^ offset.hashCode() ^ Integer.rotateLeft(zone.hashCode(), 3);2201}22022203//-----------------------------------------------------------------------2204/**2205* Outputs this date-time as a {@code String}, such as2206* {@code 2007-12-03T10:15:30+01:00[Europe/Paris]}.2207* <p>2208* The format consists of the {@code LocalDateTime} followed by the {@code ZoneOffset}.2209* If the {@code ZoneId} is not the same as the offset, then the ID is output.2210* The output is compatible with ISO-8601 if the offset and ID are the same.2211*2212* @return a string representation of this date-time, not null2213*/2214@Override // override for Javadoc2215public String toString() {2216String str = dateTime.toString() + offset.toString();2217if (offset != zone) {2218str += '[' + zone.toString() + ']';2219}2220return str;2221}22222223//-----------------------------------------------------------------------2224/**2225* Writes the object using a2226* <a href="{@docRoot}/serialized-form.html#java.time.Ser">dedicated serialized form</a>.2227* @serialData2228* <pre>2229* out.writeByte(6); // identifies a ZonedDateTime2230* // the <a href="{@docRoot}/serialized-form.html#java.time.LocalDateTime">dateTime</a> excluding the one byte header2231* // the <a href="{@docRoot}/serialized-form.html#java.time.ZoneOffset">offset</a> excluding the one byte header2232* // the <a href="{@docRoot}/serialized-form.html#java.time.ZoneId">zone ID</a> excluding the one byte header2233* </pre>2234*2235* @return the instance of {@code Ser}, not null2236*/2237@java.io.Serial2238private Object writeReplace() {2239return new Ser(Ser.ZONE_DATE_TIME_TYPE, this);2240}22412242/**2243* Defend against malicious streams.2244*2245* @param s the stream to read2246* @throws InvalidObjectException always2247*/2248@java.io.Serial2249private void readObject(ObjectInputStream s) throws InvalidObjectException {2250throw new InvalidObjectException("Deserialization via serialization delegate");2251}22522253void writeExternal(DataOutput out) throws IOException {2254dateTime.writeExternal(out);2255offset.writeExternal(out);2256zone.write(out);2257}22582259static ZonedDateTime readExternal(ObjectInput in) throws IOException, ClassNotFoundException {2260LocalDateTime dateTime = LocalDateTime.readExternal(in);2261ZoneOffset offset = ZoneOffset.readExternal(in);2262ZoneId zone = (ZoneId) Ser.read(in);2263return ZonedDateTime.ofLenient(dateTime, offset, zone);2264}22652266}226722682269