src/share/classes/java/time/chrono/HijrahDate.java
Print this page
*** 68,126 ****
import java.io.ObjectInput;
import java.io.ObjectOutput;
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.TemporalUnit;
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}.
* <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.
! * <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>
! *
* <h3>Specification for implementors</h3>
* This class is immutable and thread-safe.
*
* @since 1.8
*/
--- 68,109 ----
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Serializable;
import java.time.Clock;
import java.time.DateTimeException;
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.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;
/**
* A date in the Hijrah calendar system.
* <p>
! * 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 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>
! * 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.
*
* @since 1.8
*/
*** 130,223 ****
/**
* Serialization version.
*/
private static final long serialVersionUID = -5207853542612002020L;
-
/**
* The Chronology of this HijrahDate.
*/
private final HijrahChronology chrono;
/**
! * The era.
*/
! private final transient HijrahEra era;
! /**
! * The year.
! */
! private final transient int yearOfEra;
/**
* The month-of-year.
*/
private final transient int monthOfYear;
/**
* 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.
*
! * @param prolepticYear the proleptic year to represent in the Hijrah
* @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);
}
/**
! * 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
*/
- 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.
* <p>
* This will query the {@link Clock#systemDefaultZone() system clock} in the default
* time-zone to obtain the current date.
* <p>
* Using this method will prevent the ability to use an alternate clock for testing
--- 113,168 ----
/**
* Serialization version.
*/
private static final long serialVersionUID = -5207853542612002020L;
/**
* The Chronology of this HijrahDate.
*/
private final HijrahChronology chrono;
/**
! * The proleptic year.
*/
! private final transient int prolepticYear;
/**
* The month-of-year.
*/
private final transient int monthOfYear;
/**
* The day-of-month.
*/
private final transient int dayOfMonth;
//-------------------------------------------------------------------------
/**
! * 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 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 new HijrahDate(chrono, prolepticYear, monthOfYear, dayOfMonth);
}
/**
! * 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
*/
static HijrahDate ofEpochDay(HijrahChronology chrono, long epochDay) {
return new HijrahDate(chrono, epochDay);
}
//-----------------------------------------------------------------------
/**
! * 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.
* <p>
* Using this method will prevent the ability to use an alternate clock for testing
*** 228,238 ****
public static HijrahDate now() {
return now(Clock.systemDefaultZone());
}
/**
! * Obtains the current {@code HijrahDate} from the system clock 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.
* <p>
* Using this method will prevent the ability to use an alternate clock for testing
--- 173,184 ----
public static HijrahDate now() {
return now(Clock.systemDefaultZone());
}
/**
! * 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.
* <p>
* Using this method will prevent the ability to use an alternate clock for testing
*** 244,254 ****
public static HijrahDate now(ZoneId zone) {
return now(Clock.system(zone));
}
/**
! * Obtains the current {@code HijrahDate} 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.
* The alternate clock may be introduced using {@linkplain Clock dependency injection}.
*
--- 190,201 ----
public static HijrahDate now(ZoneId zone) {
return now(Clock.system(zone));
}
/**
! * 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.
* The alternate clock may be introduced using {@linkplain Clock dependency injection}.
*
*** 259,270 ****
public static HijrahDate now(Clock clock) {
return HijrahChronology.INSTANCE.date(LocalDate.now(clock));
}
/**
! * Obtains a {@code HijrahDate} representing a date in the Hijrah calendar
! * system 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.
*
* @param prolepticYear the Hijrah proleptic-year
--- 206,217 ----
public static HijrahDate now(Clock clock) {
return HijrahChronology.INSTANCE.date(LocalDate.now(clock));
}
/**
! * 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.
*
* @param prolepticYear the Hijrah proleptic-year
*** 277,287 ****
public static HijrahDate of(int prolepticYear, int month, int dayOfMonth) {
return HijrahChronology.INSTANCE.date(prolepticYear, month, dayOfMonth);
}
/**
! * Obtains a {@code HijrahDate} 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,
* which this factory converts to an instance of {@code HijrahDate}.
* <p>
--- 224,234 ----
public static HijrahDate of(int prolepticYear, int month, int dayOfMonth) {
return HijrahChronology.INSTANCE.date(prolepticYear, month, dayOfMonth);
}
/**
! * 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,
* which this factory converts to an instance of {@code HijrahDate}.
* <p>
*** 299,572 ****
return HijrahChronology.INSTANCE.date(temporal);
}
//-----------------------------------------------------------------------
/**
! * Constructs an instance with the specified date.
*
! * @param gregorianDay the number of days from 0001/01/01 (Gregorian), caller calculated
! */
! private HijrahDate(HijrahChronology chrono, long gregorianDay) {
this.chrono = chrono;
! int[] dateInfo = chrono.getHijrahDateInfo(gregorianDay);
! chrono.checkValidYearOfEra(dateInfo[1]);
! chrono.checkValidMonth(dateInfo[2]);
! chrono.checkValidDayOfMonth(dateInfo[3]);
! chrono.checkValidDayOfYear(dateInfo[4]);
!
! 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);
}
//-----------------------------------------------------------------------
@Override
public HijrahChronology getChronology() {
return chrono;
}
@Override
public ValueRange range(TemporalField field) {
if (field instanceof ChronoField) {
if (isSupported(field)) {
ChronoField f = (ChronoField) field;
switch (f) {
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
}
return getChronology().range(f);
}
! throw new DateTimeException("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_MONTH: return this.dayOfMonth;
! case DAY_OF_YEAR: return this.dayOfYear;
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 MONTH_OF_YEAR: return monthOfYear;
! case YEAR_OF_ERA: return yearOfEra;
! case YEAR: return yearOfEra;
! case ERA: return era.getValue();
}
! throw new DateTimeException("Unsupported field: " + field.getName());
}
return field.getFrom(this);
}
@Override
public HijrahDate with(TemporalField field, long newValue) {
if (field instanceof ChronoField) {
ChronoField f = (ChronoField) field;
! f.checkValidValue(newValue); // TODO: validate value
int nvalue = (int) newValue;
switch (f) {
! case DAY_OF_WEEK: return plusDays(newValue - dayOfWeek.getValue());
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 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 YEAR: return resolvePreviousValid(nvalue, monthOfYear, dayOfMonth);
! case ERA: return resolvePreviousValid(1 - yearOfEra, monthOfYear, dayOfMonth);
}
! throw new DateTimeException("Unsupported field: " + field.getName());
}
! return (HijrahDate) ChronoLocalDate.super.with(field, newValue);
}
! private HijrahDate resolvePreviousValid(int yearOfEra, int month, int day) {
! int monthDays = getMonthDays(month - 1, yearOfEra);
if (day > monthDays) {
day = monthDays;
}
! return HijrahDate.of(chrono, yearOfEra, month, day);
}
/**
* {@inheritDoc}
! * @throws DateTimeException {@inheritDoc}
* @throws ArithmeticException {@inheritDoc}
*/
@Override
public HijrahDate with(TemporalAdjuster adjuster) {
! return (HijrahDate)super.with(adjuster);
}
/**
* {@inheritDoc}
* @throws DateTimeException {@inheritDoc}
* @throws ArithmeticException {@inheritDoc}
*/
@Override
public HijrahDate plus(TemporalAmount amount) {
! return (HijrahDate)super.plus(amount);
}
/**
* {@inheritDoc}
* @throws DateTimeException {@inheritDoc}
* @throws ArithmeticException {@inheritDoc}
*/
@Override
public HijrahDate minus(TemporalAmount amount) {
! return (HijrahDate)super.minus(amount);
}
@Override
public long toEpochDay() {
! return chrono.getGregorianEpochDay(yearOfEra, monthOfYear, dayOfMonth);
}
//-----------------------------------------------------------------------
/**
* Checks if the year is a leap year, according to the Hijrah calendar system rules.
*
* @return true if this date is in a leap year
*/
@Override
public boolean isLeapYear() {
! return this.isLeapYear;
}
//-----------------------------------------------------------------------
@Override
HijrahDate plusYears(long years) {
if (years == 0) {
return this;
}
! int newYear = Math.addExact(this.yearOfEra, (int)years);
! return HijrahDate.of(chrono, this.era, newYear, this.monthOfYear, this.dayOfMonth);
}
@Override
! HijrahDate plusMonths(long months) {
! if (months == 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);
}
@Override
HijrahDate plusWeeks(long weeksToAdd) {
! return (HijrahDate)super.plusWeeks(weeksToAdd);
}
@Override
HijrahDate plusDays(long days) {
! return new HijrahDate(chrono, this.gregorianEpochDay + days);
}
@Override
public HijrahDate plus(long amountToAdd, TemporalUnit unit) {
! return (HijrahDate)super.plus(amountToAdd, unit);
}
@Override
public HijrahDate minus(long amountToSubtract, TemporalUnit unit) {
! return (HijrahDate)super.minus(amountToSubtract, unit);
}
@Override
HijrahDate minusYears(long yearsToSubtract) {
! return (HijrahDate)super.minusYears(yearsToSubtract);
}
@Override
HijrahDate minusMonths(long monthsToSubtract) {
! return (HijrahDate)super.minusMonths(monthsToSubtract);
}
@Override
HijrahDate minusWeeks(long weeksToSubtract) {
! return (HijrahDate)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
}
@Override // for javadoc and covariant return type
public final ChronoLocalDateTime<HijrahDate> atTime(LocalTime localTime) {
! return (ChronoLocalDateTime<HijrahDate>)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
int days = end.dayOfMonth - this.dayOfMonth;
if (totalMonths > 0 && days < 0) {
totalMonths--;
HijrahDate calcDate = this.plusMonths(totalMonths);
days = (int) (end.toEpochDay() - calcDate.toEpochDay()); // safe
--- 246,591 ----
return HijrahChronology.INSTANCE.date(temporal);
}
//-----------------------------------------------------------------------
/**
! * Constructs an {@code HijrahDate} with the proleptic-year, month-of-year and
! * day-of-month fields.
*
! * @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, int prolepticYear, int monthOfYear, int dayOfMonth) {
! // Computing the Gregorian day checks the valid ranges
! chrono.getEpochDay(prolepticYear, monthOfYear, dayOfMonth);
!
this.chrono = chrono;
! this.prolepticYear = prolepticYear;
! this.monthOfYear = monthOfYear;
! this.dayOfMonth = dayOfMonth;
! }
! /**
! * 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) {
if (isSupported(field)) {
ChronoField f = (ChronoField) field;
switch (f) {
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
! // 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 UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
}
return field.rangeRefinedBy(this);
}
@Override
public long getLong(TemporalField field) {
if (field instanceof ChronoField) {
switch ((ChronoField) field) {
! 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.getDayOfYear();
case EPOCH_DAY: return toEpochDay();
case ALIGNED_WEEK_OF_MONTH: return ((dayOfMonth - 1) / 7) + 1;
! case ALIGNED_WEEK_OF_YEAR: return ((getDayOfYear() - 1) / 7) + 1;
case MONTH_OF_YEAR: return monthOfYear;
! case PROLEPTIC_MONTH: return getProlepticMonth();
! case YEAR_OF_ERA: return prolepticYear;
! case YEAR: return prolepticYear;
! case ERA: return getEraValue();
}
! 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;
! // 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 - 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(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(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 - prolepticYear, monthOfYear, dayOfMonth);
}
! throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
}
! return ChronoLocalDate.super.with(field, newValue);
}
! private HijrahDate resolvePreviousValid(int prolepticYear, int month, int day) {
! int monthDays = chrono.getMonthLength(prolepticYear, month);
if (day > monthDays) {
day = monthDays;
}
! return HijrahDate.of(chrono, prolepticYear, month, day);
}
/**
* {@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 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 );
}
/**
* {@inheritDoc}
* @throws DateTimeException {@inheritDoc}
* @throws ArithmeticException {@inheritDoc}
*/
@Override
public HijrahDate plus(TemporalAmount amount) {
! return super.plus(amount);
}
/**
* {@inheritDoc}
* @throws DateTimeException {@inheritDoc}
* @throws ArithmeticException {@inheritDoc}
*/
@Override
public HijrahDate minus(TemporalAmount amount) {
! return super.minus(amount);
}
@Override
public long toEpochDay() {
! 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);
}
//-----------------------------------------------------------------------
/**
* Checks if the year is a leap year, according to the Hijrah calendar system rules.
*
* @return true if this date is in a leap year
*/
@Override
public boolean isLeapYear() {
! return chrono.isLeapYear(prolepticYear);
}
//-----------------------------------------------------------------------
@Override
HijrahDate plusYears(long years) {
if (years == 0) {
return this;
}
! int newYear = Math.addExact(this.prolepticYear, (int)years);
! return resolvePreviousValid(newYear, monthOfYear, dayOfMonth);
}
@Override
! HijrahDate plusMonths(long monthsToAdd) {
! if (monthsToAdd == 0) {
return this;
}
! 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 super.plusWeeks(weeksToAdd);
}
@Override
HijrahDate plusDays(long days) {
! return new HijrahDate(chrono, toEpochDay() + days);
}
@Override
public HijrahDate plus(long amountToAdd, TemporalUnit unit) {
! return super.plus(amountToAdd, unit);
}
@Override
public HijrahDate minus(long amountToSubtract, TemporalUnit unit) {
! return super.minus(amountToSubtract, unit);
}
@Override
HijrahDate minusYears(long yearsToSubtract) {
! return super.minusYears(yearsToSubtract);
}
@Override
HijrahDate minusMonths(long monthsToSubtract) {
! return super.minusMonths(monthsToSubtract);
}
@Override
HijrahDate minusWeeks(long weeksToSubtract) {
! return super.minusWeeks(weeksToSubtract);
}
@Override
HijrahDate minusDays(long daysToSubtract) {
! return super.minusDays(daysToSubtract);
}
@Override // for javadoc and covariant return type
public final ChronoLocalDateTime<HijrahDate> atTime(LocalTime localTime) {
! return super.atTime(localTime);
}
@Override
public Period periodUntil(ChronoLocalDate<?> endDate) {
// TODO: untested
! 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--;
HijrahDate calcDate = this.plusMonths(totalMonths);
days = (int) (end.toEpochDay() - calcDate.toEpochDay()); // safe
*** 602,612 ****
private Object readResolve() {
return this;
}
static ChronoLocalDate<HijrahDate> readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
! HijrahChronology chrono = (HijrahChronology)in.readObject();
int year = in.readInt();
int month = in.readByte();
int dayOfMonth = in.readByte();
return chrono.date(year, month, dayOfMonth);
}
--- 621,631 ----
private Object readResolve() {
return this;
}
static ChronoLocalDate<HijrahDate> readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
! HijrahChronology chrono = (HijrahChronology) in.readObject();
int year = in.readInt();
int month = in.readByte();
int dayOfMonth = in.readByte();
return chrono.date(year, month, dayOfMonth);
}