src/share/classes/java/time/YearMonth.java
Print this page
@@ -57,11 +57,11 @@
* 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;
+package java.time;
import static java.time.temporal.ChronoField.EPOCH_MONTH;
import static java.time.temporal.ChronoField.ERA;
import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
import static java.time.temporal.ChronoField.YEAR;
@@ -72,19 +72,27 @@
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.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.format.SignStyle;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.Queries;
+import java.time.temporal.Temporal;
+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.ValueRange;
import java.util.Objects;
/**
* A year-month in the ISO-8601 calendar system, such as {@code 2007-12}.
* <p>
@@ -210,12 +218,13 @@
//-----------------------------------------------------------------------
/**
* Obtains an instance of {@code YearMonth} 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 YearMonth}.
+ * This obtains a year-month 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 YearMonth}.
* <p>
* The conversion extracts the {@link ChronoField#YEAR YEAR} and
* {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} fields.
* The extraction is only permitted if the temporal object has an ISO
* chronology, or can be converted to a {@code LocalDate}.
@@ -230,11 +239,11 @@
public static YearMonth from(TemporalAccessor temporal) {
if (temporal instanceof YearMonth) {
return (YearMonth) temporal;
}
try {
- if (ISOChrono.INSTANCE.equals(Chrono.from(temporal)) == false) {
+ if (IsoChronology.INSTANCE.equals(Chronology.from(temporal)) == false) {
temporal = LocalDate.from(temporal);
}
return of(temporal.get(YEAR), temporal.get(MONTH_OF_YEAR));
} catch (DateTimeException ex) {
throw new DateTimeException("Unable to obtain YearMonth from TemporalAccessor: " + temporal.getClass(), ex);
@@ -306,12 +315,10 @@
* This checks if this year-month 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 EPOCH_MONTH}
* <li>{@code YEAR_OF_ERA}
@@ -319,11 +326,11 @@
* <li>{@code ERA}
* </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)}
+ * 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 year-month, false if not
@@ -332,11 +339,11 @@
public boolean isSupported(TemporalField field) {
if (field instanceof ChronoField) {
return field == YEAR || field == MONTH_OF_YEAR ||
field == EPOCH_MONTH || field == YEAR_OF_ERA || field == ERA;
}
- return field != null && field.doIsSupported(this);
+ return field != null && field.isSupportedBy(this);
}
/**
* Gets the range of valid values for the specified field.
* <p>
@@ -349,11 +356,11 @@
* 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)}
+ * 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
@@ -380,11 +387,11 @@
* values based on this year-month, except {@code EPOCH_MONTH} which is too
* large to fit in an {@code int} and throw a {@code DateTimeException}.
* 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)}
+ * 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
@@ -407,11 +414,11 @@
* The {@link #isSupported(TemporalField) supported fields} will return valid
* values based on this year-month.
* 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)}
+ * 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
@@ -428,11 +435,11 @@
case YEAR: return year;
case ERA: return (year < 1 ? 0 : 1);
}
throw new DateTimeException("Unsupported field: " + field.getName());
}
- return field.doGet(this);
+ return field.getFrom(this);
}
private long getEpochMonth() {
return ((year - 1970) * 12L) + (month - 1);
}
@@ -450,18 +457,33 @@
public int getYear() {
return year;
}
/**
+ * 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);
}
@@ -483,11 +505,11 @@
* This is historically inaccurate, but is correct for the ISO-8601 standard.
*
* @return true if the year is leap, false otherwise
*/
public boolean isLeapYear() {
- return ISOChrono.INSTANCE.isLeapYear(year);
+ return IsoChronology.INSTANCE.isLeapYear(year);
}
/**
* Checks if the day-of-month is valid for this year-month.
* <p>
@@ -526,11 +548,11 @@
//-----------------------------------------------------------------------
/**
* Returns an adjusted copy of this year-month.
* <p>
- * This returns a new {@code YearMonth}, based on this one, with the year-month adjusted.
+ * This returns a {@code YearMonth}, based on this one, with the year-month adjusted.
* The adjustment takes place using the specified adjuster strategy object.
* Read the documentation of the adjuster to understand what adjustment will be made.
* <p>
* A simple adjuster might simply set the one of the fields, such as the year field.
* A more complex adjuster might set the year-month to the next month that
@@ -553,11 +575,11 @@
}
/**
* Returns a copy of this year-month with the specified field set to a new value.
* <p>
- * This returns a new {@code YearMonth}, based on this one, with the value
+ * This returns a {@code YearMonth}, based on this one, with the value
* for the specified field changed.
* This can be used to change any supported field, such as the year or month.
* If it is not possible to set the value, because the field is not supported or for
* some other reason, an exception is thrown.
* <p>
@@ -585,11 +607,11 @@
* then a {@code DateTimeException} will be thrown.
* <p>
* 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.doWith(Temporal, long)}
+ * is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)}
* passing {@code this} as the argument. In this case, the field determines
* whether and how to adjust the instant.
* <p>
* This instance is immutable and unaffected by this method call.
*
@@ -611,11 +633,11 @@
case YEAR: return withYear((int) newValue);
case ERA: return (getLong(ERA) == newValue ? this : withYear(1 - year));
}
throw new DateTimeException("Unsupported field: " + field.getName());
}
- return field.doWith(this, newValue);
+ return field.adjustInto(this, newValue);
}
//-----------------------------------------------------------------------
/**
* Returns a copy of this {@code YearMonth} with the year altered.
@@ -645,34 +667,83 @@
return with(year, month);
}
//-----------------------------------------------------------------------
/**
- * Returns a copy of this year-month with the specified period added.
+ * Returns a copy of this year-month with the specified amount added.
* <p>
- * This method returns a new year-month based on this year-month with the specified period added.
- * The adder is typically {@link java.time.Period} but may be any other type implementing
- * the {@link TemporalAdder} interface.
- * The calculation is delegated to the specified adjuster, which typically calls
- * back to {@link #plus(long, TemporalUnit)}.
+ * This returns a {@code YearMonth}, based on this one, with the specified amount added.
+ * The amount is typically {@link Period} but may be any other type implementing
+ * the {@link TemporalAmount} interface.
+ * <p>
+ * The calculation is delegated to the amount object by calling
+ * {@link TemporalAmount#addTo(Temporal)}. The amount implementation is free
+ * to implement the addition in any way it wishes, however it typically
+ * calls back to {@link #plus(long, TemporalUnit)}. Consult the documentation
+ * of the amount implementation to determine if it can be successfully added.
* <p>
* This instance is immutable and unaffected by this method call.
*
- * @param adder the adder to use, not null
+ * @param amountToAdd the amount to add, not null
* @return a {@code YearMonth} based on this year-month with the addition made, not null
* @throws DateTimeException if the addition cannot be made
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
- public YearMonth plus(TemporalAdder adder) {
- return (YearMonth) adder.addTo(this);
+ public YearMonth plus(TemporalAmount amountToAdd) {
+ return (YearMonth) amountToAdd.addTo(this);
}
/**
- * {@inheritDoc}
- * @throws DateTimeException {@inheritDoc}
- * @throws ArithmeticException {@inheritDoc}
+ * Returns a copy of this year-month with the specified amount added.
+ * <p>
+ * This returns a {@code YearMonth}, based on this one, with the amount
+ * in terms of the unit added. If it is not possible to add the amount, because the
+ * unit is not supported or for some other reason, an exception is thrown.
+ * <p>
+ * If the field is a {@link ChronoUnit} then the addition is implemented here.
+ * The supported fields behave as follows:
+ * <ul>
+ * <li>{@code MONTHS} -
+ * Returns a {@code YearMonth} with the specified number of months added.
+ * This is equivalent to {@link #plusMonths(long)}.
+ * <li>{@code YEARS} -
+ * Returns a {@code YearMonth} with the specified number of years added.
+ * This is equivalent to {@link #plusYears(long)}.
+ * <li>{@code DECADES} -
+ * Returns a {@code YearMonth} with the specified number of decades added.
+ * This is equivalent to calling {@link #plusYears(long)} with the amount
+ * multiplied by 10.
+ * <li>{@code CENTURIES} -
+ * Returns a {@code YearMonth} with the specified number of centuries added.
+ * This is equivalent to calling {@link #plusYears(long)} with the amount
+ * multiplied by 100.
+ * <li>{@code MILLENNIA} -
+ * Returns a {@code YearMonth} with the specified number of millennia added.
+ * This is equivalent to calling {@link #plusYears(long)} with the amount
+ * multiplied by 1,000.
+ * <li>{@code ERAS} -
+ * Returns a {@code YearMonth} with the specified number of eras added.
+ * Only two eras are supported so the amount must be one, zero or minus one.
+ * If the amount is non-zero then the year is changed such that the year-of-era
+ * is unchanged.
+ * </ul>
+ * <p>
+ * All other {@code ChronoUnit} instances will throw a {@code DateTimeException}.
+ * <p>
+ * If the field is not a {@code ChronoUnit}, then the result of this method
+ * is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)}
+ * passing {@code this} as the argument. In this case, the unit determines
+ * whether and how to perform the addition.
+ * <p>
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param amountToAdd the amount of the unit to add to the result, may be negative
+ * @param unit the unit of the amount to add, not null
+ * @return a {@code YearMonth} based on this year-month with the specified amount added, not null
+ * @throws DateTimeException if the addition cannot be made
+ * @throws ArithmeticException if numeric overflow occurs
*/
@Override
public YearMonth plus(long amountToAdd, TemporalUnit unit) {
if (unit instanceof ChronoUnit) {
switch ((ChronoUnit) unit) {
@@ -683,11 +754,11 @@
case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000));
case ERAS: return with(ERA, Math.addExact(getLong(ERA), amountToAdd));
}
throw new DateTimeException("Unsupported unit: " + unit.getName());
}
- return unit.doPlus(this, amountToAdd);
+ return unit.addTo(this, amountToAdd);
}
/**
* Returns a copy of this year-month with the specified period in years added.
* <p>
@@ -725,34 +796,51 @@
return with(newYear, newMonth);
}
//-----------------------------------------------------------------------
/**
- * Returns a copy of this year-month with the specified period subtracted.
+ * Returns a copy of this year-month with the specified amount subtracted.
* <p>
- * This method returns a new year-month based on this year-month with the specified period subtracted.
- * The subtractor is typically {@link java.time.Period} but may be any other type implementing
- * the {@link TemporalSubtractor} interface.
- * The calculation is delegated to the specified adjuster, which typically calls
- * back to {@link #minus(long, TemporalUnit)}.
+ * This returns a {@code YearMonth}, based on this one, with the specified amount subtracted.
+ * The amount is typically {@link Period} but may be any other type implementing
+ * the {@link TemporalAmount} interface.
+ * <p>
+ * The calculation is delegated to the amount object by calling
+ * {@link TemporalAmount#subtractFrom(Temporal)}. The amount implementation is free
+ * to implement the subtraction in any way it wishes, however it typically
+ * calls back to {@link #minus(long, TemporalUnit)}. Consult the documentation
+ * of the amount implementation to determine if it can be successfully subtracted.
* <p>
* This instance is immutable and unaffected by this method call.
*
- * @param subtractor the subtractor to use, not null
+ * @param amountToSubtract the amount to subtract, not null
* @return a {@code YearMonth} based on this year-month with the subtraction made, not null
* @throws DateTimeException if the subtraction cannot be made
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
- public YearMonth minus(TemporalSubtractor subtractor) {
- return (YearMonth) subtractor.subtractFrom(this);
+ public YearMonth minus(TemporalAmount amountToSubtract) {
+ return (YearMonth) amountToSubtract.subtractFrom(this);
}
/**
- * {@inheritDoc}
- * @throws DateTimeException {@inheritDoc}
- * @throws ArithmeticException {@inheritDoc}
+ * Returns a copy of this year-month with the specified amount subtracted.
+ * <p>
+ * This returns a {@code YearMonth}, based on this one, with the amount
+ * in terms of the unit subtracted. If it is not possible to subtract the amount,
+ * because the unit is not supported or for some other reason, an exception is thrown.
+ * <p>
+ * This method is equivalent to {@link #plus(long, TemporalUnit)} with the amount negated.
+ * See that method for a full description of how addition, and thus subtraction, works.
+ * <p>
+ * This instance is immutable and unaffected by this method call.
+ *
+ * @param amountToSubtract the amount of the unit to subtract from the result, may be negative
+ * @param unit the unit of the amount to subtract, not null
+ * @return a {@code YearMonth} based on this year-month with the specified amount subtracted, not null
+ * @throws DateTimeException if the subtraction cannot be made
+ * @throws ArithmeticException if numeric overflow occurs
*/
@Override
public YearMonth minus(long amountToSubtract, TemporalUnit unit) {
return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit));
}
@@ -803,12 +891,12 @@
* @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;
+ if (query == Queries.chronology()) {
+ return (R) IsoChronology.INSTANCE;
} else if (query == Queries.precision()) {
return (R) MONTHS;
}
return Temporal.super.query(query);
}
@@ -839,11 +927,11 @@
* @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) {
+ if (Chronology.from(temporal).equals(IsoChronology.INSTANCE) == false) {
throw new DateTimeException("Adjustment only supported on ISO date-time");
}
return temporal.with(EPOCH_MONTH, getEpochMonth());
}
@@ -861,18 +949,19 @@
* The calculation returns a whole number, representing the number of
* complete units between the two year-months.
* For example, the period in decades between 2012-06 and 2032-05
* will only be one decade as it is one month short of two decades.
* <p>
- * This method operates in association with {@link TemporalUnit#between}.
- * The result of this method is a {@code long} representing the amount of
- * the specified unit. By contrast, the result of {@code between} is an
- * object that can be used directly in addition/subtraction:
+ * There are two equivalent ways of using this method.
+ * The first is to invoke this method.
+ * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}:
* <pre>
- * long period = start.periodUntil(end, YEARS); // this method
- * dateTime.plus(YEARS.between(start, end)); // use in plus/minus
+ * // these two lines are equivalent
+ * amount = start.periodUntil(end, MONTHS);
+ * amount = MONTHS.between(start, end);
* </pre>
+ * The choice should be made based on which makes the code more readable.
* <p>
* The calculation is implemented in this method for {@link ChronoUnit}.
* The units {@code MONTHS}, {@code YEARS}, {@code DECADES},
* {@code CENTURIES}, {@code MILLENNIA} and {@code ERAS} are supported.
* Other {@code ChronoUnit} values will throw an exception.
@@ -907,36 +996,53 @@
case MILLENNIA: return monthsUntil / 12000;
case ERAS: return end.getLong(ERA) - getLong(ERA);
}
throw new DateTimeException("Unsupported unit: " + unit.getName());
}
- return unit.between(this, endYearMonth).getAmount();
+ return unit.between(this, endYearMonth);
}
//-----------------------------------------------------------------------
/**
- * Returns a date formed from this year-month at the specified day-of-month.
+ * Combines this year-month with a day-of-month to create a {@code LocalDate}.
+ * <p>
+ * This returns a {@code LocalDate} formed from this year-month and the specified day-of-month.
* <p>
- * This combines this year-month and the specified day-of-month to form a {@code LocalDate}.
* The day-of-month value must be valid for the year-month.
* <p>
* This method can be used as part of a chain to produce a date:
* <pre>
* LocalDate date = year.atMonth(month).atDay(day);
* </pre>
- * <p>
- * This instance is immutable and unaffected by this method call.
*
* @param dayOfMonth the day-of-month to use, from 1 to 31
* @return the date formed from this year-month and the specified day, not null
- * @throws DateTimeException when the day is invalid for the year-month
+ * @throws DateTimeException if the day is invalid for the year-month
* @see #isValidDay(int)
*/
public LocalDate atDay(int dayOfMonth) {
return LocalDate.of(year, month, dayOfMonth);
}
+ /**
+ * Returns a {@code LocalDate} at the end of the month.
+ * <p>
+ * This returns a {@code LocalDate} based on this year-month.
+ * The day-of-month is set to the last valid day of the month, taking
+ * into account leap years.
+ * <p>
+ * This method can be used as part of a chain to produce a date:
+ * <pre>
+ * LocalDate date = year.atMonth(month).atEndOfMonth();
+ * </pre>
+ *
+ * @return the last valid date of this year-month, not null
+ */
+ public LocalDate atEndOfMonth() {
+ return LocalDate.of(year, month, lengthOfMonth());
+ }
+
//-----------------------------------------------------------------------
/**
* Compares this year-month to another year-month.
* <p>
* The comparison is based first on the value of the year, then on the value of the month.
@@ -1033,27 +1139,27 @@
/**
* Outputs this year-month as a {@code String} using the formatter.
* <p>
* This year-month will be passed to the formatter
- * {@link DateTimeFormatter#print(TemporalAccessor) print method}.
+ * {@link DateTimeFormatter#format(TemporalAccessor) format method}.
*
* @param formatter the formatter to use, not null
* @return the formatted year-month string, not null
* @throws DateTimeException if an error occurs during printing
*/
public String toString(DateTimeFormatter formatter) {
Objects.requireNonNull(formatter, "formatter");
- return formatter.print(this);
+ 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(5); // identifies this as a Year
+ * out.writeByte(12); // identifies this as a YearMonth
* out.writeInt(year);
* out.writeByte(month);
* </pre>
*
* @return the instance of {@code Ser}, not null