1 2 /* 3 * hunt-time: A time library for D programming language. 4 * 5 * Copyright (C) 2015-2018 HuntLabs 6 * 7 * Website: https://www.huntlabs.net/ 8 * 9 * Licensed under the Apache-2.0 License. 10 * 11 */ 12 13 module hunt.time.chrono.HijrahChronology; 14 15 // import hunt.time.temporal.ChronoField; 16 17 // // import hunt.io.FilePermission; 18 // import hunt.stream.Common; 19 20 // //import hunt.io.ObjectInputStream; 21 // import hunt.stream.Common; 22 // // import hunt.security.AccessController; 23 // // import hunt.security.PrivilegedAction; 24 // import hunt.time.Clock; 25 // import hunt.time.Exceptions; 26 // import hunt.time.Instant; 27 // import hunt.time.LocalDate; 28 // import hunt.time.ZoneId; 29 // import hunt.time.format.ResolverStyle; 30 // import hunt.time.temporal.ChronoField; 31 // import hunt.time.temporal.TemporalAccessor; 32 // import hunt.time.temporal.TemporalField; 33 // import hunt.time.temporal.ValueRange; 34 // import hunt.time.util; 35 // //import hunt.concurrent.ConcurrentMap;; 36 37 // import hunt.collection.List; 38 // import hunt.collection.Map; 39 // // import hunt.util.Properties; 40 41 // // import sun.util.logging.PlatformLogger; 42 43 // /** 44 // * The Hijrah calendar is a lunar calendar supporting Islamic calendars. 45 // * !(p) 46 // * The HijrahChronology follows the rules of the Hijrah calendar system. The Hijrah 47 // * calendar has several variants based on differences _in when the new moon is 48 // * determined to have occurred and where the observation is made. 49 // * In some variants the length of each month is 50 // * computed algorithmically from the astronomical data for the moon and earth and 51 // * _in others the length of the month is determined by an authorized sighting 52 // * of the new moon. For the algorithmically based calendars the calendar 53 // * can project into the future. 54 // * For sighting based calendars only historical data from past 55 // * sightings is available. 56 // * !(p) 57 // * The length of each month is 29 or 30 days. 58 // * Ordinary years have 354 days; leap years have 355 days. 59 // * 60 // * !(p) 61 // * CLDR and LDML identify variants: 62 // * <table class="striped" style="text-align:left"> 63 // * <caption style="display:none">Variants of Hijrah Calendars</caption> 64 // * !(thead) 65 // * !(tr) 66 // * <th scope="col">Chronology ID</th> 67 // * <th scope="col">Calendar Type</th> 68 // * <th scope="col">Locale extension, see {@link java.util.Locale}</th> 69 // * <th scope="col">Description</th> 70 // * </tr> 71 // * </thead> 72 // * !(tbody) 73 // * !(tr) 74 // * <th scope="row">Hijrah-umalqura</th> 75 // * !(td)islamic-umalqura</td> 76 // * !(td)ca-islamic-umalqura</td> 77 // * !(td)Islamic - Umm Al-Qura calendar of Saudi Arabia</td> 78 // * </tr> 79 // * </tbody> 80 // * </table> 81 // * !(p)Additional variants may be available through {@link Chronology#getAvailableChronologies()}. 82 // * 83 // * !(p)Example</p> 84 // * !(p) 85 // * Selecting the chronology from the locale uses {@link Chronology#ofLocale} 86 // * to find the Chronology based on Locale supported BCP 47 extension mechanism 87 // * to request a specific calendar ("ca"). For example, 88 // * </p> 89 // * !(pre) 90 // * Locale locale = Locale.forLanguageTag("en-US-u-ca-islamic-umalqura"); 91 // * Chronology chrono = Chronology.ofLocale(locale); 92 // * </pre> 93 // * 94 // * @implSpec 95 // * This class is immutable and thread-safe. 96 // * 97 // * @implNote 98 // * Each Hijrah variant is configured individually. Each variant is defined by a 99 // * property resource that defines the {@code ID}, the {@code calendar type}, 100 // * the start of the calendar, the alignment with the 101 // * ISO calendar, and the length of each month for a range of years. 102 // * The variants are loaded by HijrahChronology as a resource from 103 // * hijrah-config-<calendar type>.properties. 104 // * !(p) 105 // * The Hijrah property resource is a set of properties that describe the calendar. 106 // * The syntax is defined by {@code java.util.Properties#load(Reader)}. 107 // * <table class="striped" style="text-align:left"> 108 // * <caption style="display:none">Configuration of Hijrah Calendar</caption> 109 // * !(thead) 110 // * !(tr) 111 // * <th scope="col">Property Name</th> 112 // * <th scope="col">Property value</th> 113 // * <th scope="col">Description</th> 114 // * </tr> 115 // * </thead> 116 // * !(tbody) 117 // * !(tr) 118 // * <th scope="row">id</th> 119 // * !(td)Chronology Id, for example, "Hijrah-umalqura"</td> 120 // * !(td)The Id of the calendar _in common usage</td> 121 // * </tr> 122 // * !(tr) 123 // * <th scope="row">type</th> 124 // * !(td)Calendar type, for example, "islamic-umalqura"</td> 125 // * !(td)LDML defines the calendar types</td> 126 // * </tr> 127 // * !(tr) 128 // * <th scope="row">_version</th> 129 // * !(td)Version, for example: "1.8.0_1"</td> 130 // * !(td)The _version of the Hijrah variant data</td> 131 // * </tr> 132 // * !(tr) 133 // * <th scope="row">iso-start</th> 134 // * !(td)ISO start date, formatted as {@code yyyy-MM-dd}, for example: "1900-04-30"</td> 135 // * !(td)The ISO date of the first day of the minimum Hijrah year.</td> 136 // * </tr> 137 // * !(tr) 138 // * <th scope="row">yyyy - a numeric 4 digit year, for example "1434"</th> 139 // * !(td)The value is a sequence of 12 month lengths, 140 // * for example: "29 30 29 30 29 30 30 30 29 30 29 29"</td> 141 // * !(td)The lengths of the 12 months of the year separated by whitespace. 142 // * A numeric year property must be present for every year without any gaps. 143 // * The month lengths must be between 29-32 inclusive. 144 // * </td> 145 // * </tr> 146 // * </tbody> 147 // * </table> 148 // * 149 // * @since 1.8 150 // */ 151 // public final class HijrahChronology : AbstractChronology , Serializable { 152 153 // mixin MakeServiceLoader!AbstractChronology; 154 // /** 155 // * The Hijrah Calendar id. 156 // */ 157 // private final /*transient*/ string typeId; 158 // /** 159 // * The Hijrah calendarType. 160 // */ 161 // private final /*transient*/ string calendarType; 162 // /** 163 // * Serialization _version. 164 // */ 165 // private static final long serialVersionUID = 3127340209035924785L; 166 // /** 167 // * Singleton instance of the Islamic Umm Al-Qura calendar of Saudi Arabia. 168 // * Other Hijrah chronology variants may be available from 169 // * {@link Chronology#getAvailableChronologies}. 170 // */ 171 // public static final HijrahChronology INSTANCE; 172 // /** 173 // * Flag to indicate the initialization of configuration data is complete. 174 // * @see #checkCalendarInit() 175 // */ 176 // private /*transient*/ /* volatile */ bool initComplete; 177 // /** 178 // * Array of epoch days indexed by Hijrah Epoch month. 179 // * Computed by {@link #loadCalendarData}. 180 // */ 181 // private /*transient*/ int[] hijrahEpochMonthStartDays; 182 // /** 183 // * The minimum epoch day of this Hijrah calendar. 184 // * Computed by {@link #loadCalendarData}. 185 // */ 186 // private /*transient*/ int minEpochDay; 187 // /** 188 // * The maximum epoch day for which calendar data is available. 189 // * Computed by {@link #loadCalendarData}. 190 // */ 191 // private /*transient*/ int maxEpochDay; 192 // /** 193 // * The minimum epoch month. 194 // * Computed by {@link #loadCalendarData}. 195 // */ 196 // private /*transient*/ int hijrahStartEpochMonth; 197 // /** 198 // * The minimum length of a month. 199 // * Computed by {@link #createEpochMonths}. 200 // */ 201 // private /*transient*/ int minMonthLength; 202 // /** 203 // * The maximum length of a month. 204 // * Computed by {@link #createEpochMonths}. 205 // */ 206 // private /*transient*/ int maxMonthLength; 207 // /** 208 // * The minimum length of a year _in days. 209 // * Computed by {@link #createEpochMonths}. 210 // */ 211 // private /*transient*/ int minYearLength; 212 // /** 213 // * The maximum length of a year _in days. 214 // * Computed by {@link #createEpochMonths}. 215 // */ 216 // private /*transient*/ int maxYearLength; 217 218 // /** 219 // * Prefix of resource names for Hijrah calendar variants. 220 // */ 221 // private static final string RESOURCE_PREFIX = "hijrah-config-"; 222 223 // /** 224 // * Suffix of resource names for Hijrah calendar variants. 225 // */ 226 // private static final string RESOURCE_SUFFIX = ".properties"; 227 228 // /** 229 // * Static initialization of the built-_in calendars. 230 // * The data is not loaded until it is used. 231 // */ 232 // static this(){ 233 // INSTANCE = new HijrahChronology("Hijrah-umalqura", "islamic-umalqura"); 234 // // Register it by its aliases 235 // AbstractChronology.registerChrono(INSTANCE, "Hijrah"); 236 // AbstractChronology.registerChrono(INSTANCE, "islamic"); 237 // } 238 239 // /** 240 // * Create a HijrahChronology for the named variant and type. 241 // * 242 // * @param id the id of the calendar 243 // * @param calType the typeId of the calendar 244 // * @throws IllegalArgumentException if the id or typeId is empty 245 // */ 246 // private this(string id, string calType) { 247 // if (id.isEmpty()) { 248 // throw new IllegalArgumentException("calendar id is empty"); 249 // } 250 // if (calType.isEmpty()) { 251 // throw new IllegalArgumentException("calendar typeId is empty"); 252 // } 253 // this.typeId = id; 254 // this.calendarType = calType; 255 // } 256 257 // /** 258 // * Check and ensure that the calendar data has been initialized. 259 // * The initialization check is performed at the boundary between 260 // * public and package methods. If a public calls another public method 261 // * a check is not necessary _in the caller. 262 // * The constructors of HijrahDate call {@link #getEpochDay} or 263 // * {@link #getHijrahDateInfo} so every call from HijrahDate to a 264 // * HijrahChronology via package private methods has been checked. 265 // * 266 // * @throws DateTimeException if the calendar data configuration is 267 // * malformed or IOExceptions occur loading the data 268 // */ 269 // private void checkCalendarInit() { 270 // // Keep this short so it can be inlined for performance 271 // if (initComplete == false) { 272 // loadCalendarData(); 273 // initComplete = true; 274 // } 275 // } 276 277 // //----------------------------------------------------------------------- 278 // /** 279 // * Gets the ID of the chronology. 280 // * !(p) 281 // * The ID uniquely identifies the {@code Chronology}. It can be used to 282 // * lookup the {@code Chronology} using {@link Chronology#of(string)}. 283 // * 284 // * @return the chronology ID, non-null 285 // * @see #getCalendarType() 286 // */ 287 // override 288 // public string getId() { 289 // return typeId; 290 // } 291 292 // /** 293 // * Gets the calendar type of the Islamic calendar. 294 // * !(p) 295 // * The calendar type is an identifier defined by the 296 // * !(em)Unicode Locale Data Markup Language (LDML)</em> specification. 297 // * It can be used to lookup the {@code Chronology} using {@link Chronology#of(string)}. 298 // * 299 // * @return the calendar system type; non-null if the calendar has 300 // * a standard type, otherwise null 301 // * @see #getId() 302 // */ 303 // override 304 // public string getCalendarType() { 305 // return calendarType; 306 // } 307 308 // //----------------------------------------------------------------------- 309 // /** 310 // * Obtains a local date _in Hijrah calendar system from the 311 // * era, year-of-era, month-of-year and day-of-month fields. 312 // * 313 // * @param era the Hijrah era, not null 314 // * @param yearOfEra the year-of-era 315 // * @param month the month-of-year 316 // * @param dayOfMonth the day-of-month 317 // * @return the Hijrah local date, not null 318 // * @throws DateTimeException if unable to create the date 319 // * @throws ClassCastException if the {@code era} is not a {@code HijrahEra} 320 // */ 321 // override 322 // public HijrahDate date(Era era, int yearOfEra, int month, int dayOfMonth) { 323 // return date(prolepticYear(era, yearOfEra), month, dayOfMonth); 324 // } 325 326 // /** 327 // * Obtains a local date _in Hijrah calendar system from the 328 // * proleptic-year, month-of-year and day-of-month fields. 329 // * 330 // * @param prolepticYear the proleptic-year 331 // * @param month the month-of-year 332 // * @param dayOfMonth the day-of-month 333 // * @return the Hijrah local date, not null 334 // * @throws DateTimeException if unable to create the date 335 // */ 336 // override 337 // public HijrahDate date(int prolepticYear, int month, int dayOfMonth) { 338 // return HijrahDate.of(this, prolepticYear, month, dayOfMonth); 339 // } 340 341 // /** 342 // * Obtains a local date _in Hijrah calendar system from the 343 // * era, year-of-era and day-of-year fields. 344 // * 345 // * @param era the Hijrah era, not null 346 // * @param yearOfEra the year-of-era 347 // * @param dayOfYear the day-of-year 348 // * @return the Hijrah local date, not null 349 // * @throws DateTimeException if unable to create the date 350 // * @throws ClassCastException if the {@code era} is not a {@code HijrahEra} 351 // */ 352 // override 353 // public HijrahDate dateYearDay(Era era, int yearOfEra, int dayOfYear) { 354 // return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear); 355 // } 356 357 // /** 358 // * Obtains a local date _in Hijrah calendar system from the 359 // * proleptic-year and day-of-year fields. 360 // * 361 // * @param prolepticYear the proleptic-year 362 // * @param dayOfYear the day-of-year 363 // * @return the Hijrah local date, not null 364 // * @throws DateTimeException if the value of the year is _out of range, 365 // * or if the day-of-year is invalid for the year 366 // */ 367 // override 368 // public HijrahDate dateYearDay(int prolepticYear, int dayOfYear) { 369 // HijrahDate date = HijrahDate.of(this, prolepticYear, 1, 1); 370 // if (dayOfYear > date.lengthOfYear()) { 371 // throw new DateTimeException("Invalid dayOfYear: " ~ dayOfYear); 372 // } 373 // return date.plusDays(dayOfYear - 1); 374 // } 375 376 // /** 377 // * Obtains a local date _in the Hijrah calendar system from the epoch-day. 378 // * 379 // * @param epochDay the epoch day 380 // * @return the Hijrah local date, not null 381 // * @throws DateTimeException if unable to create the date 382 // */ 383 // override // override with covariant return type 384 // public HijrahDate dateEpochDay(long epochDay) { 385 // return HijrahDate.ofEpochDay(this, epochDay); 386 // } 387 388 // override 389 // public HijrahDate dateNow() { 390 // return dateNow(Clock.systemDefaultZone()); 391 // } 392 393 // override 394 // public HijrahDate dateNow(ZoneId zone) { 395 // return dateNow(Clock.system(zone)); 396 // } 397 398 // override 399 // public HijrahDate dateNow(Clock clock) { 400 // return date(LocalDate.now(clock)); 401 // } 402 403 // override 404 // public HijrahDate date(TemporalAccessor temporal) { 405 // if (cast(HijrahDate)(temporal) !is null) { 406 // return cast(HijrahDate) temporal; 407 // } 408 // return HijrahDate.ofEpochDay(this, temporal.getLong(EPOCH_DAY)); 409 // } 410 411 // override 412 // /*@SuppressWarnings("unchecked")*/ 413 // public ChronoLocalDateTime!(HijrahDate) localDateTime(TemporalAccessor temporal) { 414 // return cast(ChronoLocalDateTime!(HijrahDate)) super.localDateTime(temporal); 415 // } 416 417 // override 418 // /*@SuppressWarnings("unchecked")*/ 419 // public ChronoZonedDateTime!(HijrahDate) zonedDateTime(TemporalAccessor temporal) { 420 // return cast(ChronoZonedDateTime!(HijrahDate)) super.zonedDateTime(temporal); 421 // } 422 423 // override 424 // /*@SuppressWarnings("unchecked")*/ 425 // public ChronoZonedDateTime!(HijrahDate) zonedDateTime(Instant instant, ZoneId zone) { 426 // return cast(ChronoZonedDateTime!(HijrahDate)) super.zonedDateTime(instant, zone); 427 // } 428 429 // //----------------------------------------------------------------------- 430 // override 431 // public bool isLeapYear(long prolepticYear) { 432 // checkCalendarInit(); 433 // if (prolepticYear < getMinimumYear() || prolepticYear > getMaximumYear()) { 434 // return false; 435 // } 436 // int len = getYearLength(cast(int) prolepticYear); 437 // return (len > 354); 438 // } 439 440 // override 441 // public int prolepticYear(Era era, int yearOfEra) { 442 // if ((cast(HijrahEra)(era) !is null) == false) { 443 // throw new ClassCastException("Era must be HijrahEra"); 444 // } 445 // return yearOfEra; 446 // } 447 448 // /** 449 // * Creates the HijrahEra object from the numeric value. 450 // * The Hijrah calendar system has only one era covering the 451 // * proleptic years greater than zero. 452 // * This method returns the singleton HijrahEra for the value 1. 453 // * 454 // * @param eraValue the era value 455 // * @return the calendar system era, not null 456 // * @throws DateTimeException if unable to create the era 457 // */ 458 // override 459 // public HijrahEra eraOf(int eraValue) { 460 // switch (eraValue) { 461 // case 1: 462 // return HijrahEra.AH; 463 // default: 464 // throw new DateTimeException("invalid Hijrah era"); 465 // } 466 // } 467 468 // override 469 // public List!(Era) eras() { 470 // return List.of(HijrahEra.values()); 471 // } 472 473 // //----------------------------------------------------------------------- 474 // override 475 // public ValueRange range(ChronoField field) { 476 // checkCalendarInit(); 477 // if (cast(ChronoField)(field) !is null) { 478 // ChronoField f = field; 479 // switch (f) { 480 // case DAY_OF_MONTH: 481 // return ValueRange.of(1, 1, getMinimumMonthLength(), getMaximumMonthLength()); 482 // case DAY_OF_YEAR: 483 // return ValueRange.of(1, getMaximumDayOfYear()); 484 // case ALIGNED_WEEK_OF_MONTH: 485 // return ValueRange.of(1, 5); 486 // case YEAR: 487 // case YEAR_OF_ERA: 488 // return ValueRange.of(getMinimumYear(), getMaximumYear()); 489 // case ERA: 490 // return ValueRange.of(1, 1); 491 // default: 492 // return field.range(); 493 // } 494 // } 495 // return field.range(); 496 // } 497 498 // //----------------------------------------------------------------------- 499 // override // override for return type 500 // public HijrahDate resolveDate(Map!(TemporalField, Long) fieldValues, ResolverStyle resolverStyle) { 501 // return cast(HijrahDate) super.resolveDate(fieldValues, resolverStyle); 502 // } 503 504 // //----------------------------------------------------------------------- 505 // /** 506 // * Check the validity of a year. 507 // * 508 // * @param prolepticYear the year to check 509 // */ 510 // int checkValidYear(long prolepticYear) { 511 // if (prolepticYear < getMinimumYear() || prolepticYear > getMaximumYear()) { 512 // throw new DateTimeException("Invalid Hijrah year: " ~ prolepticYear); 513 // } 514 // return cast(int) prolepticYear; 515 // } 516 517 // void checkValidDayOfYear(int dayOfYear) { 518 // if (dayOfYear < 1 || dayOfYear > getMaximumDayOfYear()) { 519 // throw new DateTimeException("Invalid Hijrah day of year: " ~ dayOfYear); 520 // } 521 // } 522 523 // void checkValidMonth(int month) { 524 // if (month < 1 || month > 12) { 525 // throw new DateTimeException("Invalid Hijrah month: " ~ month); 526 // } 527 // } 528 529 // //----------------------------------------------------------------------- 530 // /** 531 // * Returns an array containing the Hijrah year, month and day 532 // * computed from the epoch day. 533 // * 534 // * @param epochDay the EpochDay 535 // * @return int[0] = YEAR, int[1] = MONTH, int[2] = DATE 536 // */ 537 // int[] getHijrahDateInfo(int epochDay) { 538 // checkCalendarInit(); // ensure that the chronology is initialized 539 // if (epochDay < minEpochDay || epochDay >= maxEpochDay) { 540 // throw new DateTimeException("Hijrah date _out of range"); 541 // } 542 543 // int epochMonth = epochDayToEpochMonth(epochDay); 544 // int year = epochMonthToYear(epochMonth); 545 // int month = epochMonthToMonth(epochMonth); 546 // int day1 = epochMonthToEpochDay(epochMonth); 547 // int date = epochDay - day1; // epochDay - dayOfEpoch(year, month); 548 549 // int[] dateInfo = new int[3]; 550 // dateInfo[0] = year; 551 // dateInfo[1] = month + 1; // change to 1-based. 552 // dateInfo[2] = date + 1; // change to 1-based. 553 // return dateInfo; 554 // } 555 556 // /** 557 // * Return the epoch day computed from Hijrah year, month, and day. 558 // * 559 // * @param prolepticYear the year to represent, 0-origin 560 // * @param monthOfYear the month-of-year to represent, 1-origin 561 // * @param dayOfMonth the day-of-month to represent, 1-origin 562 // * @return the epoch day 563 // */ 564 // long getEpochDay(int prolepticYear, int monthOfYear, int dayOfMonth) { 565 // checkCalendarInit(); // ensure that the chronology is initialized 566 // checkValidMonth(monthOfYear); 567 // int epochMonth = yearToEpochMonth(prolepticYear) + (monthOfYear - 1); 568 // if (epochMonth < 0 || epochMonth >= hijrahEpochMonthStartDays.length) { 569 // throw new DateTimeException("Invalid Hijrah date, year: " ~ 570 // prolepticYear + ", month: " ~ monthOfYear); 571 // } 572 // if (dayOfMonth < 1 || dayOfMonth > getMonthLength(prolepticYear, monthOfYear)) { 573 // throw new DateTimeException("Invalid Hijrah day of month: " ~ dayOfMonth); 574 // } 575 // return epochMonthToEpochDay(epochMonth) + (dayOfMonth - 1); 576 // } 577 578 // /** 579 // * Returns day of year for the year and month. 580 // * 581 // * @param prolepticYear a proleptic year 582 // * @param month a month, 1-origin 583 // * @return the day of year, 1-origin 584 // */ 585 // int getDayOfYear(int prolepticYear, int month) { 586 // return yearMonthToDayOfYear(prolepticYear, (month - 1)); 587 // } 588 589 // /** 590 // * Returns month length for the year and month. 591 // * 592 // * @param prolepticYear a proleptic year 593 // * @param monthOfYear a month, 1-origin. 594 // * @return the length of the month 595 // */ 596 // int getMonthLength(int prolepticYear, int monthOfYear) { 597 // int epochMonth = yearToEpochMonth(prolepticYear) + (monthOfYear - 1); 598 // if (epochMonth < 0 || epochMonth >= hijrahEpochMonthStartDays.length) { 599 // throw new DateTimeException("Invalid Hijrah date, year: " ~ 600 // prolepticYear + ", month: " ~ monthOfYear); 601 // } 602 // return epochMonthLength(epochMonth); 603 // } 604 605 // /** 606 // * Returns year length. 607 // * Note: The 12th month must exist _in the data. 608 // * 609 // * @param prolepticYear a proleptic year 610 // * @return year length _in days 611 // */ 612 // int getYearLength(int prolepticYear) { 613 // return yearMonthToDayOfYear(prolepticYear, 12); 614 // } 615 616 // /** 617 // * Return the minimum supported Hijrah year. 618 // * 619 // * @return the minimum 620 // */ 621 // int getMinimumYear() { 622 // return epochMonthToYear(0); 623 // } 624 625 // /** 626 // * Return the maximum supported Hijrah year. 627 // * 628 // * @return the minimum 629 // */ 630 // int getMaximumYear() { 631 // return epochMonthToYear(hijrahEpochMonthStartDays.length - 1) - 1; 632 // } 633 634 // /** 635 // * Returns maximum day-of-month. 636 // * 637 // * @return maximum day-of-month 638 // */ 639 // int getMaximumMonthLength() { 640 // return maxMonthLength; 641 // } 642 643 // /** 644 // * Returns smallest maximum day-of-month. 645 // * 646 // * @return smallest maximum day-of-month 647 // */ 648 // int getMinimumMonthLength() { 649 // return minMonthLength; 650 // } 651 652 // /** 653 // * Returns maximum day-of-year. 654 // * 655 // * @return maximum day-of-year 656 // */ 657 // int getMaximumDayOfYear() { 658 // return maxYearLength; 659 // } 660 661 // /** 662 // * Returns smallest maximum day-of-year. 663 // * 664 // * @return smallest maximum day-of-year 665 // */ 666 // int getSmallestMaximumDayOfYear() { 667 // return minYearLength; 668 // } 669 670 // /** 671 // * Returns the epochMonth found by locating the epochDay _in the table. The 672 // * epochMonth is the index _in the table 673 // * 674 // * @param epochDay 675 // * @return The index of the element of the start of the month containing the 676 // * epochDay. 677 // */ 678 // private int epochDayToEpochMonth(int epochDay) { 679 // // binary search 680 // int ndx = Arrays.binarySearch(hijrahEpochMonthStartDays, epochDay); 681 // if (ndx < 0) { 682 // ndx = -ndx - 2; 683 // } 684 // return ndx; 685 // } 686 687 // /** 688 // * Returns the year computed from the epochMonth 689 // * 690 // * @param epochMonth the epochMonth 691 // * @return the Hijrah Year 692 // */ 693 // private int epochMonthToYear(int epochMonth) { 694 // return (epochMonth + hijrahStartEpochMonth) / 12; 695 // } 696 697 // /** 698 // * Returns the epochMonth for the Hijrah Year. 699 // * 700 // * @param year the HijrahYear 701 // * @return the epochMonth for the beginning of the year. 702 // */ 703 // private int yearToEpochMonth(int year) { 704 // return (year * 12) - hijrahStartEpochMonth; 705 // } 706 707 // /** 708 // * Returns the Hijrah month from the epochMonth. 709 // * 710 // * @param epochMonth the epochMonth 711 // * @return the month of the Hijrah Year 712 // */ 713 // private int epochMonthToMonth(int epochMonth) { 714 // return (epochMonth + hijrahStartEpochMonth) % 12; 715 // } 716 717 // /** 718 // * Returns the epochDay for the start of the epochMonth. 719 // * 720 // * @param epochMonth the epochMonth 721 // * @return the epochDay for the start of the epochMonth. 722 // */ 723 // private int epochMonthToEpochDay(int epochMonth) { 724 // return hijrahEpochMonthStartDays[epochMonth]; 725 726 // } 727 728 // /** 729 // * Returns the day of year for the requested HijrahYear and month. 730 // * 731 // * @param prolepticYear the Hijrah year 732 // * @param month the Hijrah month 733 // * @return the day of year for the start of the month of the year 734 // */ 735 // private int yearMonthToDayOfYear(int prolepticYear, int month) { 736 // int epochMonthFirst = yearToEpochMonth(prolepticYear); 737 // return epochMonthToEpochDay(epochMonthFirst + month) 738 // - epochMonthToEpochDay(epochMonthFirst); 739 // } 740 741 // /** 742 // * Returns the length of the epochMonth. It is computed from the start of 743 // * the following month minus the start of the requested month. 744 // * 745 // * @param epochMonth the epochMonth; assumed to be within range 746 // * @return the length _in days of the epochMonth 747 // */ 748 // private int epochMonthLength(int epochMonth) { 749 // // The very last entry _in the epochMonth table is not the start of a month 750 // return hijrahEpochMonthStartDays[epochMonth + 1] 751 // - hijrahEpochMonthStartDays[epochMonth]; 752 // } 753 754 // //----------------------------------------------------------------------- 755 // private static final string KEY_ID = "id"; 756 // private static final string KEY_TYPE = "type"; 757 // private static final string KEY_VERSION = "_version"; 758 // private static final string KEY_ISO_START = "iso-start"; 759 760 // /** 761 // * Return the configuration properties from the resource. 762 // * !(p) 763 // * The location of the variant configuration resource is: 764 // * !(pre) 765 // * "/java/time/chrono/hijrah-config-" ~ calendarType ~ ".properties" 766 // * </pre> 767 // * 768 // * @param calendarType the calendarType of the calendar variant 769 // * @return a Properties containing the properties read from the resource. 770 // * @throws Exception if access to the property resource fails 771 // */ 772 // private Properties readConfigProperties(final string calendarType) /* throws Exception */ { 773 // // string resourceName = RESOURCE_PREFIX + calendarType + RESOURCE_SUFFIX; 774 // // PrivilegedAction!(InputStream) getResourceAction = () -> HijrahChronology.class.getResourceAsStream(resourceName); 775 // // FilePermission perm1 = new FilePermission("<!(ALL FILES)>", "read"); 776 // // RuntimePermission perm2 = new RuntimePermission("accessSystemModules"); 777 // // try (InputStream is = AccessController.doPrivileged(getResourceAction, null, perm1, perm2)) { 778 // // if (is is null) { 779 // // throw new RuntimeException("Hijrah calendar resource not found: /java/time/chrono/" ~ resourceName); 780 // // } 781 // // Properties props = new Properties(); 782 // // props.load(is); 783 // // return props; 784 // // } 785 // implementationMissing(false); 786 // return null; 787 // } 788 789 // /** 790 // * Loads and processes the Hijrah calendar properties file for this calendarType. 791 // * The starting Hijrah date and the corresponding ISO date are 792 // * extracted and used to calculate the epochDate offset. 793 // * The _version number is identified and ignored. 794 // * Everything else is the data for a year with containing the length of each 795 // * of 12 months. 796 // * 797 // * @throws DateTimeException if initialization of the calendar data from the 798 // * resource fails 799 // */ 800 // private void loadCalendarData() { 801 // try { 802 // Properties props = readConfigProperties(calendarType); 803 804 // Map!(Integer, int[]) years = new HashMap!(Integer, int[])(); 805 // int minYear = Integer.MAX_VALUE; 806 // int maxYear = Integer.MIN_VALUE; 807 // string id = null; 808 // string type = null; 809 // string _version = null; 810 // int isoStart = 0; 811 // foreach(Map.Entry!(Object, Object) entry ; props.entrySet()) { 812 // string key = cast(string) entry.getKey(); 813 // switch (key) { 814 // case KEY_ID: 815 // id = cast(string)entry.getValue(); 816 // break; 817 // case KEY_TYPE: 818 // type = cast(string)entry.getValue(); 819 // break; 820 // case KEY_VERSION: 821 // _version = cast(string)entry.getValue(); 822 // break; 823 // case KEY_ISO_START: { 824 // int[] ymd = parseYMD(cast(string) entry.getValue()); 825 // isoStart = cast(int) LocalDate.of(ymd[0], ymd[1], ymd[2]).toEpochDay(); 826 // break; 827 // } 828 // default: 829 // try { 830 // // Everything else is either a year or invalid 831 // int year = Integer.parseInt(key); 832 // int[] months = parseMonths(cast(string) entry.getValue()); 833 // years.put(year, months); 834 // maxYear = Math.max(maxYear, year); 835 // minYear = Math.min(minYear, year); 836 // } catch (NumberFormatException nfe) { 837 // throw new IllegalArgumentException("bad key: " ~ key); 838 // } 839 // } 840 // } 841 842 // if (!getId().equals(id)) { 843 // throw new IllegalArgumentException("Configuration is for a different calendar: " ~ id); 844 // } 845 // if (!getCalendarType().equals(type)) { 846 // throw new IllegalArgumentException("Configuration is for a different calendar type: " ~ type); 847 // } 848 // if (_version is null || _version.isEmpty()) { 849 // throw new IllegalArgumentException("Configuration does not contain a _version"); 850 // } 851 // if (isoStart == 0) { 852 // throw new IllegalArgumentException("Configuration does not contain a ISO start date"); 853 // } 854 855 // // Now create and validate the array of epochDays indexed by epochMonth 856 // hijrahStartEpochMonth = minYear * 12; 857 // minEpochDay = isoStart; 858 // hijrahEpochMonthStartDays = createEpochMonths(minEpochDay, minYear, maxYear, years); 859 // maxEpochDay = hijrahEpochMonthStartDays[hijrahEpochMonthStartDays.length - 1]; 860 861 // // Compute the min and max year length _in days. 862 // for (int year = minYear; year < maxYear; year++) { 863 // int length = getYearLength(year); 864 // minYearLength = Math.min(minYearLength, length); 865 // maxYearLength = Math.max(maxYearLength, length); 866 // } 867 // } catch (Exception ex) { 868 // // Log error and throw a DateTimeException 869 // PlatformLogger logger = PlatformLogger.getLogger("hunt.time.chrono"); 870 // logger.severe("Unable to initialize Hijrah calendar proxy: " ~ typeId, ex); 871 // throw new DateTimeException("Unable to initialize HijrahCalendar: " ~ typeId, ex); 872 // } 873 // } 874 875 // /** 876 // * Converts the map of year to month lengths ranging from minYear to maxYear 877 // * into a linear contiguous array of epochDays. The index is the hijrahMonth 878 // * computed from year and month and offset by minYear. The value of each 879 // * entry is the epochDay corresponding to the first day of the month. 880 // * 881 // * @param minYear The minimum year for which data is provided 882 // * @param maxYear The maximum year for which data is provided 883 // * @param years a Map of year to the array of 12 month lengths 884 // * @return array of epochDays for each month from min to max 885 // */ 886 // private int[] createEpochMonths(int epochDay, int minYear, int maxYear, Map!(Integer, int[]) years) { 887 // // Compute the size for the array of dates 888 // int numMonths = (maxYear - minYear + 1) * 12 + 1; 889 890 // // Initialize the running epochDay as the corresponding ISO Epoch day 891 // int epochMonth = 0; // index into array of epochMonths 892 // int[] epochMonths = new int[numMonths]; 893 // minMonthLength = Integer.MAX_VALUE; 894 // maxMonthLength = Integer.MIN_VALUE; 895 896 // // Only whole years are valid, any zero's _in the array are illegal 897 // for (int year = minYear; year <= maxYear; year++) { 898 // int[] months = years.get(year);// must not be gaps 899 // for (int month = 0; month < 12; month++) { 900 // int length = months[month]; 901 // epochMonths[epochMonth++] = epochDay; 902 903 // if (length < 29 || length > 32) { 904 // throw new IllegalArgumentException("Invalid month length _in year: " ~ minYear); 905 // } 906 // epochDay += length; 907 // minMonthLength = Math.min(minMonthLength, length); 908 // maxMonthLength = Math.max(maxMonthLength, length); 909 // } 910 // } 911 912 // // Insert the final epochDay 913 // epochMonths[epochMonth++] = epochDay; 914 915 // if (epochMonth != epochMonths.length) { 916 // throw new IllegalStateException("Did not fill epochMonths exactly: ndx = " ~ epochMonth 917 // ~ " should be " ~ epochMonths.length); 918 // } 919 920 // return epochMonths; 921 // } 922 923 // /** 924 // * Parses the 12 months lengths from a property value for a specific year. 925 // * 926 // * @param line the value of a year property 927 // * @return an array of int[12] containing the 12 month lengths 928 // * @throws IllegalArgumentException if the number of months is not 12 929 // * @throws NumberFormatException if the 12 tokens are not numbers 930 // */ 931 // private int[] parseMonths(string line) { 932 // int[] months = new int[12]; 933 // string[] numbers = line.split("\\s"); 934 // if (numbers.length != 12) { 935 // throw new IllegalArgumentException("wrong number of months on line: " ~ Arrays.toString(numbers) ~ "; count: " ~ numbers.length); 936 // } 937 // for (int i = 0; i < 12; i++) { 938 // try { 939 // months[i] = Integer.parseInt(numbers[i]); 940 // } catch (NumberFormatException nfe) { 941 // throw new IllegalArgumentException("bad key: " ~ numbers[i]); 942 // } 943 // } 944 // return months; 945 // } 946 947 // /** 948 // * Parse yyyy-MM-dd into a 3 element array [yyyy, mm, dd]. 949 // * 950 // * @param string the input string 951 // * @return the 3 element array with year, month, day 952 // */ 953 // private int[] parseYMD(string string) { 954 // // yyyy-MM-dd 955 // string = string.trim(); 956 // try { 957 // if (string[4] != '-' || string[7] != '-') { 958 // throw new IllegalArgumentException("date must be yyyy-MM-dd"); 959 // } 960 // int[] ymd = new int[3]; 961 // ymd[0] = Integer.parseInt(string, 0, 4, 10); 962 // ymd[1] = Integer.parseInt(string, 5, 7, 10); 963 // ymd[2] = Integer.parseInt(string, 8, 10, 10); 964 // return ymd; 965 // } catch (NumberFormatException ex) { 966 // throw new IllegalArgumentException("date must be yyyy-MM-dd", ex); 967 // } 968 // } 969 970 // //----------------------------------------------------------------------- 971 // /** 972 // * Writes the Chronology using a 973 // * <a href="{@docRoot}/serialized-form.html#hunt.time.chrono.Ser">dedicated serialized form</a>. 974 // * @serialData 975 // * !(pre) 976 // * _out.writeByte(1); // identifies a Chronology 977 // * _out.writeUTF(getId()); 978 // * </pre> 979 // * 980 // * @return the instance of {@code Ser}, not null 981 // */ 982 // override 983 // Object writeReplace() { 984 // return super.writeReplace(); 985 // } 986 987 // /** 988 // * Defend against malicious streams. 989 // * 990 // * @param s the stream to read 991 // * @throws InvalidObjectException always 992 // */ 993 // private void readObject(ObjectInputStream s) /*throws InvalidObjectException*/ { 994 // throw new InvalidObjectException("Deserialization via serialization delegate"); 995 // } 996 // }