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