1 /* 2 * hunt-time: A time library for D programming language. 3 * 4 * Copyright (C) 2015-2018 HuntLabs 5 * 6 * Website: https://www.huntlabs.net/ 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 12 module hunt.time.chrono.ChronoPeriod; 13 14 import hunt.time.Exceptions; 15 import hunt.time.temporal.ChronoUnit; 16 import hunt.time.temporal.Temporal; 17 import hunt.time.temporal.TemporalAmount; 18 import hunt.time.temporal.TemporalUnit; 19 import hunt.time.Exceptions; 20 import hunt.collection.List; 21 import hunt.time.chrono.ChronoLocalDate; 22 import hunt.time.chrono.Chronology; 23 24 /** 25 * A date-based amount of time, such as '3 years, 4 months and 5 days' _in an 26 * arbitrary chronology, intended for advanced globalization use cases. 27 * !(p) 28 * This interface models a date-based amount of time _in a calendar system. 29 * While most calendar systems use years, months and days, some do not. 30 * Therefore, this interface operates solely _in terms of a set of supported 31 * units that are defined by the {@code Chronology}. 32 * The set of supported units is fixed for a given chronology. 33 * The amount of a supported unit may be set to zero. 34 * !(p) 35 * The period is modeled as a directed amount of time, meaning that individual 36 * parts of the period may be negative. 37 * 38 * @implSpec 39 * This interface must be implemented with care to ensure other classes operate correctly. 40 * All implementations that can be instantiated must be final, immutable and thread-safe. 41 * Subclasses should be Serializable wherever possible. 42 * 43 * @since 1.8 44 */ 45 public interface ChronoPeriod 46 : TemporalAmount { 47 48 /** 49 * Obtains a {@code ChronoPeriod} consisting of amount of time between two dates. 50 * !(p) 51 * The start date is included, but the end date is not. 52 * The period is calculated using {@link ChronoLocalDate#until(ChronoLocalDate)}. 53 * As such, the calculation is chronology specific. 54 * !(p) 55 * The chronology of the first date is used. 56 * The chronology of the second date is ignored, with the date being converted 57 * to the target chronology system before the calculation starts. 58 * !(p) 59 * The result of this method can be a negative period if the end is before the start. 60 * In most cases, the positive/negative sign will be the same _in each of the supported fields. 61 * 62 * @param startDateInclusive the start date, inclusive, specifying the chronology of the calculation, not null 63 * @param endDateExclusive the end date, exclusive, _in any chronology, not null 64 * @return the period between this date and the end date, not null 65 * @see ChronoLocalDate#until(ChronoLocalDate) 66 */ 67 public static ChronoPeriod between(ChronoLocalDate startDateInclusive, ChronoLocalDate endDateExclusive) { 68 assert(startDateInclusive, "startDateInclusive"); 69 assert(endDateExclusive, "endDateExclusive"); 70 return startDateInclusive.until(endDateExclusive); 71 } 72 73 //----------------------------------------------------------------------- 74 /** 75 * Gets the value of the requested unit. 76 * !(p) 77 * The supported units are chronology specific. 78 * They will typically be {@link ChronoUnit#YEARS YEARS}, 79 * {@link ChronoUnit#MONTHS MONTHS} and {@link ChronoUnit#DAYS DAYS}. 80 * Requesting an unsupported unit will throw an exception. 81 * 82 * @param unit the {@code TemporalUnit} for which to return the value 83 * @return the long value of the unit 84 * @throws DateTimeException if the unit is not supported 85 * @throws UnsupportedTemporalTypeException if the unit is not supported 86 */ 87 override 88 long get(TemporalUnit unit); 89 90 /** 91 * Gets the set of units supported by this period. 92 * !(p) 93 * The supported units are chronology specific. 94 * They will typically be {@link ChronoUnit#YEARS YEARS}, 95 * {@link ChronoUnit#MONTHS MONTHS} and {@link ChronoUnit#DAYS DAYS}. 96 * They are returned _in order from largest to smallest. 97 * !(p) 98 * This set can be used _in conjunction with {@link #get(TemporalUnit)} 99 * to access the entire state of the period. 100 * 101 * @return a list containing the supported units, not null 102 */ 103 override 104 List!(TemporalUnit) getUnits(); 105 106 /** 107 * Gets the chronology that defines the meaning of the supported units. 108 * !(p) 109 * The period is defined by the chronology. 110 * It controls the supported units and restricts addition/subtraction 111 * to {@code ChronoLocalDate} instances of the same chronology. 112 * 113 * @return the chronology defining the period, not null 114 */ 115 Chronology getChronology(); 116 117 //----------------------------------------------------------------------- 118 /** 119 * Checks if all the supported units of this period are zero. 120 * 121 * @return true if this period is zero-length 122 */ 123 bool isZero(); 124 // bool isZero() { 125 // foreach(TemporalUnit unit ; getUnits()) { 126 // if (get(unit) != 0) { 127 // return false; 128 // } 129 // } 130 // return true; 131 // } 132 133 /** 134 * Checks if any of the supported units of this period are negative. 135 * 136 * @return true if any unit of this period is negative 137 */ 138 bool isNegative(); 139 // bool isNegative() { 140 // foreach(TemporalUnit unit ; getUnits()) { 141 // if (get(unit) < 0) { 142 // return true; 143 // } 144 // } 145 // return false; 146 // } 147 148 //----------------------------------------------------------------------- 149 /** 150 * Returns a copy of this period with the specified period added. 151 * !(p) 152 * If the specified amount is a {@code ChronoPeriod} then it must have 153 * the same chronology as this period. Implementations may choose to 154 * accept or reject other {@code TemporalAmount} implementations. 155 * !(p) 156 * This instance is immutable and unaffected by this method call. 157 * 158 * @param amountToAdd the period to add, not null 159 * @return a {@code ChronoPeriod} based on this period with the requested period added, not null 160 * @throws ArithmeticException if numeric overflow occurs 161 */ 162 ChronoPeriod plus(TemporalAmount amountToAdd); 163 164 /** 165 * Returns a copy of this period with the specified period subtracted. 166 * !(p) 167 * If the specified amount is a {@code ChronoPeriod} then it must have 168 * the same chronology as this period. Implementations may choose to 169 * accept or reject other {@code TemporalAmount} implementations. 170 * !(p) 171 * This instance is immutable and unaffected by this method call. 172 * 173 * @param amountToSubtract the period to subtract, not null 174 * @return a {@code ChronoPeriod} based on this period with the requested period subtracted, not null 175 * @throws ArithmeticException if numeric overflow occurs 176 */ 177 ChronoPeriod minus(TemporalAmount amountToSubtract); 178 179 //----------------------------------------------------------------------- 180 /** 181 * Returns a new instance with each amount _in this period _in this period 182 * multiplied by the specified scalar. 183 * !(p) 184 * This returns a period with each supported unit individually multiplied. 185 * For example, a period of "2 years, -3 months and 4 days" multiplied by 186 * 3 will return "6 years, -9 months and 12 days". 187 * No normalization is performed. 188 * 189 * @param scalar the scalar to multiply by, not null 190 * @return a {@code ChronoPeriod} based on this period with the amounts multiplied 191 * by the scalar, not null 192 * @throws ArithmeticException if numeric overflow occurs 193 */ 194 ChronoPeriod multipliedBy(int scalar); 195 196 /** 197 * Returns a new instance with each amount _in this period negated. 198 * !(p) 199 * This returns a period with each supported unit individually negated. 200 * For example, a period of "2 years, -3 months and 4 days" will be 201 * negated to "-2 years, 3 months and -4 days". 202 * No normalization is performed. 203 * 204 * @return a {@code ChronoPeriod} based on this period with the amounts negated, not null 205 * @throws ArithmeticException if numeric overflow occurs, which only happens if 206 * one of the units has the value {@code Long.MIN_VALUE} 207 */ 208 ChronoPeriod negated(); 209 // ChronoPeriod negated() { 210 // return multipliedBy(-1); 211 // } 212 213 //----------------------------------------------------------------------- 214 /** 215 * Returns a copy of this period with the amounts of each unit normalized. 216 * !(p) 217 * The process of normalization is specific to each calendar system. 218 * For example, _in the ISO calendar system, the years and months are 219 * normalized but the days are not, such that "15 months" would be 220 * normalized to "1 year and 3 months". 221 * !(p) 222 * This instance is immutable and unaffected by this method call. 223 * 224 * @return a {@code ChronoPeriod} based on this period with the amounts of each 225 * unit normalized, not null 226 * @throws ArithmeticException if numeric overflow occurs 227 */ 228 ChronoPeriod normalized(); 229 230 //------------------------------------------------------------------------- 231 /** 232 * Adds this period to the specified temporal object. 233 * !(p) 234 * This returns a temporal object of the same observable type as the input 235 * with this period added. 236 * !(p) 237 * In most cases, it is clearer to reverse the calling pattern by using 238 * {@link Temporal#plus(TemporalAmount)}. 239 * !(pre) 240 * // these two lines are equivalent, but the second approach is recommended 241 * dateTime = thisPeriod.addTo(dateTime); 242 * dateTime = dateTime.plus(thisPeriod); 243 * </pre> 244 * !(p) 245 * The specified temporal must have the same chronology as this period. 246 * This returns a temporal with the non-zero supported units added. 247 * !(p) 248 * This instance is immutable and unaffected by this method call. 249 * 250 * @param temporal the temporal object to adjust, not null 251 * @return an object of the same type with the adjustment made, not null 252 * @throws DateTimeException if unable to add 253 * @throws ArithmeticException if numeric overflow occurs 254 */ 255 override 256 Temporal addTo(Temporal temporal); 257 258 /** 259 * Subtracts this period from the specified temporal object. 260 * !(p) 261 * This returns a temporal object of the same observable type as the input 262 * with this period subtracted. 263 * !(p) 264 * In most cases, it is clearer to reverse the calling pattern by using 265 * {@link Temporal#minus(TemporalAmount)}. 266 * !(pre) 267 * // these two lines are equivalent, but the second approach is recommended 268 * dateTime = thisPeriod.subtractFrom(dateTime); 269 * dateTime = dateTime.minus(thisPeriod); 270 * </pre> 271 * !(p) 272 * The specified temporal must have the same chronology as this period. 273 * This returns a temporal with the non-zero supported units subtracted. 274 * !(p) 275 * This instance is immutable and unaffected by this method call. 276 * 277 * @param temporal the temporal object to adjust, not null 278 * @return an object of the same type with the adjustment made, not null 279 * @throws DateTimeException if unable to subtract 280 * @throws ArithmeticException if numeric overflow occurs 281 */ 282 override 283 Temporal subtractFrom(Temporal temporal); 284 285 //----------------------------------------------------------------------- 286 /** 287 * Checks if this period is equal to another period, including the chronology. 288 * !(p) 289 * Compares this period with another ensuring that the type, each amount and 290 * the chronology are the same. 291 * Note that this means that a period of "15 Months" is not equal to a period 292 * of "1 Year and 3 Months". 293 * 294 * @param obj the object to check, null returns false 295 * @return true if this is equal to the other period 296 */ 297 // override 298 // bool opEquals(Object obj); 299 300 /** 301 * A hash code for this period. 302 * 303 * @return a suitable hash code 304 */ 305 // override 306 // size_t toHash() @trusted nothrow; 307 308 //----------------------------------------------------------------------- 309 /** 310 * Outputs this period as a {@code string}. 311 * !(p) 312 * The output will include the period amounts and chronology. 313 * 314 * @return a string representation of this period, not null 315 */ 316 // override 317 // string toString(); 318 319 }