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.temporal.TemporalField; 13 14 import hunt.time.Exceptions; 15 import hunt.time.chrono.Chronology; 16 import hunt.time.format.ResolverStyle; 17 import hunt.time.temporal.TemporalUnit; 18 import hunt.time.temporal.ValueRange; 19 import hunt.time.temporal.TemporalAccessor; 20 import hunt.time.temporal.Temporal; 21 22 import hunt.collection.Map; 23 import hunt.Long; 24 import hunt.util.Locale; 25 26 /** 27 * A field of date-time, such as month-of-year or hour-of-minute. 28 * !(p) 29 * Date and time is expressed using fields which partition the time-line into something 30 * meaningful for humans. Implementations of this interface represent those fields. 31 * !(p) 32 * The most commonly used units are defined _in {@link ChronoField}. 33 * Further fields are supplied _in {@link IsoFields}, {@link WeekFields} and {@link JulianFields}. 34 * Fields can also be written by application code by implementing this interface. 35 * !(p) 36 * The field works using double dispatch. Client code calls methods on a date-time like 37 * {@code LocalDateTime} which check if the field is a {@code ChronoField}. 38 * If it is, then the date-time must handle it. 39 * Otherwise, the method call is re-dispatched to the matching method _in this interface. 40 * 41 * @implSpec 42 * This interface must be implemented with care to ensure other classes operate correctly. 43 * All implementations that can be instantiated must be final, immutable and thread-safe. 44 * Implementations should be {@code Serializable} where possible. 45 * An enum is as effective implementation choice. 46 * 47 * @since 1.8 48 */ 49 public interface TemporalField { 50 51 /** 52 * Gets the display name for the field _in the requested locale. 53 * !(p) 54 * If there is no display name for the locale then a suitable must be returned. 55 * !(p) 56 * The implementation must check the locale is not null 57 * and return {@code toString()}. 58 * 59 * @param locale the locale to use, not null 60 * @return the display name for the locale or a suitable , not null 61 */ 62 string getDisplayName(Locale locale); 63 // string getDisplayName(Locale locale) { 64 // assert(locale, "locale"); 65 // return toString(); 66 // } 67 68 /** 69 * Gets the unit that the field is measured _in. 70 * !(p) 71 * The unit of the field is the period that varies within the range. 72 * For example, _in the field 'MonthOfYear', the unit is 'Months'. 73 * See also {@link #getRangeUnit()}. 74 * 75 * @return the unit defining the base unit of the field, not null 76 */ 77 TemporalUnit getBaseUnit(); 78 79 /** 80 * Gets the range that the field is bound by. 81 * !(p) 82 * The range of the field is the period that the field varies within. 83 * For example, _in the field 'MonthOfYear', the range is 'Years'. 84 * See also {@link #getBaseUnit()}. 85 * !(p) 86 * The range is never null. For example, the 'Year' field is shorthand for 87 * 'YearOfForever'. It therefore has a unit of 'Years' and a range of 'Forever'. 88 * 89 * @return the unit defining the range of the field, not null 90 */ 91 TemporalUnit getRangeUnit(); 92 93 /** 94 * Gets the range of valid values for the field. 95 * !(p) 96 * All fields can be expressed as a {@code long} integer. 97 * This method returns an object that describes the valid range for that value. 98 * This method is generally only applicable to the ISO-8601 calendar system. 99 * !(p) 100 * Note that the result only describes the minimum and maximum valid values 101 * and it is important not to read too much into them. For example, there 102 * could be values within the range that are invalid for the field. 103 * 104 * @return the range of valid values for the field, not null 105 */ 106 ValueRange range(); 107 108 //----------------------------------------------------------------------- 109 /** 110 * Checks if this field represents a component of a date. 111 * !(p) 112 * A field is date-based if it can be derived from 113 * {@link ChronoField#EPOCH_DAY EPOCH_DAY}. 114 * Note that it is valid for both {@code isDateBased()} and {@code isTimeBased()} 115 * to return false, such as when representing a field like minute-of-week. 116 * 117 * @return true if this field is a component of a date 118 */ 119 bool isDateBased(); 120 121 /** 122 * Checks if this field represents a component of a time. 123 * !(p) 124 * A field is time-based if it can be derived from 125 * {@link ChronoField#NANO_OF_DAY NANO_OF_DAY}. 126 * Note that it is valid for both {@code isDateBased()} and {@code isTimeBased()} 127 * to return false, such as when representing a field like minute-of-week. 128 * 129 * @return true if this field is a component of a time 130 */ 131 bool isTimeBased(); 132 133 //----------------------------------------------------------------------- 134 /** 135 * Checks if this field is supported by the temporal object. 136 * !(p) 137 * This determines whether the temporal accessor supports this field. 138 * If this returns false, then the temporal cannot be queried for this field. 139 * !(p) 140 * There are two equivalent ways of using this method. 141 * The first is to invoke this method directly. 142 * The second is to use {@link TemporalAccessor#isSupported(TemporalField)}: 143 * !(pre) 144 * // these two lines are equivalent, but the second approach is recommended 145 * temporal = thisField.isSupportedBy(temporal); 146 * temporal = temporal.isSupported(thisField); 147 * </pre> 148 * It is recommended to use the second approach, {@code isSupported(TemporalField)}, 149 * as it is a lot clearer to read _in code. 150 * !(p) 151 * Implementations should determine whether they are supported using the fields 152 * available _in {@link ChronoField}. 153 * 154 * @param temporal the temporal object to query, not null 155 * @return true if the date-time can be queried for this field, false if not 156 */ 157 bool isSupportedBy(TemporalAccessor temporal); 158 159 /** 160 * Get the range of valid values for this field using the temporal object to 161 * refine the result. 162 * !(p) 163 * This uses the temporal object to find the range of valid values for the field. 164 * This is similar to {@link #range()}, however this method refines the result 165 * using the temporal. For example, if the field is {@code DAY_OF_MONTH} the 166 * {@code range} method is not accurate as there are four possible month lengths, 167 * 28, 29, 30 and 31 days. Using this method with a date allows the range to be 168 * accurate, returning just one of those four options. 169 * !(p) 170 * There are two equivalent ways of using this method. 171 * The first is to invoke this method directly. 172 * The second is to use {@link TemporalAccessor#range(TemporalField)}: 173 * !(pre) 174 * // these two lines are equivalent, but the second approach is recommended 175 * temporal = thisField.rangeRefinedBy(temporal); 176 * temporal = temporal.range(thisField); 177 * </pre> 178 * It is recommended to use the second approach, {@code range(TemporalField)}, 179 * as it is a lot clearer to read _in code. 180 * !(p) 181 * Implementations should perform any queries or calculations using the fields 182 * available _in {@link ChronoField}. 183 * If the field is not supported an {@code UnsupportedTemporalTypeException} must be thrown. 184 * 185 * @param temporal the temporal object used to refine the result, not null 186 * @return the range of valid values for this field, not null 187 * @throws DateTimeException if the range for the field cannot be obtained 188 * @throws UnsupportedTemporalTypeException if the field is not supported by the temporal 189 */ 190 ValueRange rangeRefinedBy(TemporalAccessor temporal); 191 192 /** 193 * Gets the value of this field from the specified temporal object. 194 * !(p) 195 * This queries the temporal object for the value of this field. 196 * !(p) 197 * There are two equivalent ways of using this method. 198 * The first is to invoke this method directly. 199 * The second is to use {@link TemporalAccessor#getLong(TemporalField)} 200 * (or {@link TemporalAccessor#get(TemporalField)}): 201 * !(pre) 202 * // these two lines are equivalent, but the second approach is recommended 203 * temporal = thisField.getFrom(temporal); 204 * temporal = temporal.getLong(thisField); 205 * </pre> 206 * It is recommended to use the second approach, {@code getLong(TemporalField)}, 207 * as it is a lot clearer to read _in code. 208 * !(p) 209 * Implementations should perform any queries or calculations using the fields 210 * available _in {@link ChronoField}. 211 * If the field is not supported an {@code UnsupportedTemporalTypeException} must be thrown. 212 * 213 * @param temporal the temporal object to query, not null 214 * @return the value of this field, not null 215 * @throws DateTimeException if a value for the field cannot be obtained 216 * @throws UnsupportedTemporalTypeException if the field is not supported by the temporal 217 * @throws ArithmeticException if numeric overflow occurs 218 */ 219 long getFrom(TemporalAccessor temporal); 220 221 /** 222 * Returns a copy of the specified temporal object with the value of this field set. 223 * !(p) 224 * This returns a new temporal object based on the specified one with the value for 225 * this field changed. For example, on a {@code LocalDate}, this could be used to 226 * set the year, month or day-of-month. 227 * The returned object has the same observable type as the specified object. 228 * !(p) 229 * In some cases, changing a field is not fully defined. For example, if the target object is 230 * a date representing the 31st January, then changing the month to February would be unclear. 231 * In cases like this, the implementation is responsible for resolving the result. 232 * Typically it will choose the previous valid date, which would be the last valid 233 * day of February _in this example. 234 * !(p) 235 * There are two equivalent ways of using this method. 236 * The first is to invoke this method directly. 237 * The second is to use {@link Temporal#_with(TemporalField, long)}: 238 * !(pre) 239 * // these two lines are equivalent, but the second approach is recommended 240 * temporal = thisField.adjustInto(temporal); 241 * temporal = temporal._with(thisField); 242 * </pre> 243 * It is recommended to use the second approach, {@code _with(TemporalField)}, 244 * as it is a lot clearer to read _in code. 245 * !(p) 246 * Implementations should perform any queries or calculations using the fields 247 * available _in {@link ChronoField}. 248 * If the field is not supported an {@code UnsupportedTemporalTypeException} must be thrown. 249 * !(p) 250 * Implementations must not alter the specified temporal object. 251 * Instead, an adjusted copy of the original must be returned. 252 * This provides equivalent, safe behavior for immutable and mutable implementations. 253 * 254 * @param !(R) the type of the Temporal object 255 * @param temporal the temporal object to adjust, not null 256 * @param newValue the new value of the field 257 * @return the adjusted temporal object, not null 258 * @throws DateTimeException if the field cannot be set 259 * @throws UnsupportedTemporalTypeException if the field is not supported by the temporal 260 * @throws ArithmeticException if numeric overflow occurs 261 */ 262 Temporal adjustInto(Temporal temporal, long newValue); 263 264 /** 265 * Resolves this field to provide a simpler alternative or a date. 266 * !(p) 267 * This method is invoked during the resolve phase of parsing. 268 * It is designed to allow application defined fields to be simplified into 269 * more standard fields, such as those on {@code ChronoField}, or into a date. 270 * !(p) 271 * Applications should not normally invoke this method directly. 272 * 273 * @implSpec 274 * If an implementation represents a field that can be simplified, or 275 * combined with others, then this method must be implemented. 276 * !(p) 277 * The specified map contains the current state of the parse. 278 * The map is mutable and must be mutated to resolve the field and 279 * any related fields. This method will only be invoked during parsing 280 * if the map contains this field, and implementations should therefore 281 * assume this field is present. 282 * !(p) 283 * Resolving a field will consist of looking at the value of this field, 284 * and potentially other fields, and either updating the map with a 285 * simpler value, such as a {@code ChronoField}, or returning a 286 * complete {@code ChronoLocalDate}. If a resolve is successful, 287 * the code must remove all the fields that were resolved from the map, 288 * including this field. 289 * !(p) 290 * For example, the {@code IsoFields} class contains the quarter-of-year 291 * and day-of-quarter fields. The implementation of this method _in that class 292 * resolves the two fields plus the {@link ChronoField#YEAR YEAR} into a 293 * complete {@code LocalDate}. The resolve method will remove all three 294 * fields from the map before returning the {@code LocalDate}. 295 * !(p) 296 * A partially complete temporal is used to allow the chronology and zone 297 * to be queried. In general, only the chronology will be needed. 298 * Querying items other than the zone or chronology is undefined and 299 * must not be relied on. 300 * The behavior of other methods such as {@code get}, {@code getLong}, 301 * {@code range} and {@code isSupported} is unpredictable and the results undefined. 302 * !(p) 303 * If resolution should be possible, but the data is invalid, the resolver 304 * style should be used to determine an appropriate level of leniency, which 305 * may require throwing a {@code DateTimeException} or {@code ArithmeticException}. 306 * If no resolution is possible, the resolve method must return null. 307 * !(p) 308 * When resolving time fields, the map will be altered and null returned. 309 * When resolving date fields, the date is normally returned from the method, 310 * with the map altered to remove the resolved fields. However, it would also 311 * be acceptable for the date fields to be resolved into other {@code ChronoField} 312 * instances that can produce a date, such as {@code EPOCH_DAY}. 313 * !(p) 314 * Not all {@code TemporalAccessor} implementations are accepted as return values. 315 * Implementations that call this method must accept {@code ChronoLocalDate}, 316 * {@code ChronoLocalDateTime}, {@code ChronoZonedDateTime} and {@code LocalTime}. 317 * !(p) 318 * The implementation must return null. 319 * 320 * @param fieldValues the map of fields to values, which can be updated, not null 321 * @param partialTemporal the partially complete temporal to query for zone and 322 * chronology; querying for other things is undefined and not recommended, not null 323 * @param resolverStyle the requested type of resolve, not null 324 * @return the resolved temporal object; null if resolving only 325 * changed the map, or no resolve occurred 326 * @throws ArithmeticException if numeric overflow occurs 327 * @throws DateTimeException if resolving results _in an error. This must not be thrown 328 * by querying a field on the temporal without first checking if it is supported 329 */ 330 TemporalAccessor resolve( 331 Map!(TemporalField, Long) fieldValues, 332 TemporalAccessor partialTemporal, 333 ResolverStyle resolverStyle); 334 // TemporalAccessor resolve( 335 // Map!(TemporalField, Long) fieldValues, 336 // TemporalAccessor partialTemporal, 337 // ResolverStyle resolverStyle) { 338 // return null; 339 // } 340 341 /** 342 * Gets a descriptive name for the field. 343 * !(p) 344 * The should be of the format 'BaseOfRange', such as 'MonthOfYear', 345 * unless the field has a range of {@code FOREVER}, when only 346 * the base unit is mentioned, such as 'Year' or 'Era'. 347 * 348 * @return the name of the field, not null 349 */ 350 // override 351 string toString(); 352 353 // int opCmp(Object o); 354 355 int opCmp(TemporalField o); 356 357 }