1 /* 2 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 /* 27 * This file is available under and governed by the GNU General Public 28 * License version 2 only, as published by the Free Software Foundation. 29 * However, the following notice accompanied the original version of this 30 * file: 31 * 32 * Copyright (c) 2013, Stephen Colebourne & Michael Nascimento Santos 33 * 34 * All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions are met: 38 * 39 * * Redistributions of source code must retain the above copyright notice, 40 * this list of conditions and the following disclaimer. 41 * 42 * * Redistributions in binary form must reproduce the above copyright notice, 43 * this list of conditions and the following disclaimer in the documentation 44 * and/or other materials provided with the distribution. 45 * 46 * * Neither the name of JSR-310 nor the names of its contributors 47 * may be used to endorse or promote products derived from this software 48 * without specific prior written permission. 49 * 50 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 51 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 52 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 53 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 54 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 55 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 56 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 57 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 58 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 59 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 60 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 61 */ 62 package java.time.chrono; 63 64 import java.time.DateTimeException; 65 import java.time.temporal.ChronoUnit; 66 import java.time.temporal.Temporal; 67 import java.time.temporal.TemporalAmount; 68 import java.time.temporal.TemporalUnit; 69 import java.time.temporal.UnsupportedTemporalTypeException; 70 import java.util.List; 71 import java.util.Objects; 72 73 /** 74 * A date-based amount of time, such as '3 years, 4 months and 5 days' in an 75 * arbitrary chronology, intended for advanced globalization use cases. 76 * <p> 77 * This interface models a date-based amount of time in a calendar system. 78 * While most calendar systems use years, months and days, some do not. 79 * Therefore, this interface operates solely in terms of a set of supported 80 * units that are defined by the {@code Chronology}. 81 * The set of supported units is fixed for a given chronology. 82 * The amount of a supported unit may be set to zero. 83 * <p> 84 * The period is modeled as a directed amount of time, meaning that individual 85 * parts of the period may be negative. 86 * 87 * @implSpec 88 * This interface must be implemented with care to ensure other classes operate correctly. 89 * All implementations that can be instantiated must be final, immutable and thread-safe. 90 * Subclasses should be Serializable wherever possible. 91 * 92 * @since 1.8 93 */ 94 public interface ChronoPeriod 95 extends TemporalAmount { 96 97 /** 98 * Obtains a {@code ChronoPeriod} consisting of amount of time between two dates. 99 * <p> 100 * The start date is included, but the end date is not. 101 * The period is calculated using {@link ChronoLocalDate#until(ChronoLocalDate)}. 102 * As such, the calculation is chronology specific. 103 * <p> 104 * The chronology of the first date is used. 105 * The chronology of the second date is ignored, with the date being converted 106 * to the target chronology system before the calculation starts. 107 * <p> 108 * The result of this method can be a negative period if the end is before the start. 109 * In most cases, the positive/negative sign will be the same in each of the supported fields. 110 * 111 * @param startDateInclusive the start date, inclusive, specifying the chronology of the calculation, not null 112 * @param endDateExclusive the end date, exclusive, in any chronology, not null 113 * @return the period between this date and the end date, not null 114 * @see ChronoLocalDate#until(ChronoLocalDate) 115 */ between(ChronoLocalDate startDateInclusive, ChronoLocalDate endDateExclusive)116 public static ChronoPeriod between(ChronoLocalDate startDateInclusive, ChronoLocalDate endDateExclusive) { 117 Objects.requireNonNull(startDateInclusive, "startDateInclusive"); 118 Objects.requireNonNull(endDateExclusive, "endDateExclusive"); 119 return startDateInclusive.until(endDateExclusive); 120 } 121 122 //----------------------------------------------------------------------- 123 /** 124 * Gets the value of the requested unit. 125 * <p> 126 * The supported units are chronology specific. 127 * They will typically be {@link ChronoUnit#YEARS YEARS}, 128 * {@link ChronoUnit#MONTHS MONTHS} and {@link ChronoUnit#DAYS DAYS}. 129 * Requesting an unsupported unit will throw an exception. 130 * 131 * @param unit the {@code TemporalUnit} for which to return the value 132 * @return the long value of the unit 133 * @throws DateTimeException if the unit is not supported 134 * @throws UnsupportedTemporalTypeException if the unit is not supported 135 */ 136 @Override get(TemporalUnit unit)137 long get(TemporalUnit unit); 138 139 /** 140 * Gets the set of units supported by this period. 141 * <p> 142 * The supported units are chronology specific. 143 * They will typically be {@link ChronoUnit#YEARS YEARS}, 144 * {@link ChronoUnit#MONTHS MONTHS} and {@link ChronoUnit#DAYS DAYS}. 145 * They are returned in order from largest to smallest. 146 * <p> 147 * This set can be used in conjunction with {@link #get(TemporalUnit)} 148 * to access the entire state of the period. 149 * 150 * @return a list containing the supported units, not null 151 */ 152 @Override getUnits()153 List<TemporalUnit> getUnits(); 154 155 /** 156 * Gets the chronology that defines the meaning of the supported units. 157 * <p> 158 * The period is defined by the chronology. 159 * It controls the supported units and restricts addition/subtraction 160 * to {@code ChronoLocalDate} instances of the same chronology. 161 * 162 * @return the chronology defining the period, not null 163 */ getChronology()164 Chronology getChronology(); 165 166 //----------------------------------------------------------------------- 167 /** 168 * Checks if all the supported units of this period are zero. 169 * 170 * @return true if this period is zero-length 171 */ isZero()172 default boolean isZero() { 173 for (TemporalUnit unit : getUnits()) { 174 if (get(unit) != 0) { 175 return false; 176 } 177 } 178 return true; 179 } 180 181 /** 182 * Checks if any of the supported units of this period are negative. 183 * 184 * @return true if any unit of this period is negative 185 */ isNegative()186 default boolean isNegative() { 187 for (TemporalUnit unit : getUnits()) { 188 if (get(unit) < 0) { 189 return true; 190 } 191 } 192 return false; 193 } 194 195 //----------------------------------------------------------------------- 196 /** 197 * Returns a copy of this period with the specified period added. 198 * <p> 199 * If the specified amount is a {@code ChronoPeriod} then it must have 200 * the same chronology as this period. Implementations may choose to 201 * accept or reject other {@code TemporalAmount} implementations. 202 * <p> 203 * This instance is immutable and unaffected by this method call. 204 * 205 * @param amountToAdd the period to add, not null 206 * @return a {@code ChronoPeriod} based on this period with the requested period added, not null 207 * @throws ArithmeticException if numeric overflow occurs 208 */ plus(TemporalAmount amountToAdd)209 ChronoPeriod plus(TemporalAmount amountToAdd); 210 211 /** 212 * Returns a copy of this period with the specified period subtracted. 213 * <p> 214 * If the specified amount is a {@code ChronoPeriod} then it must have 215 * the same chronology as this period. Implementations may choose to 216 * accept or reject other {@code TemporalAmount} implementations. 217 * <p> 218 * This instance is immutable and unaffected by this method call. 219 * 220 * @param amountToSubtract the period to subtract, not null 221 * @return a {@code ChronoPeriod} based on this period with the requested period subtracted, not null 222 * @throws ArithmeticException if numeric overflow occurs 223 */ minus(TemporalAmount amountToSubtract)224 ChronoPeriod minus(TemporalAmount amountToSubtract); 225 226 //----------------------------------------------------------------------- 227 /** 228 * Returns a new instance with each amount in this period in this period 229 * multiplied by the specified scalar. 230 * <p> 231 * This returns a period with each supported unit individually multiplied. 232 * For example, a period of "2 years, -3 months and 4 days" multiplied by 233 * 3 will return "6 years, -9 months and 12 days". 234 * No normalization is performed. 235 * 236 * @param scalar the scalar to multiply by, not null 237 * @return a {@code ChronoPeriod} based on this period with the amounts multiplied 238 * by the scalar, not null 239 * @throws ArithmeticException if numeric overflow occurs 240 */ multipliedBy(int scalar)241 ChronoPeriod multipliedBy(int scalar); 242 243 /** 244 * Returns a new instance with each amount in this period negated. 245 * <p> 246 * This returns a period with each supported unit individually negated. 247 * For example, a period of "2 years, -3 months and 4 days" will be 248 * negated to "-2 years, 3 months and -4 days". 249 * No normalization is performed. 250 * 251 * @return a {@code ChronoPeriod} based on this period with the amounts negated, not null 252 * @throws ArithmeticException if numeric overflow occurs, which only happens if 253 * one of the units has the value {@code Long.MIN_VALUE} 254 */ negated()255 default ChronoPeriod negated() { 256 return multipliedBy(-1); 257 } 258 259 //----------------------------------------------------------------------- 260 /** 261 * Returns a copy of this period with the amounts of each unit normalized. 262 * <p> 263 * The process of normalization is specific to each calendar system. 264 * For example, in the ISO calendar system, the years and months are 265 * normalized but the days are not, such that "15 months" would be 266 * normalized to "1 year and 3 months". 267 * <p> 268 * This instance is immutable and unaffected by this method call. 269 * 270 * @return a {@code ChronoPeriod} based on this period with the amounts of each 271 * unit normalized, not null 272 * @throws ArithmeticException if numeric overflow occurs 273 */ normalized()274 ChronoPeriod normalized(); 275 276 //------------------------------------------------------------------------- 277 /** 278 * Adds this period to the specified temporal object. 279 * <p> 280 * This returns a temporal object of the same observable type as the input 281 * with this period added. 282 * <p> 283 * In most cases, it is clearer to reverse the calling pattern by using 284 * {@link Temporal#plus(TemporalAmount)}. 285 * <pre> 286 * // these two lines are equivalent, but the second approach is recommended 287 * dateTime = thisPeriod.addTo(dateTime); 288 * dateTime = dateTime.plus(thisPeriod); 289 * </pre> 290 * <p> 291 * The specified temporal must have the same chronology as this period. 292 * This returns a temporal with the non-zero supported units added. 293 * <p> 294 * This instance is immutable and unaffected by this method call. 295 * 296 * @param temporal the temporal object to adjust, not null 297 * @return an object of the same type with the adjustment made, not null 298 * @throws DateTimeException if unable to add 299 * @throws ArithmeticException if numeric overflow occurs 300 */ 301 @Override addTo(Temporal temporal)302 Temporal addTo(Temporal temporal); 303 304 /** 305 * Subtracts this period from the specified temporal object. 306 * <p> 307 * This returns a temporal object of the same observable type as the input 308 * with this period subtracted. 309 * <p> 310 * In most cases, it is clearer to reverse the calling pattern by using 311 * {@link Temporal#minus(TemporalAmount)}. 312 * <pre> 313 * // these two lines are equivalent, but the second approach is recommended 314 * dateTime = thisPeriod.subtractFrom(dateTime); 315 * dateTime = dateTime.minus(thisPeriod); 316 * </pre> 317 * <p> 318 * The specified temporal must have the same chronology as this period. 319 * This returns a temporal with the non-zero supported units subtracted. 320 * <p> 321 * This instance is immutable and unaffected by this method call. 322 * 323 * @param temporal the temporal object to adjust, not null 324 * @return an object of the same type with the adjustment made, not null 325 * @throws DateTimeException if unable to subtract 326 * @throws ArithmeticException if numeric overflow occurs 327 */ 328 @Override subtractFrom(Temporal temporal)329 Temporal subtractFrom(Temporal temporal); 330 331 //----------------------------------------------------------------------- 332 /** 333 * Checks if this period is equal to another period, including the chronology. 334 * <p> 335 * Compares this period with another ensuring that the type, each amount and 336 * the chronology are the same. 337 * Note that this means that a period of "15 Months" is not equal to a period 338 * of "1 Year and 3 Months". 339 * 340 * @param obj the object to check, null returns false 341 * @return true if this is equal to the other period 342 */ 343 @Override equals(Object obj)344 boolean equals(Object obj); 345 346 /** 347 * A hash code for this period. 348 * 349 * @return a suitable hash code 350 */ 351 @Override hashCode()352 int hashCode(); 353 354 //----------------------------------------------------------------------- 355 /** 356 * Outputs this period as a {@code String}. 357 * <p> 358 * The output will include the period amounts and chronology. 359 * 360 * @return a string representation of this period, not null 361 */ 362 @Override toString()363 String toString(); 364 365 } 366