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