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 // }