src/share/classes/java/time/MonthDay.java
Print this page
*** 57,85 ****
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
! package java.time.temporal;
import static java.time.temporal.ChronoField.DAY_OF_MONTH;
import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectStreamException;
import java.io.Serializable;
! import java.time.Clock;
! import java.time.DateTimeException;
! import java.time.LocalDate;
! import java.time.Month;
! import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.DateTimeParseException;
import java.util.Objects;
/**
* A month-day in the ISO-8601 calendar system, such as {@code --12-03}.
* <p>
--- 57,90 ----
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
! package java.time;
import static java.time.temporal.ChronoField.DAY_OF_MONTH;
import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectStreamException;
import java.io.Serializable;
! import java.time.chrono.Chronology;
! import java.time.chrono.IsoChronology;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.DateTimeParseException;
+ import java.time.temporal.ChronoField;
+ import java.time.temporal.Queries;
+ import java.time.temporal.Temporal;
+ import java.time.temporal.TemporalAccessor;
+ import java.time.temporal.TemporalAdjuster;
+ import java.time.temporal.TemporalField;
+ import java.time.temporal.TemporalQuery;
+ import java.time.temporal.ValueRange;
import java.util.Objects;
/**
* A month-day in the ISO-8601 calendar system, such as {@code --12-03}.
* <p>
*** 196,207 ****
* February 29th is permitted, as that month-day can sometimes be valid.
*
* @param month the month-of-year to represent, not null
* @param dayOfMonth the day-of-month to represent, from 1 to 31
* @return the month-day, not null
! * @throws DateTimeException if the value of any field is out of range
! * @throws DateTimeException if the day-of-month is invalid for the month
*/
public static MonthDay of(Month month, int dayOfMonth) {
Objects.requireNonNull(month, "month");
DAY_OF_MONTH.checkValidValue(dayOfMonth);
if (dayOfMonth > month.maxLength()) {
--- 201,212 ----
* February 29th is permitted, as that month-day can sometimes be valid.
*
* @param month the month-of-year to represent, not null
* @param dayOfMonth the day-of-month to represent, from 1 to 31
* @return the month-day, not null
! * @throws DateTimeException if the value of any field is out of range,
! * or if the day-of-month is invalid for the month
*/
public static MonthDay of(Month month, int dayOfMonth) {
Objects.requireNonNull(month, "month");
DAY_OF_MONTH.checkValidValue(dayOfMonth);
if (dayOfMonth > month.maxLength()) {
*** 222,244 ****
* February 29th is permitted, as that month-day can sometimes be valid.
*
* @param month the month-of-year to represent, from 1 (January) to 12 (December)
* @param dayOfMonth the day-of-month to represent, from 1 to 31
* @return the month-day, not null
! * @throws DateTimeException if the value of any field is out of range
! * @throws DateTimeException if the day-of-month is invalid for the month
*/
public static MonthDay of(int month, int dayOfMonth) {
return of(Month.of(month), dayOfMonth);
}
//-----------------------------------------------------------------------
/**
* Obtains an instance of {@code MonthDay} from a temporal object.
* <p>
! * A {@code TemporalAccessor} represents some form of date and time information.
! * This factory converts the arbitrary temporal object to an instance of {@code MonthDay}.
* <p>
* The conversion extracts the {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} and
* {@link ChronoField#DAY_OF_MONTH DAY_OF_MONTH} fields.
* The extraction is only permitted if the date-time has an ISO chronology.
* <p>
--- 227,250 ----
* February 29th is permitted, as that month-day can sometimes be valid.
*
* @param month the month-of-year to represent, from 1 (January) to 12 (December)
* @param dayOfMonth the day-of-month to represent, from 1 to 31
* @return the month-day, not null
! * @throws DateTimeException if the value of any field is out of range,
! * or if the day-of-month is invalid for the month
*/
public static MonthDay of(int month, int dayOfMonth) {
return of(Month.of(month), dayOfMonth);
}
//-----------------------------------------------------------------------
/**
* Obtains an instance of {@code MonthDay} from a temporal object.
* <p>
! * This obtains a month-day 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 MonthDay}.
* <p>
* The conversion extracts the {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} and
* {@link ChronoField#DAY_OF_MONTH DAY_OF_MONTH} fields.
* The extraction is only permitted if the date-time has an ISO chronology.
* <p>
*** 252,262 ****
public static MonthDay from(TemporalAccessor temporal) {
if (temporal instanceof MonthDay) {
return (MonthDay) temporal;
}
try {
! if (ISOChrono.INSTANCE.equals(Chrono.from(temporal)) == false) {
temporal = LocalDate.from(temporal);
}
return of(temporal.get(MONTH_OF_YEAR), temporal.get(DAY_OF_MONTH));
} catch (DateTimeException ex) {
throw new DateTimeException("Unable to obtain MonthDay from TemporalAccessor: " + temporal.getClass(), ex);
--- 258,268 ----
public static MonthDay from(TemporalAccessor temporal) {
if (temporal instanceof MonthDay) {
return (MonthDay) temporal;
}
try {
! if (IsoChronology.INSTANCE.equals(Chronology.from(temporal)) == false) {
temporal = LocalDate.from(temporal);
}
return of(temporal.get(MONTH_OF_YEAR), temporal.get(DAY_OF_MONTH));
} catch (DateTimeException ex) {
throw new DateTimeException("Unable to obtain MonthDay from TemporalAccessor: " + temporal.getClass(), ex);
*** 312,332 ****
* This checks if this month-day can be queried for the specified field.
* If false, then calling the {@link #range(TemporalField) range} and
* {@link #get(TemporalField) get} methods will throw an exception.
* <p>
* If the field is a {@link ChronoField} then the query is implemented here.
- * The {@link #isSupported(TemporalField) supported fields} will return valid
- * values based on this date-time.
* The supported fields are:
* <ul>
* <li>{@code MONTH_OF_YEAR}
* <li>{@code YEAR}
* </ul>
* All other {@code ChronoField} instances will return false.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
! * is obtained by invoking {@code TemporalField.doIsSupported(TemporalAccessor)}
* passing {@code this} as the argument.
* Whether the field is supported is determined by the field.
*
* @param field the field to check, null returns false
* @return true if the field is supported on this month-day, false if not
--- 318,336 ----
* This checks if this month-day can be queried for the specified field.
* If false, then calling the {@link #range(TemporalField) range} and
* {@link #get(TemporalField) get} methods will throw an exception.
* <p>
* If the field is a {@link ChronoField} then the query is implemented here.
* The supported fields are:
* <ul>
* <li>{@code MONTH_OF_YEAR}
* <li>{@code YEAR}
* </ul>
* All other {@code ChronoField} instances will return false.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
! * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
* passing {@code this} as the argument.
* Whether the field is supported is determined by the field.
*
* @param field the field to check, null returns false
* @return true if the field is supported on this month-day, false if not
*** 334,344 ****
@Override
public boolean isSupported(TemporalField field) {
if (field instanceof ChronoField) {
return field == MONTH_OF_YEAR || field == DAY_OF_MONTH;
}
! return field != null && field.doIsSupported(this);
}
/**
* Gets the range of valid values for the specified field.
* <p>
--- 338,348 ----
@Override
public boolean isSupported(TemporalField field) {
if (field instanceof ChronoField) {
return field == MONTH_OF_YEAR || field == DAY_OF_MONTH;
}
! return field != null && field.isSupportedBy(this);
}
/**
* Gets the range of valid values for the specified field.
* <p>
*** 351,361 ****
* The {@link #isSupported(TemporalField) supported fields} will return
* appropriate range instances.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
! * is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)}
* passing {@code this} as the argument.
* Whether the range can be obtained is determined by the field.
*
* @param field the field to query the range for, not null
* @return the range of valid values for the field, not null
--- 355,365 ----
* The {@link #isSupported(TemporalField) supported fields} will return
* appropriate range instances.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
! * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
* passing {@code this} as the argument.
* Whether the range can be obtained is determined by the field.
*
* @param field the field to query the range for, not null
* @return the range of valid values for the field, not null
*** 383,393 ****
* The {@link #isSupported(TemporalField) supported fields} will return valid
* values based on this month-day.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
! * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
* passing {@code this} as the argument. Whether the value can be obtained,
* and what the value represents, is determined by the field.
*
* @param field the field to get, not null
* @return the value for the field
--- 387,397 ----
* The {@link #isSupported(TemporalField) supported fields} will return valid
* values based on this month-day.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
! * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
* passing {@code this} as the argument. Whether the value can be obtained,
* and what the value represents, is determined by the field.
*
* @param field the field to get, not null
* @return the value for the field
*** 410,420 ****
* The {@link #isSupported(TemporalField) supported fields} will return valid
* values based on this month-day.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
! * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)}
* passing {@code this} as the argument. Whether the value can be obtained,
* and what the value represents, is determined by the field.
*
* @param field the field to get, not null
* @return the value for the field
--- 414,424 ----
* The {@link #isSupported(TemporalField) supported fields} will return valid
* values based on this month-day.
* All other {@code ChronoField} instances will throw a {@code DateTimeException}.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
! * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
* passing {@code this} as the argument. Whether the value can be obtained,
* and what the value represents, is determined by the field.
*
* @param field the field to get, not null
* @return the value for the field
*** 429,451 ****
case DAY_OF_MONTH: return day;
case MONTH_OF_YEAR: return month;
}
throw new DateTimeException("Unsupported field: " + field.getName());
}
! return field.doGet(this);
}
//-----------------------------------------------------------------------
/**
* Gets the month-of-year field using the {@code Month} enum.
* <p>
* This method returns the enum {@link Month} for the month.
* This avoids confusion as to what {@code int} values mean.
* If you need access to the primitive {@code int} value then the enum
* provides the {@link Month#getValue() int value}.
*
* @return the month-of-year, not null
*/
public Month getMonth() {
return Month.of(month);
}
--- 433,470 ----
case DAY_OF_MONTH: return day;
case MONTH_OF_YEAR: return month;
}
throw new DateTimeException("Unsupported field: " + field.getName());
}
! return field.getFrom(this);
}
//-----------------------------------------------------------------------
/**
+ * Gets the month-of-year field from 1 to 12.
+ * <p>
+ * This method returns the month as an {@code int} from 1 to 12.
+ * Application code is frequently clearer if the enum {@link Month}
+ * is used by calling {@link #getMonth()}.
+ *
+ * @return the month-of-year, from 1 to 12
+ * @see #getMonth()
+ */
+ public int getMonthValue() {
+ return month;
+ }
+
+ /**
* Gets the month-of-year field using the {@code Month} enum.
* <p>
* This method returns the enum {@link Month} for the month.
* This avoids confusion as to what {@code int} values mean.
* If you need access to the primitive {@code int} value then the enum
* provides the {@link Month#getValue() int value}.
*
* @return the month-of-year, not null
+ * @see #getMonthValue()
*/
public Month getMonth() {
return Month.of(month);
}
*** 522,533 ****
* <p>
* This instance is immutable and unaffected by this method call.
*
* @param dayOfMonth the day-of-month to set in the return month-day, from 1 to 31
* @return a {@code MonthDay} based on this month-day with the requested day, not null
! * @throws DateTimeException if the day-of-month value is invalid
! * @throws DateTimeException if the day-of-month is invalid for the month
*/
public MonthDay withDayOfMonth(int dayOfMonth) {
if (dayOfMonth == this.day) {
return this;
}
--- 541,552 ----
* <p>
* This instance is immutable and unaffected by this method call.
*
* @param dayOfMonth the day-of-month to set in the return month-day, from 1 to 31
* @return a {@code MonthDay} based on this month-day with the requested day, not null
! * @throws DateTimeException if the day-of-month value is invalid,
! * or if the day-of-month is invalid for the month
*/
public MonthDay withDayOfMonth(int dayOfMonth) {
if (dayOfMonth == this.day) {
return this;
}
*** 554,565 ****
* @throws ArithmeticException if numeric overflow occurs (defined by the query)
*/
@SuppressWarnings("unchecked")
@Override
public <R> R query(TemporalQuery<R> query) {
! if (query == Queries.chrono()) {
! return (R) ISOChrono.INSTANCE;
}
return TemporalAccessor.super.query(query);
}
/**
--- 573,584 ----
* @throws ArithmeticException if numeric overflow occurs (defined by the query)
*/
@SuppressWarnings("unchecked")
@Override
public <R> R query(TemporalQuery<R> query) {
! if (query == Queries.chronology()) {
! return (R) IsoChronology.INSTANCE;
}
return TemporalAccessor.super.query(query);
}
/**
*** 589,618 ****
* @throws DateTimeException if unable to make the adjustment
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
public Temporal adjustInto(Temporal temporal) {
! if (Chrono.from(temporal).equals(ISOChrono.INSTANCE) == false) {
throw new DateTimeException("Adjustment only supported on ISO date-time");
}
temporal = temporal.with(MONTH_OF_YEAR, month);
return temporal.with(DAY_OF_MONTH, Math.min(temporal.range(DAY_OF_MONTH).getMaximum(), day));
}
//-----------------------------------------------------------------------
/**
! * Returns a date formed from this month-day at the specified year.
* <p>
- * This combines this month-day and the specified year to form a {@code LocalDate}.
* A month-day of February 29th will be adjusted to February 28th in the resulting
* date if the year is not a leap year.
* <p>
* This instance is immutable and unaffected by this method call.
*
* @param year the year to use, from MIN_YEAR to MAX_YEAR
* @return the local date formed from this month-day and the specified year, not null
! * @see Year#atMonthDay(MonthDay)
*/
public LocalDate atYear(int year) {
return LocalDate.of(year, month, isValidYear(year) ? day : 28);
}
--- 608,638 ----
* @throws DateTimeException if unable to make the adjustment
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
public Temporal adjustInto(Temporal temporal) {
! if (Chronology.from(temporal).equals(IsoChronology.INSTANCE) == false) {
throw new DateTimeException("Adjustment only supported on ISO date-time");
}
temporal = temporal.with(MONTH_OF_YEAR, month);
return temporal.with(DAY_OF_MONTH, Math.min(temporal.range(DAY_OF_MONTH).getMaximum(), day));
}
//-----------------------------------------------------------------------
/**
! * Combines this month-day with a year to create a {@code LocalDate}.
! * <p>
! * This returns a {@code LocalDate} formed from this month-day and the specified year.
* <p>
* A month-day of February 29th will be adjusted to February 28th in the resulting
* date if the year is not a leap year.
* <p>
* This instance is immutable and unaffected by this method call.
*
* @param year the year to use, from MIN_YEAR to MAX_YEAR
* @return the local date formed from this month-day and the specified year, not null
! * @throws DateTimeException if the year is outside the valid range of years
*/
public LocalDate atYear(int year) {
return LocalDate.of(year, month, isValidYear(year) ? day : 28);
}
*** 624,633 ****
--- 644,654 ----
* It is "consistent with equals", as defined by {@link Comparable}.
*
* @param other the other month-day to compare to, not null
* @return the comparator value, negative if less, positive if greater
*/
+ @Override
public int compareTo(MonthDay other) {
int cmp = (month - other.month);
if (cmp == 0) {
cmp = (day - other.day);
}
*** 703,729 ****
/**
* Outputs this month-day as a {@code String} using the formatter.
* <p>
* This month-day will be passed to the formatter
! * {@link DateTimeFormatter#print(TemporalAccessor) print method}.
*
* @param formatter the formatter to use, not null
* @return the formatted month-day string, not null
* @throws DateTimeException if an error occurs during printing
*/
public String toString(DateTimeFormatter formatter) {
Objects.requireNonNull(formatter, "formatter");
! return formatter.print(this);
}
//-----------------------------------------------------------------------
/**
* Writes the object using a
* <a href="../../../serialized-form.html#java.time.temporal.Ser">dedicated serialized form</a>.
* <pre>
! * out.writeByte(6); // identifies this as a Year
* out.writeByte(month);
* out.writeByte(day);
* </pre>
*
* @return the instance of {@code Ser}, not null
--- 724,750 ----
/**
* Outputs this month-day as a {@code String} using the formatter.
* <p>
* This month-day will be passed to the formatter
! * {@link DateTimeFormatter#format(TemporalAccessor) format method}.
*
* @param formatter the formatter to use, not null
* @return the formatted month-day string, not null
* @throws DateTimeException if an error occurs during printing
*/
public String toString(DateTimeFormatter formatter) {
Objects.requireNonNull(formatter, "formatter");
! return formatter.format(this);
}
//-----------------------------------------------------------------------
/**
* Writes the object using a
* <a href="../../../serialized-form.html#java.time.temporal.Ser">dedicated serialized form</a>.
* <pre>
! * out.writeByte(13); // identifies this as a MonthDay
* out.writeByte(month);
* out.writeByte(day);
* </pre>
*
* @return the instance of {@code Ser}, not null