Home | History | Annotate | Download | only in time
      1 /*
      2  * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
      3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      4  *
      5  * This code is free software; you can redistribute it and/or modify it
      6  * under the terms of the GNU General Public License version 2 only, as
      7  * published by the Free Software Foundation.  Oracle designates this
      8  * particular file as subject to the "Classpath" exception as provided
      9  * by Oracle in the LICENSE file that accompanied this code.
     10  *
     11  * This code is distributed in the hope that it will be useful, but WITHOUT
     12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14  * version 2 for more details (a copy is included in the LICENSE file that
     15  * accompanied this code).
     16  *
     17  * You should have received a copy of the GNU General Public License version
     18  * 2 along with this work; if not, write to the Free Software Foundation,
     19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     20  *
     21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     22  * or visit www.oracle.com if you need additional information or have any
     23  * questions.
     24  */
     25 
     26 /*
     27  * This file is available under and governed by the GNU General Public
     28  * License version 2 only, as published by the Free Software Foundation.
     29  * However, the following notice accompanied the original version of this
     30  * file:
     31  *
     32  * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
     33  *
     34  * All rights reserved.
     35  *
     36  * Redistribution and use in source and binary forms, with or without
     37  * modification, are permitted provided that the following conditions are met:
     38  *
     39  *  * Redistributions of source code must retain the above copyright notice,
     40  *    this list of conditions and the following disclaimer.
     41  *
     42  *  * Redistributions in binary form must reproduce the above copyright notice,
     43  *    this list of conditions and the following disclaimer in the documentation
     44  *    and/or other materials provided with the distribution.
     45  *
     46  *  * Neither the name of JSR-310 nor the names of its contributors
     47  *    may be used to endorse or promote products derived from this software
     48  *    without specific prior written permission.
     49  *
     50  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     51  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     52  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     53  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     54  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     55  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     56  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     57  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     58  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     59  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     60  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     61  */
     62 package java.time;
     63 
     64 import static java.time.temporal.ChronoField.INSTANT_SECONDS;
     65 import static java.time.temporal.ChronoField.NANO_OF_SECOND;
     66 import static java.time.temporal.ChronoField.OFFSET_SECONDS;
     67 
     68 import java.io.DataOutput;
     69 import java.io.IOException;
     70 import java.io.ObjectInput;
     71 import java.io.InvalidObjectException;
     72 import java.io.ObjectInputStream;
     73 import java.io.Serializable;
     74 import java.time.chrono.ChronoZonedDateTime;
     75 import java.time.format.DateTimeFormatter;
     76 import java.time.format.DateTimeParseException;
     77 import java.time.temporal.ChronoField;
     78 import java.time.temporal.ChronoUnit;
     79 import java.time.temporal.Temporal;
     80 import java.time.temporal.TemporalAccessor;
     81 import java.time.temporal.TemporalAdjuster;
     82 import java.time.temporal.TemporalAmount;
     83 import java.time.temporal.TemporalField;
     84 import java.time.temporal.TemporalQueries;
     85 import java.time.temporal.TemporalQuery;
     86 import java.time.temporal.TemporalUnit;
     87 import java.time.temporal.UnsupportedTemporalTypeException;
     88 import java.time.temporal.ValueRange;
     89 import java.time.zone.ZoneOffsetTransition;
     90 import java.time.zone.ZoneRules;
     91 import java.util.List;
     92 import java.util.Objects;
     93 
     94 // Android-changed: removed ValueBased paragraph.
     95 /**
     96  * A date-time with a time-zone in the ISO-8601 calendar system,
     97  * such as {@code 2007-12-03T10:15:30+01:00 Europe/Paris}.
     98  * <p>
     99  * {@code ZonedDateTime} is an immutable representation of a date-time with a time-zone.
    100  * This class stores all date and time fields, to a precision of nanoseconds,
    101  * and a time-zone, with a zone offset used to handle ambiguous local date-times.
    102  * For example, the value
    103  * "2nd October 2007 at 13:45.30.123456789 +02:00 in the Europe/Paris time-zone"
    104  * can be stored in a {@code ZonedDateTime}.
    105  * <p>
    106  * This class handles conversion from the local time-line of {@code LocalDateTime}
    107  * to the instant time-line of {@code Instant}.
    108  * The difference between the two time-lines is the offset from UTC/Greenwich,
    109  * represented by a {@code ZoneOffset}.
    110  * <p>
    111  * Converting between the two time-lines involves calculating the offset using the
    112  * {@link ZoneRules rules} accessed from the {@code ZoneId}.
    113  * Obtaining the offset for an instant is simple, as there is exactly one valid
    114  * offset for each instant. By contrast, obtaining the offset for a local date-time
    115  * is not straightforward. There are three cases:
    116  * <ul>
    117  * <li>Normal, with one valid offset. For the vast majority of the year, the normal
    118  *  case applies, where there is a single valid offset for the local date-time.</li>
    119  * <li>Gap, with zero valid offsets. This is when clocks jump forward typically
    120  *  due to the spring daylight savings change from "winter" to "summer".
    121  *  In a gap there are local date-time values with no valid offset.</li>
    122  * <li>Overlap, with two valid offsets. This is when clocks are set back typically
    123  *  due to the autumn daylight savings change from "summer" to "winter".
    124  *  In an overlap there are local date-time values with two valid offsets.</li>
    125  * </ul>
    126  * <p>
    127  * Any method that converts directly or implicitly from a local date-time to an
    128  * instant by obtaining the offset has the potential to be complicated.
    129  * <p>
    130  * For Gaps, the general strategy is that if the local date-time falls in the
    131  * middle of a Gap, then the resulting zoned date-time will have a local date-time
    132  * shifted forwards by the length of the Gap, resulting in a date-time in the later
    133  * offset, typically "summer" time.
    134  * <p>
    135  * For Overlaps, the general strategy is that if the local date-time falls in the
    136  * middle of an Overlap, then the previous offset will be retained. If there is no
    137  * previous offset, or the previous offset is invalid, then the earlier offset is
    138  * used, typically "summer" time.. Two additional methods,
    139  * {@link #withEarlierOffsetAtOverlap()} and {@link #withLaterOffsetAtOverlap()},
    140  * help manage the case of an overlap.
    141  * <p>
    142  * In terms of design, this class should be viewed primarily as the combination
    143  * of a {@code LocalDateTime} and a {@code ZoneId}. The {@code ZoneOffset} is
    144  * a vital, but secondary, piece of information, used to ensure that the class
    145  * represents an instant, especially during a daylight savings overlap.
    146  *
    147  * @implSpec
    148  * A {@code ZonedDateTime} holds state equivalent to three separate objects,
    149  * a {@code LocalDateTime}, a {@code ZoneId} and the resolved {@code ZoneOffset}.
    150  * The offset and local date-time are used to define an instant when necessary.
    151  * The zone ID is used to obtain the rules for how and when the offset changes.
    152  * The offset cannot be freely set, as the zone controls which offsets are valid.
    153  * <p>
    154  * This class is immutable and thread-safe.
    155  *
    156  * @since 1.8
    157  */
    158 public final class ZonedDateTime
    159         implements Temporal, ChronoZonedDateTime<LocalDate>, Serializable {
    160 
    161     /**
    162      * Serialization version.
    163      */
    164     private static final long serialVersionUID = -6260982410461394882L;
    165 
    166     /**
    167      * The local date-time.
    168      */
    169     private final LocalDateTime dateTime;
    170     /**
    171      * The offset from UTC/Greenwich.
    172      */
    173     private final ZoneOffset offset;
    174     /**
    175      * The time-zone.
    176      */
    177     private final ZoneId zone;
    178 
    179     //-----------------------------------------------------------------------
    180     /**
    181      * Obtains the current date-time from the system clock in the default time-zone.
    182      * <p>
    183      * This will query the {@link Clock#systemDefaultZone() system clock} in the default
    184      * time-zone to obtain the current date-time.
    185      * The zone and offset will be set based on the time-zone in the clock.
    186      * <p>
    187      * Using this method will prevent the ability to use an alternate clock for testing
    188      * because the clock is hard-coded.
    189      *
    190      * @return the current date-time using the system clock, not null
    191      */
    192     public static ZonedDateTime now() {
    193         return now(Clock.systemDefaultZone());
    194     }
    195 
    196     /**
    197      * Obtains the current date-time from the system clock in the specified time-zone.
    198      * <p>
    199      * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date-time.
    200      * Specifying the time-zone avoids dependence on the default time-zone.
    201      * The offset will be calculated from the specified time-zone.
    202      * <p>
    203      * Using this method will prevent the ability to use an alternate clock for testing
    204      * because the clock is hard-coded.
    205      *
    206      * @param zone  the zone ID to use, not null
    207      * @return the current date-time using the system clock, not null
    208      */
    209     public static ZonedDateTime now(ZoneId zone) {
    210         return now(Clock.system(zone));
    211     }
    212 
    213     /**
    214      * Obtains the current date-time from the specified clock.
    215      * <p>
    216      * This will query the specified clock to obtain the current date-time.
    217      * The zone and offset will be set based on the time-zone in the clock.
    218      * <p>
    219      * Using this method allows the use of an alternate clock for testing.
    220      * The alternate clock may be introduced using {@link Clock dependency injection}.
    221      *
    222      * @param clock  the clock to use, not null
    223      * @return the current date-time, not null
    224      */
    225     public static ZonedDateTime now(Clock clock) {
    226         Objects.requireNonNull(clock, "clock");
    227         final Instant now = clock.instant();  // called once
    228         return ofInstant(now, clock.getZone());
    229     }
    230 
    231     //-----------------------------------------------------------------------
    232     /**
    233      * Obtains an instance of {@code ZonedDateTime} from a local date and time.
    234      * <p>
    235      * This creates a zoned date-time matching the input local date and time as closely as possible.
    236      * Time-zone rules, such as daylight savings, mean that not every local date-time
    237      * is valid for the specified zone, thus the local date-time may be adjusted.
    238      * <p>
    239      * The local date time and first combined to form a local date-time.
    240      * The local date-time is then resolved to a single instant on the time-line.
    241      * This is achieved by finding a valid offset from UTC/Greenwich for the local
    242      * date-time as defined by the {@link ZoneRules rules} of the zone ID.
    243      *<p>
    244      * In most cases, there is only one valid offset for a local date-time.
    245      * In the case of an overlap, when clocks are set back, there are two valid offsets.
    246      * This method uses the earlier offset typically corresponding to "summer".
    247      * <p>
    248      * In the case of a gap, when clocks jump forward, there is no valid offset.
    249      * Instead, the local date-time is adjusted to be later by the length of the gap.
    250      * For a typical one hour daylight savings change, the local date-time will be
    251      * moved one hour later into the offset typically corresponding to "summer".
    252      *
    253      * @param date  the local date, not null
    254      * @param time  the local time, not null
    255      * @param zone  the time-zone, not null
    256      * @return the offset date-time, not null
    257      */
    258     public static ZonedDateTime of(LocalDate date, LocalTime time, ZoneId zone) {
    259         return of(LocalDateTime.of(date, time), zone);
    260     }
    261 
    262     /**
    263      * Obtains an instance of {@code ZonedDateTime} from a local date-time.
    264      * <p>
    265      * This creates a zoned date-time matching the input local date-time as closely as possible.
    266      * Time-zone rules, such as daylight savings, mean that not every local date-time
    267      * is valid for the specified zone, thus the local date-time may be adjusted.
    268      * <p>
    269      * The local date-time is resolved to a single instant on the time-line.
    270      * This is achieved by finding a valid offset from UTC/Greenwich for the local
    271      * date-time as defined by the {@link ZoneRules rules} of the zone ID.
    272      *<p>
    273      * In most cases, there is only one valid offset for a local date-time.
    274      * In the case of an overlap, when clocks are set back, there are two valid offsets.
    275      * This method uses the earlier offset typically corresponding to "summer".
    276      * <p>
    277      * In the case of a gap, when clocks jump forward, there is no valid offset.
    278      * Instead, the local date-time is adjusted to be later by the length of the gap.
    279      * For a typical one hour daylight savings change, the local date-time will be
    280      * moved one hour later into the offset typically corresponding to "summer".
    281      *
    282      * @param localDateTime  the local date-time, not null
    283      * @param zone  the time-zone, not null
    284      * @return the zoned date-time, not null
    285      */
    286     public static ZonedDateTime of(LocalDateTime localDateTime, ZoneId zone) {
    287         return ofLocal(localDateTime, zone, null);
    288     }
    289 
    290     /**
    291      * Obtains an instance of {@code ZonedDateTime} from a year, month, day,
    292      * hour, minute, second, nanosecond and time-zone.
    293      * <p>
    294      * This creates a zoned date-time matching the local date-time of the seven
    295      * specified fields as closely as possible.
    296      * Time-zone rules, such as daylight savings, mean that not every local date-time
    297      * is valid for the specified zone, thus the local date-time may be adjusted.
    298      * <p>
    299      * The local date-time is resolved to a single instant on the time-line.
    300      * This is achieved by finding a valid offset from UTC/Greenwich for the local
    301      * date-time as defined by the {@link ZoneRules rules} of the zone ID.
    302      *<p>
    303      * In most cases, there is only one valid offset for a local date-time.
    304      * In the case of an overlap, when clocks are set back, there are two valid offsets.
    305      * This method uses the earlier offset typically corresponding to "summer".
    306      * <p>
    307      * In the case of a gap, when clocks jump forward, there is no valid offset.
    308      * Instead, the local date-time is adjusted to be later by the length of the gap.
    309      * For a typical one hour daylight savings change, the local date-time will be
    310      * moved one hour later into the offset typically corresponding to "summer".
    311      * <p>
    312      * This method exists primarily for writing test cases.
    313      * Non test-code will typically use other methods to create an offset time.
    314      * {@code LocalDateTime} has five additional convenience variants of the
    315      * equivalent factory method taking fewer arguments.
    316      * They are not provided here to reduce the footprint of the API.
    317      *
    318      * @param year  the year to represent, from MIN_YEAR to MAX_YEAR
    319      * @param month  the month-of-year to represent, from 1 (January) to 12 (December)
    320      * @param dayOfMonth  the day-of-month to represent, from 1 to 31
    321      * @param hour  the hour-of-day to represent, from 0 to 23
    322      * @param minute  the minute-of-hour to represent, from 0 to 59
    323      * @param second  the second-of-minute to represent, from 0 to 59
    324      * @param nanoOfSecond  the nano-of-second to represent, from 0 to 999,999,999
    325      * @param zone  the time-zone, not null
    326      * @return the offset date-time, not null
    327      * @throws DateTimeException if the value of any field is out of range, or
    328      *  if the day-of-month is invalid for the month-year
    329      */
    330     public static ZonedDateTime of(
    331             int year, int month, int dayOfMonth,
    332             int hour, int minute, int second, int nanoOfSecond, ZoneId zone) {
    333         LocalDateTime dt = LocalDateTime.of(year, month, dayOfMonth, hour, minute, second, nanoOfSecond);
    334         return ofLocal(dt, zone, null);
    335     }
    336 
    337     /**
    338      * Obtains an instance of {@code ZonedDateTime} from a local date-time
    339      * using the preferred offset if possible.
    340      * <p>
    341      * The local date-time is resolved to a single instant on the time-line.
    342      * This is achieved by finding a valid offset from UTC/Greenwich for the local
    343      * date-time as defined by the {@link ZoneRules rules} of the zone ID.
    344      *<p>
    345      * In most cases, there is only one valid offset for a local date-time.
    346      * In the case of an overlap, where clocks are set back, there are two valid offsets.
    347      * If the preferred offset is one of the valid offsets then it is used.
    348      * Otherwise the earlier valid offset is used, typically corresponding to "summer".
    349      * <p>
    350      * In the case of a gap, where clocks jump forward, there is no valid offset.
    351      * Instead, the local date-time is adjusted to be later by the length of the gap.
    352      * For a typical one hour daylight savings change, the local date-time will be
    353      * moved one hour later into the offset typically corresponding to "summer".
    354      *
    355      * @param localDateTime  the local date-time, not null
    356      * @param zone  the time-zone, not null
    357      * @param preferredOffset  the zone offset, null if no preference
    358      * @return the zoned date-time, not null
    359      */
    360     public static ZonedDateTime ofLocal(LocalDateTime localDateTime, ZoneId zone, ZoneOffset preferredOffset) {
    361         Objects.requireNonNull(localDateTime, "localDateTime");
    362         Objects.requireNonNull(zone, "zone");
    363         if (zone instanceof ZoneOffset) {
    364             return new ZonedDateTime(localDateTime, (ZoneOffset) zone, zone);
    365         }
    366         ZoneRules rules = zone.getRules();
    367         List<ZoneOffset> validOffsets = rules.getValidOffsets(localDateTime);
    368         ZoneOffset offset;
    369         if (validOffsets.size() == 1) {
    370             offset = validOffsets.get(0);
    371         } else if (validOffsets.size() == 0) {
    372             ZoneOffsetTransition trans = rules.getTransition(localDateTime);
    373             localDateTime = localDateTime.plusSeconds(trans.getDuration().getSeconds());
    374             offset = trans.getOffsetAfter();
    375         } else {
    376             if (preferredOffset != null && validOffsets.contains(preferredOffset)) {
    377                 offset = preferredOffset;
    378             } else {
    379                 offset = Objects.requireNonNull(validOffsets.get(0), "offset");  // protect against bad ZoneRules
    380             }
    381         }
    382         return new ZonedDateTime(localDateTime, offset, zone);
    383     }
    384 
    385     //-----------------------------------------------------------------------
    386     /**
    387      * Obtains an instance of {@code ZonedDateTime} from an {@code Instant}.
    388      * <p>
    389      * This creates a zoned date-time with the same instant as that specified.
    390      * Calling {@link #toInstant()} will return an instant equal to the one used here.
    391      * <p>
    392      * Converting an instant to a zoned date-time is simple as there is only one valid
    393      * offset for each instant.
    394      *
    395      * @param instant  the instant to create the date-time from, not null
    396      * @param zone  the time-zone, not null
    397      * @return the zoned date-time, not null
    398      * @throws DateTimeException if the result exceeds the supported range
    399      */
    400     public static ZonedDateTime ofInstant(Instant instant, ZoneId zone) {
    401         Objects.requireNonNull(instant, "instant");
    402         Objects.requireNonNull(zone, "zone");
    403         return create(instant.getEpochSecond(), instant.getNano(), zone);
    404     }
    405 
    406     /**
    407      * Obtains an instance of {@code ZonedDateTime} from the instant formed by combining
    408      * the local date-time and offset.
    409      * <p>
    410      * This creates a zoned date-time by {@link LocalDateTime#toInstant(ZoneOffset) combining}
    411      * the {@code LocalDateTime} and {@code ZoneOffset}.
    412      * This combination uniquely specifies an instant without ambiguity.
    413      * <p>
    414      * Converting an instant to a zoned date-time is simple as there is only one valid
    415      * offset for each instant. If the valid offset is different to the offset specified,
    416      * then the date-time and offset of the zoned date-time will differ from those specified.
    417      * <p>
    418      * If the {@code ZoneId} to be used is a {@code ZoneOffset}, this method is equivalent
    419      * to {@link #of(LocalDateTime, ZoneId)}.
    420      *
    421      * @param localDateTime  the local date-time, not null
    422      * @param offset  the zone offset, not null
    423      * @param zone  the time-zone, not null
    424      * @return the zoned date-time, not null
    425      */
    426     public static ZonedDateTime ofInstant(LocalDateTime localDateTime, ZoneOffset offset, ZoneId zone) {
    427         Objects.requireNonNull(localDateTime, "localDateTime");
    428         Objects.requireNonNull(offset, "offset");
    429         Objects.requireNonNull(zone, "zone");
    430         if (zone.getRules().isValidOffset(localDateTime, offset)) {
    431             return new ZonedDateTime(localDateTime, offset, zone);
    432         }
    433         return create(localDateTime.toEpochSecond(offset), localDateTime.getNano(), zone);
    434     }
    435 
    436     /**
    437      * Obtains an instance of {@code ZonedDateTime} using seconds from the
    438      * epoch of 1970-01-01T00:00:00Z.
    439      *
    440      * @param epochSecond  the number of seconds from the epoch of 1970-01-01T00:00:00Z
    441      * @param nanoOfSecond  the nanosecond within the second, from 0 to 999,999,999
    442      * @param zone  the time-zone, not null
    443      * @return the zoned date-time, not null
    444      * @throws DateTimeException if the result exceeds the supported range
    445      */
    446     private static ZonedDateTime create(long epochSecond, int nanoOfSecond, ZoneId zone) {
    447         ZoneRules rules = zone.getRules();
    448         Instant instant = Instant.ofEpochSecond(epochSecond, nanoOfSecond);  // TODO: rules should be queryable by epochSeconds
    449         ZoneOffset offset = rules.getOffset(instant);
    450         LocalDateTime ldt = LocalDateTime.ofEpochSecond(epochSecond, nanoOfSecond, offset);
    451         return new ZonedDateTime(ldt, offset, zone);
    452     }
    453 
    454     //-----------------------------------------------------------------------
    455     /**
    456      * Obtains an instance of {@code ZonedDateTime} strictly validating the
    457      * combination of local date-time, offset and zone ID.
    458      * <p>
    459      * This creates a zoned date-time ensuring that the offset is valid for the
    460      * local date-time according to the rules of the specified zone.
    461      * If the offset is invalid, an exception is thrown.
    462      *
    463      * @param localDateTime  the local date-time, not null
    464      * @param offset  the zone offset, not null
    465      * @param zone  the time-zone, not null
    466      * @return the zoned date-time, not null
    467      */
    468     public static ZonedDateTime ofStrict(LocalDateTime localDateTime, ZoneOffset offset, ZoneId zone) {
    469         Objects.requireNonNull(localDateTime, "localDateTime");
    470         Objects.requireNonNull(offset, "offset");
    471         Objects.requireNonNull(zone, "zone");
    472         ZoneRules rules = zone.getRules();
    473         if (rules.isValidOffset(localDateTime, offset) == false) {
    474             ZoneOffsetTransition trans = rules.getTransition(localDateTime);
    475             if (trans != null && trans.isGap()) {
    476                 // error message says daylight savings for simplicity
    477                 // even though there are other kinds of gaps
    478                 throw new DateTimeException("LocalDateTime '" + localDateTime +
    479                         "' does not exist in zone '" + zone +
    480                         "' due to a gap in the local time-line, typically caused by daylight savings");
    481             }
    482             throw new DateTimeException("ZoneOffset '" + offset + "' is not valid for LocalDateTime '" +
    483                     localDateTime + "' in zone '" + zone + "'");
    484         }
    485         return new ZonedDateTime(localDateTime, offset, zone);
    486     }
    487 
    488     /**
    489      * Obtains an instance of {@code ZonedDateTime} leniently, for advanced use cases,
    490      * allowing any combination of local date-time, offset and zone ID.
    491      * <p>
    492      * This creates a zoned date-time with no checks other than no nulls.
    493      * This means that the resulting zoned date-time may have an offset that is in conflict
    494      * with the zone ID.
    495      * <p>
    496      * This method is intended for advanced use cases.
    497      * For example, consider the case where a zoned date-time with valid fields is created
    498      * and then stored in a database or serialization-based store. At some later point,
    499      * the object is then re-loaded. However, between those points in time, the government
    500      * that defined the time-zone has changed the rules, such that the originally stored
    501      * local date-time now does not occur. This method can be used to create the object
    502      * in an "invalid" state, despite the change in rules.
    503      *
    504      * @param localDateTime  the local date-time, not null
    505      * @param offset  the zone offset, not null
    506      * @param zone  the time-zone, not null
    507      * @return the zoned date-time, not null
    508      */
    509     private static ZonedDateTime ofLenient(LocalDateTime localDateTime, ZoneOffset offset, ZoneId zone) {
    510         Objects.requireNonNull(localDateTime, "localDateTime");
    511         Objects.requireNonNull(offset, "offset");
    512         Objects.requireNonNull(zone, "zone");
    513         if (zone instanceof ZoneOffset && offset.equals(zone) == false) {
    514             throw new IllegalArgumentException("ZoneId must match ZoneOffset");
    515         }
    516         return new ZonedDateTime(localDateTime, offset, zone);
    517     }
    518 
    519     //-----------------------------------------------------------------------
    520     /**
    521      * Obtains an instance of {@code ZonedDateTime} from a temporal object.
    522      * <p>
    523      * This obtains a zoned date-time based on the specified temporal.
    524      * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
    525      * which this factory converts to an instance of {@code ZonedDateTime}.
    526      * <p>
    527      * The conversion will first obtain a {@code ZoneId} from the temporal object,
    528      * falling back to a {@code ZoneOffset} if necessary. It will then try to obtain
    529      * an {@code Instant}, falling back to a {@code LocalDateTime} if necessary.
    530      * The result will be either the combination of {@code ZoneId} or {@code ZoneOffset}
    531      * with {@code Instant} or {@code LocalDateTime}.
    532      * Implementations are permitted to perform optimizations such as accessing
    533      * those fields that are equivalent to the relevant objects.
    534      * <p>
    535      * This method matches the signature of the functional interface {@link TemporalQuery}
    536      * allowing it to be used as a query via method reference, {@code ZonedDateTime::from}.
    537      *
    538      * @param temporal  the temporal object to convert, not null
    539      * @return the zoned date-time, not null
    540      * @throws DateTimeException if unable to convert to an {@code ZonedDateTime}
    541      */
    542     public static ZonedDateTime from(TemporalAccessor temporal) {
    543         if (temporal instanceof ZonedDateTime) {
    544             return (ZonedDateTime) temporal;
    545         }
    546         try {
    547             ZoneId zone = ZoneId.from(temporal);
    548             if (temporal.isSupported(INSTANT_SECONDS)) {
    549                 long epochSecond = temporal.getLong(INSTANT_SECONDS);
    550                 int nanoOfSecond = temporal.get(NANO_OF_SECOND);
    551                 return create(epochSecond, nanoOfSecond, zone);
    552             } else {
    553                 LocalDate date = LocalDate.from(temporal);
    554                 LocalTime time = LocalTime.from(temporal);
    555                 return of(date, time, zone);
    556             }
    557         } catch (DateTimeException ex) {
    558             throw new DateTimeException("Unable to obtain ZonedDateTime from TemporalAccessor: " +
    559                     temporal + " of type " + temporal.getClass().getName(), ex);
    560         }
    561     }
    562 
    563     //-----------------------------------------------------------------------
    564     /**
    565      * Obtains an instance of {@code ZonedDateTime} from a text string such as
    566      * {@code 2007-12-03T10:15:30+01:00[Europe/Paris]}.
    567      * <p>
    568      * The string must represent a valid date-time and is parsed using
    569      * {@link java.time.format.DateTimeFormatter#ISO_ZONED_DATE_TIME}.
    570      *
    571      * @param text  the text to parse such as "2007-12-03T10:15:30+01:00[Europe/Paris]", not null
    572      * @return the parsed zoned date-time, not null
    573      * @throws DateTimeParseException if the text cannot be parsed
    574      */
    575     public static ZonedDateTime parse(CharSequence text) {
    576         return parse(text, DateTimeFormatter.ISO_ZONED_DATE_TIME);
    577     }
    578 
    579     /**
    580      * Obtains an instance of {@code ZonedDateTime} from a text string using a specific formatter.
    581      * <p>
    582      * The text is parsed using the formatter, returning a date-time.
    583      *
    584      * @param text  the text to parse, not null
    585      * @param formatter  the formatter to use, not null
    586      * @return the parsed zoned date-time, not null
    587      * @throws DateTimeParseException if the text cannot be parsed
    588      */
    589     public static ZonedDateTime parse(CharSequence text, DateTimeFormatter formatter) {
    590         Objects.requireNonNull(formatter, "formatter");
    591         return formatter.parse(text, ZonedDateTime::from);
    592     }
    593 
    594     //-----------------------------------------------------------------------
    595     /**
    596      * Constructor.
    597      *
    598      * @param dateTime  the date-time, validated as not null
    599      * @param offset  the zone offset, validated as not null
    600      * @param zone  the time-zone, validated as not null
    601      */
    602     private ZonedDateTime(LocalDateTime dateTime, ZoneOffset offset, ZoneId zone) {
    603         this.dateTime = dateTime;
    604         this.offset = offset;
    605         this.zone = zone;
    606     }
    607 
    608     /**
    609      * Resolves the new local date-time using this zone ID, retaining the offset if possible.
    610      *
    611      * @param newDateTime  the new local date-time, not null
    612      * @return the zoned date-time, not null
    613      */
    614     private ZonedDateTime resolveLocal(LocalDateTime newDateTime) {
    615         return ofLocal(newDateTime, zone, offset);
    616     }
    617 
    618     /**
    619      * Resolves the new local date-time using the offset to identify the instant.
    620      *
    621      * @param newDateTime  the new local date-time, not null
    622      * @return the zoned date-time, not null
    623      */
    624     private ZonedDateTime resolveInstant(LocalDateTime newDateTime) {
    625         return ofInstant(newDateTime, offset, zone);
    626     }
    627 
    628     /**
    629      * Resolves the offset into this zoned date-time for the with methods.
    630      * <p>
    631      * This typically ignores the offset, unless it can be used to switch offset in a DST overlap.
    632      *
    633      * @param offset  the offset, not null
    634      * @return the zoned date-time, not null
    635      */
    636     private ZonedDateTime resolveOffset(ZoneOffset offset) {
    637         if (offset.equals(this.offset) == false && zone.getRules().isValidOffset(dateTime, offset)) {
    638             return new ZonedDateTime(dateTime, offset, zone);
    639         }
    640         return this;
    641     }
    642 
    643     //-----------------------------------------------------------------------
    644     /**
    645      * Checks if the specified field is supported.
    646      * <p>
    647      * This checks if this date-time can be queried for the specified field.
    648      * If false, then calling the {@link #range(TemporalField) range},
    649      * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)}
    650      * methods will throw an exception.
    651      * <p>
    652      * If the field is a {@link ChronoField} then the query is implemented here.
    653      * The supported fields are:
    654      * <ul>
    655      * <li>{@code NANO_OF_SECOND}
    656      * <li>{@code NANO_OF_DAY}
    657      * <li>{@code MICRO_OF_SECOND}
    658      * <li>{@code MICRO_OF_DAY}
    659      * <li>{@code MILLI_OF_SECOND}
    660      * <li>{@code MILLI_OF_DAY}
    661      * <li>{@code SECOND_OF_MINUTE}
    662      * <li>{@code SECOND_OF_DAY}
    663      * <li>{@code MINUTE_OF_HOUR}
    664      * <li>{@code MINUTE_OF_DAY}
    665      * <li>{@code HOUR_OF_AMPM}
    666      * <li>{@code CLOCK_HOUR_OF_AMPM}
    667      * <li>{@code HOUR_OF_DAY}
    668      * <li>{@code CLOCK_HOUR_OF_DAY}
    669      * <li>{@code AMPM_OF_DAY}
    670      * <li>{@code DAY_OF_WEEK}
    671      * <li>{@code ALIGNED_DAY_OF_WEEK_IN_MONTH}
    672      * <li>{@code ALIGNED_DAY_OF_WEEK_IN_YEAR}
    673      * <li>{@code DAY_OF_MONTH}
    674      * <li>{@code DAY_OF_YEAR}
    675      * <li>{@code EPOCH_DAY}
    676      * <li>{@code ALIGNED_WEEK_OF_MONTH}
    677      * <li>{@code ALIGNED_WEEK_OF_YEAR}
    678      * <li>{@code MONTH_OF_YEAR}
    679      * <li>{@code PROLEPTIC_MONTH}
    680      * <li>{@code YEAR_OF_ERA}
    681      * <li>{@code YEAR}
    682      * <li>{@code ERA}
    683      * <li>{@code INSTANT_SECONDS}
    684      * <li>{@code OFFSET_SECONDS}
    685      * </ul>
    686      * All other {@code ChronoField} instances will return false.
    687      * <p>
    688      * If the field is not a {@code ChronoField}, then the result of this method
    689      * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
    690      * passing {@code this} as the argument.
    691      * Whether the field is supported is determined by the field.
    692      *
    693      * @param field  the field to check, null returns false
    694      * @return true if the field is supported on this date-time, false if not
    695      */
    696     @Override
    697     public boolean isSupported(TemporalField field) {
    698         return field instanceof ChronoField || (field != null && field.isSupportedBy(this));
    699     }
    700 
    701     /**
    702      * Checks if the specified unit is supported.
    703      * <p>
    704      * This checks if the specified unit can be added to, or subtracted from, this date-time.
    705      * If false, then calling the {@link #plus(long, TemporalUnit)} and
    706      * {@link #minus(long, TemporalUnit) minus} methods will throw an exception.
    707      * <p>
    708      * If the unit is a {@link ChronoUnit} then the query is implemented here.
    709      * The supported units are:
    710      * <ul>
    711      * <li>{@code NANOS}
    712      * <li>{@code MICROS}
    713      * <li>{@code MILLIS}
    714      * <li>{@code SECONDS}
    715      * <li>{@code MINUTES}
    716      * <li>{@code HOURS}
    717      * <li>{@code HALF_DAYS}
    718      * <li>{@code DAYS}
    719      * <li>{@code WEEKS}
    720      * <li>{@code MONTHS}
    721      * <li>{@code YEARS}
    722      * <li>{@code DECADES}
    723      * <li>{@code CENTURIES}
    724      * <li>{@code MILLENNIA}
    725      * <li>{@code ERAS}
    726      * </ul>
    727      * All other {@code ChronoUnit} instances will return false.
    728      * <p>
    729      * If the unit is not a {@code ChronoUnit}, then the result of this method
    730      * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)}
    731      * passing {@code this} as the argument.
    732      * Whether the unit is supported is determined by the unit.
    733      *
    734      * @param unit  the unit to check, null returns false
    735      * @return true if the unit can be added/subtracted, false if not
    736      */
    737     @Override  // override for Javadoc
    738     public boolean isSupported(TemporalUnit unit) {
    739         return ChronoZonedDateTime.super.isSupported(unit);
    740     }
    741 
    742     //-----------------------------------------------------------------------
    743     /**
    744      * Gets the range of valid values for the specified field.
    745      * <p>
    746      * The range object expresses the minimum and maximum valid values for a field.
    747      * This date-time is used to enhance the accuracy of the returned range.
    748      * If it is not possible to return the range, because the field is not supported
    749      * or for some other reason, an exception is thrown.
    750      * <p>
    751      * If the field is a {@link ChronoField} then the query is implemented here.
    752      * The {@link #isSupported(TemporalField) supported fields} will return
    753      * appropriate range instances.
    754      * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
    755      * <p>
    756      * If the field is not a {@code ChronoField}, then the result of this method
    757      * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
    758      * passing {@code this} as the argument.
    759      * Whether the range can be obtained is determined by the field.
    760      *
    761      * @param field  the field to query the range for, not null
    762      * @return the range of valid values for the field, not null
    763      * @throws DateTimeException if the range for the field cannot be obtained
    764      * @throws UnsupportedTemporalTypeException if the field is not supported
    765      */
    766     @Override
    767     public ValueRange range(TemporalField field) {
    768         if (field instanceof ChronoField) {
    769             if (field == INSTANT_SECONDS || field == OFFSET_SECONDS) {
    770                 return field.range();
    771             }
    772             return dateTime.range(field);
    773         }
    774         return field.rangeRefinedBy(this);
    775     }
    776 
    777     /**
    778      * Gets the value of the specified field from this date-time as an {@code int}.
    779      * <p>
    780      * This queries this date-time for the value of the specified field.
    781      * The returned value will always be within the valid range of values for the field.
    782      * If it is not possible to return the value, because the field is not supported
    783      * or for some other reason, an exception is thrown.
    784      * <p>
    785      * If the field is a {@link ChronoField} then the query is implemented here.
    786      * The {@link #isSupported(TemporalField) supported fields} will return valid
    787      * values based on this date-time, except {@code NANO_OF_DAY}, {@code MICRO_OF_DAY},
    788      * {@code EPOCH_DAY}, {@code PROLEPTIC_MONTH} and {@code INSTANT_SECONDS} which are too
    789      * large to fit in an {@code int} and throw a {@code DateTimeException}.
    790      * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
    791      * <p>
    792      * If the field is not a {@code ChronoField}, then the result of this method
    793      * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
    794      * passing {@code this} as the argument. Whether the value can be obtained,
    795      * and what the value represents, is determined by the field.
    796      *
    797      * @param field  the field to get, not null
    798      * @return the value for the field
    799      * @throws DateTimeException if a value for the field cannot be obtained or
    800      *         the value is outside the range of valid values for the field
    801      * @throws UnsupportedTemporalTypeException if the field is not supported or
    802      *         the range of values exceeds an {@code int}
    803      * @throws ArithmeticException if numeric overflow occurs
    804      */
    805     @Override  // override for Javadoc and performance
    806     public int get(TemporalField field) {
    807         if (field instanceof ChronoField) {
    808             switch ((ChronoField) field) {
    809                 case INSTANT_SECONDS:
    810                     throw new UnsupportedTemporalTypeException("Invalid field 'InstantSeconds' for get() method, use getLong() instead");
    811                 case OFFSET_SECONDS:
    812                     return getOffset().getTotalSeconds();
    813             }
    814             return dateTime.get(field);
    815         }
    816         return ChronoZonedDateTime.super.get(field);
    817     }
    818 
    819     /**
    820      * Gets the value of the specified field from this date-time as a {@code long}.
    821      * <p>
    822      * This queries this date-time for the value of the specified field.
    823      * If it is not possible to return the value, because the field is not supported
    824      * or for some other reason, an exception is thrown.
    825      * <p>
    826      * If the field is a {@link ChronoField} then the query is implemented here.
    827      * The {@link #isSupported(TemporalField) supported fields} will return valid
    828      * values based on this date-time.
    829      * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
    830      * <p>
    831      * If the field is not a {@code ChronoField}, then the result of this method
    832      * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
    833      * passing {@code this} as the argument. Whether the value can be obtained,
    834      * and what the value represents, is determined by the field.
    835      *
    836      * @param field  the field to get, not null
    837      * @return the value for the field
    838      * @throws DateTimeException if a value for the field cannot be obtained
    839      * @throws UnsupportedTemporalTypeException if the field is not supported
    840      * @throws ArithmeticException if numeric overflow occurs
    841      */
    842     @Override
    843     public long getLong(TemporalField field) {
    844         if (field instanceof ChronoField) {
    845             switch ((ChronoField) field) {
    846                 case INSTANT_SECONDS: return toEpochSecond();
    847                 case OFFSET_SECONDS: return getOffset().getTotalSeconds();
    848             }
    849             return dateTime.getLong(field);
    850         }
    851         return field.getFrom(this);
    852     }
    853 
    854     //-----------------------------------------------------------------------
    855     /**
    856      * Gets the zone offset, such as '+01:00'.
    857      * <p>
    858      * This is the offset of the local date-time from UTC/Greenwich.
    859      *
    860      * @return the zone offset, not null
    861      */
    862     @Override
    863     public ZoneOffset getOffset() {
    864         return offset;
    865     }
    866 
    867     /**
    868      * Returns a copy of this date-time changing the zone offset to the
    869      * earlier of the two valid offsets at a local time-line overlap.
    870      * <p>
    871      * This method only has any effect when the local time-line overlaps, such as
    872      * at an autumn daylight savings cutover. In this scenario, there are two
    873      * valid offsets for the local date-time. Calling this method will return
    874      * a zoned date-time with the earlier of the two selected.
    875      * <p>
    876      * If this method is called when it is not an overlap, {@code this}
    877      * is returned.
    878      * <p>
    879      * This instance is immutable and unaffected by this method call.
    880      *
    881      * @return a {@code ZonedDateTime} based on this date-time with the earlier offset, not null
    882      */
    883     @Override
    884     public ZonedDateTime withEarlierOffsetAtOverlap() {
    885         ZoneOffsetTransition trans = getZone().getRules().getTransition(dateTime);
    886         if (trans != null && trans.isOverlap()) {
    887             ZoneOffset earlierOffset = trans.getOffsetBefore();
    888             if (earlierOffset.equals(offset) == false) {
    889                 return new ZonedDateTime(dateTime, earlierOffset, zone);
    890             }
    891         }
    892         return this;
    893     }
    894 
    895     /**
    896      * Returns a copy of this date-time changing the zone offset to the
    897      * later of the two valid offsets at a local time-line overlap.
    898      * <p>
    899      * This method only has any effect when the local time-line overlaps, such as
    900      * at an autumn daylight savings cutover. In this scenario, there are two
    901      * valid offsets for the local date-time. Calling this method will return
    902      * a zoned date-time with the later of the two selected.
    903      * <p>
    904      * If this method is called when it is not an overlap, {@code this}
    905      * is returned.
    906      * <p>
    907      * This instance is immutable and unaffected by this method call.
    908      *
    909      * @return a {@code ZonedDateTime} based on this date-time with the later offset, not null
    910      */
    911     @Override
    912     public ZonedDateTime withLaterOffsetAtOverlap() {
    913         ZoneOffsetTransition trans = getZone().getRules().getTransition(toLocalDateTime());
    914         if (trans != null) {
    915             ZoneOffset laterOffset = trans.getOffsetAfter();
    916             if (laterOffset.equals(offset) == false) {
    917                 return new ZonedDateTime(dateTime, laterOffset, zone);
    918             }
    919         }
    920         return this;
    921     }
    922 
    923     //-----------------------------------------------------------------------
    924     /**
    925      * Gets the time-zone, such as 'Europe/Paris'.
    926      * <p>
    927      * This returns the zone ID. This identifies the time-zone {@link ZoneRules rules}
    928      * that determine when and how the offset from UTC/Greenwich changes.
    929      * <p>
    930      * The zone ID may be same as the {@linkplain #getOffset() offset}.
    931      * If this is true, then any future calculations, such as addition or subtraction,
    932      * have no complex edge cases due to time-zone rules.
    933      * See also {@link #withFixedOffsetZone()}.
    934      *
    935      * @return the time-zone, not null
    936      */
    937     @Override
    938     public ZoneId getZone() {
    939         return zone;
    940     }
    941 
    942     /**
    943      * Returns a copy of this date-time with a different time-zone,
    944      * retaining the local date-time if possible.
    945      * <p>
    946      * This method changes the time-zone and retains the local date-time.
    947      * The local date-time is only changed if it is invalid for the new zone,
    948      * determined using the same approach as
    949      * {@link #ofLocal(LocalDateTime, ZoneId, ZoneOffset)}.
    950      * <p>
    951      * To change the zone and adjust the local date-time,
    952      * use {@link #withZoneSameInstant(ZoneId)}.
    953      * <p>
    954      * This instance is immutable and unaffected by this method call.
    955      *
    956      * @param zone  the time-zone to change to, not null
    957      * @return a {@code ZonedDateTime} based on this date-time with the requested zone, not null
    958      */
    959     @Override
    960     public ZonedDateTime withZoneSameLocal(ZoneId zone) {
    961         Objects.requireNonNull(zone, "zone");
    962         return this.zone.equals(zone) ? this : ofLocal(dateTime, zone, offset);
    963     }
    964 
    965     /**
    966      * Returns a copy of this date-time with a different time-zone,
    967      * retaining the instant.
    968      * <p>
    969      * This method changes the time-zone and retains the instant.
    970      * This normally results in a change to the local date-time.
    971      * <p>
    972      * This method is based on retaining the same instant, thus gaps and overlaps
    973      * in the local time-line have no effect on the result.
    974      * <p>
    975      * To change the offset while keeping the local time,
    976      * use {@link #withZoneSameLocal(ZoneId)}.
    977      *
    978      * @param zone  the time-zone to change to, not null
    979      * @return a {@code ZonedDateTime} based on this date-time with the requested zone, not null
    980      * @throws DateTimeException if the result exceeds the supported date range
    981      */
    982     @Override
    983     public ZonedDateTime withZoneSameInstant(ZoneId zone) {
    984         Objects.requireNonNull(zone, "zone");
    985         return this.zone.equals(zone) ? this :
    986             create(dateTime.toEpochSecond(offset), dateTime.getNano(), zone);
    987     }
    988 
    989     /**
    990      * Returns a copy of this date-time with the zone ID set to the offset.
    991      * <p>
    992      * This returns a zoned date-time where the zone ID is the same as {@link #getOffset()}.
    993      * The local date-time, offset and instant of the result will be the same as in this date-time.
    994      * <p>
    995      * Setting the date-time to a fixed single offset means that any future
    996      * calculations, such as addition or subtraction, have no complex edge cases
    997      * due to time-zone rules.
    998      * This might also be useful when sending a zoned date-time across a network,
    999      * as most protocols, such as ISO-8601, only handle offsets,
   1000      * and not region-based zone IDs.
   1001      * <p>
   1002      * This is equivalent to {@code ZonedDateTime.of(zdt.toLocalDateTime(), zdt.getOffset())}.
   1003      *
   1004      * @return a {@code ZonedDateTime} with the zone ID set to the offset, not null
   1005      */
   1006     public ZonedDateTime withFixedOffsetZone() {
   1007         return this.zone.equals(offset) ? this : new ZonedDateTime(dateTime, offset, offset);
   1008     }
   1009 
   1010     //-----------------------------------------------------------------------
   1011     /**
   1012      * Gets the {@code LocalDateTime} part of this date-time.
   1013      * <p>
   1014      * This returns a {@code LocalDateTime} with the same year, month, day and time
   1015      * as this date-time.
   1016      *
   1017      * @return the local date-time part of this date-time, not null
   1018      */
   1019     @Override  // override for return type
   1020     public LocalDateTime toLocalDateTime() {
   1021         return dateTime;
   1022     }
   1023 
   1024     //-----------------------------------------------------------------------
   1025     /**
   1026      * Gets the {@code LocalDate} part of this date-time.
   1027      * <p>
   1028      * This returns a {@code LocalDate} with the same year, month and day
   1029      * as this date-time.
   1030      *
   1031      * @return the date part of this date-time, not null
   1032      */
   1033     @Override  // override for return type
   1034     public LocalDate toLocalDate() {
   1035         return dateTime.toLocalDate();
   1036     }
   1037 
   1038     /**
   1039      * Gets the year field.
   1040      * <p>
   1041      * This method returns the primitive {@code int} value for the year.
   1042      * <p>
   1043      * The year returned by this method is proleptic as per {@code get(YEAR)}.
   1044      * To obtain the year-of-era, use {@code get(YEAR_OF_ERA)}.
   1045      *
   1046      * @return the year, from MIN_YEAR to MAX_YEAR
   1047      */
   1048     public int getYear() {
   1049         return dateTime.getYear();
   1050     }
   1051 
   1052     /**
   1053      * Gets the month-of-year field from 1 to 12.
   1054      * <p>
   1055      * This method returns the month as an {@code int} from 1 to 12.
   1056      * Application code is frequently clearer if the enum {@link Month}
   1057      * is used by calling {@link #getMonth()}.
   1058      *
   1059      * @return the month-of-year, from 1 to 12
   1060      * @see #getMonth()
   1061      */
   1062     public int getMonthValue() {
   1063         return dateTime.getMonthValue();
   1064     }
   1065 
   1066     /**
   1067      * Gets the month-of-year field using the {@code Month} enum.
   1068      * <p>
   1069      * This method returns the enum {@link Month} for the month.
   1070      * This avoids confusion as to what {@code int} values mean.
   1071      * If you need access to the primitive {@code int} value then the enum
   1072      * provides the {@link Month#getValue() int value}.
   1073      *
   1074      * @return the month-of-year, not null
   1075      * @see #getMonthValue()
   1076      */
   1077     public Month getMonth() {
   1078         return dateTime.getMonth();
   1079     }
   1080 
   1081     /**
   1082      * Gets the day-of-month field.
   1083      * <p>
   1084      * This method returns the primitive {@code int} value for the day-of-month.
   1085      *
   1086      * @return the day-of-month, from 1 to 31
   1087      */
   1088     public int getDayOfMonth() {
   1089         return dateTime.getDayOfMonth();
   1090     }
   1091 
   1092     /**
   1093      * Gets the day-of-year field.
   1094      * <p>
   1095      * This method returns the primitive {@code int} value for the day-of-year.
   1096      *
   1097      * @return the day-of-year, from 1 to 365, or 366 in a leap year
   1098      */
   1099     public int getDayOfYear() {
   1100         return dateTime.getDayOfYear();
   1101     }
   1102 
   1103     /**
   1104      * Gets the day-of-week field, which is an enum {@code DayOfWeek}.
   1105      * <p>
   1106      * This method returns the enum {@link DayOfWeek} for the day-of-week.
   1107      * This avoids confusion as to what {@code int} values mean.
   1108      * If you need access to the primitive {@code int} value then the enum
   1109      * provides the {@link DayOfWeek#getValue() int value}.
   1110      * <p>
   1111      * Additional information can be obtained from the {@code DayOfWeek}.
   1112      * This includes textual names of the values.
   1113      *
   1114      * @return the day-of-week, not null
   1115      */
   1116     public DayOfWeek getDayOfWeek() {
   1117         return dateTime.getDayOfWeek();
   1118     }
   1119 
   1120     //-----------------------------------------------------------------------
   1121     /**
   1122      * Gets the {@code LocalTime} part of this date-time.
   1123      * <p>
   1124      * This returns a {@code LocalTime} with the same hour, minute, second and
   1125      * nanosecond as this date-time.
   1126      *
   1127      * @return the time part of this date-time, not null
   1128      */
   1129     @Override  // override for Javadoc and performance
   1130     public LocalTime toLocalTime() {
   1131         return dateTime.toLocalTime();
   1132     }
   1133 
   1134     /**
   1135      * Gets the hour-of-day field.
   1136      *
   1137      * @return the hour-of-day, from 0 to 23
   1138      */
   1139     public int getHour() {
   1140         return dateTime.getHour();
   1141     }
   1142 
   1143     /**
   1144      * Gets the minute-of-hour field.
   1145      *
   1146      * @return the minute-of-hour, from 0 to 59
   1147      */
   1148     public int getMinute() {
   1149         return dateTime.getMinute();
   1150     }
   1151 
   1152     /**
   1153      * Gets the second-of-minute field.
   1154      *
   1155      * @return the second-of-minute, from 0 to 59
   1156      */
   1157     public int getSecond() {
   1158         return dateTime.getSecond();
   1159     }
   1160 
   1161     /**
   1162      * Gets the nano-of-second field.
   1163      *
   1164      * @return the nano-of-second, from 0 to 999,999,999
   1165      */
   1166     public int getNano() {
   1167         return dateTime.getNano();
   1168     }
   1169 
   1170     //-----------------------------------------------------------------------
   1171     /**
   1172      * Returns an adjusted copy of this date-time.
   1173      * <p>
   1174      * This returns a {@code ZonedDateTime}, based on this one, with the date-time adjusted.
   1175      * The adjustment takes place using the specified adjuster strategy object.
   1176      * Read the documentation of the adjuster to understand what adjustment will be made.
   1177      * <p>
   1178      * A simple adjuster might simply set the one of the fields, such as the year field.
   1179      * A more complex adjuster might set the date to the last day of the month.
   1180      * A selection of common adjustments is provided in
   1181      * {@link java.time.temporal.TemporalAdjusters TemporalAdjusters}.
   1182      * These include finding the "last day of the month" and "next Wednesday".
   1183      * Key date-time classes also implement the {@code TemporalAdjuster} interface,
   1184      * such as {@link Month} and {@link java.time.MonthDay MonthDay}.
   1185      * The adjuster is responsible for handling special cases, such as the varying
   1186      * lengths of month and leap years.
   1187      * <p>
   1188      * For example this code returns a date on the last day of July:
   1189      * <pre>
   1190      *  import static java.time.Month.*;
   1191      *  import static java.time.temporal.TemporalAdjusters.*;
   1192      *
   1193      *  result = zonedDateTime.with(JULY).with(lastDayOfMonth());
   1194      * </pre>
   1195      * <p>
   1196      * The classes {@link LocalDate} and {@link LocalTime} implement {@code TemporalAdjuster},
   1197      * thus this method can be used to change the date, time or offset:
   1198      * <pre>
   1199      *  result = zonedDateTime.with(date);
   1200      *  result = zonedDateTime.with(time);
   1201      * </pre>
   1202      * <p>
   1203      * {@link ZoneOffset} also implements {@code TemporalAdjuster} however using it
   1204      * as an argument typically has no effect. The offset of a {@code ZonedDateTime} is
   1205      * controlled primarily by the time-zone. As such, changing the offset does not generally
   1206      * make sense, because there is only one valid offset for the local date-time and zone.
   1207      * If the zoned date-time is in a daylight savings overlap, then the offset is used
   1208      * to switch between the two valid offsets. In all other cases, the offset is ignored.
   1209      * <p>
   1210      * The result of this method is obtained by invoking the
   1211      * {@link TemporalAdjuster#adjustInto(Temporal)} method on the
   1212      * specified adjuster passing {@code this} as the argument.
   1213      * <p>
   1214      * This instance is immutable and unaffected by this method call.
   1215      *
   1216      * @param adjuster the adjuster to use, not null
   1217      * @return a {@code ZonedDateTime} based on {@code this} with the adjustment made, not null
   1218      * @throws DateTimeException if the adjustment cannot be made
   1219      * @throws ArithmeticException if numeric overflow occurs
   1220      */
   1221     @Override
   1222     public ZonedDateTime with(TemporalAdjuster adjuster) {
   1223         // optimizations
   1224         if (adjuster instanceof LocalDate) {
   1225             return resolveLocal(LocalDateTime.of((LocalDate) adjuster, dateTime.toLocalTime()));
   1226         } else if (adjuster instanceof LocalTime) {
   1227             return resolveLocal(LocalDateTime.of(dateTime.toLocalDate(), (LocalTime) adjuster));
   1228         } else if (adjuster instanceof LocalDateTime) {
   1229             return resolveLocal((LocalDateTime) adjuster);
   1230         } else if (adjuster instanceof OffsetDateTime) {
   1231             OffsetDateTime odt = (OffsetDateTime) adjuster;
   1232             return ofLocal(odt.toLocalDateTime(), zone, odt.getOffset());
   1233         } else if (adjuster instanceof Instant) {
   1234             Instant instant = (Instant) adjuster;
   1235             return create(instant.getEpochSecond(), instant.getNano(), zone);
   1236         } else if (adjuster instanceof ZoneOffset) {
   1237             return resolveOffset((ZoneOffset) adjuster);
   1238         }
   1239         return (ZonedDateTime) adjuster.adjustInto(this);
   1240     }
   1241 
   1242     /**
   1243      * Returns a copy of this date-time with the specified field set to a new value.
   1244      * <p>
   1245      * This returns a {@code ZonedDateTime}, based on this one, with the value
   1246      * for the specified field changed.
   1247      * This can be used to change any supported field, such as the year, month or day-of-month.
   1248      * If it is not possible to set the value, because the field is not supported or for
   1249      * some other reason, an exception is thrown.
   1250      * <p>
   1251      * In some cases, changing the specified field can cause the resulting date-time to become invalid,
   1252      * such as changing the month from 31st January to February would make the day-of-month invalid.
   1253      * In cases like this, the field is responsible for resolving the date. Typically it will choose
   1254      * the previous valid date, which would be the last valid day of February in this example.
   1255      * <p>
   1256      * If the field is a {@link ChronoField} then the adjustment is implemented here.
   1257      * <p>
   1258      * The {@code INSTANT_SECONDS} field will return a date-time with the specified instant.
   1259      * The zone and nano-of-second are unchanged.
   1260      * The result will have an offset derived from the new instant and original zone.
   1261      * If the new instant value is outside the valid range then a {@code DateTimeException} will be thrown.
   1262      * <p>
   1263      * The {@code OFFSET_SECONDS} field will typically be ignored.
   1264      * The offset of a {@code ZonedDateTime} is controlled primarily by the time-zone.
   1265      * As such, changing the offset does not generally make sense, because there is only
   1266      * one valid offset for the local date-time and zone.
   1267      * If the zoned date-time is in a daylight savings overlap, then the offset is used
   1268      * to switch between the two valid offsets. In all other cases, the offset is ignored.
   1269      * If the new offset value is outside the valid range then a {@code DateTimeException} will be thrown.
   1270      * <p>
   1271      * The other {@link #isSupported(TemporalField) supported fields} will behave as per
   1272      * the matching method on {@link LocalDateTime#with(TemporalField, long) LocalDateTime}.
   1273      * The zone is not part of the calculation and will be unchanged.
   1274      * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
   1275      * then the offset will be retained if possible, otherwise the earlier offset will be used.
   1276      * If in a gap, the local date-time will be adjusted forward by the length of the gap.
   1277      * <p>
   1278      * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
   1279      * <p>
   1280      * If the field is not a {@code ChronoField}, then the result of this method
   1281      * is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)}
   1282      * passing {@code this} as the argument. In this case, the field determines
   1283      * whether and how to adjust the instant.
   1284      * <p>
   1285      * This instance is immutable and unaffected by this method call.
   1286      *
   1287      * @param field  the field to set in the result, not null
   1288      * @param newValue  the new value of the field in the result
   1289      * @return a {@code ZonedDateTime} based on {@code this} with the specified field set, not null
   1290      * @throws DateTimeException if the field cannot be set
   1291      * @throws UnsupportedTemporalTypeException if the field is not supported
   1292      * @throws ArithmeticException if numeric overflow occurs
   1293      */
   1294     @Override
   1295     public ZonedDateTime with(TemporalField field, long newValue) {
   1296         if (field instanceof ChronoField) {
   1297             ChronoField f = (ChronoField) field;
   1298             switch (f) {
   1299                 case INSTANT_SECONDS:
   1300                     return create(newValue, getNano(), zone);
   1301                 case OFFSET_SECONDS:
   1302                     ZoneOffset offset = ZoneOffset.ofTotalSeconds(f.checkValidIntValue(newValue));
   1303                     return resolveOffset(offset);
   1304             }
   1305             return resolveLocal(dateTime.with(field, newValue));
   1306         }
   1307         return field.adjustInto(this, newValue);
   1308     }
   1309 
   1310     //-----------------------------------------------------------------------
   1311     /**
   1312      * Returns a copy of this {@code ZonedDateTime} with the year altered.
   1313      * <p>
   1314      * This operates on the local time-line,
   1315      * {@link LocalDateTime#withYear(int) changing the year} of the local date-time.
   1316      * This is then converted back to a {@code ZonedDateTime}, using the zone ID
   1317      * to obtain the offset.
   1318      * <p>
   1319      * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
   1320      * then the offset will be retained if possible, otherwise the earlier offset will be used.
   1321      * If in a gap, the local date-time will be adjusted forward by the length of the gap.
   1322      * <p>
   1323      * This instance is immutable and unaffected by this method call.
   1324      *
   1325      * @param year  the year to set in the result, from MIN_YEAR to MAX_YEAR
   1326      * @return a {@code ZonedDateTime} based on this date-time with the requested year, not null
   1327      * @throws DateTimeException if the year value is invalid
   1328      */
   1329     public ZonedDateTime withYear(int year) {
   1330         return resolveLocal(dateTime.withYear(year));
   1331     }
   1332 
   1333     /**
   1334      * Returns a copy of this {@code ZonedDateTime} with the month-of-year altered.
   1335      * <p>
   1336      * This operates on the local time-line,
   1337      * {@link LocalDateTime#withMonth(int) changing the month} of the local date-time.
   1338      * This is then converted back to a {@code ZonedDateTime}, using the zone ID
   1339      * to obtain the offset.
   1340      * <p>
   1341      * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
   1342      * then the offset will be retained if possible, otherwise the earlier offset will be used.
   1343      * If in a gap, the local date-time will be adjusted forward by the length of the gap.
   1344      * <p>
   1345      * This instance is immutable and unaffected by this method call.
   1346      *
   1347      * @param month  the month-of-year to set in the result, from 1 (January) to 12 (December)
   1348      * @return a {@code ZonedDateTime} based on this date-time with the requested month, not null
   1349      * @throws DateTimeException if the month-of-year value is invalid
   1350      */
   1351     public ZonedDateTime withMonth(int month) {
   1352         return resolveLocal(dateTime.withMonth(month));
   1353     }
   1354 
   1355     /**
   1356      * Returns a copy of this {@code ZonedDateTime} with the day-of-month altered.
   1357      * <p>
   1358      * This operates on the local time-line,
   1359      * {@link LocalDateTime#withDayOfMonth(int) changing the day-of-month} of the local date-time.
   1360      * This is then converted back to a {@code ZonedDateTime}, using the zone ID
   1361      * to obtain the offset.
   1362      * <p>
   1363      * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
   1364      * then the offset will be retained if possible, otherwise the earlier offset will be used.
   1365      * If in a gap, the local date-time will be adjusted forward by the length of the gap.
   1366      * <p>
   1367      * This instance is immutable and unaffected by this method call.
   1368      *
   1369      * @param dayOfMonth  the day-of-month to set in the result, from 1 to 28-31
   1370      * @return a {@code ZonedDateTime} based on this date-time with the requested day, not null
   1371      * @throws DateTimeException if the day-of-month value is invalid,
   1372      *  or if the day-of-month is invalid for the month-year
   1373      */
   1374     public ZonedDateTime withDayOfMonth(int dayOfMonth) {
   1375         return resolveLocal(dateTime.withDayOfMonth(dayOfMonth));
   1376     }
   1377 
   1378     /**
   1379      * Returns a copy of this {@code ZonedDateTime} with the day-of-year altered.
   1380      * <p>
   1381      * This operates on the local time-line,
   1382      * {@link LocalDateTime#withDayOfYear(int) changing the day-of-year} of the local date-time.
   1383      * This is then converted back to a {@code ZonedDateTime}, using the zone ID
   1384      * to obtain the offset.
   1385      * <p>
   1386      * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
   1387      * then the offset will be retained if possible, otherwise the earlier offset will be used.
   1388      * If in a gap, the local date-time will be adjusted forward by the length of the gap.
   1389      * <p>
   1390      * This instance is immutable and unaffected by this method call.
   1391      *
   1392      * @param dayOfYear  the day-of-year to set in the result, from 1 to 365-366
   1393      * @return a {@code ZonedDateTime} based on this date with the requested day, not null
   1394      * @throws DateTimeException if the day-of-year value is invalid,
   1395      *  or if the day-of-year is invalid for the year
   1396      */
   1397     public ZonedDateTime withDayOfYear(int dayOfYear) {
   1398         return resolveLocal(dateTime.withDayOfYear(dayOfYear));
   1399     }
   1400 
   1401     //-----------------------------------------------------------------------
   1402     /**
   1403      * Returns a copy of this {@code ZonedDateTime} with the hour-of-day altered.
   1404      * <p>
   1405      * This operates on the local time-line,
   1406      * {@linkplain LocalDateTime#withHour(int) changing the time} of the local date-time.
   1407      * This is then converted back to a {@code ZonedDateTime}, using the zone ID
   1408      * to obtain the offset.
   1409      * <p>
   1410      * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
   1411      * then the offset will be retained if possible, otherwise the earlier offset will be used.
   1412      * If in a gap, the local date-time will be adjusted forward by the length of the gap.
   1413      * <p>
   1414      * This instance is immutable and unaffected by this method call.
   1415      *
   1416      * @param hour  the hour-of-day to set in the result, from 0 to 23
   1417      * @return a {@code ZonedDateTime} based on this date-time with the requested hour, not null
   1418      * @throws DateTimeException if the hour value is invalid
   1419      */
   1420     public ZonedDateTime withHour(int hour) {
   1421         return resolveLocal(dateTime.withHour(hour));
   1422     }
   1423 
   1424     /**
   1425      * Returns a copy of this {@code ZonedDateTime} with the minute-of-hour altered.
   1426      * <p>
   1427      * This operates on the local time-line,
   1428      * {@linkplain LocalDateTime#withMinute(int) changing the time} of the local date-time.
   1429      * This is then converted back to a {@code ZonedDateTime}, using the zone ID
   1430      * to obtain the offset.
   1431      * <p>
   1432      * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
   1433      * then the offset will be retained if possible, otherwise the earlier offset will be used.
   1434      * If in a gap, the local date-time will be adjusted forward by the length of the gap.
   1435      * <p>
   1436      * This instance is immutable and unaffected by this method call.
   1437      *
   1438      * @param minute  the minute-of-hour to set in the result, from 0 to 59
   1439      * @return a {@code ZonedDateTime} based on this date-time with the requested minute, not null
   1440      * @throws DateTimeException if the minute value is invalid
   1441      */
   1442     public ZonedDateTime withMinute(int minute) {
   1443         return resolveLocal(dateTime.withMinute(minute));
   1444     }
   1445 
   1446     /**
   1447      * Returns a copy of this {@code ZonedDateTime} with the second-of-minute altered.
   1448      * <p>
   1449      * This operates on the local time-line,
   1450      * {@linkplain LocalDateTime#withSecond(int) changing the time} of the local date-time.
   1451      * This is then converted back to a {@code ZonedDateTime}, using the zone ID
   1452      * to obtain the offset.
   1453      * <p>
   1454      * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
   1455      * then the offset will be retained if possible, otherwise the earlier offset will be used.
   1456      * If in a gap, the local date-time will be adjusted forward by the length of the gap.
   1457      * <p>
   1458      * This instance is immutable and unaffected by this method call.
   1459      *
   1460      * @param second  the second-of-minute to set in the result, from 0 to 59
   1461      * @return a {@code ZonedDateTime} based on this date-time with the requested second, not null
   1462      * @throws DateTimeException if the second value is invalid
   1463      */
   1464     public ZonedDateTime withSecond(int second) {
   1465         return resolveLocal(dateTime.withSecond(second));
   1466     }
   1467 
   1468     /**
   1469      * Returns a copy of this {@code ZonedDateTime} with the nano-of-second altered.
   1470      * <p>
   1471      * This operates on the local time-line,
   1472      * {@linkplain LocalDateTime#withNano(int) changing the time} of the local date-time.
   1473      * This is then converted back to a {@code ZonedDateTime}, using the zone ID
   1474      * to obtain the offset.
   1475      * <p>
   1476      * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
   1477      * then the offset will be retained if possible, otherwise the earlier offset will be used.
   1478      * If in a gap, the local date-time will be adjusted forward by the length of the gap.
   1479      * <p>
   1480      * This instance is immutable and unaffected by this method call.
   1481      *
   1482      * @param nanoOfSecond  the nano-of-second to set in the result, from 0 to 999,999,999
   1483      * @return a {@code ZonedDateTime} based on this date-time with the requested nanosecond, not null
   1484      * @throws DateTimeException if the nano value is invalid
   1485      */
   1486     public ZonedDateTime withNano(int nanoOfSecond) {
   1487         return resolveLocal(dateTime.withNano(nanoOfSecond));
   1488     }
   1489 
   1490     //-----------------------------------------------------------------------
   1491     /**
   1492      * Returns a copy of this {@code ZonedDateTime} with the time truncated.
   1493      * <p>
   1494      * Truncation returns a copy of the original date-time with fields
   1495      * smaller than the specified unit set to zero.
   1496      * For example, truncating with the {@link ChronoUnit#MINUTES minutes} unit
   1497      * will set the second-of-minute and nano-of-second field to zero.
   1498      * <p>
   1499      * The unit must have a {@linkplain TemporalUnit#getDuration() duration}
   1500      * that divides into the length of a standard day without remainder.
   1501      * This includes all supplied time units on {@link ChronoUnit} and
   1502      * {@link ChronoUnit#DAYS DAYS}. Other units throw an exception.
   1503      * <p>
   1504      * This operates on the local time-line,
   1505      * {@link LocalDateTime#truncatedTo(TemporalUnit) truncating}
   1506      * the underlying local date-time. This is then converted back to a
   1507      * {@code ZonedDateTime}, using the zone ID to obtain the offset.
   1508      * <p>
   1509      * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
   1510      * then the offset will be retained if possible, otherwise the earlier offset will be used.
   1511      * If in a gap, the local date-time will be adjusted forward by the length of the gap.
   1512      * <p>
   1513      * This instance is immutable and unaffected by this method call.
   1514      *
   1515      * @param unit  the unit to truncate to, not null
   1516      * @return a {@code ZonedDateTime} based on this date-time with the time truncated, not null
   1517      * @throws DateTimeException if unable to truncate
   1518      * @throws UnsupportedTemporalTypeException if the unit is not supported
   1519      */
   1520     public ZonedDateTime truncatedTo(TemporalUnit unit) {
   1521         return resolveLocal(dateTime.truncatedTo(unit));
   1522     }
   1523 
   1524     //-----------------------------------------------------------------------
   1525     /**
   1526      * Returns a copy of this date-time with the specified amount added.
   1527      * <p>
   1528      * This returns a {@code ZonedDateTime}, based on this one, with the specified amount added.
   1529      * The amount is typically {@link Period} or {@link Duration} but may be
   1530      * any other type implementing the {@link TemporalAmount} interface.
   1531      * <p>
   1532      * The calculation is delegated to the amount object by calling
   1533      * {@link TemporalAmount#addTo(Temporal)}. The amount implementation is free
   1534      * to implement the addition in any way it wishes, however it typically
   1535      * calls back to {@link #plus(long, TemporalUnit)}. Consult the documentation
   1536      * of the amount implementation to determine if it can be successfully added.
   1537      * <p>
   1538      * This instance is immutable and unaffected by this method call.
   1539      *
   1540      * @param amountToAdd  the amount to add, not null
   1541      * @return a {@code ZonedDateTime} based on this date-time with the addition made, not null
   1542      * @throws DateTimeException if the addition cannot be made
   1543      * @throws ArithmeticException if numeric overflow occurs
   1544      */
   1545     @Override
   1546     public ZonedDateTime plus(TemporalAmount amountToAdd) {
   1547         if (amountToAdd instanceof Period) {
   1548             Period periodToAdd = (Period) amountToAdd;
   1549             return resolveLocal(dateTime.plus(periodToAdd));
   1550         }
   1551         Objects.requireNonNull(amountToAdd, "amountToAdd");
   1552         return (ZonedDateTime) amountToAdd.addTo(this);
   1553     }
   1554 
   1555     /**
   1556      * Returns a copy of this date-time with the specified amount added.
   1557      * <p>
   1558      * This returns a {@code ZonedDateTime}, based on this one, with the amount
   1559      * in terms of the unit added. If it is not possible to add the amount, because the
   1560      * unit is not supported or for some other reason, an exception is thrown.
   1561      * <p>
   1562      * If the field is a {@link ChronoUnit} then the addition is implemented here.
   1563      * The zone is not part of the calculation and will be unchanged in the result.
   1564      * The calculation for date and time units differ.
   1565      * <p>
   1566      * Date units operate on the local time-line.
   1567      * The period is first added to the local date-time, then converted back
   1568      * to a zoned date-time using the zone ID.
   1569      * The conversion uses {@link #ofLocal(LocalDateTime, ZoneId, ZoneOffset)}
   1570      * with the offset before the addition.
   1571      * <p>
   1572      * Time units operate on the instant time-line.
   1573      * The period is first added to the local date-time, then converted back to
   1574      * a zoned date-time using the zone ID.
   1575      * The conversion uses {@link #ofInstant(LocalDateTime, ZoneOffset, ZoneId)}
   1576      * with the offset before the addition.
   1577      * <p>
   1578      * If the field is not a {@code ChronoUnit}, then the result of this method
   1579      * is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)}
   1580      * passing {@code this} as the argument. In this case, the unit determines
   1581      * whether and how to perform the addition.
   1582      * <p>
   1583      * This instance is immutable and unaffected by this method call.
   1584      *
   1585      * @param amountToAdd  the amount of the unit to add to the result, may be negative
   1586      * @param unit  the unit of the amount to add, not null
   1587      * @return a {@code ZonedDateTime} based on this date-time with the specified amount added, not null
   1588      * @throws DateTimeException if the addition cannot be made
   1589      * @throws UnsupportedTemporalTypeException if the unit is not supported
   1590      * @throws ArithmeticException if numeric overflow occurs
   1591      */
   1592     @Override
   1593     public ZonedDateTime plus(long amountToAdd, TemporalUnit unit) {
   1594         if (unit instanceof ChronoUnit) {
   1595             if (unit.isDateBased()) {
   1596                 return resolveLocal(dateTime.plus(amountToAdd, unit));
   1597             } else {
   1598                 return resolveInstant(dateTime.plus(amountToAdd, unit));
   1599             }
   1600         }
   1601         return unit.addTo(this, amountToAdd);
   1602     }
   1603 
   1604     //-----------------------------------------------------------------------
   1605     /**
   1606      * Returns a copy of this {@code ZonedDateTime} with the specified number of years added.
   1607      * <p>
   1608      * This operates on the local time-line,
   1609      * {@link LocalDateTime#plusYears(long) adding years} to the local date-time.
   1610      * This is then converted back to a {@code ZonedDateTime}, using the zone ID
   1611      * to obtain the offset.
   1612      * <p>
   1613      * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
   1614      * then the offset will be retained if possible, otherwise the earlier offset will be used.
   1615      * If in a gap, the local date-time will be adjusted forward by the length of the gap.
   1616      * <p>
   1617      * This instance is immutable and unaffected by this method call.
   1618      *
   1619      * @param years  the years to add, may be negative
   1620      * @return a {@code ZonedDateTime} based on this date-time with the years added, not null
   1621      * @throws DateTimeException if the result exceeds the supported date range
   1622      */
   1623     public ZonedDateTime plusYears(long years) {
   1624         return resolveLocal(dateTime.plusYears(years));
   1625     }
   1626 
   1627     /**
   1628      * Returns a copy of this {@code ZonedDateTime} with the specified number of months added.
   1629      * <p>
   1630      * This operates on the local time-line,
   1631      * {@link LocalDateTime#plusMonths(long) adding months} to the local date-time.
   1632      * This is then converted back to a {@code ZonedDateTime}, using the zone ID
   1633      * to obtain the offset.
   1634      * <p>
   1635      * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
   1636      * then the offset will be retained if possible, otherwise the earlier offset will be used.
   1637      * If in a gap, the local date-time will be adjusted forward by the length of the gap.
   1638      * <p>
   1639      * This instance is immutable and unaffected by this method call.
   1640      *
   1641      * @param months  the months to add, may be negative
   1642      * @return a {@code ZonedDateTime} based on this date-time with the months added, not null
   1643      * @throws DateTimeException if the result exceeds the supported date range
   1644      */
   1645     public ZonedDateTime plusMonths(long months) {
   1646         return resolveLocal(dateTime.plusMonths(months));
   1647     }
   1648 
   1649     /**
   1650      * Returns a copy of this {@code ZonedDateTime} with the specified number of weeks added.
   1651      * <p>
   1652      * This operates on the local time-line,
   1653      * {@link LocalDateTime#plusWeeks(long) adding weeks} to the local date-time.
   1654      * This is then converted back to a {@code ZonedDateTime}, using the zone ID
   1655      * to obtain the offset.
   1656      * <p>
   1657      * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
   1658      * then the offset will be retained if possible, otherwise the earlier offset will be used.
   1659      * If in a gap, the local date-time will be adjusted forward by the length of the gap.
   1660      * <p>
   1661      * This instance is immutable and unaffected by this method call.
   1662      *
   1663      * @param weeks  the weeks to add, may be negative
   1664      * @return a {@code ZonedDateTime} based on this date-time with the weeks added, not null
   1665      * @throws DateTimeException if the result exceeds the supported date range
   1666      */
   1667     public ZonedDateTime plusWeeks(long weeks) {
   1668         return resolveLocal(dateTime.plusWeeks(weeks));
   1669     }
   1670 
   1671     /**
   1672      * Returns a copy of this {@code ZonedDateTime} with the specified number of days added.
   1673      * <p>
   1674      * This operates on the local time-line,
   1675      * {@link LocalDateTime#plusDays(long) adding days} to the local date-time.
   1676      * This is then converted back to a {@code ZonedDateTime}, using the zone ID
   1677      * to obtain the offset.
   1678      * <p>
   1679      * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
   1680      * then the offset will be retained if possible, otherwise the earlier offset will be used.
   1681      * If in a gap, the local date-time will be adjusted forward by the length of the gap.
   1682      * <p>
   1683      * This instance is immutable and unaffected by this method call.
   1684      *
   1685      * @param days  the days to add, may be negative
   1686      * @return a {@code ZonedDateTime} based on this date-time with the days added, not null
   1687      * @throws DateTimeException if the result exceeds the supported date range
   1688      */
   1689     public ZonedDateTime plusDays(long days) {
   1690         return resolveLocal(dateTime.plusDays(days));
   1691     }
   1692 
   1693     //-----------------------------------------------------------------------
   1694     /**
   1695      * Returns a copy of this {@code ZonedDateTime} with the specified number of hours added.
   1696      * <p>
   1697      * This operates on the instant time-line, such that adding one hour will
   1698      * always be a duration of one hour later.
   1699      * This may cause the local date-time to change by an amount other than one hour.
   1700      * Note that this is a different approach to that used by days, months and years,
   1701      * thus adding one day is not the same as adding 24 hours.
   1702      * <p>
   1703      * For example, consider a time-zone where the spring DST cutover means that the
   1704      * local times 01:00 to 01:59 occur twice changing from offset +02:00 to +01:00.
   1705      * <ul>
   1706      * <li>Adding one hour to 00:30+02:00 will result in 01:30+02:00
   1707      * <li>Adding one hour to 01:30+02:00 will result in 01:30+01:00
   1708      * <li>Adding one hour to 01:30+01:00 will result in 02:30+01:00
   1709      * <li>Adding three hours to 00:30+02:00 will result in 02:30+01:00
   1710      * </ul>
   1711      * <p>
   1712      * This instance is immutable and unaffected by this method call.
   1713      *
   1714      * @param hours  the hours to add, may be negative
   1715      * @return a {@code ZonedDateTime} based on this date-time with the hours added, not null
   1716      * @throws DateTimeException if the result exceeds the supported date range
   1717      */
   1718     public ZonedDateTime plusHours(long hours) {
   1719         return resolveInstant(dateTime.plusHours(hours));
   1720     }
   1721 
   1722     /**
   1723      * Returns a copy of this {@code ZonedDateTime} with the specified number of minutes added.
   1724      * <p>
   1725      * This operates on the instant time-line, such that adding one minute will
   1726      * always be a duration of one minute later.
   1727      * This may cause the local date-time to change by an amount other than one minute.
   1728      * Note that this is a different approach to that used by days, months and years.
   1729      * <p>
   1730      * This instance is immutable and unaffected by this method call.
   1731      *
   1732      * @param minutes  the minutes to add, may be negative
   1733      * @return a {@code ZonedDateTime} based on this date-time with the minutes added, not null
   1734      * @throws DateTimeException if the result exceeds the supported date range
   1735      */
   1736     public ZonedDateTime plusMinutes(long minutes) {
   1737         return resolveInstant(dateTime.plusMinutes(minutes));
   1738     }
   1739 
   1740     /**
   1741      * Returns a copy of this {@code ZonedDateTime} with the specified number of seconds added.
   1742      * <p>
   1743      * This operates on the instant time-line, such that adding one second will
   1744      * always be a duration of one second later.
   1745      * This may cause the local date-time to change by an amount other than one second.
   1746      * Note that this is a different approach to that used by days, months and years.
   1747      * <p>
   1748      * This instance is immutable and unaffected by this method call.
   1749      *
   1750      * @param seconds  the seconds to add, may be negative
   1751      * @return a {@code ZonedDateTime} based on this date-time with the seconds added, not null
   1752      * @throws DateTimeException if the result exceeds the supported date range
   1753      */
   1754     public ZonedDateTime plusSeconds(long seconds) {
   1755         return resolveInstant(dateTime.plusSeconds(seconds));
   1756     }
   1757 
   1758     /**
   1759      * Returns a copy of this {@code ZonedDateTime} with the specified number of nanoseconds added.
   1760      * <p>
   1761      * This operates on the instant time-line, such that adding one nano will
   1762      * always be a duration of one nano later.
   1763      * This may cause the local date-time to change by an amount other than one nano.
   1764      * Note that this is a different approach to that used by days, months and years.
   1765      * <p>
   1766      * This instance is immutable and unaffected by this method call.
   1767      *
   1768      * @param nanos  the nanos to add, may be negative
   1769      * @return a {@code ZonedDateTime} based on this date-time with the nanoseconds added, not null
   1770      * @throws DateTimeException if the result exceeds the supported date range
   1771      */
   1772     public ZonedDateTime plusNanos(long nanos) {
   1773         return resolveInstant(dateTime.plusNanos(nanos));
   1774     }
   1775 
   1776     //-----------------------------------------------------------------------
   1777     /**
   1778      * Returns a copy of this date-time with the specified amount subtracted.
   1779      * <p>
   1780      * This returns a {@code ZonedDateTime}, based on this one, with the specified amount subtracted.
   1781      * The amount is typically {@link Period} or {@link Duration} but may be
   1782      * any other type implementing the {@link TemporalAmount} interface.
   1783      * <p>
   1784      * The calculation is delegated to the amount object by calling
   1785      * {@link TemporalAmount#subtractFrom(Temporal)}. The amount implementation is free
   1786      * to implement the subtraction in any way it wishes, however it typically
   1787      * calls back to {@link #minus(long, TemporalUnit)}. Consult the documentation
   1788      * of the amount implementation to determine if it can be successfully subtracted.
   1789      * <p>
   1790      * This instance is immutable and unaffected by this method call.
   1791      *
   1792      * @param amountToSubtract  the amount to subtract, not null
   1793      * @return a {@code ZonedDateTime} based on this date-time with the subtraction made, not null
   1794      * @throws DateTimeException if the subtraction cannot be made
   1795      * @throws ArithmeticException if numeric overflow occurs
   1796      */
   1797     @Override
   1798     public ZonedDateTime minus(TemporalAmount amountToSubtract) {
   1799         if (amountToSubtract instanceof Period) {
   1800             Period periodToSubtract = (Period) amountToSubtract;
   1801             return resolveLocal(dateTime.minus(periodToSubtract));
   1802         }
   1803         Objects.requireNonNull(amountToSubtract, "amountToSubtract");
   1804         return (ZonedDateTime) amountToSubtract.subtractFrom(this);
   1805     }
   1806 
   1807     /**
   1808      * Returns a copy of this date-time with the specified amount subtracted.
   1809      * <p>
   1810      * This returns a {@code ZonedDateTime}, based on this one, with the amount
   1811      * in terms of the unit subtracted. If it is not possible to subtract the amount,
   1812      * because the unit is not supported or for some other reason, an exception is thrown.
   1813      * <p>
   1814      * The calculation for date and time units differ.
   1815      * <p>
   1816      * Date units operate on the local time-line.
   1817      * The period is first subtracted from the local date-time, then converted back
   1818      * to a zoned date-time using the zone ID.
   1819      * The conversion uses {@link #ofLocal(LocalDateTime, ZoneId, ZoneOffset)}
   1820      * with the offset before the subtraction.
   1821      * <p>
   1822      * Time units operate on the instant time-line.
   1823      * The period is first subtracted from the local date-time, then converted back to
   1824      * a zoned date-time using the zone ID.
   1825      * The conversion uses {@link #ofInstant(LocalDateTime, ZoneOffset, ZoneId)}
   1826      * with the offset before the subtraction.
   1827      * <p>
   1828      * This method is equivalent to {@link #plus(long, TemporalUnit)} with the amount negated.
   1829      * See that method for a full description of how addition, and thus subtraction, works.
   1830      * <p>
   1831      * This instance is immutable and unaffected by this method call.
   1832      *
   1833      * @param amountToSubtract  the amount of the unit to subtract from the result, may be negative
   1834      * @param unit  the unit of the amount to subtract, not null
   1835      * @return a {@code ZonedDateTime} based on this date-time with the specified amount subtracted, not null
   1836      * @throws DateTimeException if the subtraction cannot be made
   1837      * @throws UnsupportedTemporalTypeException if the unit is not supported
   1838      * @throws ArithmeticException if numeric overflow occurs
   1839      */
   1840     @Override
   1841     public ZonedDateTime minus(long amountToSubtract, TemporalUnit unit) {
   1842         return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit));
   1843     }
   1844 
   1845     //-----------------------------------------------------------------------
   1846     /**
   1847      * Returns a copy of this {@code ZonedDateTime} with the specified number of years subtracted.
   1848      * <p>
   1849      * This operates on the local time-line,
   1850      * {@link LocalDateTime#minusYears(long) subtracting years} to the local date-time.
   1851      * This is then converted back to a {@code ZonedDateTime}, using the zone ID
   1852      * to obtain the offset.
   1853      * <p>
   1854      * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
   1855      * then the offset will be retained if possible, otherwise the earlier offset will be used.
   1856      * If in a gap, the local date-time will be adjusted forward by the length of the gap.
   1857      * <p>
   1858      * This instance is immutable and unaffected by this method call.
   1859      *
   1860      * @param years  the years to subtract, may be negative
   1861      * @return a {@code ZonedDateTime} based on this date-time with the years subtracted, not null
   1862      * @throws DateTimeException if the result exceeds the supported date range
   1863      */
   1864     public ZonedDateTime minusYears(long years) {
   1865         return (years == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-years));
   1866     }
   1867 
   1868     /**
   1869      * Returns a copy of this {@code ZonedDateTime} with the specified number of months subtracted.
   1870      * <p>
   1871      * This operates on the local time-line,
   1872      * {@link LocalDateTime#minusMonths(long) subtracting months} to the local date-time.
   1873      * This is then converted back to a {@code ZonedDateTime}, using the zone ID
   1874      * to obtain the offset.
   1875      * <p>
   1876      * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
   1877      * then the offset will be retained if possible, otherwise the earlier offset will be used.
   1878      * If in a gap, the local date-time will be adjusted forward by the length of the gap.
   1879      * <p>
   1880      * This instance is immutable and unaffected by this method call.
   1881      *
   1882      * @param months  the months to subtract, may be negative
   1883      * @return a {@code ZonedDateTime} based on this date-time with the months subtracted, not null
   1884      * @throws DateTimeException if the result exceeds the supported date range
   1885      */
   1886     public ZonedDateTime minusMonths(long months) {
   1887         return (months == Long.MIN_VALUE ? plusMonths(Long.MAX_VALUE).plusMonths(1) : plusMonths(-months));
   1888     }
   1889 
   1890     /**
   1891      * Returns a copy of this {@code ZonedDateTime} with the specified number of weeks subtracted.
   1892      * <p>
   1893      * This operates on the local time-line,
   1894      * {@link LocalDateTime#minusWeeks(long) subtracting weeks} to the local date-time.
   1895      * This is then converted back to a {@code ZonedDateTime}, using the zone ID
   1896      * to obtain the offset.
   1897      * <p>
   1898      * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
   1899      * then the offset will be retained if possible, otherwise the earlier offset will be used.
   1900      * If in a gap, the local date-time will be adjusted forward by the length of the gap.
   1901      * <p>
   1902      * This instance is immutable and unaffected by this method call.
   1903      *
   1904      * @param weeks  the weeks to subtract, may be negative
   1905      * @return a {@code ZonedDateTime} based on this date-time with the weeks subtracted, not null
   1906      * @throws DateTimeException if the result exceeds the supported date range
   1907      */
   1908     public ZonedDateTime minusWeeks(long weeks) {
   1909         return (weeks == Long.MIN_VALUE ? plusWeeks(Long.MAX_VALUE).plusWeeks(1) : plusWeeks(-weeks));
   1910     }
   1911 
   1912     /**
   1913      * Returns a copy of this {@code ZonedDateTime} with the specified number of days subtracted.
   1914      * <p>
   1915      * This operates on the local time-line,
   1916      * {@link LocalDateTime#minusDays(long) subtracting days} to the local date-time.
   1917      * This is then converted back to a {@code ZonedDateTime}, using the zone ID
   1918      * to obtain the offset.
   1919      * <p>
   1920      * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
   1921      * then the offset will be retained if possible, otherwise the earlier offset will be used.
   1922      * If in a gap, the local date-time will be adjusted forward by the length of the gap.
   1923      * <p>
   1924      * This instance is immutable and unaffected by this method call.
   1925      *
   1926      * @param days  the days to subtract, may be negative
   1927      * @return a {@code ZonedDateTime} based on this date-time with the days subtracted, not null
   1928      * @throws DateTimeException if the result exceeds the supported date range
   1929      */
   1930     public ZonedDateTime minusDays(long days) {
   1931         return (days == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-days));
   1932     }
   1933 
   1934     //-----------------------------------------------------------------------
   1935     /**
   1936      * Returns a copy of this {@code ZonedDateTime} with the specified number of hours subtracted.
   1937      * <p>
   1938      * This operates on the instant time-line, such that subtracting one hour will
   1939      * always be a duration of one hour earlier.
   1940      * This may cause the local date-time to change by an amount other than one hour.
   1941      * Note that this is a different approach to that used by days, months and years,
   1942      * thus subtracting one day is not the same as adding 24 hours.
   1943      * <p>
   1944      * For example, consider a time-zone where the spring DST cutover means that the
   1945      * local times 01:00 to 01:59 occur twice changing from offset +02:00 to +01:00.
   1946      * <ul>
   1947      * <li>Subtracting one hour from 02:30+01:00 will result in 01:30+02:00
   1948      * <li>Subtracting one hour from 01:30+01:00 will result in 01:30+02:00
   1949      * <li>Subtracting one hour from 01:30+02:00 will result in 00:30+01:00
   1950      * <li>Subtracting three hours from 02:30+01:00 will result in 00:30+02:00
   1951      * </ul>
   1952      * <p>
   1953      * This instance is immutable and unaffected by this method call.
   1954      *
   1955      * @param hours  the hours to subtract, may be negative
   1956      * @return a {@code ZonedDateTime} based on this date-time with the hours subtracted, not null
   1957      * @throws DateTimeException if the result exceeds the supported date range
   1958      */
   1959     public ZonedDateTime minusHours(long hours) {
   1960         return (hours == Long.MIN_VALUE ? plusHours(Long.MAX_VALUE).plusHours(1) : plusHours(-hours));
   1961     }
   1962 
   1963     /**
   1964      * Returns a copy of this {@code ZonedDateTime} with the specified number of minutes subtracted.
   1965      * <p>
   1966      * This operates on the instant time-line, such that subtracting one minute will
   1967      * always be a duration of one minute earlier.
   1968      * This may cause the local date-time to change by an amount other than one minute.
   1969      * Note that this is a different approach to that used by days, months and years.
   1970      * <p>
   1971      * This instance is immutable and unaffected by this method call.
   1972      *
   1973      * @param minutes  the minutes to subtract, may be negative
   1974      * @return a {@code ZonedDateTime} based on this date-time with the minutes subtracted, not null
   1975      * @throws DateTimeException if the result exceeds the supported date range
   1976      */
   1977     public ZonedDateTime minusMinutes(long minutes) {
   1978         return (minutes == Long.MIN_VALUE ? plusMinutes(Long.MAX_VALUE).plusMinutes(1) : plusMinutes(-minutes));
   1979     }
   1980 
   1981     /**
   1982      * Returns a copy of this {@code ZonedDateTime} with the specified number of seconds subtracted.
   1983      * <p>
   1984      * This operates on the instant time-line, such that subtracting one second will
   1985      * always be a duration of one second earlier.
   1986      * This may cause the local date-time to change by an amount other than one second.
   1987      * Note that this is a different approach to that used by days, months and years.
   1988      * <p>
   1989      * This instance is immutable and unaffected by this method call.
   1990      *
   1991      * @param seconds  the seconds to subtract, may be negative
   1992      * @return a {@code ZonedDateTime} based on this date-time with the seconds subtracted, not null
   1993      * @throws DateTimeException if the result exceeds the supported date range
   1994      */
   1995     public ZonedDateTime minusSeconds(long seconds) {
   1996         return (seconds == Long.MIN_VALUE ? plusSeconds(Long.MAX_VALUE).plusSeconds(1) : plusSeconds(-seconds));
   1997     }
   1998 
   1999     /**
   2000      * Returns a copy of this {@code ZonedDateTime} with the specified number of nanoseconds subtracted.
   2001      * <p>
   2002      * This operates on the instant time-line, such that subtracting one nano will
   2003      * always be a duration of one nano earlier.
   2004      * This may cause the local date-time to change by an amount other than one nano.
   2005      * Note that this is a different approach to that used by days, months and years.
   2006      * <p>
   2007      * This instance is immutable and unaffected by this method call.
   2008      *
   2009      * @param nanos  the nanos to subtract, may be negative
   2010      * @return a {@code ZonedDateTime} based on this date-time with the nanoseconds subtracted, not null
   2011      * @throws DateTimeException if the result exceeds the supported date range
   2012      */
   2013     public ZonedDateTime minusNanos(long nanos) {
   2014         return (nanos == Long.MIN_VALUE ? plusNanos(Long.MAX_VALUE).plusNanos(1) : plusNanos(-nanos));
   2015     }
   2016 
   2017     //-----------------------------------------------------------------------
   2018     /**
   2019      * Queries this date-time using the specified query.
   2020      * <p>
   2021      * This queries this date-time using the specified query strategy object.
   2022      * The {@code TemporalQuery} object defines the logic to be used to
   2023      * obtain the result. Read the documentation of the query to understand
   2024      * what the result of this method will be.
   2025      * <p>
   2026      * The result of this method is obtained by invoking the
   2027      * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the
   2028      * specified query passing {@code this} as the argument.
   2029      *
   2030      * @param <R> the type of the result
   2031      * @param query  the query to invoke, not null
   2032      * @return the query result, null may be returned (defined by the query)
   2033      * @throws DateTimeException if unable to query (defined by the query)
   2034      * @throws ArithmeticException if numeric overflow occurs (defined by the query)
   2035      */
   2036     @SuppressWarnings("unchecked")
   2037     @Override  // override for Javadoc
   2038     public <R> R query(TemporalQuery<R> query) {
   2039         if (query == TemporalQueries.localDate()) {
   2040             return (R) toLocalDate();
   2041         }
   2042         return ChronoZonedDateTime.super.query(query);
   2043     }
   2044 
   2045     /**
   2046      * Calculates the amount of time until another date-time in terms of the specified unit.
   2047      * <p>
   2048      * This calculates the amount of time between two {@code ZonedDateTime}
   2049      * objects in terms of a single {@code TemporalUnit}.
   2050      * The start and end points are {@code this} and the specified date-time.
   2051      * The result will be negative if the end is before the start.
   2052      * For example, the amount in days between two date-times can be calculated
   2053      * using {@code startDateTime.until(endDateTime, DAYS)}.
   2054      * <p>
   2055      * The {@code Temporal} passed to this method is converted to a
   2056      * {@code ZonedDateTime} using {@link #from(TemporalAccessor)}.
   2057      * If the time-zone differs between the two zoned date-times, the specified
   2058      * end date-time is normalized to have the same zone as this date-time.
   2059      * <p>
   2060      * The calculation returns a whole number, representing the number of
   2061      * complete units between the two date-times.
   2062      * For example, the amount in months between 2012-06-15T00:00Z and 2012-08-14T23:59Z
   2063      * will only be one month as it is one minute short of two months.
   2064      * <p>
   2065      * There are two equivalent ways of using this method.
   2066      * The first is to invoke this method.
   2067      * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}:
   2068      * <pre>
   2069      *   // these two lines are equivalent
   2070      *   amount = start.until(end, MONTHS);
   2071      *   amount = MONTHS.between(start, end);
   2072      * </pre>
   2073      * The choice should be made based on which makes the code more readable.
   2074      * <p>
   2075      * The calculation is implemented in this method for {@link ChronoUnit}.
   2076      * The units {@code NANOS}, {@code MICROS}, {@code MILLIS}, {@code SECONDS},
   2077      * {@code MINUTES}, {@code HOURS} and {@code HALF_DAYS}, {@code DAYS},
   2078      * {@code WEEKS}, {@code MONTHS}, {@code YEARS}, {@code DECADES},
   2079      * {@code CENTURIES}, {@code MILLENNIA} and {@code ERAS} are supported.
   2080      * Other {@code ChronoUnit} values will throw an exception.
   2081      * <p>
   2082      * The calculation for date and time units differ.
   2083      * <p>
   2084      * Date units operate on the local time-line, using the local date-time.
   2085      * For example, the period from noon on day 1 to noon the following day
   2086      * in days will always be counted as exactly one day, irrespective of whether
   2087      * there was a daylight savings change or not.
   2088      * <p>
   2089      * Time units operate on the instant time-line.
   2090      * The calculation effectively converts both zoned date-times to instants
   2091      * and then calculates the period between the instants.
   2092      * For example, the period from noon on day 1 to noon the following day
   2093      * in hours may be 23, 24 or 25 hours (or some other amount) depending on
   2094      * whether there was a daylight savings change or not.
   2095      * <p>
   2096      * If the unit is not a {@code ChronoUnit}, then the result of this method
   2097      * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
   2098      * passing {@code this} as the first argument and the converted input temporal
   2099      * as the second argument.
   2100      * <p>
   2101      * This instance is immutable and unaffected by this method call.
   2102      *
   2103      * @param endExclusive  the end date, exclusive, which is converted to a {@code ZonedDateTime}, not null
   2104      * @param unit  the unit to measure the amount in, not null
   2105      * @return the amount of time between this date-time and the end date-time
   2106      * @throws DateTimeException if the amount cannot be calculated, or the end
   2107      *  temporal cannot be converted to a {@code ZonedDateTime}
   2108      * @throws UnsupportedTemporalTypeException if the unit is not supported
   2109      * @throws ArithmeticException if numeric overflow occurs
   2110      */
   2111     @Override
   2112     public long until(Temporal endExclusive, TemporalUnit unit) {
   2113         ZonedDateTime end = ZonedDateTime.from(endExclusive);
   2114         if (unit instanceof ChronoUnit) {
   2115             end = end.withZoneSameInstant(zone);
   2116             if (unit.isDateBased()) {
   2117                 return dateTime.until(end.dateTime, unit);
   2118             } else {
   2119                 return toOffsetDateTime().until(end.toOffsetDateTime(), unit);
   2120             }
   2121         }
   2122         return unit.between(this, end);
   2123     }
   2124 
   2125     /**
   2126      * Formats this date-time using the specified formatter.
   2127      * <p>
   2128      * This date-time will be passed to the formatter to produce a string.
   2129      *
   2130      * @param formatter  the formatter to use, not null
   2131      * @return the formatted date-time string, not null
   2132      * @throws DateTimeException if an error occurs during printing
   2133      */
   2134     @Override  // override for Javadoc and performance
   2135     public String format(DateTimeFormatter formatter) {
   2136         Objects.requireNonNull(formatter, "formatter");
   2137         return formatter.format(this);
   2138     }
   2139 
   2140     //-----------------------------------------------------------------------
   2141     /**
   2142      * Converts this date-time to an {@code OffsetDateTime}.
   2143      * <p>
   2144      * This creates an offset date-time using the local date-time and offset.
   2145      * The zone ID is ignored.
   2146      *
   2147      * @return an offset date-time representing the same local date-time and offset, not null
   2148      */
   2149     public OffsetDateTime toOffsetDateTime() {
   2150         return OffsetDateTime.of(dateTime, offset);
   2151     }
   2152 
   2153     //-----------------------------------------------------------------------
   2154     /**
   2155      * Checks if this date-time is equal to another date-time.
   2156      * <p>
   2157      * The comparison is based on the offset date-time and the zone.
   2158      * Only objects of type {@code ZonedDateTime} are compared, other types return false.
   2159      *
   2160      * @param obj  the object to check, null returns false
   2161      * @return true if this is equal to the other date-time
   2162      */
   2163     @Override
   2164     public boolean equals(Object obj) {
   2165         if (this == obj) {
   2166             return true;
   2167         }
   2168         if (obj instanceof ZonedDateTime) {
   2169             ZonedDateTime other = (ZonedDateTime) obj;
   2170             return dateTime.equals(other.dateTime) &&
   2171                 offset.equals(other.offset) &&
   2172                 zone.equals(other.zone);
   2173         }
   2174         return false;
   2175     }
   2176 
   2177     /**
   2178      * A hash code for this date-time.
   2179      *
   2180      * @return a suitable hash code
   2181      */
   2182     @Override
   2183     public int hashCode() {
   2184         return dateTime.hashCode() ^ offset.hashCode() ^ Integer.rotateLeft(zone.hashCode(), 3);
   2185     }
   2186 
   2187     //-----------------------------------------------------------------------
   2188     /**
   2189      * Outputs this date-time as a {@code String}, such as
   2190      * {@code 2007-12-03T10:15:30+01:00[Europe/Paris]}.
   2191      * <p>
   2192      * The format consists of the {@code LocalDateTime} followed by the {@code ZoneOffset}.
   2193      * If the {@code ZoneId} is not the same as the offset, then the ID is output.
   2194      * The output is compatible with ISO-8601 if the offset and ID are the same.
   2195      *
   2196      * @return a string representation of this date-time, not null
   2197      */
   2198     @Override  // override for Javadoc
   2199     public String toString() {
   2200         String str = dateTime.toString() + offset.toString();
   2201         if (offset != zone) {
   2202             str += '[' + zone.toString() + ']';
   2203         }
   2204         return str;
   2205     }
   2206 
   2207     //-----------------------------------------------------------------------
   2208     /**
   2209      * Writes the object using a
   2210      * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
   2211      * @serialData
   2212      * <pre>
   2213      *  out.writeByte(6);  // identifies a ZonedDateTime
   2214      *  // the <a href="../../serialized-form.html#java.time.LocalDateTime">dateTime</a> excluding the one byte header
   2215      *  // the <a href="../../serialized-form.html#java.time.ZoneOffset">offset</a> excluding the one byte header
   2216      *  // the <a href="../../serialized-form.html#java.time.ZoneId">zone ID</a> excluding the one byte header
   2217      * </pre>
   2218      *
   2219      * @return the instance of {@code Ser}, not null
   2220      */
   2221     private Object writeReplace() {
   2222         return new Ser(Ser.ZONE_DATE_TIME_TYPE, this);
   2223     }
   2224 
   2225     /**
   2226      * Defend against malicious streams.
   2227      *
   2228      * @param s the stream to read
   2229      * @throws InvalidObjectException always
   2230      */
   2231     private void readObject(ObjectInputStream s) throws InvalidObjectException {
   2232         throw new InvalidObjectException("Deserialization via serialization delegate");
   2233     }
   2234 
   2235     void writeExternal(DataOutput out) throws IOException {
   2236         dateTime.writeExternal(out);
   2237         offset.writeExternal(out);
   2238         zone.write(out);
   2239     }
   2240 
   2241     static ZonedDateTime readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
   2242         LocalDateTime dateTime = LocalDateTime.readExternal(in);
   2243         ZoneOffset offset = ZoneOffset.readExternal(in);
   2244         ZoneId zone = (ZoneId) Ser.read(in);
   2245         return ZonedDateTime.ofLenient(dateTime, offset, zone);
   2246     }
   2247 
   2248 }
   2249