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