jdk/src/share/classes/java/time/chrono/HijrahDate.java
changeset 16852 60207b2b4b42
parent 15658 55b829ca2334
child 17474 8c100beabcc0
--- a/jdk/src/share/classes/java/time/chrono/HijrahDate.java	Thu Apr 11 19:15:24 2013 -0700
+++ b/jdk/src/share/classes/java/time/chrono/HijrahDate.java	Fri Apr 12 07:57:35 2013 -0700
@@ -70,55 +70,38 @@
 import java.io.Serializable;
 import java.time.Clock;
 import java.time.DateTimeException;
-import java.time.DayOfWeek;
 import java.time.LocalDate;
 import java.time.LocalTime;
 import java.time.Period;
 import java.time.ZoneId;
 import java.time.temporal.ChronoField;
-import java.time.temporal.TemporalQuery;
 import java.time.temporal.TemporalAccessor;
 import java.time.temporal.TemporalAdjuster;
 import java.time.temporal.TemporalAmount;
 import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQuery;
 import java.time.temporal.TemporalUnit;
+import java.time.temporal.UnsupportedTemporalTypeException;
 import java.time.temporal.ValueRange;
-import java.util.Objects;
 
 /**
  * A date in the Hijrah calendar system.
  * <p>
- * This date operates using the {@linkplain HijrahChronology Hijrah calendar}.
+ * This date operates using one of several variants of the
+ * {@linkplain HijrahChronology Hijrah calendar}.
  * <p>
  * The Hijrah calendar has a different total of days in a year than
- * Gregorian calendar, and a month is based on the period of a complete
- * revolution of the moon around the earth (as between successive new moons).
- * The calendar cycles becomes longer and unstable, and sometimes a manual
- * adjustment (for entering deviation) is necessary for correctness
- * because of the complex algorithm.
+ * Gregorian calendar, and the length of each month is based on the period
+ * of a complete revolution of the moon around the earth
+ * (as between successive new moons).
+ * Refer to the {@link HijrahChronology} for details of supported variants.
  * <p>
- * HijrahDate supports the manual adjustment feature by providing a configuration
- * file. The configuration file contains the adjustment (deviation) data with following format.
- * <pre>
- *   StartYear/StartMonth(0-based)-EndYear/EndMonth(0-based):Deviation day (1, 2, -1, or -2)
- *   Line separator or ";" is used for the separator of each deviation data.</pre>
- *   Here is the example.
- * <pre>
- *     1429/0-1429/1:1
- *     1429/2-1429/7:1;1429/6-1429/11:1
- *     1429/11-9999/11:1</pre>
- * The default location of the configuration file is:
- * <pre>
- *   $CLASSPATH/java/time/i18n</pre>
- * And the default file name is:
- * <pre>
- *   hijrah_deviation.cfg</pre>
- * The default location and file name can be overriden by setting
- * following two Java's system property.
- * <pre>
- *   Location: java.time.i18n.HijrahDate.deviationConfigDir
- *   File name: java.time.i18n.HijrahDate.deviationConfigFile</pre>
- *
+ * Each HijrahDate is created bound to a particular HijrahChronology,
+ * The same chronology is propagated to each HijrahDate computed from the date.
+ * To use a different Hijrah variant, its HijrahChronology can be used
+ * to create new HijrahDate instances.
+ * Alternatively, the {@link #withVariant} method can be used to convert
+ * to a new HijrahChronology.
  * <h3>Specification for implementors</h3>
  * This class is immutable and thread-safe.
  *
@@ -132,19 +115,14 @@
      * Serialization version.
      */
     private static final long serialVersionUID = -5207853542612002020L;
-
     /**
      * The Chronology of this HijrahDate.
      */
     private final HijrahChronology chrono;
     /**
-     * The era.
+     * The proleptic year.
      */
-    private final transient HijrahEra era;
-    /**
-     * The year.
-     */
-    private final transient int yearOfEra;
+    private final transient int prolepticYear;
     /**
      * The month-of-year.
      */
@@ -153,69 +131,36 @@
      * The day-of-month.
      */
     private final transient int dayOfMonth;
-    /**
-     * The day-of-year.
-     */
-    private final transient int dayOfYear;
-    /**
-     * The day-of-week.
-     */
-    private final transient DayOfWeek dayOfWeek;
-    /**
-     * Gregorian days for this object. Holding number of days since 1970/01/01.
-     * The number of days are calculated with pure Gregorian calendar
-     * based.
-     */
-    private final long gregorianEpochDay;
-    /**
-     * True if year is leap year.
-     */
-    private final transient boolean isLeapYear;
 
     //-------------------------------------------------------------------------
     /**
-     * Obtains an instance of {@code HijrahDate} from the Hijrah era year,
-     * month-of-year and day-of-month. This uses the Hijrah era.
+     * Obtains an instance of {@code HijrahDate} from the Hijrah proleptic year,
+     * month-of-year and day-of-month.
      *
-     * @param prolepticYear  the proleptic year to represent in the Hijrah
+     * @param prolepticYear  the proleptic year to represent in the Hijrah calendar
      * @param monthOfYear  the month-of-year to represent, from 1 to 12
      * @param dayOfMonth  the day-of-month to represent, from 1 to 30
      * @return the Hijrah date, never null
      * @throws DateTimeException if the value of any field is out of range
      */
     static HijrahDate of(HijrahChronology chrono, int prolepticYear, int monthOfYear, int dayOfMonth) {
-        return (prolepticYear >= 1) ?
-            HijrahDate.of(chrono, HijrahEra.AH, prolepticYear, monthOfYear, dayOfMonth) :
-            HijrahDate.of(chrono, HijrahEra.BEFORE_AH, 1 - prolepticYear, monthOfYear, dayOfMonth);
+        return new HijrahDate(chrono, prolepticYear, monthOfYear, dayOfMonth);
     }
 
     /**
-     * Obtains an instance of {@code HijrahDate} from the era, year-of-era
-     * month-of-year and day-of-month.
-     *
-     * @param era  the era to represent, not null
-     * @param yearOfEra  the year-of-era to represent, from 1 to 9999
-     * @param monthOfYear  the month-of-year to represent, from 1 to 12
-     * @param dayOfMonth  the day-of-month to represent, from 1 to 31
-     * @return the Hijrah date, never null
-     * @throws DateTimeException if the value of any field is out of range
+     * Returns a HijrahDate for the chronology and epochDay.
+     * @param chrono The Hijrah chronology
+     * @param epochDay the epoch day
+     * @return a HijrahDate for the epoch day; non-null
      */
-    private static HijrahDate of(HijrahChronology chrono, HijrahEra era, int yearOfEra, int monthOfYear, int dayOfMonth) {
-        Objects.requireNonNull(era, "era");
-        chrono.checkValidYearOfEra(yearOfEra);
-        chrono.checkValidMonth(monthOfYear);
-        chrono.checkValidDayOfMonth(dayOfMonth);
-        long gregorianDays = chrono.getGregorianEpochDay(era.prolepticYear(yearOfEra), monthOfYear, dayOfMonth);
-        return new HijrahDate(chrono, gregorianDays);
-    }
-
     static HijrahDate ofEpochDay(HijrahChronology chrono, long epochDay) {
         return new HijrahDate(chrono, epochDay);
     }
 
     //-----------------------------------------------------------------------
     /**
-     * Obtains the current {@code HijrahDate} from the system clock in the default time-zone.
+     * Obtains the current {@code HijrahDate} of the Islamic Umm Al-Qura calendar
+     * in the default time-zone.
      * <p>
      * This will query the {@link Clock#systemDefaultZone() system clock} in the default
      * time-zone to obtain the current date.
@@ -230,7 +175,8 @@
     }
 
     /**
-     * Obtains the current {@code HijrahDate} from the system clock in the specified time-zone.
+     * Obtains the current {@code HijrahDate} of the Islamic Umm Al-Qura calendar
+     * in the specified time-zone.
      * <p>
      * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date.
      * Specifying the time-zone avoids dependence on the default time-zone.
@@ -246,7 +192,8 @@
     }
 
     /**
-     * Obtains the current {@code HijrahDate} from the specified clock.
+     * Obtains the current {@code HijrahDate} of the Islamic Umm Al-Qura calendar
+     * from the specified clock.
      * <p>
      * This will query the specified clock to obtain the current date - today.
      * Using this method allows the use of an alternate clock for testing.
@@ -261,8 +208,8 @@
     }
 
     /**
-     * Obtains a {@code HijrahDate} representing a date in the Hijrah calendar
-     * system from the proleptic-year, month-of-year and day-of-month fields.
+     * Obtains a {@code HijrahDate} of the Islamic Umm Al-Qura calendar
+     * from the proleptic-year, month-of-year and day-of-month fields.
      * <p>
      * This returns a {@code HijrahDate} with the specified fields.
      * The day must be valid for the year and month, otherwise an exception will be thrown.
@@ -279,7 +226,7 @@
     }
 
     /**
-     * Obtains a {@code HijrahDate} from a temporal object.
+     * Obtains a {@code HijrahDate} of the Islamic Umm Al-Qura calendar from a temporal object.
      * <p>
      * This obtains a date in the Hijrah calendar system based on the specified temporal.
      * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
@@ -301,35 +248,93 @@
 
     //-----------------------------------------------------------------------
     /**
-     * Constructs an instance with the specified date.
+     * Constructs an {@code HijrahDate} with the proleptic-year, month-of-year and
+     * day-of-month fields.
      *
-     * @param gregorianDay  the number of days from 0001/01/01 (Gregorian), caller calculated
+     * @param chrono The chronology to create the date with
+     * @param prolepticYear the proleptic year
+     * @param monthOfYear the month of year
+     * @param dayOfMonth the day of month
      */
-    private HijrahDate(HijrahChronology chrono, long gregorianDay) {
-        this.chrono = chrono;
-        int[] dateInfo = chrono.getHijrahDateInfo(gregorianDay);
+    private HijrahDate(HijrahChronology chrono, int prolepticYear, int monthOfYear, int dayOfMonth) {
+        // Computing the Gregorian day checks the valid ranges
+        chrono.getEpochDay(prolepticYear, monthOfYear, dayOfMonth);
 
-        chrono.checkValidYearOfEra(dateInfo[1]);
-        chrono.checkValidMonth(dateInfo[2]);
-        chrono.checkValidDayOfMonth(dateInfo[3]);
-        chrono.checkValidDayOfYear(dateInfo[4]);
+        this.chrono = chrono;
+        this.prolepticYear = prolepticYear;
+        this.monthOfYear = monthOfYear;
+        this.dayOfMonth = dayOfMonth;
+    }
 
-        this.era = HijrahEra.of(dateInfo[0]);
-        this.yearOfEra = dateInfo[1];
-        this.monthOfYear = dateInfo[2];
-        this.dayOfMonth = dateInfo[3];
-        this.dayOfYear = dateInfo[4];
-        this.dayOfWeek = DayOfWeek.of(dateInfo[5]);
-        this.gregorianEpochDay = gregorianDay;
-        this.isLeapYear = chrono.isLeapYear(this.yearOfEra);
+    /**
+     * Constructs an instance with the Epoch Day.
+     *
+     * @param epochDay  the epochDay
+     */
+    private HijrahDate(HijrahChronology chrono, long epochDay) {
+        int[] dateInfo = chrono.getHijrahDateInfo((int)epochDay);
+
+        this.chrono = chrono;
+        this.prolepticYear = dateInfo[0];
+        this.monthOfYear = dateInfo[1];
+        this.dayOfMonth = dateInfo[2];
     }
 
     //-----------------------------------------------------------------------
+    /**
+     * Gets the chronology of this date, which is the Hijrah calendar system.
+     * <p>
+     * The {@code Chronology} represents the calendar system in use.
+     * The era and other fields in {@link ChronoField} are defined by the chronology.
+     *
+     * @return the Hijrah chronology, not null
+     */
     @Override
     public HijrahChronology getChronology() {
         return chrono;
     }
 
+    /**
+     * Gets the era applicable at this date.
+     * <p>
+     * The Hijrah calendar system has one era, 'AH',
+     * defined by {@link HijrahEra}.
+     *
+     * @return the era applicable at this date, not null
+     */
+    @Override
+    public HijrahEra getEra() {
+        return HijrahEra.AH;
+    }
+
+    /**
+     * Returns the length of the month represented by this date.
+     * <p>
+     * This returns the length of the month in days.
+     * Month lengths in the Hijrah calendar system vary between 29 and 30 days.
+     *
+     * @return the length of the month in days
+     */
+    @Override
+    public int lengthOfMonth() {
+        return chrono.getMonthLength(prolepticYear, monthOfYear);
+    }
+
+    /**
+     * Returns the length of the year represented by this date.
+     * <p>
+     * This returns the length of the year in days.
+     * A Hijrah calendar system year is typically shorter than
+     * that of the ISO calendar system.
+     *
+     * @return the length of the year in days
+     */
+    @Override
+    public int lengthOfYear() {
+        return chrono.getYearLength(prolepticYear);
+    }
+
+    //-----------------------------------------------------------------------
     @Override
     public ValueRange range(TemporalField field) {
         if (field instanceof ChronoField) {
@@ -339,83 +344,106 @@
                     case DAY_OF_MONTH: return ValueRange.of(1, lengthOfMonth());
                     case DAY_OF_YEAR: return ValueRange.of(1, lengthOfYear());
                     case ALIGNED_WEEK_OF_MONTH: return ValueRange.of(1, 5);  // TODO
-                    case YEAR_OF_ERA: return ValueRange.of(1, 1000);  // TODO
+                    // TODO does the limited range of valid years cause years to
+                    // start/end part way through? that would affect range
                 }
                 return getChronology().range(f);
             }
-            throw new DateTimeException("Unsupported field: " + field.getName());
+            throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
         }
         return field.rangeRefinedBy(this);
     }
 
-    @Override   // Override for javadoc
-    public int get(TemporalField field) {
-        return super.get(field);
-    }
-
     @Override
     public long getLong(TemporalField field) {
         if (field instanceof ChronoField) {
             switch ((ChronoField) field) {
-                case DAY_OF_WEEK: return dayOfWeek.getValue();
-                case ALIGNED_DAY_OF_WEEK_IN_MONTH: return ((dayOfWeek.getValue() - 1) % 7) + 1;
-                case ALIGNED_DAY_OF_WEEK_IN_YEAR: return ((dayOfYear - 1) % 7) + 1;
+                case DAY_OF_WEEK: return getDayOfWeek();
+                case ALIGNED_DAY_OF_WEEK_IN_MONTH: return ((getDayOfWeek() - 1) % 7) + 1;
+                case ALIGNED_DAY_OF_WEEK_IN_YEAR: return ((getDayOfYear() - 1) % 7) + 1;
                 case DAY_OF_MONTH: return this.dayOfMonth;
-                case DAY_OF_YEAR: return this.dayOfYear;
+                case DAY_OF_YEAR: return this.getDayOfYear();
                 case EPOCH_DAY: return toEpochDay();
                 case ALIGNED_WEEK_OF_MONTH: return ((dayOfMonth - 1) / 7) + 1;
-                case ALIGNED_WEEK_OF_YEAR: return ((dayOfYear - 1) / 7) + 1;
+                case ALIGNED_WEEK_OF_YEAR: return ((getDayOfYear() - 1) / 7) + 1;
                 case MONTH_OF_YEAR: return monthOfYear;
-                case YEAR_OF_ERA: return yearOfEra;
-                case YEAR: return yearOfEra;
-                case ERA: return era.getValue();
+                case PROLEPTIC_MONTH: return getProlepticMonth();
+                case YEAR_OF_ERA: return prolepticYear;
+                case YEAR: return prolepticYear;
+                case ERA: return getEraValue();
             }
-            throw new DateTimeException("Unsupported field: " + field.getName());
+            throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
         }
         return field.getFrom(this);
     }
 
+    private long getProlepticMonth() {
+        return prolepticYear * 12L + monthOfYear - 1;
+    }
+
     @Override
     public HijrahDate with(TemporalField field, long newValue) {
         if (field instanceof ChronoField) {
             ChronoField f = (ChronoField) field;
-            f.checkValidValue(newValue);        // TODO: validate value
+            // not using checkValidIntValue so EPOCH_DAY and PROLEPTIC_MONTH work
+            chrono.range(f).checkValidValue(newValue, f);    // TODO: validate value
             int nvalue = (int) newValue;
             switch (f) {
-                case DAY_OF_WEEK: return plusDays(newValue - dayOfWeek.getValue());
+                case DAY_OF_WEEK: return plusDays(newValue - getDayOfWeek());
                 case ALIGNED_DAY_OF_WEEK_IN_MONTH: return plusDays(newValue - getLong(ALIGNED_DAY_OF_WEEK_IN_MONTH));
                 case ALIGNED_DAY_OF_WEEK_IN_YEAR: return plusDays(newValue - getLong(ALIGNED_DAY_OF_WEEK_IN_YEAR));
-                case DAY_OF_MONTH: return resolvePreviousValid(yearOfEra, monthOfYear, nvalue);
-                case DAY_OF_YEAR: return resolvePreviousValid(yearOfEra, ((nvalue - 1) / 30) + 1, ((nvalue - 1) % 30) + 1);
-                case EPOCH_DAY: return new HijrahDate(chrono, nvalue);
+                case DAY_OF_MONTH: return resolvePreviousValid(prolepticYear, monthOfYear, nvalue);
+                case DAY_OF_YEAR: return resolvePreviousValid(prolepticYear, ((nvalue - 1) / 30) + 1, ((nvalue - 1) % 30) + 1);
+                case EPOCH_DAY: return new HijrahDate(chrono, newValue);
                 case ALIGNED_WEEK_OF_MONTH: return plusDays((newValue - getLong(ALIGNED_WEEK_OF_MONTH)) * 7);
                 case ALIGNED_WEEK_OF_YEAR: return plusDays((newValue - getLong(ALIGNED_WEEK_OF_YEAR)) * 7);
-                case MONTH_OF_YEAR: return resolvePreviousValid(yearOfEra, nvalue, dayOfMonth);
-                case YEAR_OF_ERA: return resolvePreviousValid(yearOfEra >= 1 ? nvalue : 1 - nvalue, monthOfYear, dayOfMonth);
+                case MONTH_OF_YEAR: return resolvePreviousValid(prolepticYear, nvalue, dayOfMonth);
+                case PROLEPTIC_MONTH: return plusMonths(newValue - getProlepticMonth());
+                case YEAR_OF_ERA: return resolvePreviousValid(prolepticYear >= 1 ? nvalue : 1 - nvalue, monthOfYear, dayOfMonth);
                 case YEAR: return resolvePreviousValid(nvalue, monthOfYear, dayOfMonth);
-                case ERA: return resolvePreviousValid(1 - yearOfEra, monthOfYear, dayOfMonth);
+                case ERA: return resolvePreviousValid(1 - prolepticYear, monthOfYear, dayOfMonth);
             }
-            throw new DateTimeException("Unsupported field: " + field.getName());
+            throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
         }
-        return (HijrahDate) ChronoLocalDate.super.with(field, newValue);
+        return ChronoLocalDate.super.with(field, newValue);
     }
 
-    private HijrahDate resolvePreviousValid(int yearOfEra, int month, int day) {
-        int monthDays = getMonthDays(month - 1, yearOfEra);
+    private HijrahDate resolvePreviousValid(int prolepticYear, int month, int day) {
+        int monthDays = chrono.getMonthLength(prolepticYear, month);
         if (day > monthDays) {
             day = monthDays;
         }
-        return HijrahDate.of(chrono, yearOfEra, month, day);
+        return HijrahDate.of(chrono, prolepticYear, month, day);
     }
 
     /**
      * {@inheritDoc}
-     * @throws DateTimeException {@inheritDoc}
+     * @throws DateTimeException if unable to make the adjustment.
+     *     For example, if the adjuster requires an ISO chronology
      * @throws ArithmeticException {@inheritDoc}
      */
     @Override
     public  HijrahDate with(TemporalAdjuster adjuster) {
-        return (HijrahDate)super.with(adjuster);
+        return super.with(adjuster);
+    }
+
+    /**
+     * Returns a {@code HijrahDate} with the Chronology requested.
+     * <p>
+     * The year, month, and day are checked against the new requested
+     * HijrahChronology.  If the chronology has a shorter month length
+     * for the month, the day is reduced to be the last day of the month.
+     *
+     * @param chronology the new HijrahChonology, non-null
+     * @return a HijrahDate with the requested HijrahChronology, non-null
+     */
+    public HijrahDate withVariant(HijrahChronology chronology) {
+        if (chrono == chronology) {
+            return this;
+        }
+        // Like resolvePreviousValid the day is constrained to stay in the same month
+        int monthDays = chronology.getDayOfYear(prolepticYear, monthOfYear);
+        return HijrahDate.of(chronology, prolepticYear, monthOfYear,(dayOfMonth > monthDays) ? monthDays : dayOfMonth );
     }
 
     /**
@@ -425,7 +453,7 @@
      */
     @Override
     public HijrahDate plus(TemporalAmount amount) {
-        return (HijrahDate)super.plus(amount);
+        return super.plus(amount);
     }
 
     /**
@@ -435,12 +463,42 @@
      */
     @Override
     public HijrahDate minus(TemporalAmount amount) {
-        return (HijrahDate)super.minus(amount);
+        return super.minus(amount);
     }
 
     @Override
     public long toEpochDay() {
-         return chrono.getGregorianEpochDay(yearOfEra, monthOfYear, dayOfMonth);
+        return chrono.getEpochDay(prolepticYear, monthOfYear, dayOfMonth);
+    }
+
+    /**
+     * Gets the day-of-year field.
+     * <p>
+     * This method returns the primitive {@code int} value for the day-of-year.
+     *
+     * @return the day-of-year
+     */
+    private int getDayOfYear() {
+        return chrono.getDayOfYear(prolepticYear, monthOfYear);
+    }
+
+    /**
+     * Gets the day-of-week value.
+     *
+     * @return the day-of-week; computed from the epochday
+     */
+    private int getDayOfWeek() {
+        int dow0 = (int)Math.floorMod(toEpochDay() + 3, 7);
+        return dow0 + 1;
+    }
+
+    /**
+     * Gets the Era of this date.
+     *
+     * @return the Era of this date; computed from epochDay
+     */
+    private int getEraValue() {
+        return (prolepticYear > 1 ? 1 : 0);
     }
 
     //-----------------------------------------------------------------------
@@ -451,7 +509,7 @@
      */
     @Override
     public boolean isLeapYear() {
-        return this.isLeapYear;
+        return chrono.isLeapYear(prolepticYear);
     }
 
     //-----------------------------------------------------------------------
@@ -460,111 +518,72 @@
         if (years == 0) {
             return this;
         }
-        int newYear = Math.addExact(this.yearOfEra, (int)years);
-        return HijrahDate.of(chrono, this.era, newYear, this.monthOfYear, this.dayOfMonth);
+        int newYear = Math.addExact(this.prolepticYear, (int)years);
+        return resolvePreviousValid(newYear, monthOfYear, dayOfMonth);
     }
 
     @Override
-    HijrahDate plusMonths(long months) {
-        if (months == 0) {
+    HijrahDate plusMonths(long monthsToAdd) {
+        if (monthsToAdd == 0) {
             return this;
         }
-        int newMonth = this.monthOfYear - 1;
-        newMonth = newMonth + (int)months;
-        int years = newMonth / 12;
-        newMonth = newMonth % 12;
-        while (newMonth < 0) {
-            newMonth += 12;
-            years = Math.subtractExact(years, 1);
-        }
-        int newYear = Math.addExact(this.yearOfEra, years);
-        return HijrahDate.of(chrono, this.era, newYear, newMonth + 1, this.dayOfMonth);
+        long monthCount = prolepticYear * 12L + (monthOfYear - 1);
+        long calcMonths = monthCount + monthsToAdd;  // safe overflow
+        int newYear = chrono.checkValidYear(Math.floorDiv(calcMonths, 12L));
+        int newMonth = (int)Math.floorMod(calcMonths, 12L) + 1;
+        return resolvePreviousValid(newYear, newMonth, dayOfMonth);
     }
 
     @Override
     HijrahDate plusWeeks(long weeksToAdd) {
-        return (HijrahDate)super.plusWeeks(weeksToAdd);
+        return super.plusWeeks(weeksToAdd);
     }
 
     @Override
     HijrahDate plusDays(long days) {
-        return new HijrahDate(chrono, this.gregorianEpochDay + days);
+        return new HijrahDate(chrono, toEpochDay() + days);
     }
 
     @Override
     public HijrahDate plus(long amountToAdd, TemporalUnit unit) {
-        return (HijrahDate)super.plus(amountToAdd, unit);
+        return super.plus(amountToAdd, unit);
     }
 
     @Override
     public HijrahDate minus(long amountToSubtract, TemporalUnit unit) {
-        return (HijrahDate)super.minus(amountToSubtract, unit);
+        return super.minus(amountToSubtract, unit);
     }
 
     @Override
     HijrahDate minusYears(long yearsToSubtract) {
-        return (HijrahDate)super.minusYears(yearsToSubtract);
+        return super.minusYears(yearsToSubtract);
     }
 
     @Override
     HijrahDate minusMonths(long monthsToSubtract) {
-        return (HijrahDate)super.minusMonths(monthsToSubtract);
+        return super.minusMonths(monthsToSubtract);
     }
 
     @Override
     HijrahDate minusWeeks(long weeksToSubtract) {
-        return (HijrahDate)super.minusWeeks(weeksToSubtract);
+        return super.minusWeeks(weeksToSubtract);
     }
 
     @Override
     HijrahDate minusDays(long daysToSubtract) {
-        return (HijrahDate)super.minusDays(daysToSubtract);
-    }
-
-    /**
-     * Returns month days from the beginning of year.
-     *
-     * @param month  month (0-based)
-     * @parma year  year
-     * @return month days from the beginning of year
-     */
-    private int getMonthDays(int month, int year) {
-        int[] newMonths = chrono.getAdjustedMonthDays(year);
-        return newMonths[month];
-    }
-
-    /**
-     * Returns month length.
-     *
-     * @param month  month (0-based)
-     * @param year  year
-     * @return month length
-     */
-    private int getMonthLength(int month, int year) {
-      int[] newMonths = chrono.getAdjustedMonthLength(year);
-      return newMonths[month];
-    }
-
-    @Override
-    public int lengthOfMonth() {
-        return getMonthLength(monthOfYear - 1, yearOfEra);
-    }
-
-    @Override
-    public int lengthOfYear() {
-        return chrono.getYearLength(yearOfEra);  // TODO: proleptic year
+        return super.minusDays(daysToSubtract);
     }
 
     @Override        // for javadoc and covariant return type
     public final ChronoLocalDateTime<HijrahDate> atTime(LocalTime localTime) {
-        return (ChronoLocalDateTime<HijrahDate>)super.atTime(localTime);
+        return super.atTime(localTime);
     }
 
     @Override
     public Period periodUntil(ChronoLocalDate<?> endDate) {
         // TODO: untested
-        HijrahDate end = (HijrahDate) getChronology().date(endDate);
-        long totalMonths = (end.yearOfEra - this.yearOfEra) * 12 + (end.monthOfYear - this.monthOfYear);  // safe
+        HijrahDate end = getChronology().date(endDate);
+        long totalMonths = (end.prolepticYear - this.prolepticYear) * 12 + (end.monthOfYear - this.monthOfYear);  // safe
         int days = end.dayOfMonth - this.dayOfMonth;
         if (totalMonths > 0 && days < 0) {
             totalMonths--;
@@ -604,7 +623,7 @@
     }
 
     static ChronoLocalDate<HijrahDate> readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
-        HijrahChronology chrono = (HijrahChronology)in.readObject();
+        HijrahChronology chrono = (HijrahChronology) in.readObject();
         int year = in.readInt();
         int month = in.readByte();
         int dayOfMonth = in.readByte();