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