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.ChronoUnit;
13 
14 import hunt.time.Duration;
15 import hunt.time.temporal.TemporalUnit;
16 import hunt.time.temporal.Temporal;
17 import hunt.time.temporal.TemporalField;
18 import hunt.time.temporal.ValueRange;
19 
20 import hunt.Exceptions;
21 import hunt.Enum;
22 import hunt.Long;
23 import hunt.time.util.Common;
24 import hunt.util.Comparator;
25 
26 import std.concurrency : initOnce;
27 
28 /**
29  * A standard set of date periods units.
30  * !(p)
31  * This set of units provide unit-based access to manipulate a date, time or date-time.
32  * The standard set of units can be extended by implementing {@link TemporalUnit}.
33  * !(p)
34  * These units are intended to be applicable _in multiple calendar systems.
35  * For example, most non-ISO calendar systems define units of years, months and days,
36  * just with slightly different rules.
37  * The documentation of each unit explains how it operates.
38  *
39  * @implSpec
40  * This is a final, immutable and thread-safe enum.
41  *
42  * @since 1.8
43  */
44 class ChronoUnit : TemporalUnit
45 {
46 
47     /**
48      * Unit that represents the concept of a nanosecond, the smallest supported unit of time.
49      * For the ISO calendar system, it is equal to the 1,000,000,000th part of the second unit.
50      */
51     static ChronoUnit NANOS() {
52         __gshared ChronoUnit _NANOS;
53         return initOnce!(_NANOS)(new ChronoUnit("Nanos", 0, Duration.ofNanos(1)));
54     }
55 
56     /**
57      * Unit that represents the concept of a microsecond.
58      * For the ISO calendar system, it is equal to the 1,000,000th part of the second unit.
59      */
60     static ChronoUnit MICROS() {
61         __gshared ChronoUnit _MICROS;
62         return initOnce!(_MICROS)(new ChronoUnit("Micros", 1, Duration.ofNanos(1000)));
63     }
64 
65     /**
66      * Unit that represents the concept of a millisecond.
67      * For the ISO calendar system, it is equal to the 1000th part of the second unit.
68      */
69     static ChronoUnit MILLIS() {
70         __gshared ChronoUnit _MILLIS;
71         return initOnce!(_MILLIS)(new ChronoUnit("Millis", 2, Duration.ofNanos(1000_000)));
72     }
73 
74     /**
75      * Unit that represents the concept of a second.
76      * For the ISO calendar system, it is equal to the second _in the SI system
77      * of units, except around a leap-second.
78      */
79     static ChronoUnit SECONDS() {
80         __gshared ChronoUnit _SECONDS;
81         return initOnce!(_SECONDS)(new ChronoUnit("Seconds", 3, Duration.ofSeconds(1)));
82     }
83 
84     /**
85      * Unit that represents the concept of a minute.
86      * For the ISO calendar system, it is equal to 60 seconds.
87      */
88     static ChronoUnit MINUTES() {
89         __gshared ChronoUnit _MINUTES;
90         return initOnce!(_MINUTES)(new ChronoUnit("Minutes", 4, Duration.ofSeconds(60)));
91     }
92 
93     /**
94      * Unit that represents the concept of an hour.
95      * For the ISO calendar system, it is equal to 60 minutes.
96      */
97     static ChronoUnit HOURS() {
98         __gshared ChronoUnit _HOURS;
99         return initOnce!(_HOURS)(new ChronoUnit("Hours", 5, Duration.ofSeconds(3600)));
100     }
101 
102     /**
103      * Unit that represents the concept of half a day, as used _in AM/PM.
104      * For the ISO calendar system, it is equal to 12 hours.
105      */
106     static ChronoUnit HALF_DAYS() {
107         __gshared ChronoUnit _HALF_DAYS;
108         return initOnce!(_HALF_DAYS)(new ChronoUnit("HalfDays", 6, Duration.ofSeconds(43200)));
109     }
110 
111     /**
112      * Unit that represents the concept of a day.
113      * For the ISO calendar system, it is the standard day from midnight to midnight.
114      * The estimated duration of a day is {@code 24 Hours}.
115      * !(p)
116      * When used with other calendar systems it must correspond to the day defined by
117      * the rising and setting of the Sun on Earth. It is not required that days begin
118      * at midnight - when converting between calendar systems, the date should be
119      * equivalent at midday.
120      */
121     static ChronoUnit DAYS() {
122         __gshared ChronoUnit _DAYS;
123         return initOnce!(_DAYS)(new ChronoUnit("Days", 7, Duration.ofSeconds(86400)));
124     }
125 
126     /**
127      * Unit that represents the concept of a week.
128      * For the ISO calendar system, it is equal to 7 days.
129      * !(p)
130      * When used with other calendar systems it must correspond to an integral number of days.
131      */
132     static ChronoUnit WEEKS() {
133         __gshared ChronoUnit _WEEKS;
134         return initOnce!(_WEEKS)(new ChronoUnit("Weeks", 8, Duration.ofSeconds(7 * 86400L)));
135     }
136 
137     /**
138      * Unit that represents the concept of a month.
139      * For the ISO calendar system, the length of the month varies by month-of-year.
140      * The estimated duration of a month is one twelfth of {@code 365.2425 Days}.
141      * !(p)
142      * When used with other calendar systems it must correspond to an integral number of days.
143      */
144     static ChronoUnit MONTHS() {
145         __gshared ChronoUnit _MONTHS;
146         return initOnce!(_MONTHS)(new ChronoUnit("Months", 9, Duration.ofSeconds(31556952L / 12)));
147     }
148 
149     /**
150      * Unit that represents the concept of a year.
151      * For the ISO calendar system, it is equal to 12 months.
152      * The estimated duration of a year is {@code 365.2425 Days}.
153      * !(p)
154      * When used with other calendar systems it must correspond to an integral number of days
155      * or months roughly equal to a year defined by the passage of the Earth around the Sun.
156      */
157     static ChronoUnit YEARS() {
158         __gshared ChronoUnit _YEARS;
159         return initOnce!(_YEARS)(new ChronoUnit("Years", 10, Duration.ofSeconds(31556952L)));
160     }
161 
162     /**
163      * Unit that represents the concept of a decade.
164      * For the ISO calendar system, it is equal to 10 years.
165      * !(p)
166      * When used with other calendar systems it must correspond to an integral number of days
167      * and is normally an integral number of years.
168      */
169     static ChronoUnit DECADES() {
170         __gshared ChronoUnit _DECADES;
171         return initOnce!(_DECADES)(new ChronoUnit("Decades", 11, Duration.ofSeconds(31556952L * 10L)));
172     }
173 
174     /**
175      * Unit that represents the concept of a century.
176      * For the ISO calendar system, it is equal to 100 years.
177      * !(p)
178      * When used with other calendar systems it must correspond to an integral number of days
179      * and is normally an integral number of years.
180      */
181     static ChronoUnit CENTURIES() {
182         __gshared ChronoUnit _CENTURIES;
183         return initOnce!(_CENTURIES)(new ChronoUnit("Centuries", 12, Duration.ofSeconds(31556952L * 100L)));
184     }
185 
186     /**
187      * Unit that represents the concept of a millennium.
188      * For the ISO calendar system, it is equal to 1000 years.
189      * !(p)
190      * When used with other calendar systems it must correspond to an integral number of days
191      * and is normally an integral number of years.
192      */
193     static ChronoUnit MILLENNIA() {
194         __gshared ChronoUnit _MILLENNIA;
195         return initOnce!(_MILLENNIA)(new ChronoUnit("Millennia", 13, Duration.ofSeconds(31556952L * 1000L)));
196     }
197 
198     /**
199      * Unit that represents the concept of an era.
200      * The ISO calendar system doesn't have eras thus it is impossible to add
201      * an era to a date or date-time.
202      * The estimated duration of the era is artificially defined as {@code 1,000,000,000 Years}.
203      * !(p)
204      * When used with other calendar systems there are no restrictions on the unit.
205      */
206     static ChronoUnit ERAS() {
207         __gshared ChronoUnit _ERAS;
208         return initOnce!(_ERAS)(new ChronoUnit("Eras", 14, Duration.ofSeconds(31556952L * 1000_000_000L)));
209     }
210 
211     /**
212      * Artificial unit that represents the concept of forever.
213      * This is primarily used with {@link TemporalField} to represent unbounded fields
214      * such as the year or era.
215      * The estimated duration of this unit is artificially defined as the largest duration
216      * supported by {@link Duration}.
217      */
218     static ChronoUnit FOREVER() {
219         __gshared ChronoUnit _FOREVER;
220         return initOnce!(_FOREVER)(new ChronoUnit("Forever", 15, Duration.ofSeconds(Long.MAX_VALUE, 999_999_999)));
221     }
222 
223 
224     private Duration duration;
225 
226     protected this(string name, int ordinal,  Duration estimatedDuration)
227     {
228         super(name, ordinal);
229         this.duration = estimatedDuration;
230     }
231 
232 
233     //-----------------------------------------------------------------------
234     /**
235      * Gets the estimated duration of this unit _in the ISO calendar system.
236      * !(p)
237      * All of the units _in this class have an estimated duration.
238      * Days vary due to daylight saving time, while months have different lengths.
239      *
240      * @return the estimated duration of this unit, not null
241      */
242     override Duration getDuration()
243     {
244         return duration;
245     }
246 
247     /**
248      * Checks if the duration of the unit is an estimate.
249      * !(p)
250      * All time units _in this class are considered to be accurate, while all date
251      * units _in this class are considered to be estimated.
252      * !(p)
253      * This definition ignores leap seconds, but considers that Days vary due to
254      * daylight saving time and months have different lengths.
255      *
256      * @return true if the duration is estimated, false if accurate
257      */
258     override bool isDurationEstimated()
259     {
260         return this.opCmp(DAYS) >= 0;
261     }
262 
263     //-----------------------------------------------------------------------
264     /**
265      * Checks if this unit is a date unit.
266      * !(p)
267      * All units from days to eras inclusive are date-based.
268      * Time-based units and {@code FOREVER} return false.
269      *
270      * @return true if a date unit, false if a time unit
271      */
272     override bool isDateBased()
273     {
274         return this.opCmp(DAYS) >= 0 && this != FOREVER;
275     }
276 
277     /**
278      * Checks if this unit is a time unit.
279      * !(p)
280      * All units from nanos to half-days inclusive are time-based.
281      * Date-based units and {@code FOREVER} return false.
282      *
283      * @return true if a time unit, false if a date unit
284      */
285     override bool isTimeBased()
286     {
287         return this.opCmp(DAYS) < 0;
288     }
289 
290     //-----------------------------------------------------------------------
291     override bool isSupportedBy(Temporal temporal)
292     {
293         return temporal.isSupported(this);
294     }
295 
296     /*@SuppressWarnings("unchecked")*/
297     override Temporal addTo(Temporal temporal, long amount) /* if(is(R : Temporal)) */
298     {
299         return cast(Temporal) temporal.plus(amount, this);
300     }
301 
302     //-----------------------------------------------------------------------
303     override long between(Temporal temporal1Inclusive, Temporal temporal2Exclusive)
304     {
305         return temporal1Inclusive.until(temporal2Exclusive, this);
306     }
307 
308     //-----------------------------------------------------------------------
309     // override string toString()
310     // {
311     //     return name;
312     // }
313 
314     // bool opEquals(ref const ChronoUnit h) nothrow
315     // {
316     //     return name == h.name;
317     // }
318 
319     // override bool opEquals(Object obj)
320     // {
321     //     if (this is obj)
322     //     {
323     //         return true;
324     //     }
325     //     if (cast(ChronoUnit)(obj) !is null)
326     //     {
327     //         ChronoUnit other = cast(ChronoUnit) obj;
328     //         return name == other.name;
329     //     }
330     //     return false;
331     // }
332 
333     // int compareTo(ChronoUnit obj)
334     // {
335     //     return compare(this.name, obj.name);
336     // }
337 }