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.Era; 13 14 import hunt.time.temporal.ChronoField; 15 import hunt.time.temporal.ChronoUnit; 16 17 import hunt.time.Exceptions; 18 import hunt.time.Exceptions; 19 // import hunt.time.format.DateTimeFormatterBuilder; 20 import hunt.time.format.TextStyle; 21 import hunt.time.temporal.ChronoField; 22 import hunt.time.temporal.Temporal; 23 import hunt.time.temporal.TemporalAccessor; 24 import hunt.time.temporal.TemporalAdjuster; 25 import hunt.time.temporal.TemporalField; 26 import hunt.time.temporal.TemporalQueries; 27 import hunt.time.temporal.TemporalQuery; 28 import hunt.time.temporal.ValueRange; 29 // import hunt.time.util.Locale; 30 31 /** 32 * An era of the time-line. 33 * !(p) 34 * Most calendar systems have a single epoch dividing the time-line into two eras. 35 * However, some calendar systems, have multiple eras, such as one for the reign 36 * of each leader. 37 * In all cases, the era is conceptually the largest division of the time-line. 38 * Each chronology defines the Era's that are known Eras and a 39 * {@link Chronology#eras Chronology.eras} to get the valid eras. 40 * !(p) 41 * For example, the Thai Buddhist calendar system divides time into two eras, 42 * before and after a single date. By contrast, the Japanese calendar system 43 * has one era for the reign of each Emperor. 44 * !(p) 45 * Instances of {@code Era} may be compared using the {@code ==} operator. 46 * 47 * @implSpec 48 * This interface must be implemented with care to ensure other classes operate correctly. 49 * All implementations must be singletons - final, immutable and thread-safe. 50 * It is recommended to use an enum whenever possible. 51 * 52 * @since 1.8 53 */ 54 public interface Era : TemporalAccessor, TemporalAdjuster { 55 56 /** 57 * Gets the numeric value associated with the era as defined by the chronology. 58 * Each chronology defines the predefined Eras and methods to list the Eras 59 * of the chronology. 60 * !(p) 61 * All fields, including eras, have an associated numeric value. 62 * The meaning of the numeric value for era is determined by the chronology 63 * according to these principles: 64 * !(ul) 65 * !(li)The era _in use at the epoch 1970-01-01 (ISO) has the value 1. 66 * !(li)Later eras have sequentially higher values. 67 * !(li)Earlier eras have sequentially lower values, which may be negative. 68 * </ul> 69 * 70 * @return the numeric era value 71 */ 72 int getValue(); 73 74 //----------------------------------------------------------------------- 75 /** 76 * Checks if the specified field is supported. 77 * !(p) 78 * This checks if this era can be queried for the specified field. 79 * If false, then calling the {@link #range(TemporalField) range} and 80 * {@link #get(TemporalField) get} methods will throw an exception. 81 * !(p) 82 * If the field is a {@link ChronoField} then the query is implemented here. 83 * The {@code ERA} field returns true. 84 * All other {@code ChronoField} instances will return false. 85 * !(p) 86 * If the field is not a {@code ChronoField}, then the result of this method 87 * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)} 88 * passing {@code this} as the argument. 89 * Whether the field is supported is determined by the field. 90 * 91 * @param field the field to check, null returns false 92 * @return true if the field is supported on this era, false if not 93 */ 94 // override 95 // bool isSupported(TemporalField field) { 96 // if (cast(ChronoField)(field) !is null) { 97 // return field == ERA; 98 // } 99 // return field !is null && field.isSupportedBy(this); 100 // } 101 102 /** 103 * Gets the range of valid values for the specified field. 104 * !(p) 105 * The range object expresses the minimum and maximum valid values for a field. 106 * This era is used to enhance the accuracy of the returned range. 107 * If it is not possible to return the range, because the field is not supported 108 * or for some other reason, an exception is thrown. 109 * !(p) 110 * If the field is a {@link ChronoField} then the query is implemented here. 111 * The {@code ERA} field returns the range. 112 * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}. 113 * !(p) 114 * If the field is not a {@code ChronoField}, then the result of this method 115 * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)} 116 * passing {@code this} as the argument. 117 * Whether the range can be obtained is determined by the field. 118 * !(p) 119 * The implementation must return a range for {@code ERA} from 120 * zero to one, suitable for two era calendar systems such as ISO. 121 * 122 * @param field the field to query the range for, not null 123 * @return the range of valid values for the field, not null 124 * @throws DateTimeException if the range for the field cannot be obtained 125 * @throws UnsupportedTemporalTypeException if the unit is not supported 126 */ 127 // override // override for Javadoc 128 // ValueRange range(TemporalField field) { 129 // return /* TemporalAccessor. */super.range(field); 130 // } 131 132 /** 133 * Gets the value of the specified field from this era as an {@code int}. 134 * !(p) 135 * This queries this era for the value of the specified field. 136 * The returned value will always be within the valid range of values for the field. 137 * If it is not possible to return the value, because the field is not supported 138 * or for some other reason, an exception is thrown. 139 * !(p) 140 * If the field is a {@link ChronoField} then the query is implemented here. 141 * The {@code ERA} field returns the value of the era. 142 * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}. 143 * !(p) 144 * If the field is not a {@code ChronoField}, then the result of this method 145 * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} 146 * passing {@code this} as the argument. Whether the value can be obtained, 147 * and what the value represents, is determined by the field. 148 * 149 * @param field the field to get, not null 150 * @return the value for the field 151 * @throws DateTimeException if a value for the field cannot be obtained or 152 * the value is outside the range of valid values for the field 153 * @throws UnsupportedTemporalTypeException if the field is not supported or 154 * the range of values exceeds an {@code int} 155 * @throws ArithmeticException if numeric overflow occurs 156 */ 157 // override // override for Javadoc and performance 158 // int get(TemporalField field) { 159 // if (field == ERA) { 160 // return getValue(); 161 // } 162 // return /* TemporalAccessor. */super.get(field); 163 // } 164 165 /** 166 * Gets the value of the specified field from this era as a {@code long}. 167 * !(p) 168 * This queries this era for the value of the specified field. 169 * If it is not possible to return the value, because the field is not supported 170 * or for some other reason, an exception is thrown. 171 * !(p) 172 * If the field is a {@link ChronoField} then the query is implemented here. 173 * The {@code ERA} field returns the value of the era. 174 * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}. 175 * !(p) 176 * If the field is not a {@code ChronoField}, then the result of this method 177 * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} 178 * passing {@code this} as the argument. Whether the value can be obtained, 179 * and what the value represents, is determined by the field. 180 * 181 * @param field the field to get, not null 182 * @return the value for the field 183 * @throws DateTimeException if a value for the field cannot be obtained 184 * @throws UnsupportedTemporalTypeException if the field is not supported 185 * @throws ArithmeticException if numeric overflow occurs 186 */ 187 // override 188 // long getLong(TemporalField field) { 189 // if (field == ERA) { 190 // return getValue(); 191 // } else if (cast(ChronoField)(field) !is null) { 192 // throw new UnsupportedTemporalTypeException("Unsupported field: " ~ field); 193 // } 194 // return field.getFrom(this); 195 // } 196 197 //----------------------------------------------------------------------- 198 /** 199 * Queries this era using the specified query. 200 * !(p) 201 * This queries this era using the specified query strategy object. 202 * The {@code TemporalQuery} object defines the logic to be used to 203 * obtain the result. Read the documentation of the query to understand 204 * what the result of this method will be. 205 * !(p) 206 * The result of this method is obtained by invoking the 207 * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the 208 * specified query passing {@code this} as the argument. 209 * 210 * @param !(R) the type of the result 211 * @param query the query to invoke, not null 212 * @return the query result, null may be returned (defined by the query) 213 * @throws DateTimeException if unable to query (defined by the query) 214 * @throws ArithmeticException if numeric overflow occurs (defined by the query) 215 */ 216 /*@SuppressWarnings("unchecked")*/ 217 // override 218 R query(R)(TemporalQuery!(R) query) { 219 if (query == TemporalQueries.precision()) { 220 return cast(R) ERAS; 221 } 222 return /* TemporalAccessor. */super_query(query); 223 } 224 R super_query(R)(TemporalQuery!(R) query) { 225 if (query == TemporalQueries.zoneId() 226 || query == TemporalQueries.chronology() 227 || query == TemporalQueries.precision()) { 228 return null; 229 } 230 return query.queryFrom(this); 231 } 232 /** 233 * Adjusts the specified temporal object to have the same era as this object. 234 * !(p) 235 * This returns a temporal object of the same observable type as the input 236 * with the era changed to be the same as this. 237 * !(p) 238 * The adjustment is equivalent to using {@link Temporal#_with(TemporalField, long)} 239 * passing {@link ChronoField#ERA} as the field. 240 * !(p) 241 * In most cases, it is clearer to reverse the calling pattern by using 242 * {@link Temporal#_with(TemporalAdjuster)}: 243 * !(pre) 244 * // these two lines are equivalent, but the second approach is recommended 245 * temporal = thisEra.adjustInto(temporal); 246 * temporal = temporal._with(thisEra); 247 * </pre> 248 * !(p) 249 * This instance is immutable and unaffected by this method call. 250 * 251 * @param temporal the target object to be adjusted, not null 252 * @return the adjusted object, not null 253 * @throws DateTimeException if unable to make the adjustment 254 * @throws ArithmeticException if numeric overflow occurs 255 */ 256 // override 257 // Temporal adjustInto(Temporal temporal) { 258 // return temporal._with(ERA, getValue()); 259 // } 260 261 //----------------------------------------------------------------------- 262 /** 263 * Gets the textual representation of this era. 264 * !(p) 265 * This returns the textual name used to identify the era, 266 * suitable for presentation to the user. 267 * The parameters control the style of the returned text and the locale. 268 * !(p) 269 * If no textual mapping is found then the {@link #getValue() numeric value} is returned. 270 * 271 * @apiNote This implementation is suitable for most implementations. 272 * 273 * @param style the style of the text required, not null 274 * @param locale the locale to use, not null 275 * @return the text value of the era, not null 276 */ 277 // string getDisplayName(TextStyle style, Locale locale); 278 // string getDisplayName(TextStyle style, Locale locale) { 279 // return new DateTimeFormatterBuilder().appendText(ERA, style).toFormatter(locale).format(this); 280 // } 281 282 // NOTE: methods to convert year-of-era/proleptic-year cannot be here as they may depend on month/day (Japanese) 283 string toString(); 284 }