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.JulianFields;
13 
14 import hunt.time.temporal.ChronoField;
15 import hunt.time.temporal.ChronoUnit;
16 
17 import hunt.time.Exceptions;
18 import hunt.time.chrono.ChronoLocalDate;
19 import hunt.time.chrono.Chronology;
20 import hunt.time.format.ResolverStyle;
21 import hunt.collection.Map;
22 import hunt.time.temporal.TemporalField;
23 import hunt.time.temporal.TemporalUnit;
24 import hunt.time.temporal.ValueRange;
25 import hunt.time.temporal.TemporalAccessor;
26 // import hunt.lang;
27 import hunt.Assert;
28 /**
29  * A set of date fields that provide access to Julian Days.
30  * !(p)
31  * The Julian Day is a standard way of expressing date and time commonly used _in the scientific community.
32  * It is expressed as a decimal number of whole days where days start at midday.
33  * This class represents variations on Julian Days that count whole days from midnight.
34  * !(p)
35  * The fields are implemented relative to {@link ChronoField#EPOCH_DAY EPOCH_DAY}.
36  * The fields are supported, and can be queried and set if {@code EPOCH_DAY} is available.
37  * The fields work with all chronologies.
38  *
39  * @implSpec
40  * This is an immutable and thread-safe class.
41  *
42  * @since 1.8
43  */
44 // public final class JulianFields {
45 
46 //     /**
47 //      * The offset from Julian to EPOCH DAY.
48 //      */
49 //     private enum long JULIAN_DAY_OFFSET = 2440588L;
50 
51 //     /**
52 //      * Julian Day field.
53 //      * !(p)
54 //      * This is an integer-based version of the Julian Day Number.
55 //      * Julian Day is a well-known system that represents the count of whole days since day 0,
56 //      * which is defined to be January 1, 4713 BCE _in the Julian calendar, and -4713-11-24 Gregorian.
57 //      * The field  has "JulianDay" as 'name', and 'DAYS' as 'baseUnit'.
58 //      * The field always refers to the local date-time, ignoring the offset or zone.
59 //      * !(p)
60 //      * For date-times, 'JULIAN_DAY.getFrom()' assumes the same value from
61 //      * midnight until just before the next midnight.
62 //      * When 'JULIAN_DAY.adjustInto()' is applied to a date-time, the time of day portion remains unaltered.
63 //      * 'JULIAN_DAY.adjustInto()' and 'JULIAN_DAY.getFrom()' only apply to {@code Temporal} objects that
64 //      * can be converted into {@link ChronoField#EPOCH_DAY}.
65 //      * An {@link UnsupportedTemporalTypeException} is thrown for any other type of object.
66 //      * !(p)
67 //      * In the resolving phase of parsing, a date can be created from a Julian Day field.
68 //      * In {@linkplain ResolverStyle#STRICT strict mode} and {@linkplain ResolverStyle#SMART smart mode}
69 //      * the Julian Day value is validated against the _range of valid values.
70 //      * In {@linkplain ResolverStyle#LENIENT lenient mode} no validation occurs.
71 //      *
72 //      * !(h3)Astronomical and Scientific Notes</h3>
73 //      * The standard astronomical definition uses a fraction to indicate the time-of-day,
74 //      * where each day is counted from midday to midday. For example,
75 //      * a fraction of 0 represents midday, a fraction of 0.25
76 //      * represents 18:00, a fraction of 0.5 represents midnight and a fraction
77 //      * of 0.75 represents 06:00.
78 //      * !(p)
79 //      * By contrast, this implementation has no fractional part, and counts
80 //      * days from midnight to midnight.
81 //      * This implementation uses an integer and days starting at midnight.
82 //      * The integer value for the Julian Day Number is the astronomical Julian Day value at midday
83 //      * of the date _in question.
84 //      * This amounts to the astronomical Julian Day, rounded to an integer {@code JDN = floor(JD + 0.5)}.
85 //      *
86 //      * !(pre)
87 //      *  | ISO date          |  Julian Day Number | Astronomical Julian Day |
88 //      *  | 1970-01-01T00:00  |         2,440,588  |         2,440,587.5     |
89 //      *  | 1970-01-01T06:00  |         2,440,588  |         2,440,587.75    |
90 //      *  | 1970-01-01T12:00  |         2,440,588  |         2,440,588.0     |
91 //      *  | 1970-01-01T18:00  |         2,440,588  |         2,440,588.25    |
92 //      *  | 1970-01-02T00:00  |         2,440,589  |         2,440,588.5     |
93 //      *  | 1970-01-02T06:00  |         2,440,589  |         2,440,588.75    |
94 //      *  | 1970-01-02T12:00  |         2,440,589  |         2,440,589.0     |
95 //      * </pre>
96 //      * !(p)
97 //      * Julian Days are sometimes taken to imply Universal Time or UTC, but this
98 //      * implementation always uses the Julian Day number for the local date,
99 //      * regardless of the offset or time-zone.
100 //      */
101 //     public __gshared TemporalField JULIAN_DAY;
102 
103 //     /**
104 //      * Modified Julian Day field.
105 //      * !(p)
106 //      * This is an integer-based version of the Modified Julian Day Number.
107 //      * Modified Julian Day (MJD) is a well-known system that counts days continuously.
108 //      * It is defined relative to astronomical Julian Day as  {@code MJD = JD - 2400000.5}.
109 //      * Each Modified Julian Day runs from midnight to midnight.
110 //      * The field always refers to the local date-time, ignoring the offset or zone.
111 //      * !(p)
112 //      * For date-times, 'MODIFIED_JULIAN_DAY.getFrom()' assumes the same value from
113 //      * midnight until just before the next midnight.
114 //      * When 'MODIFIED_JULIAN_DAY.adjustInto()' is applied to a date-time, the time of day portion remains unaltered.
115 //      * 'MODIFIED_JULIAN_DAY.adjustInto()' and 'MODIFIED_JULIAN_DAY.getFrom()' only apply to {@code Temporal} objects
116 //      * that can be converted into {@link ChronoField#EPOCH_DAY}.
117 //      * An {@link UnsupportedTemporalTypeException} is thrown for any other type of object.
118 //      * !(p)
119 //      * This implementation is an integer version of MJD with the decimal part rounded to floor.
120 //      * !(p)
121 //      * In the resolving phase of parsing, a date can be created from a Modified Julian Day field.
122 //      * In {@linkplain ResolverStyle#STRICT strict mode} and {@linkplain ResolverStyle#SMART smart mode}
123 //      * the Modified Julian Day value is validated against the _range of valid values.
124 //      * In {@linkplain ResolverStyle#LENIENT lenient mode} no validation occurs.
125 //      *
126 //      * !(h3)Astronomical and Scientific Notes</h3>
127 //      * !(pre)
128 //      *  | ISO date          | Modified Julian Day |      Decimal MJD |
129 //      *  | 1970-01-01T00:00  |             40,587  |       40,587.0   |
130 //      *  | 1970-01-01T06:00  |             40,587  |       40,587.25  |
131 //      *  | 1970-01-01T12:00  |             40,587  |       40,587.5   |
132 //      *  | 1970-01-01T18:00  |             40,587  |       40,587.75  |
133 //      *  | 1970-01-02T00:00  |             40,588  |       40,588.0   |
134 //      *  | 1970-01-02T06:00  |             40,588  |       40,588.25  |
135 //      *  | 1970-01-02T12:00  |             40,588  |       40,588.5   |
136 //      * </pre>
137 //      *
138 //      * Modified Julian Days are sometimes taken to imply Universal Time or UTC, but this
139 //      * implementation always uses the Modified Julian Day for the local date,
140 //      * regardless of the offset or time-zone.
141 //      */
142 //     public __gshared TemporalField MODIFIED_JULIAN_DAY;
143 
144 //     /**
145 //      * Rata Die field.
146 //      * !(p)
147 //      * Rata Die counts whole days continuously starting day 1 at midnight at the beginning of 0001-01-01 (ISO).
148 //      * The field always refers to the local date-time, ignoring the offset or zone.
149 //      * !(p)
150 //      * For date-times, 'RATA_DIE.getFrom()' assumes the same value from
151 //      * midnight until just before the next midnight.
152 //      * When 'RATA_DIE.adjustInto()' is applied to a date-time, the time of day portion remains unaltered.
153 //      * 'RATA_DIE.adjustInto()' and 'RATA_DIE.getFrom()' only apply to {@code Temporal} objects
154 //      * that can be converted into {@link ChronoField#EPOCH_DAY}.
155 //      * An {@link UnsupportedTemporalTypeException} is thrown for any other type of object.
156 //      * !(p)
157 //      * In the resolving phase of parsing, a date can be created from a Rata Die field.
158 //      * In {@linkplain ResolverStyle#STRICT strict mode} and {@linkplain ResolverStyle#SMART smart mode}
159 //      * the Rata Die value is validated against the _range of valid values.
160 //      * In {@linkplain ResolverStyle#LENIENT lenient mode} no validation occurs.
161 //      */
162 //     public __gshared TemporalField RATA_DIE;
163 
164 //     shared static this()
165 //     {
166 //         JULIAN_DAY = Field.JULIAN_DAY;
167 //         MODIFIED_JULIAN_DAY = Field.MODIFIED_JULIAN_DAY;
168 //         RATA_DIE = Field.RATA_DIE;
169 //     }
170 
171 //     /**
172 //      * Restricted constructor.
173 //      */
174 //     private this() {
175 //         throw new AssertionError("Not instantiable");
176 //     }
177 
178 //     /**
179 //      * Implementation of JulianFields.  Each instance is a singleton.
180 //      */
181 //     private static class Field : TemporalField {
182 //         static Field JULIAN_DAY;
183 //         static Field MODIFIED_JULIAN_DAY;
184 //         static Field RATA_DIE;
185 
186 //         static this()
187 //         {
188 //              JULIAN_DAY = new Field("JulianDay", ChronoUnit.DAYS, ChronoUnit.FOREVER, JULIAN_DAY_OFFSET);
189 //              MODIFIED_JULIAN_DAY = new Field("ModifiedJulianDay", ChronoUnit.DAYS, ChronoUnit.FOREVER, 40587L);
190 //              RATA_DIE = new Field("RataDie", ChronoUnit.DAYS, ChronoUnit.FOREVER, 719163L);
191 //         }
192 
193 //         private  /*transient*/ string name;
194 //         private  /*transient*/ TemporalUnit baseUnit;
195 //         private  /*transient*/ TemporalUnit rangeUnit;
196 //         private  /*transient*/ ValueRange _range;
197 //         private  /*transient*/ long offset;
198 
199 //         private this(string name, TemporalUnit baseUnit, TemporalUnit rangeUnit, long offset) {
200 //             this.name = name;
201 //             this.baseUnit = baseUnit;
202 //             this.rangeUnit = rangeUnit;
203 //             this._range = ValueRange.of(-365243219162L + offset, 365241780471L + offset);
204 //             this.offset = offset;
205 //         }
206 
207 //         //-----------------------------------------------------------------------
208 //         override
209 //         public TemporalUnit getBaseUnit() {
210 //             return baseUnit;
211 //         }
212 
213 //         override
214 //         public TemporalUnit getRangeUnit() {
215 //             return rangeUnit;
216 //         }
217 
218 //         override
219 //         public bool isDateBased() {
220 //             return true;
221 //         }
222 
223 //         override
224 //         public bool isTimeBased() {
225 //             return false;
226 //         }
227 
228 //         // override
229 //         public ValueRange range() {
230 //             return _range;
231 //         }
232 
233 //         //-----------------------------------------------------------------------
234 //         override
235 //         public bool isSupportedBy(TemporalAccessor temporal) {
236 //             return temporal.isSupported(ChronoField.EPOCH_DAY);
237 //         }
238 
239 //         override
240 //         public ValueRange rangeRefinedBy(TemporalAccessor temporal) {
241 //             if (isSupportedBy(temporal) == false) {
242 //                 throw new DateTimeException("Unsupported field: " ~ this.toString);
243 //             }
244 //             return range();
245 //         }
246 
247 //         override
248 //         public long getFrom(TemporalAccessor temporal) {
249 //             return temporal.getLong(ChronoField.EPOCH_DAY) + offset;
250 //         }
251 
252 //         /*@SuppressWarnings("unchecked")*/
253 //         override
254 //         public  R adjustInto(R)(R temporal, long newValue) if(is(R : Temporal)) {
255 //             if (range().isValidValue(newValue) == false) {
256 //                 throw new DateTimeException("Invalid value: " ~ name ~ " " ~ newValue);
257 //             }
258 //             return cast(R) temporal._with(EPOCH_DAY, Math.subtractExact(newValue, offset));
259 //         }
260 
261 //         //-----------------------------------------------------------------------
262 //         override
263 //         public ChronoLocalDate resolve(
264 //                 Map!(TemporalField, Long) fieldValues, TemporalAccessor partialTemporal, ResolverStyle resolverStyle) {
265 //             long value = fieldValues.remove(this).longValue();
266 //             Chronology chrono = Chronology.from(partialTemporal);
267 //             if (resolverStyle == ResolverStyle.LENIENT) {
268 //                 return chrono.dateEpochDay(Math.subtractExact(value, offset));
269 //             }
270 //             range().checkValidValue(value, this);
271 //             return chrono.dateEpochDay(value - offset);
272 //         }
273 
274 //         //-----------------------------------------------------------------------
275 //         override
276 //         public string toString() {
277 //             return name;
278 //         }
279 //     }
280 // }