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