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