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.JapaneseChronology;
13 
14 // import hunt.time.temporal.ChronoField;
15 // import hunt.time.temporal.ChronoUnit;
16 
17 
18 // //import hunt.io.ObjectInputStream;
19 // import hunt.stream.Common;
20 // import hunt.time.Clock;
21 // import hunt.time.Exceptions;
22 // import hunt.time.Instant;
23 // import hunt.time.LocalDate;
24 // import hunt.time.Year;
25 // import hunt.time.ZoneId;
26 // import hunt.time.format.ResolverStyle;
27 // import hunt.time.temporal.ChronoField;
28 // import hunt.time.temporal.TemporalAccessor;
29 // import hunt.time.temporal.TemporalAdjusters;
30 // import hunt.time.temporal.TemporalField;
31 // import hunt.time.Exceptions;
32 // import hunt.time.temporal.ValueRange;
33 // import hunt.time.util.Calendar;
34 // import hunt.collection.List;
35 // // import hunt.time.util.Locale;
36 // import hunt.collection.Map;
37 // import hunt.time.chrono.AbstractChronology;
38 // import hunt.time.util.ServiceLoader;
39 // import hunt.time.chrono.JapaneseChronology;
40 // import hunt.time.chrono.Era;
41 // import hunt.time.chrono.ChronoLocalDateTime;
42 // import hunt.time.chrono.JapaneseDate;
43 // import hunt.time.chrono.JapaneseEra;
44 // // import hunt.lang;
45 // import hunt.time.chrono.chrldi
46 // // import sun.util.calendar.CalendarSystem;
47 // // import sun.util.calendar.LocalGregorianCalendar;
48 
49 // /**
50 //  * The Japanese Imperial calendar system.
51 //  * !(p)
52 //  * This chronology defines the rules of the Japanese Imperial calendar system.
53 //  * This calendar system is primarily used _in Japan.
54 //  * The Japanese Imperial calendar system is the same as the ISO calendar system
55 //  * apart from the era-based year numbering.
56 //  * !(p)
57 //  * Japan introduced the Gregorian calendar starting with Meiji 6.
58 //  * Only Meiji and later eras are supported;
59 //  * dates before Meiji 6, January 1 are not supported.
60 //  * !(p)
61 //  * The supported {@code ChronoField} instances are:
62 //  * !(ul)
63 //  * !(li){@code DAY_OF_WEEK}
64 //  * !(li){@code DAY_OF_MONTH}
65 //  * !(li){@code DAY_OF_YEAR}
66 //  * !(li){@code EPOCH_DAY}
67 //  * !(li){@code MONTH_OF_YEAR}
68 //  * !(li){@code PROLEPTIC_MONTH}
69 //  * !(li){@code YEAR_OF_ERA}
70 //  * !(li){@code YEAR}
71 //  * !(li){@code ERA}
72 //  * </ul>
73 //  *
74 //  * @implSpec
75 //  * This class is immutable and thread-safe.
76 //  *
77 //  * @since 1.8
78 //  */
79 // public final class JapaneseChronology : AbstractChronology , Serializable {
80 
81 //     mixin MakeServiceLoader!AbstractChronology;
82 
83 //     // __gshared LocalGregorianCalendar JCAL;
84 
85 //     // Locale for creating a JapaneseImpericalCalendar.
86 //     __gshared Locale LOCALE;
87 
88 //     /**
89 //      * Singleton instance for Japanese chronology.
90 //      */
91 //     public __gshared JapaneseChronology INSTANCE;
92 
93 //     /**
94 //      * Serialization version.
95 //      */
96 //     private enum long serialVersionUID = 459996390165777884L;
97 
98 //     shared static this()
99 //     {
100 //         // JCAL =
101 //         // cast(LocalGregorianCalendar) CalendarSystem.forName("japanese");
102 //         // LOCALE = Locale.forLanguageTag("ja-JP-u-ca-japanese");
103 //         // INSTANCE = new JapaneseChronology();
104 //     }
105 
106 //     //-----------------------------------------------------------------------
107 //     /**
108 //      * Restricted constructor.
109 //      */
110 //     private this() {
111 //     }
112 
113 //     //-----------------------------------------------------------------------
114 //     /**
115 //      * Gets the ID of the chronology - 'Japanese'.
116 //      * !(p)
117 //      * The ID uniquely identifies the {@code Chronology}.
118 //      * It can be used to lookup the {@code Chronology} using {@link Chronology#of(string)}.
119 //      *
120 //      * @return the chronology ID - 'Japanese'
121 //      * @see #getCalendarType()
122 //      */
123 //     // override
124 //     public string getId() {
125 //         return "Japanese";
126 //     }
127 
128 //     /**
129 //      * Gets the calendar type of the underlying calendar system - 'japanese'.
130 //      * !(p)
131 //      * The calendar type is an identifier defined by the
132 //      * !(em)Unicode Locale Data Markup Language (LDML)</em> specification.
133 //      * It can be used to lookup the {@code Chronology} using {@link Chronology#of(string)}.
134 //      * It can also be used as part of a locale, accessible via
135 //      * {@link Locale#getUnicodeLocaleType(string)} with the key 'ca'.
136 //      *
137 //      * @return the calendar system type - 'japanese'
138 //      * @see #getId()
139 //      */
140 //     // override
141 //     public string getCalendarType() {
142 //         return "japanese";
143 //     }
144 
145 //     //-----------------------------------------------------------------------
146 //     /**
147 //      * Obtains a local date _in Japanese calendar system from the
148 //      * era, year-of-era, month-of-year and day-of-month fields.
149 //      * !(p)
150 //      * The Japanese month and day-of-month are the same as those _in the
151 //      * ISO calendar system. They are not reset when the era changes.
152 //      * For example:
153 //      * !(pre)
154 //      *  6th Jan Showa 64 = ISO 1989-01-06
155 //      *  7th Jan Showa 64 = ISO 1989-01-07
156 //      *  8th Jan Heisei 1 = ISO 1989-01-08
157 //      *  9th Jan Heisei 1 = ISO 1989-01-09
158 //      * </pre>
159 //      *
160 //      * @param era  the Japanese era, not null
161 //      * @param yearOfEra  the year-of-era
162 //      * @param month  the month-of-year
163 //      * @param dayOfMonth  the day-of-month
164 //      * @return the Japanese local date, not null
165 //      * @throws DateTimeException if unable to create the date
166 //      * @throws ClassCastException if the {@code era} is not a {@code JapaneseEra}
167 //      */
168 //     override
169 //     public JapaneseDate date(Era era, int yearOfEra, int month, int dayOfMonth) {
170 //         if ((cast(JapaneseEra)(era) !is null) == false) {
171 //             throw new ClassCastException("Era must be JapaneseEra");
172 //         }
173 //         return JapaneseDate.of(cast(JapaneseEra) era, yearOfEra, month, dayOfMonth);
174 //     }
175 
176 //     /**
177 //      * Obtains a local date _in Japanese calendar system from the
178 //      * proleptic-year, month-of-year and day-of-month fields.
179 //      * !(p)
180 //      * The Japanese proleptic year, month and day-of-month are the same as those
181 //      * _in the ISO calendar system. They are not reset when the era changes.
182 //      *
183 //      * @param prolepticYear  the proleptic-year
184 //      * @param month  the month-of-year
185 //      * @param dayOfMonth  the day-of-month
186 //      * @return the Japanese local date, not null
187 //      * @throws DateTimeException if unable to create the date
188 //      */
189 //     override
190 //     public JapaneseDate date(int prolepticYear, int month, int dayOfMonth) {
191 //         return new JapaneseDate(LocalDate.of(prolepticYear, month, dayOfMonth));
192 //     }
193 
194 //     /**
195 //      * Obtains a local date _in Japanese calendar system from the
196 //      * era, year-of-era and day-of-year fields.
197 //      * !(p)
198 //      * The day-of-year _in this factory is expressed relative to the start of the year-of-era.
199 //      * This definition changes the normal meaning of day-of-year only _in those years
200 //      * where the year-of-era is reset to one due to a change _in the era.
201 //      * For example:
202 //      * !(pre)
203 //      *  6th Jan Showa 64 = day-of-year 6
204 //      *  7th Jan Showa 64 = day-of-year 7
205 //      *  8th Jan Heisei 1 = day-of-year 1
206 //      *  9th Jan Heisei 1 = day-of-year 2
207 //      * </pre>
208 //      *
209 //      * @param era  the Japanese era, not null
210 //      * @param yearOfEra  the year-of-era
211 //      * @param dayOfYear  the day-of-year
212 //      * @return the Japanese local date, not null
213 //      * @throws DateTimeException if unable to create the date
214 //      * @throws ClassCastException if the {@code era} is not a {@code JapaneseEra}
215 //      */
216 //     override
217 //     public JapaneseDate dateYearDay(Era era, int yearOfEra, int dayOfYear) {
218 //         return JapaneseDate.ofYearDay(cast(JapaneseEra) era, yearOfEra, dayOfYear);
219 //     }
220 
221 //     /**
222 //      * Obtains a local date _in Japanese calendar system from the
223 //      * proleptic-year and day-of-year fields.
224 //      * !(p)
225 //      * The day-of-year _in this factory is expressed relative to the start of the proleptic year.
226 //      * The Japanese proleptic year and day-of-year are the same as those _in the ISO calendar system.
227 //      * They are not reset when the era changes.
228 //      *
229 //      * @param prolepticYear  the proleptic-year
230 //      * @param dayOfYear  the day-of-year
231 //      * @return the Japanese local date, not null
232 //      * @throws DateTimeException if unable to create the date
233 //      */
234 //     override
235 //     public JapaneseDate dateYearDay(int prolepticYear, int dayOfYear) {
236 //         return new JapaneseDate(LocalDate.ofYearDay(prolepticYear, dayOfYear));
237 //     }
238 
239 //     /**
240 //      * Obtains a local date _in the Japanese calendar system from the epoch-day.
241 //      *
242 //      * @param epochDay  the epoch day
243 //      * @return the Japanese local date, not null
244 //      * @throws DateTimeException if unable to create the date
245 //      */
246 //     override  // override with covariant return type
247 //     public JapaneseDate dateEpochDay(long epochDay) {
248 //         return new JapaneseDate(LocalDate.ofEpochDay(epochDay));
249 //     }
250 
251 //     override
252 //     public JapaneseDate dateNow() {
253 //         return dateNow(Clock.systemDefaultZone());
254 //     }
255 
256 //     override
257 //     public JapaneseDate dateNow(ZoneId zone) {
258 //         return dateNow(Clock.system(zone));
259 //     }
260 
261 //     override
262 //     public JapaneseDate dateNow(Clock clock) {
263 //         return date(LocalDate.now(clock));
264 //     }
265 
266 //     override
267 //     public JapaneseDate date(TemporalAccessor temporal) {
268 //         if (cast(JapaneseDate)(temporal) !is null) {
269 //             return cast(JapaneseDate) temporal;
270 //         }
271 //         return new JapaneseDate(LocalDate.from(temporal));
272 //     }
273 
274 //     override
275 //     /*@SuppressWarnings("unchecked")*/
276 //     public ChronoLocalDateTime!(JapaneseDate) localDateTime(TemporalAccessor temporal) {
277 //         return cast(ChronoLocalDateTime!(JapaneseDate))super.localDateTime(temporal);
278 //     }
279 
280 //     override
281 //     /*@SuppressWarnings("unchecked")*/
282 //     public ChronoZonedDateTime!(JapaneseDate) zonedDateTime(TemporalAccessor temporal) {
283 //         return cast(ChronoZonedDateTime!(JapaneseDate))super.zonedDateTime(temporal);
284 //     }
285 
286 //     override
287 //     /*@SuppressWarnings("unchecked")*/
288 //     public ChronoZonedDateTime!(JapaneseDate) zonedDateTime(Instant instant, ZoneId zone) {
289 //         return cast(ChronoZonedDateTime!(JapaneseDate))super.zonedDateTime(instant, zone);
290 //     }
291 
292 //     //-----------------------------------------------------------------------
293 //     /**
294 //      * Checks if the specified year is a leap year.
295 //      * !(p)
296 //      * Japanese calendar leap years occur exactly _in line with ISO leap years.
297 //      * This method does not validate the year passed _in, and only has a
298 //      * well-defined result for years _in the supported range.
299 //      *
300 //      * @param prolepticYear  the proleptic-year to check, not validated for range
301 //      * @return true if the year is a leap year
302 //      */
303 //     override
304 //     public bool isLeapYear(long prolepticYear) {
305 //         return IsoChronology.INSTANCE.isLeapYear(prolepticYear);
306 //     }
307 
308 //     ///@gxc
309 //     // override
310 //     // public int prolepticYear(Era era, int yearOfEra) {
311 //     //     if ((cast(JapaneseEra)(era) !is null) == false) {
312 //     //         throw new ClassCastException("Era must be JapaneseEra");
313 //     //     }
314 
315 //     //     JapaneseEra jera = cast(JapaneseEra) era;
316 //     //     int gregorianYear = jera.getPrivateEra().getSinceDate().getYear() + yearOfEra - 1;
317 //     //     if (yearOfEra == 1) {
318 //     //         return gregorianYear;
319 //     //     }
320 //     //     if (gregorianYear >= Year.MIN_VALUE && gregorianYear <= Year.MAX_VALUE) {
321 //     //         LocalGregorianCalendar.Date jdate = JCAL.newCalendarDate(null);
322 //     //         jdate.setEra(jera.getPrivateEra()).setDate(yearOfEra, 1, 1);
323 //     //         if (JapaneseChronology.JCAL.validate(jdate)) {
324 //     //             return gregorianYear;
325 //     //         }
326 //     //     }
327 //     //     throw new DateTimeException("Invalid yearOfEra value");
328 //     // }
329 
330 //     /**
331 //      * Returns the calendar system era object from the given numeric value.
332 //      *
333 //      * See the description of each Era for the numeric values of:
334 //      * {@link JapaneseEra#HEISEI}, {@link JapaneseEra#SHOWA},{@link JapaneseEra#TAISHO},
335 //      * {@link JapaneseEra#MEIJI}), only Meiji and later eras are supported.
336 //      *
337 //      * @param eraValue  the era value
338 //      * @return the Japanese {@code Era} for the given numeric era value
339 //      * @throws DateTimeException if {@code eraValue} is invalid
340 //      */
341 //     override
342 //     public JapaneseEra eraOf(int eraValue) {
343 //         return JapaneseEra.of(eraValue);
344 //     }
345 
346 //     override
347 //     public List!(Era) eras() {
348 //         return List.of(JapaneseEra.values());
349 //     }
350 
351 //     JapaneseEra getCurrentEra() {
352 //         // Assume that the last JapaneseEra is the current one.
353 //         JapaneseEra[] eras = JapaneseEra.values();
354 //         return eras[eras.length - 1];
355 //     }
356 
357 //     //-----------------------------------------------------------------------
358 //     override
359 //     public ValueRange range(ChronoField field) {
360 //         switch (field) {
361 //             case ALIGNED_DAY_OF_WEEK_IN_MONTH:
362 //             case ALIGNED_DAY_OF_WEEK_IN_YEAR:
363 //             case ALIGNED_WEEK_OF_MONTH:
364 //             case ALIGNED_WEEK_OF_YEAR:
365 //                 throw new UnsupportedTemporalTypeException("Unsupported field: " ~ field);
366 //             case YEAR_OF_ERA: {
367 //                 Calendar jcal = Calendar.getInstance(LOCALE);
368 //                 int startYear = getCurrentEra().getPrivateEra().getSinceDate().getYear();
369 //                 return ValueRange.of(1, jcal.getGreatestMinimum(Calendar.YEAR),
370 //                         jcal.getLeastMaximum(Calendar.YEAR) + 1, // +1 due to the different definitions
371 //                         Year.MAX_VALUE - startYear);
372 //             }
373 //             case DAY_OF_YEAR: {
374 //                 Calendar jcal = Calendar.getInstance(LOCALE);
375 //                 int fieldIndex = Calendar.DAY_OF_YEAR;
376 //                 return ValueRange.of(jcal.getMinimum(fieldIndex), jcal.getGreatestMinimum(fieldIndex),
377 //                         jcal.getLeastMaximum(fieldIndex), jcal.getMaximum(fieldIndex));
378 //             }
379 //             case YEAR:
380 //                 return ValueRange.of(JapaneseDate.MEIJI_6_ISODATE.getYear(), Year.MAX_VALUE);
381 //             case ERA:
382 //                 return ValueRange.of(JapaneseEra.MEIJI.getValue(), getCurrentEra().getValue());
383 //             default:
384 //                 return field.range();
385 //         }
386 //     }
387 
388 //     //-----------------------------------------------------------------------
389 //     override  // override for return type
390 //     public JapaneseDate resolveDate(Map !(TemporalField, Long) fieldValues, ResolverStyle resolverStyle) {
391 //         return cast(JapaneseDate) super.resolveDate(fieldValues, resolverStyle);
392 //     }
393 
394 //     override  // override for special Japanese behavior
395 //     ChronoLocalDate resolveYearOfEra(Map!(TemporalField, Long) fieldValues, ResolverStyle resolverStyle) {
396 //         // validate era and year-of-era
397 //         Long eraLong = fieldValues.get(ERA);
398 //         JapaneseEra era = null;
399 //         if (eraLong !is null) {
400 //             era = eraOf(range(ERA).checkValidIntValue(eraLong, ERA));  // always validated
401 //         }
402 //         Long yoeLong = fieldValues.get(YEAR_OF_ERA);
403 //         int yoe = 0;
404 //         if (yoeLong !is null) {
405 //             yoe = range(YEAR_OF_ERA).checkValidIntValue(yoeLong, YEAR_OF_ERA);  // always validated
406 //         }
407 //         // if only year-of-era and no year then invent era unless strict
408 //         if (era is null && yoeLong !is null && fieldValues.containsKey(YEAR) == false && resolverStyle != ResolverStyle.STRICT) {
409 //             era = JapaneseEra.values()[JapaneseEra.values().length - 1];
410 //         }
411 //         // if both present, then try to create date
412 //         if (yoeLong !is null && era !is null) {
413 //             if (fieldValues.containsKey(MONTH_OF_YEAR)) {
414 //                 if (fieldValues.containsKey(DAY_OF_MONTH)) {
415 //                     return resolveYMD(era, yoe, fieldValues, resolverStyle);
416 //                 }
417 //             }
418 //             if (fieldValues.containsKey(DAY_OF_YEAR)) {
419 //                 return resolveYD(era, yoe, fieldValues, resolverStyle);
420 //             }
421 //         }
422 //         return null;
423 //     }
424 
425 //     private int prolepticYearLenient(JapaneseEra era, int yearOfEra) {
426 //         return era.getPrivateEra().getSinceDate().getYear() + yearOfEra - 1;
427 //     }
428 
429 //     private ChronoLocalDate resolveYMD(JapaneseEra era, int yoe, Map!(TemporalField,Long) fieldValues, ResolverStyle resolverStyle) {
430 //         fieldValues.remove(ERA);
431 //         fieldValues.remove(YEAR_OF_ERA);
432 //         if (resolverStyle == ResolverStyle.LENIENT) {
433 //             int y = prolepticYearLenient(era, yoe);
434 //             long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1);
435 //             long days = Math.subtractExact(fieldValues.remove(DAY_OF_MONTH), 1);
436 //             return date(y, 1, 1).plus(months, MONTHS).plus(days, DAYS);
437 //         }
438 //         int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR);
439 //         int dom = range(DAY_OF_MONTH).checkValidIntValue(fieldValues.remove(DAY_OF_MONTH), DAY_OF_MONTH);
440 //         if (resolverStyle == ResolverStyle.SMART) {  // previous valid
441 //             if (yoe < 1) {
442 //                 throw new DateTimeException("Invalid YearOfEra: " ~ yoe);
443 //             }
444 //             int y = prolepticYearLenient(era, yoe);
445 //             JapaneseDate result;
446 //             try {
447 //                 result = date(y, moy, dom);
448 //             } catch (DateTimeException ex) {
449 //                 result = date(y, moy, 1)._with(TemporalAdjusters.lastDayOfMonth());
450 //             }
451 //             // handle the era being changed
452 //             // only allow if the new date is _in the same Jan-Dec as the era change
453 //             // determine by ensuring either original yoe or result yoe is 1
454 //             if (result.getEra() != era && result.get(YEAR_OF_ERA) > 1 && yoe > 1) {
455 //                 throw new DateTimeException("Invalid YearOfEra for Era: " ~ era ~ " " ~ yoe);
456 //             }
457 //             return result;
458 //         }
459 //         return date(era, yoe, moy, dom);
460 //     }
461 
462 //     private ChronoLocalDate resolveYD(JapaneseEra era, int yoe, Map !(TemporalField,Long) fieldValues, ResolverStyle resolverStyle) {
463 //         fieldValues.remove(ERA);
464 //         fieldValues.remove(YEAR_OF_ERA);
465 //         if (resolverStyle == ResolverStyle.LENIENT) {
466 //             int y = prolepticYearLenient(era, yoe);
467 //             long days = Math.subtractExact(fieldValues.remove(DAY_OF_YEAR), 1);
468 //             return dateYearDay(y, 1).plus(days, DAYS);
469 //         }
470 //         int doy = range(DAY_OF_YEAR).checkValidIntValue(fieldValues.remove(DAY_OF_YEAR), DAY_OF_YEAR);
471 //         return dateYearDay(era, yoe, doy);  // smart is same as strict
472 //     }
473 
474 //     //-----------------------------------------------------------------------
475 //     /**
476 //      * Writes the Chronology using a
477 //      * <a href="{@docRoot}/serialized-form.html#hunt.time.chrono.Ser">dedicated serialized form</a>.
478 //      * @serialData
479 //      * !(pre)
480 //      *  _out.writeByte(1);     // identifies a Chronology
481 //      *  _out.writeUTF(getId());
482 //      * </pre>
483 //      *
484 //      * @return the instance of {@code Ser}, not null
485 //      */
486 //     override
487 //     Object writeReplace() {
488 //         return super.writeReplace();
489 //     }
490 
491 //     /**
492 //      * Defend against malicious streams.
493 //      *
494 //      * @param s the stream to read
495 //      * @throws InvalidObjectException always
496 //      */
497 //     private void readObject(ObjectInputStream s) /*throws InvalidObjectException*/ {
498 //         throw new InvalidObjectException("Deserialization via serialization delegate");
499 //     }
500 // }