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 }