提交 2eb411b8 编写于 作者: V vinnie

Merge

...@@ -103,7 +103,7 @@ import java.util.TimeZone; ...@@ -103,7 +103,7 @@ import java.util.TimeZone;
* system clock This may use {@link System#currentTimeMillis()}, or a higher * system clock This may use {@link System#currentTimeMillis()}, or a higher
* resolution clock if one is available. * resolution clock if one is available.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This abstract class must be implemented with care to ensure other operate correctly. * This abstract class must be implemented with care to ensure other operate correctly.
* All implementations that can be instantiated must be final, immutable and thread-safe. * All implementations that can be instantiated must be final, immutable and thread-safe.
* <p> * <p>
...@@ -112,13 +112,23 @@ import java.util.TimeZone; ...@@ -112,13 +112,23 @@ import java.util.TimeZone;
* obtain the time from a central time server across the network. Obviously, in this case the * obtain the time from a central time server across the network. Obviously, in this case the
* lookup could fail, and so the method is permitted to throw an exception. * lookup could fail, and so the method is permitted to throw an exception.
* <p> * <p>
* The returned instants from {@code Clock} work on a time-scale that ignores leap seconds. * The returned instants from {@code Clock} work on a time-scale that ignores leap seconds,
* If the implementation wraps a source that provides leap second information, then a mechanism * as described in {@link Instant}. If the implementation wraps a source that provides leap
* should be used to "smooth" the leap second, such as UTC-SLS. * second information, then a mechanism should be used to "smooth" the leap second.
* The Java Time-Scale mandates the use of UTC-SLS, however clock implementations may choose
* how accurate they are with the time-scale so long as they document how they work.
* Implementations are therefore not required to actually perform the UTC-SLS slew or to
* otherwise be aware of leap seconds.
* <p> * <p>
* Implementations should implement {@code Serializable} wherever possible and must * Implementations should implement {@code Serializable} wherever possible and must
* document whether or not they do support serialization. * document whether or not they do support serialization.
* *
* @implNote
* The clock implementation provided here is based on {@link System#currentTimeMillis()}.
* That method provides little to no guarantee about the accuracy of the clock.
* Applications requiring a more accurate clock must implement this abstract class
* themselves using a different external clock, such as an NTP server.
*
* @since 1.8 * @since 1.8
*/ */
public abstract class Clock { public abstract class Clock {
...@@ -370,7 +380,7 @@ public abstract class Clock { ...@@ -370,7 +380,7 @@ public abstract class Clock {
/** /**
* Gets the current millisecond instant of the clock. * Gets the current millisecond instant of the clock.
* <p> * <p>
* This returns the millisecond-based instant, measured from 1970-01-01T00:00 UTC. * This returns the millisecond-based instant, measured from 1970-01-01T00:00Z (UTC).
* This is equivalent to the definition of {@link System#currentTimeMillis()}. * This is equivalent to the definition of {@link System#currentTimeMillis()}.
* <p> * <p>
* Most applications should avoid this method and use {@link Instant} to represent * Most applications should avoid this method and use {@link Instant} to represent
...@@ -381,7 +391,7 @@ public abstract class Clock { ...@@ -381,7 +391,7 @@ public abstract class Clock {
* The default implementation currently calls {@link #instant}. * The default implementation currently calls {@link #instant}.
* *
* @return the current millisecond instant from this clock, measured from * @return the current millisecond instant from this clock, measured from
* the Java epoch of 1970-01-01T00:00 UTC, not null * the Java epoch of 1970-01-01T00:00Z (UTC), not null
* @throws DateTimeException if the instant cannot be obtained, not thrown by most implementations * @throws DateTimeException if the instant cannot be obtained, not thrown by most implementations
*/ */
public long millis() { public long millis() {
......
...@@ -67,7 +67,7 @@ package java.time; ...@@ -67,7 +67,7 @@ package java.time;
* This exception is used to indicate problems with creating, querying * This exception is used to indicate problems with creating, querying
* and manipulating date-time objects. * and manipulating date-time objects.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This class is intended for use in a single thread. * This class is intended for use in a single thread.
* *
* @since 1.8 * @since 1.8
......
...@@ -100,7 +100,7 @@ import java.util.Locale; ...@@ -100,7 +100,7 @@ import java.util.Locale;
* As such, this enum may be used by any calendar system that has the day-of-week * As such, this enum may be used by any calendar system that has the day-of-week
* concept defined exactly equivalent to the ISO calendar system. * concept defined exactly equivalent to the ISO calendar system.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This is an immutable and thread-safe enum. * This is an immutable and thread-safe enum.
* *
* @since 1.8 * @since 1.8
......
...@@ -118,7 +118,7 @@ import java.util.regex.Pattern; ...@@ -118,7 +118,7 @@ import java.util.regex.Pattern;
* most applications. * most applications.
* See {@link Instant} for a discussion as to the meaning of the second and time-scales. * See {@link Instant} for a discussion as to the meaning of the second and time-scales.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This class is immutable and thread-safe. * This class is immutable and thread-safe.
* *
* @since 1.8 * @since 1.8
......
...@@ -142,47 +142,60 @@ import java.util.Objects; ...@@ -142,47 +142,60 @@ import java.util.Objects;
* introduce other changes. * introduce other changes.
* <p> * <p>
* Given the complexity of accurate timekeeping described above, this Java API defines * Given the complexity of accurate timekeeping described above, this Java API defines
* its own time-scale with a simplification. The Java time-scale is defined as follows: * its own time-scale, the <i>Java Time-Scale</i>.
* <p>
* The Java Time-Scale divides each calendar day into exactly 86400
* subdivisions, known as seconds. These seconds may differ from the
* SI second. It closely matches the de facto international civil time
* scale, the definition of which changes from time to time.
* <p>
* The Java Time-Scale has slightly different definitions for different
* segments of the time-line, each based on the consensus international
* time scale that is used as the basis for civil time. Whenever the
* internationally-agreed time scale is modified or replaced, a new
* segment of the Java Time-Scale must be defined for it. Each segment
* must meet these requirements:
* <p><ul> * <p><ul>
* <li>midday will always be exactly as defined by the agreed international civil time</li> * <li>the Java Time-Scale shall closely match the underlying international
* <li>other times during the day will be broadly in line with the agreed international civil time</li> * civil time scale;</li>
* <li>the day will be divided into exactly 86400 subdivisions, referred to as "seconds"</li> * <li>the Java Time-Scale shall exactly match the international civil
* <li>the Java "second" may differ from an SI second</li> * time scale at noon each day;</li>
* <li>a well-defined algorithm must be specified to map each second in the accurate agreed * <li>the Java Time-Scale shall have a precisely-defined relationship to
* international civil time to each "second" in this time-scale</li> * the international civil time scale.</li>
* </ul><p> * </ul><p>
* Agreed international civil time is the base time-scale agreed by international convention, * There are currently, as of 2013, two segments in the Java time-scale.
* which in 2012 is UTC (with leap-seconds).
* <p> * <p>
* In 2012, the definition of the Java time-scale is the same as UTC for all days except * For the segment from 1972-11-03 (exact boundary discussed below) until
* those where a leap-second occurs. On days where a leap-second does occur, the time-scale * further notice, the consensus international time scale is UTC (with
* effectively eliminates the leap-second, maintaining the fiction of 86400 seconds in the day. * leap seconds). In this segment, the Java Time-Scale is identical to
* The approved well-defined algorithm to eliminate leap-seconds is specified as
* <a href="http://www.cl.cam.ac.uk/~mgk25/time/utc-sls/">UTC-SLS</a>. * <a href="http://www.cl.cam.ac.uk/~mgk25/time/utc-sls/">UTC-SLS</a>.
* This is identical to UTC on days that do not have a leap second.
* On days that do have a leap second, the leap second is spread equally
* over the last 1000 seconds of the day, maintaining the appearance of
* exactly 86400 seconds per day.
* <p> * <p>
* UTC-SLS is a simple algorithm that smoothes the leap-second over the last 1000 seconds of * For the segment prior to 1972-11-03, extending back arbitrarily far,
* the day, making each of the last 1000 seconds 1/1000th longer or shorter than an SI second. * the consensus international time scale is defined to be UT1, applied
* Implementations built on an accurate leap-second aware time source should use UTC-SLS. * proleptically, which is equivalent to the (mean) solar time on the
* Use of a different algorithm risks confusion and misinterpretation of instants around a * prime meridian (Greenwich). In this segment, the Java Time-Scale is
* leap-second and is discouraged. * identical to the consensus international time scale. The exact
* <p> * boundary between the two segments is the instant where UT1 = UTC
* The main benefit of always dividing the day into 86400 subdivisions is that it matches the * between 1972-11-03T00:00 and 1972-11-04T12:00.
* expectations of most users of the API. The alternative is to force every user to understand
* what a leap second is and to force them to have special logic to handle them.
* Most applications do not have access to a clock that is accurate enough to record leap-seconds.
* Most applications also do not have a problem with a second being a very small amount longer or
* shorter than a real SI second during a leap-second.
* <p> * <p>
* One final problem is the definition of the agreed international civil time before the * Implementations of the Java time-scale using the JSR-310 API are not
* introduction of modern UTC in 1972. This includes the Java epoch of {@code 1970-01-01}. * required to provide any clock that is sub-second accurate, or that
* It is intended that instants before 1972 be interpreted based on the solar day divided * progresses monotonically or smoothly. Implementations are therefore
* into 86400 subdivisions, as per the principles of UT1. * not required to actually perform the UTC-SLS slew or to otherwise be
* aware of leap seconds. JSR-310 does, however, require that
* implementations must document the approach they use when defining a
* clock representing the current instant.
* See {@link Clock} for details on the available clocks.
* <p> * <p>
* The Java time-scale is used for all date-time classes. * The Java time-scale is used for all date-time classes.
* This includes {@code Instant}, {@code LocalDate}, {@code LocalTime}, {@code OffsetDateTime}, * This includes {@code Instant}, {@code LocalDate}, {@code LocalTime}, {@code OffsetDateTime},
* {@code ZonedDateTime} and {@code Duration}. * {@code ZonedDateTime} and {@code Duration}.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This class is immutable and thread-safe. * This class is immutable and thread-safe.
* *
* @since 1.8 * @since 1.8
...@@ -1030,16 +1043,16 @@ public final class Instant ...@@ -1030,16 +1043,16 @@ public final class Instant
} }
/** /**
* Calculates the period between this instant and another instant in * Calculates the amount of time until another instant in terms of the specified unit.
* terms of the specified unit.
* <p> * <p>
* This calculates the period between two instants in terms of a single unit. * This calculates the amount of time between two {@code Instant}
* objects in terms of a single {@code TemporalUnit}.
* The start and end points are {@code this} and the specified instant. * The start and end points are {@code this} and the specified instant.
* The result will be negative if the end is before the start. * The result will be negative if the end is before the start.
* The calculation returns a whole number, representing the number of * The calculation returns a whole number, representing the number of
* complete units between the two instants. * complete units between the two instants.
* The {@code Temporal} passed to this method must be an {@code Instant}. * The {@code Temporal} passed to this method must be an {@code Instant}.
* For example, the period in days between two dates can be calculated * For example, the amount in days between two dates can be calculated
* using {@code startInstant.periodUntil(endInstant, SECONDS)}. * using {@code startInstant.periodUntil(endInstant, SECONDS)}.
* <p> * <p>
* There are two equivalent ways of using this method. * There are two equivalent ways of using this method.
...@@ -1064,10 +1077,10 @@ public final class Instant ...@@ -1064,10 +1077,10 @@ public final class Instant
* <p> * <p>
* This instance is immutable and unaffected by this method call. * This instance is immutable and unaffected by this method call.
* *
* @param endInstant the end date, which must be a {@code LocalDate}, not null * @param endInstant the end date, which must be an {@code Instant}, not null
* @param unit the unit to measure the period in, not null * @param unit the unit to measure the amount in, not null
* @return the amount of the period between this date and the end date * @return the amount of time between this instant and the end instant
* @throws DateTimeException if the period cannot be calculated * @throws DateTimeException if the amount cannot be calculated
* @throws UnsupportedTemporalTypeException if the unit is not supported * @throws UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs * @throws ArithmeticException if numeric overflow occurs
*/ */
...@@ -1075,7 +1088,7 @@ public final class Instant ...@@ -1075,7 +1088,7 @@ public final class Instant
public long periodUntil(Temporal endInstant, TemporalUnit unit) { public long periodUntil(Temporal endInstant, TemporalUnit unit) {
if (endInstant instanceof Instant == false) { if (endInstant instanceof Instant == false) {
Objects.requireNonNull(endInstant, "endInstant"); Objects.requireNonNull(endInstant, "endInstant");
throw new DateTimeException("Unable to calculate period between objects of two different types"); throw new DateTimeException("Unable to calculate amount as objects are of two different types");
} }
Instant end = (Instant) endInstant; Instant end = (Instant) endInstant;
if (unit instanceof ChronoUnit) { if (unit instanceof ChronoUnit) {
......
...@@ -121,7 +121,7 @@ import java.util.Objects; ...@@ -121,7 +121,7 @@ import java.util.Objects;
* However, any application that makes use of historical dates, and requires them * However, any application that makes use of historical dates, and requires them
* to be accurate will find the ISO-8601 approach unsuitable. * to be accurate will find the ISO-8601 approach unsuitable.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This class is immutable and thread-safe. * This class is immutable and thread-safe.
* *
* @since 1.8 * @since 1.8
...@@ -1489,19 +1489,19 @@ public final class LocalDate ...@@ -1489,19 +1489,19 @@ public final class LocalDate
} }
/** /**
* Calculates the period between this date and another date in * Calculates the amount of time until another date in terms of the specified unit.
* terms of the specified unit.
* <p> * <p>
* This calculates the period between two dates in terms of a single unit. * This calculates the amount of time between two {@code LocalDate}
* objects in terms of a single {@code TemporalUnit}.
* The start and end points are {@code this} and the specified date. * The start and end points are {@code this} and the specified date.
* The result will be negative if the end is before the start. * The result will be negative if the end is before the start.
* The {@code Temporal} passed to this method must be a {@code LocalDate}. * The {@code Temporal} passed to this method must be a {@code LocalDate}.
* For example, the period in days between two dates can be calculated * For example, the amount in days between two dates can be calculated
* using {@code startDate.periodUntil(endDate, DAYS)}. * using {@code startDate.periodUntil(endDate, DAYS)}.
* <p> * <p>
* The calculation returns a whole number, representing the number of * The calculation returns a whole number, representing the number of
* complete units between the two dates. * complete units between the two dates.
* For example, the period in months between 2012-06-15 and 2012-08-14 * For example, the amount in months between 2012-06-15 and 2012-08-14
* will only be one month as it is one day short of two months. * will only be one month as it is one day short of two months.
* <p> * <p>
* There are two equivalent ways of using this method. * There are two equivalent ways of using this method.
...@@ -1527,9 +1527,9 @@ public final class LocalDate ...@@ -1527,9 +1527,9 @@ public final class LocalDate
* This instance is immutable and unaffected by this method call. * This instance is immutable and unaffected by this method call.
* *
* @param endDate the end date, which must be a {@code LocalDate}, not null * @param endDate the end date, which must be a {@code LocalDate}, not null
* @param unit the unit to measure the period in, not null * @param unit the unit to measure the amount in, not null
* @return the amount of the period between this date and the end date * @return the amount of time between this date and the end date
* @throws DateTimeException if the period cannot be calculated * @throws DateTimeException if the amount cannot be calculated
* @throws UnsupportedTemporalTypeException if the unit is not supported * @throws UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs * @throws ArithmeticException if numeric overflow occurs
*/ */
...@@ -1538,7 +1538,7 @@ public final class LocalDate ...@@ -1538,7 +1538,7 @@ public final class LocalDate
Objects.requireNonNull(unit, "unit"); Objects.requireNonNull(unit, "unit");
if (endDate instanceof LocalDate == false) { if (endDate instanceof LocalDate == false) {
Objects.requireNonNull(endDate, "endDate"); Objects.requireNonNull(endDate, "endDate");
throw new DateTimeException("Unable to calculate period between objects of two different types"); throw new DateTimeException("Unable to calculate amount as objects are of two different types");
} }
LocalDate end = (LocalDate) endDate; LocalDate end = (LocalDate) endDate;
if (unit instanceof ChronoUnit) { if (unit instanceof ChronoUnit) {
......
...@@ -119,7 +119,7 @@ import java.util.Objects; ...@@ -119,7 +119,7 @@ import java.util.Objects;
* However, any application that makes use of historical dates, and requires them * However, any application that makes use of historical dates, and requires them
* to be accurate will find the ISO-8601 approach unsuitable. * to be accurate will find the ISO-8601 approach unsuitable.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This class is immutable and thread-safe. * This class is immutable and thread-safe.
* *
* @since 1.8 * @since 1.8
...@@ -1562,19 +1562,19 @@ public final class LocalDateTime ...@@ -1562,19 +1562,19 @@ public final class LocalDateTime
} }
/** /**
* Calculates the period between this date-time and another date-time in * Calculates the amount of time until another date-time in terms of the specified unit.
* terms of the specified unit.
* <p> * <p>
* This calculates the period between two date-times in terms of a single unit. * This calculates the amount of time between two {@code LocalDateTime}
* objects in terms of a single {@code TemporalUnit}.
* The start and end points are {@code this} and the specified date-time. * The start and end points are {@code this} and the specified date-time.
* The result will be negative if the end is before the start. * The result will be negative if the end is before the start.
* The {@code Temporal} passed to this method must be a {@code LocalDateTime}. * The {@code Temporal} passed to this method must be a {@code LocalDateTime}.
* For example, the period in days between two date-times can be calculated * For example, the amount in days between two date-times can be calculated
* using {@code startDateTime.periodUntil(endDateTime, DAYS)}. * using {@code startDateTime.periodUntil(endDateTime, DAYS)}.
* <p> * <p>
* The calculation returns a whole number, representing the number of * The calculation returns a whole number, representing the number of
* complete units between the two date-times. * complete units between the two date-times.
* For example, the period in months between 2012-06-15T00:00 and 2012-08-14T23:59 * For example, the amount in months between 2012-06-15T00:00 and 2012-08-14T23:59
* will only be one month as it is one minute short of two months. * will only be one month as it is one minute short of two months.
* <p> * <p>
* There are two equivalent ways of using this method. * There are two equivalent ways of using this method.
...@@ -1602,9 +1602,9 @@ public final class LocalDateTime ...@@ -1602,9 +1602,9 @@ public final class LocalDateTime
* This instance is immutable and unaffected by this method call. * This instance is immutable and unaffected by this method call.
* *
* @param endDateTime the end date-time, which must be a {@code LocalDateTime}, not null * @param endDateTime the end date-time, which must be a {@code LocalDateTime}, not null
* @param unit the unit to measure the period in, not null * @param unit the unit to measure the amount in, not null
* @return the amount of the period between this date-time and the end date-time * @return the amount of time between this date-time and the end date-time
* @throws DateTimeException if the period cannot be calculated * @throws DateTimeException if the amount cannot be calculated
* @throws UnsupportedTemporalTypeException if the unit is not supported * @throws UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs * @throws ArithmeticException if numeric overflow occurs
*/ */
...@@ -1612,7 +1612,7 @@ public final class LocalDateTime ...@@ -1612,7 +1612,7 @@ public final class LocalDateTime
public long periodUntil(Temporal endDateTime, TemporalUnit unit) { public long periodUntil(Temporal endDateTime, TemporalUnit unit) {
if (endDateTime instanceof LocalDateTime == false) { if (endDateTime instanceof LocalDateTime == false) {
Objects.requireNonNull(endDateTime, "endDateTime"); Objects.requireNonNull(endDateTime, "endDateTime");
throw new DateTimeException("Unable to calculate period between objects of two different types"); throw new DateTimeException("Unable to calculate amount as objects are of two different types");
} }
LocalDateTime end = (LocalDateTime) endDateTime; LocalDateTime end = (LocalDateTime) endDateTime;
if (unit instanceof ChronoUnit) { if (unit instanceof ChronoUnit) {
......
...@@ -109,7 +109,7 @@ import java.util.Objects; ...@@ -109,7 +109,7 @@ import java.util.Objects;
* in most of the world. This API assumes that all calendar systems use the same * in most of the world. This API assumes that all calendar systems use the same
* representation, this class, for time-of-day. * representation, this class, for time-of-day.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This class is immutable and thread-safe. * This class is immutable and thread-safe.
* *
* @since 1.8 * @since 1.8
...@@ -974,9 +974,6 @@ public final class LocalTime ...@@ -974,9 +974,6 @@ public final class LocalTime
* Returns a {@code LocalTime} with the specified number of half-days added. * Returns a {@code LocalTime} with the specified number of half-days added.
* This is equivalent to {@link #plusHours(long)} with the amount * This is equivalent to {@link #plusHours(long)} with the amount
* multiplied by 12. * multiplied by 12.
* <li>{@code DAYS} -
* Returns a {@code LocalTime} with the specified number of days added.
* This returns {@code this} time.
* </ul> * </ul>
* <p> * <p>
* All other {@code ChronoUnit} instances will throw an {@code UnsupportedTemporalTypeException}. * All other {@code ChronoUnit} instances will throw an {@code UnsupportedTemporalTypeException}.
...@@ -1007,7 +1004,6 @@ public final class LocalTime ...@@ -1007,7 +1004,6 @@ public final class LocalTime
case MINUTES: return plusMinutes(amountToAdd); case MINUTES: return plusMinutes(amountToAdd);
case HOURS: return plusHours(amountToAdd); case HOURS: return plusHours(amountToAdd);
case HALF_DAYS: return plusHours((amountToAdd % 2) * 12); case HALF_DAYS: return plusHours((amountToAdd % 2) * 12);
case DAYS: return this;
} }
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName()); throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
} }
...@@ -1291,19 +1287,19 @@ public final class LocalTime ...@@ -1291,19 +1287,19 @@ public final class LocalTime
} }
/** /**
* Calculates the period between this time and another time in * Calculates the amount of time until another time in terms of the specified unit.
* terms of the specified unit.
* <p> * <p>
* This calculates the period between two times in terms of a single unit. * This calculates the amount of time between two {@code LocalTime}
* objects in terms of a single {@code TemporalUnit}.
* The start and end points are {@code this} and the specified time. * The start and end points are {@code this} and the specified time.
* The result will be negative if the end is before the start. * The result will be negative if the end is before the start.
* The {@code Temporal} passed to this method must be a {@code LocalTime}. * The {@code Temporal} passed to this method must be a {@code LocalTime}.
* For example, the period in hours between two times can be calculated * For example, the amount in hours between two times can be calculated
* using {@code startTime.periodUntil(endTime, HOURS)}. * using {@code startTime.periodUntil(endTime, HOURS)}.
* <p> * <p>
* The calculation returns a whole number, representing the number of * The calculation returns a whole number, representing the number of
* complete units between the two times. * complete units between the two times.
* For example, the period in hours between 11:30 and 13:29 will only * For example, the amount in hours between 11:30 and 13:29 will only
* be one hour as it is one minute short of two hours. * be one hour as it is one minute short of two hours.
* <p> * <p>
* There are two equivalent ways of using this method. * There are two equivalent ways of using this method.
...@@ -1329,9 +1325,9 @@ public final class LocalTime ...@@ -1329,9 +1325,9 @@ public final class LocalTime
* This instance is immutable and unaffected by this method call. * This instance is immutable and unaffected by this method call.
* *
* @param endTime the end time, which must be a {@code LocalTime}, not null * @param endTime the end time, which must be a {@code LocalTime}, not null
* @param unit the unit to measure the period in, not null * @param unit the unit to measure the amount in, not null
* @return the amount of the period between this time and the end time * @return the amount of time between this time and the end time
* @throws DateTimeException if the period cannot be calculated * @throws DateTimeException if the amount cannot be calculated
* @throws UnsupportedTemporalTypeException if the unit is not supported * @throws UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs * @throws ArithmeticException if numeric overflow occurs
*/ */
...@@ -1339,7 +1335,7 @@ public final class LocalTime ...@@ -1339,7 +1335,7 @@ public final class LocalTime
public long periodUntil(Temporal endTime, TemporalUnit unit) { public long periodUntil(Temporal endTime, TemporalUnit unit) {
if (endTime instanceof LocalTime == false) { if (endTime instanceof LocalTime == false) {
Objects.requireNonNull(endTime, "endTime"); Objects.requireNonNull(endTime, "endTime");
throw new DateTimeException("Unable to calculate period between objects of two different types"); throw new DateTimeException("Unable to calculate amount as objects are of two different types");
} }
LocalTime end = (LocalTime) endTime; LocalTime end = (LocalTime) endTime;
if (unit instanceof ChronoUnit) { if (unit instanceof ChronoUnit) {
......
...@@ -97,7 +97,7 @@ import java.util.Locale; ...@@ -97,7 +97,7 @@ import java.util.Locale;
* As such, this enum may be used by any calendar system that has the month-of-year * As such, this enum may be used by any calendar system that has the month-of-year
* concept defined exactly equivalent to the ISO-8601 calendar system. * concept defined exactly equivalent to the ISO-8601 calendar system.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This is an immutable and thread-safe enum. * This is an immutable and thread-safe enum.
* *
* @since 1.8 * @since 1.8
......
...@@ -111,7 +111,7 @@ import java.util.Objects; ...@@ -111,7 +111,7 @@ import java.util.Objects;
* However, any application that makes use of historical dates, and requires them * However, any application that makes use of historical dates, and requires them
* to be accurate will find the ISO-8601 approach unsuitable. * to be accurate will find the ISO-8601 approach unsuitable.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This class is immutable and thread-safe. * This class is immutable and thread-safe.
* *
* @since 1.8 * @since 1.8
......
...@@ -111,7 +111,7 @@ import java.util.Objects; ...@@ -111,7 +111,7 @@ import java.util.Objects;
* in simpler applications. This class may be used when modeling date-time concepts in * in simpler applications. This class may be used when modeling date-time concepts in
* more detail, or when communicating to a database or in a network protocol. * more detail, or when communicating to a database or in a network protocol.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This class is immutable and thread-safe. * This class is immutable and thread-safe.
* *
* @since 1.8 * @since 1.8
...@@ -1521,10 +1521,10 @@ public final class OffsetDateTime ...@@ -1521,10 +1521,10 @@ public final class OffsetDateTime
} }
/** /**
* Calculates the period between this date-time and another date-time in * Calculates the amount of time until another date-time in terms of the specified unit.
* terms of the specified unit.
* <p> * <p>
* This calculates the period between two date-times in terms of a single unit. * This calculates the amount of time between two {@code OffsetDateTime}
* objects in terms of a single {@code TemporalUnit}.
* The start and end points are {@code this} and the specified date-time. * The start and end points are {@code this} and the specified date-time.
* The result will be negative if the end is before the start. * The result will be negative if the end is before the start.
* For example, the period in days between two date-times can be calculated * For example, the period in days between two date-times can be calculated
...@@ -1564,9 +1564,9 @@ public final class OffsetDateTime ...@@ -1564,9 +1564,9 @@ public final class OffsetDateTime
* This instance is immutable and unaffected by this method call. * This instance is immutable and unaffected by this method call.
* *
* @param endDateTime the end date-time, which must be an {@code OffsetDateTime}, not null * @param endDateTime the end date-time, which must be an {@code OffsetDateTime}, not null
* @param unit the unit to measure the period in, not null * @param unit the unit to measure the amount in, not null
* @return the amount of the period between this date-time and the end date-time * @return the amount of time between this date-time and the end date-time
* @throws DateTimeException if the period cannot be calculated * @throws DateTimeException if the amount cannot be calculated
* @throws UnsupportedTemporalTypeException if the unit is not supported * @throws UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs * @throws ArithmeticException if numeric overflow occurs
*/ */
...@@ -1574,7 +1574,7 @@ public final class OffsetDateTime ...@@ -1574,7 +1574,7 @@ public final class OffsetDateTime
public long periodUntil(Temporal endDateTime, TemporalUnit unit) { public long periodUntil(Temporal endDateTime, TemporalUnit unit) {
if (endDateTime instanceof OffsetDateTime == false) { if (endDateTime instanceof OffsetDateTime == false) {
Objects.requireNonNull(endDateTime, "endDateTime"); Objects.requireNonNull(endDateTime, "endDateTime");
throw new DateTimeException("Unable to calculate period between objects of two different types"); throw new DateTimeException("Unable to calculate amount as objects are of two different types");
} }
if (unit instanceof ChronoUnit) { if (unit instanceof ChronoUnit) {
OffsetDateTime end = (OffsetDateTime) endDateTime; OffsetDateTime end = (OffsetDateTime) endDateTime;
......
...@@ -102,7 +102,7 @@ import java.util.Objects; ...@@ -102,7 +102,7 @@ import java.util.Objects;
* For example, the value "13:45.30.123456789+02:00" can be stored * For example, the value "13:45.30.123456789+02:00" can be stored
* in an {@code OffsetTime}. * in an {@code OffsetTime}.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This class is immutable and thread-safe. * This class is immutable and thread-safe.
* *
* @since 1.8 * @since 1.8
...@@ -1077,10 +1077,10 @@ public final class OffsetTime ...@@ -1077,10 +1077,10 @@ public final class OffsetTime
} }
/** /**
* Calculates the period between this time and another time in * Calculates the amount of time until another time in terms of the specified unit.
* terms of the specified unit.
* <p> * <p>
* This calculates the period between two times in terms of a single unit. * This calculates the amount of time between two {@code OffsetTime}
* objects in terms of a single {@code TemporalUnit}.
* The start and end points are {@code this} and the specified time. * The start and end points are {@code this} and the specified time.
* The result will be negative if the end is before the start. * The result will be negative if the end is before the start.
* For example, the period in hours between two times can be calculated * For example, the period in hours between two times can be calculated
...@@ -1118,9 +1118,9 @@ public final class OffsetTime ...@@ -1118,9 +1118,9 @@ public final class OffsetTime
* This instance is immutable and unaffected by this method call. * This instance is immutable and unaffected by this method call.
* *
* @param endTime the end time, which must be an {@code OffsetTime}, not null * @param endTime the end time, which must be an {@code OffsetTime}, not null
* @param unit the unit to measure the period in, not null * @param unit the unit to measure the amount in, not null
* @return the amount of the period between this time and the end time * @return the amount of time between this time and the end time
* @throws DateTimeException if the period cannot be calculated * @throws DateTimeException if the amount cannot be calculated
* @throws UnsupportedTemporalTypeException if the unit is not supported * @throws UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs * @throws ArithmeticException if numeric overflow occurs
*/ */
...@@ -1128,7 +1128,7 @@ public final class OffsetTime ...@@ -1128,7 +1128,7 @@ public final class OffsetTime
public long periodUntil(Temporal endTime, TemporalUnit unit) { public long periodUntil(Temporal endTime, TemporalUnit unit) {
if (endTime instanceof OffsetTime == false) { if (endTime instanceof OffsetTime == false) {
Objects.requireNonNull(endTime, "endTime"); Objects.requireNonNull(endTime, "endTime");
throw new DateTimeException("Unable to calculate period between objects of two different types"); throw new DateTimeException("Unable to calculate amount as objects are of two different types");
} }
if (unit instanceof ChronoUnit) { if (unit instanceof ChronoUnit) {
OffsetTime end = (OffsetTime) endTime; OffsetTime end = (OffsetTime) endTime;
......
...@@ -119,7 +119,7 @@ import java.util.regex.Pattern; ...@@ -119,7 +119,7 @@ import java.util.regex.Pattern;
* The months and years fields may be {@linkplain #normalized() normalized}. * The months and years fields may be {@linkplain #normalized() normalized}.
* The normalization assumes a 12 month year, so is not appropriate for all calendar systems. * The normalization assumes a 12 month year, so is not appropriate for all calendar systems.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This class is immutable and thread-safe. * This class is immutable and thread-safe.
* *
* @since 1.8 * @since 1.8
......
...@@ -66,7 +66,7 @@ import java.io.StreamCorruptedException; ...@@ -66,7 +66,7 @@ import java.io.StreamCorruptedException;
/** /**
* The shared serialization delegate for this package. * The shared serialization delegate for this package.
* *
* <h3>Implementation notes</h3> * @implNote
* This class wraps the object being serialized, and takes a byte representing the type of the class to * This class wraps the object being serialized, and takes a byte representing the type of the class to
* be serialized. This byte can also be used for versioning the serialization format. In this case another * be serialized. This byte can also be used for versioning the serialization format. In this case another
* byte flag would be used in order to specify an alternative version of the type format. * byte flag would be used in order to specify an alternative version of the type format.
......
...@@ -115,7 +115,7 @@ import java.util.Objects; ...@@ -115,7 +115,7 @@ import java.util.Objects;
* However, any application that makes use of historical dates, and requires them * However, any application that makes use of historical dates, and requires them
* to be accurate will find the ISO-8601 approach unsuitable. * to be accurate will find the ISO-8601 approach unsuitable.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This class is immutable and thread-safe. * This class is immutable and thread-safe.
* *
* @since 1.8 * @since 1.8
...@@ -813,10 +813,10 @@ public final class Year ...@@ -813,10 +813,10 @@ public final class Year
} }
/** /**
* Calculates the period between this year and another year in * Calculates the amount of time until another year in terms of the specified unit.
* terms of the specified unit.
* <p> * <p>
* This calculates the period between two years in terms of a single unit. * This calculates the amount of time between two {@code Year}
* objects in terms of a single {@code TemporalUnit}.
* The start and end points are {@code this} and the specified year. * The start and end points are {@code this} and the specified year.
* The result will be negative if the end is before the start. * The result will be negative if the end is before the start.
* The {@code Temporal} passed to this method must be a {@code Year}. * The {@code Temporal} passed to this method must be a {@code Year}.
...@@ -851,9 +851,9 @@ public final class Year ...@@ -851,9 +851,9 @@ public final class Year
* This instance is immutable and unaffected by this method call. * This instance is immutable and unaffected by this method call.
* *
* @param endYear the end year, which must be a {@code Year}, not null * @param endYear the end year, which must be a {@code Year}, not null
* @param unit the unit to measure the period in, not null * @param unit the unit to measure the amount in, not null
* @return the amount of the period between this year and the end year * @return the amount of time between this year and the end year
* @throws DateTimeException if the period cannot be calculated * @throws DateTimeException if the amount cannot be calculated
* @throws UnsupportedTemporalTypeException if the unit is not supported * @throws UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs * @throws ArithmeticException if numeric overflow occurs
*/ */
...@@ -861,7 +861,7 @@ public final class Year ...@@ -861,7 +861,7 @@ public final class Year
public long periodUntil(Temporal endYear, TemporalUnit unit) { public long periodUntil(Temporal endYear, TemporalUnit unit) {
if (endYear instanceof Year == false) { if (endYear instanceof Year == false) {
Objects.requireNonNull(endYear, "endYear"); Objects.requireNonNull(endYear, "endYear");
throw new DateTimeException("Unable to calculate period between objects of two different types"); throw new DateTimeException("Unable to calculate amount as objects are of two different types");
} }
Year end = (Year) endYear; Year end = (Year) endYear;
if (unit instanceof ChronoUnit) { if (unit instanceof ChronoUnit) {
......
...@@ -110,7 +110,7 @@ import java.util.Objects; ...@@ -110,7 +110,7 @@ import java.util.Objects;
* However, any application that makes use of historical dates, and requires them * However, any application that makes use of historical dates, and requires them
* to be accurate will find the ISO-8601 approach unsuitable. * to be accurate will find the ISO-8601 approach unsuitable.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This class is immutable and thread-safe. * This class is immutable and thread-safe.
* *
* @since 1.8 * @since 1.8
...@@ -944,10 +944,10 @@ public final class YearMonth ...@@ -944,10 +944,10 @@ public final class YearMonth
} }
/** /**
* Calculates the period between this year-month and another year-month in * Calculates the amount of time until another year-month in terms of the specified unit.
* terms of the specified unit.
* <p> * <p>
* This calculates the period between two year-months in terms of a single unit. * This calculates the amount of time between two {@code YearMonth}
* objects in terms of a single {@code TemporalUnit}.
* The start and end points are {@code this} and the specified year-month. * The start and end points are {@code this} and the specified year-month.
* The result will be negative if the end is before the start. * The result will be negative if the end is before the start.
* The {@code Temporal} passed to this method must be a {@code YearMonth}. * The {@code Temporal} passed to this method must be a {@code YearMonth}.
...@@ -982,9 +982,9 @@ public final class YearMonth ...@@ -982,9 +982,9 @@ public final class YearMonth
* This instance is immutable and unaffected by this method call. * This instance is immutable and unaffected by this method call.
* *
* @param endYearMonth the end year-month, which must be a {@code YearMonth}, not null * @param endYearMonth the end year-month, which must be a {@code YearMonth}, not null
* @param unit the unit to measure the period in, not null * @param unit the unit to measure the amount in, not null
* @return the amount of the period between this year-month and the end year-month * @return the amount of time between this year-month and the end year-month
* @throws DateTimeException if the period cannot be calculated * @throws DateTimeException if the amount cannot be calculated
* @throws UnsupportedTemporalTypeException if the unit is not supported * @throws UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs * @throws ArithmeticException if numeric overflow occurs
*/ */
...@@ -992,7 +992,7 @@ public final class YearMonth ...@@ -992,7 +992,7 @@ public final class YearMonth
public long periodUntil(Temporal endYearMonth, TemporalUnit unit) { public long periodUntil(Temporal endYearMonth, TemporalUnit unit) {
if (endYearMonth instanceof YearMonth == false) { if (endYearMonth instanceof YearMonth == false) {
Objects.requireNonNull(endYearMonth, "endYearMonth"); Objects.requireNonNull(endYearMonth, "endYearMonth");
throw new DateTimeException("Unable to calculate period between objects of two different types"); throw new DateTimeException("Unable to calculate amount as objects are of two different types");
} }
YearMonth end = (YearMonth) endYearMonth; YearMonth end = (YearMonth) endYearMonth;
if (unit instanceof ChronoUnit) { if (unit instanceof ChronoUnit) {
......
...@@ -157,7 +157,7 @@ import java.util.TimeZone; ...@@ -157,7 +157,7 @@ import java.util.TimeZone;
* This approach is designed to allow a {@link ZonedDateTime} to be loaded and * This approach is designed to allow a {@link ZonedDateTime} to be loaded and
* queried, but not modified, on a Java Runtime with incomplete time-zone information. * queried, but not modified, on a Java Runtime with incomplete time-zone information.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This abstract class has two implementations, both of which are immutable and thread-safe. * This abstract class has two implementations, both of which are immutable and thread-safe.
* One implementation models region-based IDs, the other is {@code ZoneOffset} modelling * One implementation models region-based IDs, the other is {@code ZoneOffset} modelling
* offset-based IDs. This difference is visible in serialization. * offset-based IDs. This difference is visible in serialization.
......
...@@ -114,7 +114,7 @@ import java.util.concurrent.ConcurrentMap; ...@@ -114,7 +114,7 @@ import java.util.concurrent.ConcurrentMap;
* Implementations may choose to cache certain common offsets, however * Implementations may choose to cache certain common offsets, however
* applications must not rely on such caching. * applications must not rely on such caching.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This class is immutable and thread-safe. * This class is immutable and thread-safe.
* *
* @since 1.8 * @since 1.8
......
...@@ -83,7 +83,7 @@ import java.util.regex.Pattern; ...@@ -83,7 +83,7 @@ import java.util.regex.Pattern;
* By contrast, the region identifier is well-defined and long-lived. * By contrast, the region identifier is well-defined and long-lived.
* This separation also allows rules to be shared between regions if appropriate. * This separation also allows rules to be shared between regions if appropriate.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This class is immutable and thread-safe. * This class is immutable and thread-safe.
* *
* @since 1.8 * @since 1.8
......
...@@ -142,7 +142,7 @@ import java.util.Objects; ...@@ -142,7 +142,7 @@ import java.util.Objects;
* a vital, but secondary, piece of information, used to ensure that the class * a vital, but secondary, piece of information, used to ensure that the class
* represents an instant, especially during a daylight savings overlap. * represents an instant, especially during a daylight savings overlap.
* *
* <h3>Specification for implementors</h3> * @implSpec
* A {@code ZonedDateTime} holds state equivalent to three separate objects, * A {@code ZonedDateTime} holds state equivalent to three separate objects,
* a {@code LocalDateTime}, a {@code ZoneId} and the resolved {@code ZoneOffset}. * a {@code LocalDateTime}, a {@code ZoneId} and the resolved {@code ZoneOffset}.
* The offset and local date-time are used to define an instant when necessary. * The offset and local date-time are used to define an instant when necessary.
...@@ -1983,10 +1983,10 @@ public final class ZonedDateTime ...@@ -1983,10 +1983,10 @@ public final class ZonedDateTime
} }
/** /**
* Calculates the period between this date-time and another date-time in * Calculates the amount of time until another date-time in terms of the specified unit.
* terms of the specified unit.
* <p> * <p>
* This calculates the period between two date-times in terms of a single unit. * This calculates the amount of time between two {@code ZonedDateTime}
* objects in terms of a single {@code TemporalUnit}.
* The start and end points are {@code this} and the specified date-time. * The start and end points are {@code this} and the specified date-time.
* The result will be negative if the end is before the start. * The result will be negative if the end is before the start.
* For example, the period in days between two date-times can be calculated * For example, the period in days between two date-times can be calculated
...@@ -2040,9 +2040,9 @@ public final class ZonedDateTime ...@@ -2040,9 +2040,9 @@ public final class ZonedDateTime
* This instance is immutable and unaffected by this method call. * This instance is immutable and unaffected by this method call.
* *
* @param endDateTime the end date-time, which must be a {@code ZonedDateTime}, not null * @param endDateTime the end date-time, which must be a {@code ZonedDateTime}, not null
* @param unit the unit to measure the period in, not null * @param unit the unit to measure the amount in, not null
* @return the amount of the period between this date-time and the end date-time * @return the amount of time between this date-time and the end date-time
* @throws DateTimeException if the period cannot be calculated * @throws DateTimeException if the amount cannot be calculated
* @throws UnsupportedTemporalTypeException if the unit is not supported * @throws UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs * @throws ArithmeticException if numeric overflow occurs
*/ */
...@@ -2050,7 +2050,7 @@ public final class ZonedDateTime ...@@ -2050,7 +2050,7 @@ public final class ZonedDateTime
public long periodUntil(Temporal endDateTime, TemporalUnit unit) { public long periodUntil(Temporal endDateTime, TemporalUnit unit) {
if (endDateTime instanceof ZonedDateTime == false) { if (endDateTime instanceof ZonedDateTime == false) {
Objects.requireNonNull(endDateTime, "endDateTime"); Objects.requireNonNull(endDateTime, "endDateTime");
throw new DateTimeException("Unable to calculate period between objects of two different types"); throw new DateTimeException("Unable to calculate amount as objects are of two different types");
} }
if (unit instanceof ChronoUnit) { if (unit instanceof ChronoUnit) {
ZonedDateTime end = (ZonedDateTime) endDateTime; ZonedDateTime end = (ZonedDateTime) endDateTime;
......
...@@ -130,7 +130,7 @@ import java.util.Objects; ...@@ -130,7 +130,7 @@ import java.util.Objects;
* The subclass must function according to the {@code Chronology} class description and must provide its * The subclass must function according to the {@code Chronology} class description and must provide its
* {@link java.time.chrono.Chronology#getId() chronlogy ID} and {@link Chronology#getCalendarType() calendar type}. </p> * {@link java.time.chrono.Chronology#getId() chronlogy ID} and {@link Chronology#getCalendarType() calendar type}. </p>
* *
* <h3>Specification for implementors</h3> * @implSpec
* This abstract class must be implemented with care to ensure other classes operate correctly. * This abstract class must be implemented with care to ensure other classes operate correctly.
* All implementations that can be instantiated must be final, immutable and thread-safe. * All implementations that can be instantiated must be final, immutable and thread-safe.
* Subclasses should be Serializable wherever possible. * Subclasses should be Serializable wherever possible.
...@@ -325,11 +325,11 @@ abstract class ChronoDateImpl<D extends ChronoLocalDate<D>> ...@@ -325,11 +325,11 @@ abstract class ChronoDateImpl<D extends ChronoLocalDate<D>>
Objects.requireNonNull(endDateTime, "endDateTime"); Objects.requireNonNull(endDateTime, "endDateTime");
Objects.requireNonNull(unit, "unit"); Objects.requireNonNull(unit, "unit");
if (endDateTime instanceof ChronoLocalDate == false) { if (endDateTime instanceof ChronoLocalDate == false) {
throw new DateTimeException("Unable to calculate period between objects of two different types"); throw new DateTimeException("Unable to calculate amount as objects are of two different types");
} }
ChronoLocalDate<?> end = (ChronoLocalDate<?>) endDateTime; ChronoLocalDate<?> end = (ChronoLocalDate<?>) endDateTime;
if (getChronology().equals(end.getChronology()) == false) { if (getChronology().equals(end.getChronology()) == false) {
throw new DateTimeException("Unable to calculate period between two different chronologies"); throw new DateTimeException("Unable to calculate amount as objects have different chronologies");
} }
if (unit instanceof ChronoUnit) { if (unit instanceof ChronoUnit) {
switch ((ChronoUnit) unit) { switch ((ChronoUnit) unit) {
......
...@@ -234,7 +234,7 @@ import java.util.Objects; ...@@ -234,7 +234,7 @@ import java.util.Objects;
* Use {@link TemporalAccessor} if read-only access is required, or use {@link Temporal} * Use {@link TemporalAccessor} if read-only access is required, or use {@link Temporal}
* if read-write access is required. * if read-write access is required.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This interface must be implemented with care to ensure other classes operate correctly. * This interface must be implemented with care to ensure other classes operate correctly.
* All implementations that can be instantiated must be final, immutable and thread-safe. * All implementations that can be instantiated must be final, immutable and thread-safe.
* Subclasses should be Serializable wherever possible. * Subclasses should be Serializable wherever possible.
...@@ -257,6 +257,7 @@ public interface ChronoLocalDate<D extends ChronoLocalDate<D>> ...@@ -257,6 +257,7 @@ public interface ChronoLocalDate<D extends ChronoLocalDate<D>>
* This allows dates in different calendar systems to be compared based * This allows dates in different calendar systems to be compared based
* on the position of the date on the local time-line. * on the position of the date on the local time-line.
* The underlying comparison is equivalent to comparing the epoch-day. * The underlying comparison is equivalent to comparing the epoch-day.
* @return a comparator that compares in time-line order ignoring the chronology
* *
* @see #isAfter * @see #isAfter
* @see #isBefore * @see #isBefore
...@@ -510,17 +511,17 @@ public interface ChronoLocalDate<D extends ChronoLocalDate<D>> ...@@ -510,17 +511,17 @@ public interface ChronoLocalDate<D extends ChronoLocalDate<D>>
} }
/** /**
* Calculates the period between this date and another date in * Calculates the amount of time until another date in terms of the specified unit.
* terms of the specified unit.
* <p> * <p>
* This calculates the period between two dates in terms of a single unit. * This calculates the amount of time between two {@code ChronoLocalDate}
* objects in terms of a single {@code TemporalUnit}.
* The start and end points are {@code this} and the specified date. * The start and end points are {@code this} and the specified date.
* The result will be negative if the end is before the start. * The result will be negative if the end is before the start.
* The {@code Temporal} passed to this method must be a * The {@code Temporal} passed to this method must be a
* {@code ChronoLocalDate} in the same chronology. * {@code ChronoLocalDate} in the same chronology.
* The calculation returns a whole number, representing the number of * The calculation returns a whole number, representing the number of
* complete units between the two dates. * complete units between the two dates.
* For example, the period in days between two dates can be calculated * For example, the amount in days between two dates can be calculated
* using {@code startDate.periodUntil(endDate, DAYS)}. * using {@code startDate.periodUntil(endDate, DAYS)}.
* <p> * <p>
* There are two equivalent ways of using this method. * There are two equivalent ways of using this method.
...@@ -548,9 +549,9 @@ public interface ChronoLocalDate<D extends ChronoLocalDate<D>> ...@@ -548,9 +549,9 @@ public interface ChronoLocalDate<D extends ChronoLocalDate<D>>
* *
* @param endDate the end date, which must be a {@code ChronoLocalDate} * @param endDate the end date, which must be a {@code ChronoLocalDate}
* in the same chronology, not null * in the same chronology, not null
* @param unit the unit to measure the period in, not null * @param unit the unit to measure the amount in, not null
* @return the amount of the period between this date and the end date * @return the amount of time between this date and the end date
* @throws DateTimeException if the period cannot be calculated * @throws DateTimeException if the amount cannot be calculated
* @throws ArithmeticException if numeric overflow occurs * @throws ArithmeticException if numeric overflow occurs
*/ */
@Override // override for Javadoc @Override // override for Javadoc
......
...@@ -106,7 +106,7 @@ import java.util.Objects; ...@@ -106,7 +106,7 @@ import java.util.Objects;
* Ensure that the discussion in {@code ChronoLocalDate} has been read and understood * Ensure that the discussion in {@code ChronoLocalDate} has been read and understood
* before using this interface. * before using this interface.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This interface must be implemented with care to ensure other classes operate correctly. * This interface must be implemented with care to ensure other classes operate correctly.
* All implementations that can be instantiated must be final, immutable and thread-safe. * All implementations that can be instantiated must be final, immutable and thread-safe.
* Subclasses should be Serializable wherever possible. * Subclasses should be Serializable wherever possible.
...@@ -127,6 +127,8 @@ public interface ChronoLocalDateTime<D extends ChronoLocalDate<D>> ...@@ -127,6 +127,8 @@ public interface ChronoLocalDateTime<D extends ChronoLocalDate<D>>
* on the position of the date-time on the local time-line. * on the position of the date-time on the local time-line.
* The underlying comparison is equivalent to comparing the epoch-day and nano-of-day. * The underlying comparison is equivalent to comparing the epoch-day and nano-of-day.
* *
* @return a comparator that compares in time-line order ignoring the chronology
*
* @see #isAfter * @see #isAfter
* @see #isBefore * @see #isBefore
* @see #isEqual * @see #isEqual
......
...@@ -92,7 +92,7 @@ import java.util.Objects; ...@@ -92,7 +92,7 @@ import java.util.Objects;
* It does not store or represent a time-zone. For example, the value * It does not store or represent a time-zone. For example, the value
* "2nd October 2007 at 13:45.30.123456789" can be stored in an {@code ChronoLocalDateTime}. * "2nd October 2007 at 13:45.30.123456789" can be stored in an {@code ChronoLocalDateTime}.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This class is immutable and thread-safe. * This class is immutable and thread-safe.
* *
* @param <D> the concrete type for the date of this date-time * @param <D> the concrete type for the date of this date-time
...@@ -353,12 +353,12 @@ final class ChronoLocalDateTimeImpl<D extends ChronoLocalDate<D>> ...@@ -353,12 +353,12 @@ final class ChronoLocalDateTimeImpl<D extends ChronoLocalDate<D>>
@Override @Override
public long periodUntil(Temporal endDateTime, TemporalUnit unit) { public long periodUntil(Temporal endDateTime, TemporalUnit unit) {
if (endDateTime instanceof ChronoLocalDateTime == false) { if (endDateTime instanceof ChronoLocalDateTime == false) {
throw new DateTimeException("Unable to calculate period between objects of two different types"); throw new DateTimeException("Unable to calculate amount as objects are of two different types");
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
ChronoLocalDateTime<D> end = (ChronoLocalDateTime<D>) endDateTime; ChronoLocalDateTime<D> end = (ChronoLocalDateTime<D>) endDateTime;
if (toLocalDate().getChronology().equals(end.toLocalDate().getChronology()) == false) { if (toLocalDate().getChronology().equals(end.toLocalDate().getChronology()) == false) {
throw new DateTimeException("Unable to calculate period between two different chronologies"); throw new DateTimeException("Unable to calculate amount as objects have different chronologies");
} }
if (unit instanceof ChronoUnit) { if (unit instanceof ChronoUnit) {
ChronoUnit f = (ChronoUnit) unit; ChronoUnit f = (ChronoUnit) unit;
......
...@@ -107,7 +107,7 @@ import java.util.Objects; ...@@ -107,7 +107,7 @@ import java.util.Objects;
* Ensure that the discussion in {@code ChronoLocalDate} has been read and understood * Ensure that the discussion in {@code ChronoLocalDate} has been read and understood
* before using this interface. * before using this interface.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This interface must be implemented with care to ensure other classes operate correctly. * This interface must be implemented with care to ensure other classes operate correctly.
* All implementations that can be instantiated must be final, immutable and thread-safe. * All implementations that can be instantiated must be final, immutable and thread-safe.
* Subclasses should be Serializable wherever possible. * Subclasses should be Serializable wherever possible.
...@@ -128,6 +128,8 @@ public interface ChronoZonedDateTime<D extends ChronoLocalDate<D>> ...@@ -128,6 +128,8 @@ public interface ChronoZonedDateTime<D extends ChronoLocalDate<D>>
* on the position of the date-time on the instant time-line. * on the position of the date-time on the instant time-line.
* The underlying comparison is equivalent to comparing the epoch-second and nano-of-second. * The underlying comparison is equivalent to comparing the epoch-second and nano-of-second.
* *
* @return a comparator that compares in time-line order ignoring the chronology
*
* @see #isAfter * @see #isAfter
* @see #isBefore * @see #isBefore
* @see #isEqual * @see #isEqual
......
...@@ -95,7 +95,7 @@ import java.util.Objects; ...@@ -95,7 +95,7 @@ import java.util.Objects;
* the local time-line overlaps, typically as a result of the end of daylight time. * the local time-line overlaps, typically as a result of the end of daylight time.
* Information about the local-time can be obtained using methods on the time-zone. * Information about the local-time can be obtained using methods on the time-zone.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This class is immutable and thread-safe. * This class is immutable and thread-safe.
* *
* @param <D> the concrete type for the date of this date-time * @param <D> the concrete type for the date of this date-time
...@@ -287,12 +287,12 @@ final class ChronoZonedDateTimeImpl<D extends ChronoLocalDate<D>> ...@@ -287,12 +287,12 @@ final class ChronoZonedDateTimeImpl<D extends ChronoLocalDate<D>>
@Override @Override
public long periodUntil(Temporal endDateTime, TemporalUnit unit) { public long periodUntil(Temporal endDateTime, TemporalUnit unit) {
if (endDateTime instanceof ChronoZonedDateTime == false) { if (endDateTime instanceof ChronoZonedDateTime == false) {
throw new DateTimeException("Unable to calculate period between objects of two different types"); throw new DateTimeException("Unable to calculate amount as objects are of two different types");
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
ChronoZonedDateTime<D> end = (ChronoZonedDateTime<D>) endDateTime; ChronoZonedDateTime<D> end = (ChronoZonedDateTime<D>) endDateTime;
if (toLocalDate().getChronology().equals(end.toLocalDate().getChronology()) == false) { if (toLocalDate().getChronology().equals(end.toLocalDate().getChronology()) == false) {
throw new DateTimeException("Unable to calculate period between two different chronologies"); throw new DateTimeException("Unable to calculate amount as objects have different chronologies");
} }
if (unit instanceof ChronoUnit) { if (unit instanceof ChronoUnit) {
end = end.withZoneSameInstant(offset); end = end.withZoneSameInstant(offset);
......
...@@ -176,7 +176,7 @@ import sun.util.logging.PlatformLogger; ...@@ -176,7 +176,7 @@ import sun.util.logging.PlatformLogger;
* CLDR specification then the calendar type is the concatenation of the * CLDR specification then the calendar type is the concatenation of the
* CLDR type and, if applicable, the CLDR variant, * CLDR type and, if applicable, the CLDR variant,
* *
* <h3>Specification for implementors</h3> * @implSpec
* This class must be implemented with care to ensure other classes operate correctly. * This class must be implemented with care to ensure other classes operate correctly.
* All implementations that can be instantiated must be final, immutable and thread-safe. * All implementations that can be instantiated must be final, immutable and thread-safe.
* Subclasses should be Serializable wherever possible. * Subclasses should be Serializable wherever possible.
...@@ -338,16 +338,13 @@ public abstract class Chronology implements Comparable<Chronology> { ...@@ -338,16 +338,13 @@ public abstract class Chronology implements Comparable<Chronology> {
* <p> * <p>
* The {@code Locale} class also supports an extension mechanism that * The {@code Locale} class also supports an extension mechanism that
* can be used to identify a calendar system. The mechanism is a form * can be used to identify a calendar system. The mechanism is a form
* of key-value pairs, where the calendar system has the key "ca" * of key-value pairs, where the calendar system has the key "ca".
* and an optional variant key "cv".
* For example, the locale "en-JP-u-ca-japanese" represents the English * For example, the locale "en-JP-u-ca-japanese" represents the English
* language as used in Japan with the Japanese calendar system. * language as used in Japan with the Japanese calendar system.
* <p> * <p>
* This method finds the desired calendar system by in a manner equivalent * This method finds the desired calendar system by in a manner equivalent
* to passing "ca" to {@link Locale#getUnicodeLocaleType(String)}. * to passing "ca" to {@link Locale#getUnicodeLocaleType(String)}.
* If the "ca" key is not present, then {@code IsoChronology} is returned. * If the "ca" key is not present, then {@code IsoChronology} is returned.
* The variant, if present, is appended to the "ca" value separated by "-"
* and the concatenated value is used to find the calendar system by type.
* <p> * <p>
* Note that the behavior of this method differs from the older * Note that the behavior of this method differs from the older
* {@link java.util.Calendar#getInstance(Locale)} method. * {@link java.util.Calendar#getInstance(Locale)} method.
...@@ -374,10 +371,6 @@ public abstract class Chronology implements Comparable<Chronology> { ...@@ -374,10 +371,6 @@ public abstract class Chronology implements Comparable<Chronology> {
if (type == null || "iso".equals(type) || "iso8601".equals(type)) { if (type == null || "iso".equals(type) || "iso8601".equals(type)) {
return IsoChronology.INSTANCE; return IsoChronology.INSTANCE;
} }
String variant = locale.getUnicodeLocaleType("cv");
if (variant != null && !variant.isEmpty()) {
type = type + '-' + variant;
}
// Not pre-defined; lookup by the type // Not pre-defined; lookup by the type
do { do {
Chronology chrono = CHRONOS_BY_TYPE.get(type); Chronology chrono = CHRONOS_BY_TYPE.get(type);
...@@ -563,7 +556,7 @@ public abstract class Chronology implements Comparable<Chronology> { ...@@ -563,7 +556,7 @@ public abstract class Chronology implements Comparable<Chronology> {
* and the variant, if applicable, is appended separated by "-". * and the variant, if applicable, is appended separated by "-".
* The calendar type is used to lookup the {@code Chronology} using {@link #of(String)}. * The calendar type is used to lookup the {@code Chronology} using {@link #of(String)}.
* *
* @return the calendar system type, null if the calendar is not defined * @return the calendar system type, null if the calendar is not defined by CLDR/LDML
* @see #getId() * @see #getId()
*/ */
public abstract String getCalendarType(); public abstract String getCalendarType();
......
...@@ -93,7 +93,7 @@ import java.util.Locale; ...@@ -93,7 +93,7 @@ import java.util.Locale;
* <p> * <p>
* Instances of {@code Era} may be compared using the {@code ==} operator. * Instances of {@code Era} may be compared using the {@code ==} operator.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This interface must be implemented with care to ensure other classes operate correctly. * This interface must be implemented with care to ensure other classes operate correctly.
* All implementations must be singletons - final, immutable and thread-safe. * All implementations must be singletons - final, immutable and thread-safe.
* It is recommended to use an enum whenever possible. * It is recommended to use an enum whenever possible.
......
...@@ -133,9 +133,10 @@ import sun.util.logging.PlatformLogger; ...@@ -133,9 +133,10 @@ import sun.util.logging.PlatformLogger;
* Chronology chrono = Chronology.ofLocale(locale); * Chronology chrono = Chronology.ofLocale(locale);
* </pre> * </pre>
* *
* <h3>Specification for implementors</h3> * @implSpec
* This class is immutable and thread-safe. * This class is immutable and thread-safe.
* <h3>Implementation Note for Hijrah Calendar Variant Configuration</h3> *
* @implNote
* Each Hijrah variant is configured individually. Each variant is defined by a * Each Hijrah variant is configured individually. Each variant is defined by a
* property resource that defines the {@code ID}, the {@code calendar type}, * property resource that defines the {@code ID}, the {@code calendar type},
* the start of the calendar, the alignment with the * the start of the calendar, the alignment with the
...@@ -229,6 +230,11 @@ public final class HijrahChronology extends Chronology implements Serializable { ...@@ -229,6 +230,11 @@ public final class HijrahChronology extends Chronology implements Serializable {
* {@link Chronology#getAvailableChronologies}. * {@link Chronology#getAvailableChronologies}.
*/ */
public static final HijrahChronology INSTANCE; public static final HijrahChronology INSTANCE;
/**
* Flag to indicate the initialization of configuration data is complete.
* @see #checkCalendarInit()
*/
private volatile boolean initComplete;
/** /**
* Array of epoch days indexed by Hijrah Epoch month. * Array of epoch days indexed by Hijrah Epoch month.
* Computed by {@link #loadCalendarData}. * Computed by {@link #loadCalendarData}.
...@@ -285,7 +291,8 @@ public final class HijrahChronology extends Chronology implements Serializable { ...@@ -285,7 +291,8 @@ public final class HijrahChronology extends Chronology implements Serializable {
private static final String PROP_TYPE_SUFFIX = ".type"; private static final String PROP_TYPE_SUFFIX = ".type";
/** /**
* Name data. * Static initialization of the predefined calendars found in the
* lib/calendars.properties file.
*/ */
static { static {
try { try {
...@@ -299,8 +306,7 @@ public final class HijrahChronology extends Chronology implements Serializable { ...@@ -299,8 +306,7 @@ public final class HijrahChronology extends Chronology implements Serializable {
// Register it by its aliases // Register it by its aliases
Chronology.registerChrono(INSTANCE, "Hijrah"); Chronology.registerChrono(INSTANCE, "Hijrah");
Chronology.registerChrono(INSTANCE, "islamic"); Chronology.registerChrono(INSTANCE, "islamic");
} catch (DateTimeException ex) {
} catch (Exception ex) {
// Absence of Hijrah calendar is fatal to initializing this class. // Absence of Hijrah calendar is fatal to initializing this class.
PlatformLogger logger = PlatformLogger.getLogger("java.time.chrono"); PlatformLogger logger = PlatformLogger.getLogger("java.time.chrono");
logger.severe("Unable to initialize Hijrah calendar: Hijrah-umalqura", ex); logger.severe("Unable to initialize Hijrah calendar: Hijrah-umalqura", ex);
...@@ -327,7 +333,7 @@ public final class HijrahChronology extends Chronology implements Serializable { ...@@ -327,7 +333,7 @@ public final class HijrahChronology extends Chronology implements Serializable {
// Create and register the variant // Create and register the variant
HijrahChronology chrono = new HijrahChronology(id); HijrahChronology chrono = new HijrahChronology(id);
Chronology.registerChrono(chrono); Chronology.registerChrono(chrono);
} catch (Exception ex) { } catch (DateTimeException ex) {
// Log error and continue // Log error and continue
PlatformLogger logger = PlatformLogger.getLogger("java.time.chrono"); PlatformLogger logger = PlatformLogger.getLogger("java.time.chrono");
logger.severe("Unable to initialize Hijrah calendar: " + id, ex); logger.severe("Unable to initialize Hijrah calendar: " + id, ex);
...@@ -343,22 +349,39 @@ public final class HijrahChronology extends Chronology implements Serializable { ...@@ -343,22 +349,39 @@ public final class HijrahChronology extends Chronology implements Serializable {
* The property names are {@code "calendar.hijrah." + id} * The property names are {@code "calendar.hijrah." + id}
* and {@code "calendar.hijrah." + id + ".type"} * and {@code "calendar.hijrah." + id + ".type"}
* @param id the id of the calendar * @param id the id of the calendar
* @throws Exception if the resource can not be accessed or * @throws DateTimeException if the calendar type is missing from the properties file.
* the format is invalid * @throws IllegalArgumentException if the id is empty
*/ */
private HijrahChronology(String id) throws Exception { private HijrahChronology(String id) throws DateTimeException {
if (id.isEmpty()) { if (id.isEmpty()) {
throw new IllegalArgumentException("calendar id is empty"); throw new IllegalArgumentException("calendar id is empty");
} }
String propName = PROP_PREFIX + id + PROP_TYPE_SUFFIX;
String calType = calendarProperties.getProperty(propName);
if (calType == null || calType.isEmpty()) {
throw new DateTimeException("calendarType is missing or empty for: " + propName);
}
this.typeId = id; this.typeId = id;
this.calendarType = calendarProperties.getProperty(PROP_PREFIX + id + PROP_TYPE_SUFFIX); this.calendarType = calType;
}
try { /**
String resource = calendarProperties.getProperty(PROP_PREFIX + id); * Check and ensure that the calendar data has been initialized.
Objects.requireNonNull(resource, "Resource missing for calendar"); * The initialization check is performed at the boundary between
loadCalendarData(resource); * public and package methods. If a public calls another public method
} catch (Exception ex) { * a check is not necessary in the caller.
throw new Exception("Unable to initialize HijrahCalendar: " + id, ex); * The constructors of HijrahDate call {@link #getEpochDay} or
* {@link #getHijrahDateInfo} so every call from HijrahDate to a
* HijrahChronology via package private methods has been checked.
*
* @throws DateTimeException if the calendar data configuration is
* malformed or IOExceptions occur loading the data
*/
private void checkCalendarInit() {
// Keep this short so it can be inlined for performance
if (initComplete == false) {
loadCalendarData();
initComplete = true;
} }
} }
...@@ -509,6 +532,7 @@ public final class HijrahChronology extends Chronology implements Serializable { ...@@ -509,6 +532,7 @@ public final class HijrahChronology extends Chronology implements Serializable {
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
@Override @Override
public boolean isLeapYear(long prolepticYear) { public boolean isLeapYear(long prolepticYear) {
checkCalendarInit();
int epochMonth = yearToEpochMonth((int) prolepticYear); int epochMonth = yearToEpochMonth((int) prolepticYear);
if (epochMonth < 0 || epochMonth > maxEpochDay) { if (epochMonth < 0 || epochMonth > maxEpochDay) {
throw new DateTimeException("Hijrah date out of range"); throw new DateTimeException("Hijrah date out of range");
...@@ -543,6 +567,7 @@ public final class HijrahChronology extends Chronology implements Serializable { ...@@ -543,6 +567,7 @@ public final class HijrahChronology extends Chronology implements Serializable {
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
@Override @Override
public ValueRange range(ChronoField field) { public ValueRange range(ChronoField field) {
checkCalendarInit();
if (field instanceof ChronoField) { if (field instanceof ChronoField) {
ChronoField f = field; ChronoField f = field;
switch (f) { switch (f) {
...@@ -595,6 +620,7 @@ public final class HijrahChronology extends Chronology implements Serializable { ...@@ -595,6 +620,7 @@ public final class HijrahChronology extends Chronology implements Serializable {
* @return int[0] = YEAR, int[1] = MONTH, int[2] = DATE * @return int[0] = YEAR, int[1] = MONTH, int[2] = DATE
*/ */
int[] getHijrahDateInfo(int epochDay) { int[] getHijrahDateInfo(int epochDay) {
checkCalendarInit(); // ensure that the chronology is initialized
if (epochDay < minEpochDay || epochDay >= maxEpochDay) { if (epochDay < minEpochDay || epochDay >= maxEpochDay) {
throw new DateTimeException("Hijrah date out of range"); throw new DateTimeException("Hijrah date out of range");
} }
...@@ -621,6 +647,7 @@ public final class HijrahChronology extends Chronology implements Serializable { ...@@ -621,6 +647,7 @@ public final class HijrahChronology extends Chronology implements Serializable {
* @return the epoch day * @return the epoch day
*/ */
long getEpochDay(int prolepticYear, int monthOfYear, int dayOfMonth) { long getEpochDay(int prolepticYear, int monthOfYear, int dayOfMonth) {
checkCalendarInit(); // ensure that the chronology is initialized
checkValidMonth(monthOfYear); checkValidMonth(monthOfYear);
int epochMonth = yearToEpochMonth(prolepticYear) + (monthOfYear - 1); int epochMonth = yearToEpochMonth(prolepticYear) + (monthOfYear - 1);
if (epochMonth < 0 || epochMonth >= hijrahEpochMonthStartDays.length) { if (epochMonth < 0 || epochMonth >= hijrahEpochMonthStartDays.length) {
...@@ -846,84 +873,90 @@ public final class HijrahChronology extends Chronology implements Serializable { ...@@ -846,84 +873,90 @@ public final class HijrahChronology extends Chronology implements Serializable {
} }
/** /**
* Loads and processes the Hijrah calendar properties file. * Loads and processes the Hijrah calendar properties file for this calendarType.
* The starting Hijrah date and the corresponding ISO date are * The starting Hijrah date and the corresponding ISO date are
* extracted and used to calculate the epochDate offset. * extracted and used to calculate the epochDate offset.
* The version number is identified and ignored. * The version number is identified and ignored.
* Everything else is the data for a year with containing the length of each * Everything else is the data for a year with containing the length of each
* of 12 months. * of 12 months.
* *
* @param resourceName containing the properties defining the calendar, not null * @throws DateTimeException if initialization of the calendar data from the
* @throws IllegalArgumentException if any of the values are malformed * resource fails
* @throws NumberFormatException if numbers, including properties that should
* be years are invalid
* @throws IOException if access to the property resource fails.
*/ */
private void loadCalendarData(String resourceName) throws Exception { private void loadCalendarData() {
Properties props = readConfigProperties(resourceName); try {
String resourceName = calendarProperties.getProperty(PROP_PREFIX + typeId);
Map<Integer, int[]> years = new HashMap<>(); Objects.requireNonNull(resourceName, "Resource missing for calendar: " + PROP_PREFIX + typeId);
int minYear = Integer.MAX_VALUE; Properties props = readConfigProperties(resourceName);
int maxYear = Integer.MIN_VALUE;
String id = null; Map<Integer, int[]> years = new HashMap<>();
String type = null; int minYear = Integer.MAX_VALUE;
String version = null; int maxYear = Integer.MIN_VALUE;
int isoStart = 0; String id = null;
for (Map.Entry<Object, Object> entry : props.entrySet()) { String type = null;
String key = (String) entry.getKey(); String version = null;
switch (key) { int isoStart = 0;
case KEY_ID: for (Map.Entry<Object, Object> entry : props.entrySet()) {
id = (String)entry.getValue(); String key = (String) entry.getKey();
break; switch (key) {
case KEY_TYPE: case KEY_ID:
type = (String)entry.getValue(); id = (String)entry.getValue();
break; break;
case KEY_VERSION: case KEY_TYPE:
version = (String)entry.getValue(); type = (String)entry.getValue();
break; break;
case KEY_ISO_START: { case KEY_VERSION:
int[] ymd = parseYMD((String) entry.getValue()); version = (String)entry.getValue();
isoStart = (int) LocalDate.of(ymd[0], ymd[1], ymd[2]).toEpochDay(); break;
break; case KEY_ISO_START: {
} int[] ymd = parseYMD((String) entry.getValue());
default: isoStart = (int) LocalDate.of(ymd[0], ymd[1], ymd[2]).toEpochDay();
try { break;
// Everything else is either a year or invalid
int year = Integer.valueOf(key);
int[] months = parseMonths((String) entry.getValue());
years.put(year, months);
maxYear = Math.max(maxYear, year);
minYear = Math.min(minYear, year);
} catch (NumberFormatException nfe) {
throw new IllegalArgumentException("bad key: " + key);
} }
default:
try {
// Everything else is either a year or invalid
int year = Integer.valueOf(key);
int[] months = parseMonths((String) entry.getValue());
years.put(year, months);
maxYear = Math.max(maxYear, year);
minYear = Math.min(minYear, year);
} catch (NumberFormatException nfe) {
throw new IllegalArgumentException("bad key: " + key);
}
}
} }
}
if (!getId().equals(id)) { if (!getId().equals(id)) {
throw new IllegalArgumentException("Configuration is for a different calendar: " + id); throw new IllegalArgumentException("Configuration is for a different calendar: " + id);
} }
if (!getCalendarType().equals(type)) { if (!getCalendarType().equals(type)) {
throw new IllegalArgumentException("Configuration is for a different calendar type: " + type); throw new IllegalArgumentException("Configuration is for a different calendar type: " + type);
} }
if (version == null || version.isEmpty()) { if (version == null || version.isEmpty()) {
throw new IllegalArgumentException("Configuration does not contain a version"); throw new IllegalArgumentException("Configuration does not contain a version");
} }
if (isoStart == 0) { if (isoStart == 0) {
throw new IllegalArgumentException("Configuration does not contain a ISO start date"); throw new IllegalArgumentException("Configuration does not contain a ISO start date");
} }
// Now create and validate the array of epochDays indexed by epochMonth // Now create and validate the array of epochDays indexed by epochMonth
hijrahStartEpochMonth = minYear * 12; hijrahStartEpochMonth = minYear * 12;
minEpochDay = isoStart; minEpochDay = isoStart;
hijrahEpochMonthStartDays = createEpochMonths(minEpochDay, minYear, maxYear, years); hijrahEpochMonthStartDays = createEpochMonths(minEpochDay, minYear, maxYear, years);
maxEpochDay = hijrahEpochMonthStartDays[hijrahEpochMonthStartDays.length - 1]; maxEpochDay = hijrahEpochMonthStartDays[hijrahEpochMonthStartDays.length - 1];
// Compute the min and max year length in days. // Compute the min and max year length in days.
for (int year = minYear; year < maxYear; year++) { for (int year = minYear; year < maxYear; year++) {
int length = getYearLength(year); int length = getYearLength(year);
minYearLength = Math.min(minYearLength, length); minYearLength = Math.min(minYearLength, length);
maxYearLength = Math.max(maxYearLength, length); maxYearLength = Math.max(maxYearLength, length);
}
} catch (Exception ex) {
// Log error and throw a DateTimeException
PlatformLogger logger = PlatformLogger.getLogger("java.time.chrono");
logger.severe("Unable to initialize Hijrah calendar proxy: " + typeId, ex);
throw new DateTimeException("Unable to initialize HijrahCalendar: " + typeId, ex);
} }
} }
......
...@@ -102,7 +102,7 @@ import java.time.temporal.ValueRange; ...@@ -102,7 +102,7 @@ import java.time.temporal.ValueRange;
* to create new HijrahDate instances. * to create new HijrahDate instances.
* Alternatively, the {@link #withVariant} method can be used to convert * Alternatively, the {@link #withVariant} method can be used to convert
* to a new HijrahChronology. * to a new HijrahChronology.
* <h3>Specification for implementors</h3> * @implSpec
* This class is immutable and thread-safe. * This class is immutable and thread-safe.
* *
* @since 1.8 * @since 1.8
......
...@@ -81,7 +81,7 @@ import java.time.temporal.ValueRange; ...@@ -81,7 +81,7 @@ import java.time.temporal.ValueRange;
* <b>Do not use {@code ordinal()} to obtain the numeric representation of {@code HijrahEra}. * <b>Do not use {@code ordinal()} to obtain the numeric representation of {@code HijrahEra}.
* Use {@code getValue()} instead.</b> * Use {@code getValue()} instead.</b>
* *
* <h3>Specification for implementors</h3> * @implSpec
* This is an immutable and thread-safe enum. * This is an immutable and thread-safe enum.
* *
* @since 1.8 * @since 1.8
......
...@@ -121,7 +121,7 @@ import java.util.Objects; ...@@ -121,7 +121,7 @@ import java.util.Objects;
* <li>leap-year - Leap years occur every 4 years, except where the year is divisble by 100 and not divisble by 400. * <li>leap-year - Leap years occur every 4 years, except where the year is divisble by 100 and not divisble by 400.
* </ul><p> * </ul><p>
* *
* <h3>Specification for implementors</h3> * @implSpec
* This class is immutable and thread-safe. * This class is immutable and thread-safe.
* *
* @since 1.8 * @since 1.8
...@@ -588,7 +588,12 @@ public final class IsoChronology extends Chronology implements Serializable { ...@@ -588,7 +588,12 @@ public final class IsoChronology extends Chronology implements Serializable {
int moy = MONTH_OF_YEAR.checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR)); int moy = MONTH_OF_YEAR.checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR));
int dom = DAY_OF_MONTH.checkValidIntValue(fieldValues.remove(DAY_OF_MONTH)); int dom = DAY_OF_MONTH.checkValidIntValue(fieldValues.remove(DAY_OF_MONTH));
if (resolverStyle == ResolverStyle.SMART) { // previous valid if (resolverStyle == ResolverStyle.SMART) { // previous valid
dom = Math.min(dom, Month.of(moy).length(Year.isLeap(y))); if (moy == 4 || moy == 6 || moy == 9 || moy == 11) {
dom = Math.min(dom, 30);
} else if (moy == 2) {
dom = Math.min(dom, Month.FEBRUARY.length(Year.isLeap(y)));
}
} }
return LocalDate.of(y, moy, dom); return LocalDate.of(y, moy, dom);
} }
......
...@@ -97,7 +97,7 @@ import java.time.DateTimeException; ...@@ -97,7 +97,7 @@ import java.time.DateTimeException;
* <b>Do not use {@code ordinal()} to obtain the numeric representation of {@code IsoEra}. * <b>Do not use {@code ordinal()} to obtain the numeric representation of {@code IsoEra}.
* Use {@code getValue()} instead.</b> * Use {@code getValue()} instead.</b>
* *
* <h3>Specification for implementors</h3> * @implSpec
* This is an immutable and thread-safe enum. * This is an immutable and thread-safe enum.
* *
* @since 1.8 * @since 1.8
......
...@@ -85,7 +85,7 @@ import sun.util.calendar.LocalGregorianCalendar; ...@@ -85,7 +85,7 @@ import sun.util.calendar.LocalGregorianCalendar;
* Only Meiji (1865-04-07 - 1868-09-07) and later eras are supported. * Only Meiji (1865-04-07 - 1868-09-07) and later eras are supported.
* Older eras are handled as an unknown era where the year-of-era is the ISO year. * Older eras are handled as an unknown era where the year-of-era is the ISO year.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This class is immutable and thread-safe. * This class is immutable and thread-safe.
* *
* @since 1.8 * @since 1.8
...@@ -197,7 +197,7 @@ public final class JapaneseChronology extends Chronology implements Serializable ...@@ -197,7 +197,7 @@ public final class JapaneseChronology extends Chronology implements Serializable
*/ */
@Override @Override
public JapaneseDate dateYearDay(Era era, int yearOfEra, int dayOfYear) { public JapaneseDate dateYearDay(Era era, int yearOfEra, int dayOfYear) {
return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear); return JapaneseDate.ofYearDay((JapaneseEra) era, yearOfEra, dayOfYear);
} }
/** /**
...@@ -251,16 +251,19 @@ public final class JapaneseChronology extends Chronology implements Serializable ...@@ -251,16 +251,19 @@ public final class JapaneseChronology extends Chronology implements Serializable
} }
@Override @Override
@SuppressWarnings("unchecked")
public ChronoLocalDateTime<JapaneseDate> localDateTime(TemporalAccessor temporal) { public ChronoLocalDateTime<JapaneseDate> localDateTime(TemporalAccessor temporal) {
return (ChronoLocalDateTime<JapaneseDate>)super.localDateTime(temporal); return (ChronoLocalDateTime<JapaneseDate>)super.localDateTime(temporal);
} }
@Override @Override
@SuppressWarnings("unchecked")
public ChronoZonedDateTime<JapaneseDate> zonedDateTime(TemporalAccessor temporal) { public ChronoZonedDateTime<JapaneseDate> zonedDateTime(TemporalAccessor temporal) {
return (ChronoZonedDateTime<JapaneseDate>)super.zonedDateTime(temporal); return (ChronoZonedDateTime<JapaneseDate>)super.zonedDateTime(temporal);
} }
@Override @Override
@SuppressWarnings("unchecked")
public ChronoZonedDateTime<JapaneseDate> zonedDateTime(Instant instant, ZoneId zone) { public ChronoZonedDateTime<JapaneseDate> zonedDateTime(Instant instant, ZoneId zone) {
return (ChronoZonedDateTime<JapaneseDate>)super.zonedDateTime(instant, zone); return (ChronoZonedDateTime<JapaneseDate>)super.zonedDateTime(instant, zone);
} }
...@@ -286,19 +289,27 @@ public final class JapaneseChronology extends Chronology implements Serializable ...@@ -286,19 +289,27 @@ public final class JapaneseChronology extends Chronology implements Serializable
if (era instanceof JapaneseEra == false) { if (era instanceof JapaneseEra == false) {
throw new ClassCastException("Era must be JapaneseEra"); throw new ClassCastException("Era must be JapaneseEra");
} }
if (era == JapaneseEra.SEIREKI) {
JapaneseEra nextEra = JapaneseEra.values()[1];
int nextEraYear = nextEra.getPrivateEra().getSinceDate().getYear();
if (yearOfEra >= nextEraYear || yearOfEra < Year.MIN_VALUE) {
throw new DateTimeException("Invalid yearOfEra value");
}
return yearOfEra;
}
JapaneseEra jera = (JapaneseEra) era; JapaneseEra jera = (JapaneseEra) era;
int gregorianYear = jera.getPrivateEra().getSinceDate().getYear() + yearOfEra - 1; int gregorianYear = jera.getPrivateEra().getSinceDate().getYear() + yearOfEra - 1;
if (yearOfEra == 1) { if (yearOfEra == 1) {
return gregorianYear; return gregorianYear;
} }
LocalGregorianCalendar.Date jdate = JCAL.newCalendarDate(null); if (gregorianYear >= Year.MIN_VALUE && gregorianYear <= Year.MAX_VALUE) {
jdate.setEra(jera.getPrivateEra()).setDate(yearOfEra, 1, 1); LocalGregorianCalendar.Date jdate = JCAL.newCalendarDate(null);
if (!JapaneseChronology.JCAL.validate(jdate)) { jdate.setEra(jera.getPrivateEra()).setDate(yearOfEra, 1, 1);
throw new DateTimeException("Invalid yearOfEra value"); if (JapaneseChronology.JCAL.validate(jdate)) {
} return gregorianYear;
JCAL.normalize(jdate); }
if (jdate.getNormalizedYear() == gregorianYear) {
return gregorianYear;
} }
throw new DateTimeException("Invalid yearOfEra value"); throw new DateTimeException("Invalid yearOfEra value");
} }
...@@ -322,13 +333,20 @@ public final class JapaneseChronology extends Chronology implements Serializable ...@@ -322,13 +333,20 @@ public final class JapaneseChronology extends Chronology implements Serializable
@Override @Override
public List<Era> eras() { public List<Era> eras() {
return Arrays.asList(JapaneseEra.values()); return Arrays.<Era>asList(JapaneseEra.values());
}
JapaneseEra getCurrentEra() {
// Assume that the last JapaneseEra is the current one.
JapaneseEra[] eras = JapaneseEra.values();
return eras[eras.length - 1];
} }
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
@Override @Override
public ValueRange range(ChronoField field) { public ValueRange range(ChronoField field) {
switch (field) { switch (field) {
case YEAR:
case DAY_OF_MONTH: case DAY_OF_MONTH:
case DAY_OF_WEEK: case DAY_OF_WEEK:
case MICRO_OF_DAY: case MICRO_OF_DAY:
...@@ -345,27 +363,23 @@ public final class JapaneseChronology extends Chronology implements Serializable ...@@ -345,27 +363,23 @@ public final class JapaneseChronology extends Chronology implements Serializable
case NANO_OF_SECOND: case NANO_OF_SECOND:
case CLOCK_HOUR_OF_DAY: case CLOCK_HOUR_OF_DAY:
case CLOCK_HOUR_OF_AMPM: case CLOCK_HOUR_OF_AMPM:
case EPOCH_DAY: // TODO: if year is restricted, then so is epoch-day case EPOCH_DAY:
case PROLEPTIC_MONTH:
case MONTH_OF_YEAR:
return field.range(); return field.range();
case ERA:
return ValueRange.of(JapaneseEra.SEIREKI.getValue(),
getCurrentEra().getValue());
} }
Calendar jcal = Calendar.getInstance(LOCALE); Calendar jcal = Calendar.getInstance(LOCALE);
int fieldIndex; int fieldIndex;
switch (field) { switch (field) {
case ERA: case YEAR_OF_ERA: {
return ValueRange.of(JapaneseEra.SEIREKI.getValue(), int startYear = getCurrentEra().getPrivateEra().getSinceDate().getYear();
jcal.getMaximum(Calendar.ERA) - JapaneseEra.ERA_OFFSET);
case YEAR:
case YEAR_OF_ERA:
// TODO: this is not right
return ValueRange.of(Year.MIN_VALUE, jcal.getGreatestMinimum(Calendar.YEAR), return ValueRange.of(Year.MIN_VALUE, jcal.getGreatestMinimum(Calendar.YEAR),
jcal.getLeastMaximum(Calendar.YEAR), Year.MAX_VALUE); jcal.getLeastMaximum(Calendar.YEAR) + 1, // +1 due to the different definitions
case PROLEPTIC_MONTH: Year.MAX_VALUE - startYear);
// TODO: should be the range of months bound by the valid range of years }
return ValueRange.of((jcal.getGreatestMinimum(Calendar.YEAR) - 1) * 12,
(jcal.getLeastMaximum(Calendar.YEAR)) * 12);
case MONTH_OF_YEAR:
return ValueRange.of(jcal.getMinimum(Calendar.MONTH) + 1, jcal.getGreatestMinimum(Calendar.MONTH) + 1,
jcal.getLeastMaximum(Calendar.MONTH) + 1, jcal.getMaximum(Calendar.MONTH) + 1);
case DAY_OF_YEAR: case DAY_OF_YEAR:
fieldIndex = Calendar.DAY_OF_YEAR; fieldIndex = Calendar.DAY_OF_YEAR;
break; break;
......
...@@ -83,6 +83,7 @@ import java.time.temporal.ValueRange; ...@@ -83,6 +83,7 @@ import java.time.temporal.ValueRange;
import java.util.Calendar; import java.util.Calendar;
import java.util.Objects; import java.util.Objects;
import sun.util.calendar.CalendarDate;
import sun.util.calendar.LocalGregorianCalendar; import sun.util.calendar.LocalGregorianCalendar;
/** /**
...@@ -101,7 +102,7 @@ import sun.util.calendar.LocalGregorianCalendar; ...@@ -101,7 +102,7 @@ import sun.util.calendar.LocalGregorianCalendar;
* Calling {@code japaneseDate.get(ERA)} will return 2, corresponding to * Calling {@code japaneseDate.get(ERA)} will return 2, corresponding to
* {@code JapaneseChronology.ERA_HEISEI}.<br> * {@code JapaneseChronology.ERA_HEISEI}.<br>
* *
* <h3>Specification for implementors</h3> * @implSpec
* This class is immutable and thread-safe. * This class is immutable and thread-safe.
* *
* @since 1.8 * @since 1.8
...@@ -234,6 +235,24 @@ public final class JapaneseDate ...@@ -234,6 +235,24 @@ public final class JapaneseDate
return of(prolepticYear, date.getMonthValue(), date.getDayOfMonth()); return of(prolepticYear, date.getMonthValue(), date.getDayOfMonth());
} }
static JapaneseDate ofYearDay(JapaneseEra era, int yearOfEra, int dayOfYear) {
CalendarDate firstDay = era.getPrivateEra().getSinceDate();
LocalGregorianCalendar.Date jdate = JapaneseChronology.JCAL.newCalendarDate(null);
jdate.setEra(era.getPrivateEra());
if (yearOfEra == 1) {
jdate.setDate(yearOfEra, firstDay.getMonth(), firstDay.getDayOfMonth() + dayOfYear - 1);
} else {
jdate.setDate(yearOfEra, 1, dayOfYear);
}
JapaneseChronology.JCAL.normalize(jdate);
if (era.getPrivateEra() != jdate.getEra() || yearOfEra != jdate.getYear()) {
throw new DateTimeException("Invalid parameters");
}
LocalDate localdate = LocalDate.of(jdate.getNormalizedYear(),
jdate.getMonth(), jdate.getDayOfMonth());
return new JapaneseDate(era, yearOfEra, localdate);
}
/** /**
* Obtains a {@code JapaneseDate} representing a date in the Japanese calendar * Obtains a {@code JapaneseDate} representing a date in the Japanese calendar
* system from the era, year-of-era, month-of-year and day-of-month fields. * system from the era, year-of-era, month-of-year and day-of-month fields.
......
...@@ -91,7 +91,7 @@ import sun.util.calendar.CalendarDate; ...@@ -91,7 +91,7 @@ import sun.util.calendar.CalendarDate;
* and the year of era of Seireki is proleptic Gregorian year. * and the year of era of Seireki is proleptic Gregorian year.
* (The Julian to Gregorian transition is not supported.) * (The Julian to Gregorian transition is not supported.)
* *
* <h3>Specification for implementors</h3> * @implSpec
* This class is immutable and thread-safe. * This class is immutable and thread-safe.
* *
* @since 1.8 * @since 1.8
......
...@@ -95,7 +95,7 @@ import java.util.Locale; ...@@ -95,7 +95,7 @@ import java.util.Locale;
* are never out of step. * are never out of step.
* </ul><p> * </ul><p>
* *
* <h3>Specification for implementors</h3> * @implSpec
* This class is immutable and thread-safe. * This class is immutable and thread-safe.
* *
* @since 1.8 * @since 1.8
......
...@@ -89,7 +89,7 @@ import java.util.Objects; ...@@ -89,7 +89,7 @@ import java.util.Objects;
* This calendar system is primarily used in the Republic of China, often known as Taiwan. * This calendar system is primarily used in the Republic of China, often known as Taiwan.
* Dates are aligned such that {@code 0001-01-01 (Minguo)} is {@code 1912-01-01 (ISO)}. * Dates are aligned such that {@code 0001-01-01 (Minguo)} is {@code 1912-01-01 (ISO)}.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This class is immutable and thread-safe. * This class is immutable and thread-safe.
* *
* @since 1.8 * @since 1.8
......
...@@ -102,7 +102,7 @@ import java.time.DateTimeException; ...@@ -102,7 +102,7 @@ import java.time.DateTimeException;
* <b>Do not use {@code ordinal()} to obtain the numeric representation of {@code MinguoEra}. * <b>Do not use {@code ordinal()} to obtain the numeric representation of {@code MinguoEra}.
* Use {@code getValue()} instead.</b> * Use {@code getValue()} instead.</b>
* *
* <h3>Specification for implementors</h3> * @implSpec
* This is an immutable and thread-safe enum. * This is an immutable and thread-safe enum.
* *
* @since 1.8 * @since 1.8
......
...@@ -68,7 +68,7 @@ import java.time.LocalDateTime; ...@@ -68,7 +68,7 @@ import java.time.LocalDateTime;
/** /**
* The shared serialization delegate for this package. * The shared serialization delegate for this package.
* *
* <h3>Implementation notes</h3> * @implNote
* This class wraps the object being serialized, and takes a byte representing the type of the class to * This class wraps the object being serialized, and takes a byte representing the type of the class to
* be serialized. This byte can also be used for versioning the serialization format. In this case another * be serialized. This byte can also be used for versioning the serialization format. In this case another
* byte flag would be used in order to specify an alternative version of the type format. * byte flag would be used in order to specify an alternative version of the type format.
......
...@@ -96,7 +96,7 @@ import java.util.Locale; ...@@ -96,7 +96,7 @@ import java.util.Locale;
* are never out of step. * are never out of step.
* </ul><p> * </ul><p>
* *
* <h3>Specification for implementors</h3> * @implSpec
* This class is immutable and thread-safe. * This class is immutable and thread-safe.
* *
* @since 1.8 * @since 1.8
......
...@@ -89,7 +89,7 @@ import java.util.Objects; ...@@ -89,7 +89,7 @@ import java.util.Objects;
* This calendar system is primarily used in Thailand. * This calendar system is primarily used in Thailand.
* Dates are aligned such that {@code 2484-01-01 (Buddhist)} is {@code 1941-01-01 (ISO)}. * Dates are aligned such that {@code 2484-01-01 (Buddhist)} is {@code 1941-01-01 (ISO)}.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This class is immutable and thread-safe. * This class is immutable and thread-safe.
* *
* @since 1.8 * @since 1.8
......
...@@ -102,7 +102,7 @@ import java.time.DateTimeException; ...@@ -102,7 +102,7 @@ import java.time.DateTimeException;
* <b>Do not use {@code ordinal()} to obtain the numeric representation of {@code ThaiBuddhistEra}. * <b>Do not use {@code ordinal()} to obtain the numeric representation of {@code ThaiBuddhistEra}.
* Use {@code getValue()} instead.</b> * Use {@code getValue()} instead.</b>
* *
* <h3>Specification for implementors</h3> * @implSpec
* This is an immutable and thread-safe enum. * This is an immutable and thread-safe enum.
* *
* @since 1.8 * @since 1.8
......
...@@ -77,6 +77,7 @@ import java.text.Format; ...@@ -77,6 +77,7 @@ import java.text.Format;
import java.text.ParseException; import java.text.ParseException;
import java.text.ParsePosition; import java.text.ParsePosition;
import java.time.DateTimeException; import java.time.DateTimeException;
import java.time.Period;
import java.time.ZoneId; import java.time.ZoneId;
import java.time.ZoneOffset; import java.time.ZoneOffset;
import java.time.chrono.Chronology; import java.time.chrono.Chronology;
...@@ -121,7 +122,7 @@ import java.util.Set; ...@@ -121,7 +122,7 @@ import java.util.Set;
* </pre></blockquote> * </pre></blockquote>
* <p> * <p>
* In addition to the format, formatters can be created with desired Locale, * In addition to the format, formatters can be created with desired Locale,
* Chronology, ZoneId, and formatting symbols. * Chronology, ZoneId, and DecimalStyle.
* <p> * <p>
* The {@link #withLocale withLocale} method returns a new formatter that * The {@link #withLocale withLocale} method returns a new formatter that
* overrides the locale. The locale affects some aspects of formatting and * overrides the locale. The locale affects some aspects of formatting and
...@@ -138,8 +139,8 @@ import java.util.Set; ...@@ -138,8 +139,8 @@ import java.util.Set;
* with the requested ZoneId before formatting. During parsing the ZoneId is * with the requested ZoneId before formatting. During parsing the ZoneId is
* applied before the value is returned. * applied before the value is returned.
* <p> * <p>
* The {@link #withSymbols withSymbols} method returns a new formatter that * The {@link #withDecimalStyle withDecimalStyle} method returns a new formatter that
* overrides the {@link DateTimeFormatSymbols}. The symbols are used for * overrides the {@link DecimalStyle}. The DecimalStyle symbols are used for
* formatting and parsing. * formatting and parsing.
* <p> * <p>
* Some applications may need to use the older {@link Format java.text.Format} * Some applications may need to use the older {@link Format java.text.Format}
...@@ -417,7 +418,65 @@ import java.util.Set; ...@@ -417,7 +418,65 @@ import java.util.Set;
* that you want to output directly to ensure that future changes do not break * that you want to output directly to ensure that future changes do not break
* your application. * your application.
* *
* <h3>Specification for implementors</h3> * <h3 id="resolving">Resolving</h3>
* Parsing is implemented as a two-phase operation.
* First, the text is parsed using the layout defined by the formatter, producing
* a {@code Map} of field to value, a {@code ZoneId} and a {@code Chronology}.
* Second, the parsed data is <em>resolved</em>, by validating, combining and
* simplifying the various fields into more useful ones.
* <p>
* Five parsing methods are supplied by this class.
* Four of these perform both the parse and resolve phases.
* The fifth method, {@link #parseUnresolved(CharSequence, ParsePosition)},
* only performs the first phase, leaving the result unresolved.
* As such, it is essentially a low-level operation.
* <p>
* The resolve phase is controlled by two parameters, set on this class.
* <p>
* The {@link ResolverStyle} is an enum that offers three different approaches,
* strict, smart and lenient. The smart option is the default.
* It can be set using {@link #withResolverStyle(ResolverStyle)}.
* <p>
* The {@link #withResolverFields(TemporalField...)} parameter allows the
* set of fields that will be resolved to be filtered before resolving starts.
* For example, if the formatter has parsed a year, month, day-of-month
* and day-of-year, then there are two approaches to resolve a date:
* (year + month + day-of-month) and (year + day-of-year).
* The resolver fields allows one of the two approaches to be selected.
* If no resolver fields are set then both approaches must result in the same date.
* <p>
* Resolving separate fields to form a complete date and time is a complex
* process with behaviour distributed across a number of classes.
* It follows these steps:
* <ol>
* <li>The chronology is determined.
* The chronology of the result is either the chronology that was parsed,
* or if no chronology was parsed, it is the chronology set on this class,
* or if that is null, it is {@code IsoChronology}.
* <li>The {@code ChronoField} date fields are resolved.
* This is achieved using {@link Chronology#resolveDate(Map, ResolverStyle)}.
* Documentation about field resolution is located in the implementation
* of {@code Chronology}.
* <li>The {@code ChronoField} time fields are resolved.
* This is documented on {@link ChronoField} and is the same for all chronologies.
* <li>Any fields that are not {@code ChronoField} are processed.
* This is achieved using {@link TemporalField#resolve(TemporalAccessor, long, ResolverStyle)}.
* Documentation about field resolution is located in the implementation
* of {@code TemporalField}.
* <li>The {@code ChronoField} date and time fields are re-resolved.
* This allows fields in step four to produce {@code ChronoField} values
* and have them be processed into dates and times.
* <li>A {@code LocalTime} is formed if there is at least an hour-of-day available.
* This involves providing default values for minute, second and fraction of second.
* <li>Any remaining unresolved fields are cross-checked against any
* date and/or time that was resolved. Thus, an earlier stage would resolve
* (year + month + day-of-month) to a date, and this stage would check that
* day-of-week was valid for the date.
* <li>If an {@linkplain #parsedExcessDays() excess number of days}
* was parsed then it is added to the date if a date is available.
* </ol>
*
* @implSpec
* This class is immutable and thread-safe. * This class is immutable and thread-safe.
* *
* @since 1.8 * @since 1.8
...@@ -435,7 +494,7 @@ public final class DateTimeFormatter { ...@@ -435,7 +494,7 @@ public final class DateTimeFormatter {
/** /**
* The symbols to use for formatting, not null. * The symbols to use for formatting, not null.
*/ */
private final DateTimeFormatSymbols symbols; private final DecimalStyle decimalStyle;
/** /**
* The resolver style to use, not null. * The resolver style to use, not null.
*/ */
...@@ -1040,6 +1099,11 @@ public final class DateTimeFormatter { ...@@ -1040,6 +1099,11 @@ public final class DateTimeFormatter {
* <p> * <p>
* This returns an immutable formatter capable of formatting and parsing * This returns an immutable formatter capable of formatting and parsing
* the ISO-8601 instant format. * the ISO-8601 instant format.
* When formatting, the second-of-minute is always output.
* The nano-of-second outputs zero, three, six or nine digits digits as necessary.
* When parsing, time to at least the seconds field is required.
* Fractional seconds from zero to nine are parsed.
* The localized decimal style is not used.
* <p> * <p>
* This is a special case formatter intended to allow a human readable form * This is a special case formatter intended to allow a human readable form
* of an {@link java.time.Instant}. The {@code Instant} class is designed to * of an {@link java.time.Instant}. The {@code Instant} class is designed to
...@@ -1201,25 +1265,117 @@ public final class DateTimeFormatter { ...@@ -1201,25 +1265,117 @@ public final class DateTimeFormatter {
.toFormatter(ResolverStyle.SMART, IsoChronology.INSTANCE); .toFormatter(ResolverStyle.SMART, IsoChronology.INSTANCE);
} }
//-----------------------------------------------------------------------
/**
* A query that provides access to the excess days that were parsed.
* <p>
* This returns a singleton {@linkplain TemporalQuery query} that provides
* access to additional information from the parse. The query always returns
* a non-null period, with a zero period returned instead of null.
* <p>
* There are two situations where this query may return a non-zero period.
* <p><ul>
* <li>If the {@code ResolverStyle} is {@code LENIENT} and a time is parsed
* without a date, then the complete result of the parse consists of a
* {@code LocalTime} and an excess {@code Period} in days.
* <p>
* <li>If the {@code ResolverStyle} is {@code SMART} and a time is parsed
* without a date where the time is 24:00:00, then the complete result of
* the parse consists of a {@code LocalTime} of 00:00:00 and an excess
* {@code Period} of one day.
* </ul>
* <p>
* In both cases, if a complete {@code ChronoLocalDateTime} or {@code Instant}
* is parsed, then the excess days are added to the date part.
* As a result, this query will return a zero period.
* <p>
* The {@code SMART} behaviour handles the common "end of day" 24:00 value.
* Processing in {@code LENIENT} mode also produces the same result:
* <pre>
* Text to parse Parsed object Excess days
* "2012-12-03T00:00" LocalDateTime.of(2012, 12, 3, 0, 0) ZERO
* "2012-12-03T24:00" LocalDateTime.of(2012, 12, 4, 0, 0) ZERO
* "00:00" LocalTime.of(0, 0) ZERO
* "24:00" LocalTime.of(0, 0) Period.ofDays(1)
* </pre>
* The query can be used as follows:
* <pre>
* TemporalAccessor parsed = formatter.parse(str);
* LocalTime time = parsed.query(LocalTime::from);
* Period extraDays = parsed.query(DateTimeFormatter.parsedExcessDays());
* </pre>
*/
public static final TemporalQuery<Period> parsedExcessDays() {
return PARSED_EXCESS_DAYS;
}
private static final TemporalQuery<Period> PARSED_EXCESS_DAYS = t -> {
if (t instanceof Parsed) {
return ((Parsed) t).excessDays;
} else {
return Period.ZERO;
}
};
/**
* A query that provides access to whether a leap-second was parsed.
* <p>
* This returns a singleton {@linkplain TemporalQuery query} that provides
* access to additional information from the parse. The query always returns
* a non-null boolean, true if parsing saw a leap-second, false if not.
* <p>
* Instant parsing handles the special "leap second" time of '23:59:60'.
* Leap seconds occur at '23:59:60' in the UTC time-zone, but at other
* local times in different time-zones. To avoid this potential ambiguity,
* the handling of leap-seconds is limited to
* {@link DateTimeFormatterBuilder#appendInstant()}, as that method
* always parses the instant with the UTC zone offset.
* <p>
* If the time '23:59:60' is received, then a simple conversion is applied,
* replacing the second-of-minute of 60 with 59. This query can be used
* on the parse result to determine if the leap-second adjustment was made.
* The query will return one second of excess if it did adjust to remove
* the leap-second, and zero if not. Note that applying a leap-second
* smoothing mechanism, such as UTC-SLS, is the responsibility of the
* application, as follows:
* <pre>
* TemporalAccessor parsed = formatter.parse(str);
* Instant instant = parsed.query(Instant::from);
* if (parsed.query(DateTimeFormatter.parsedLeapSecond())) {
* // validate leap-second is correct and apply correct smoothing
* }
* </pre>
*/
public static final TemporalQuery<Boolean> parsedLeapSecond() {
return PARSED_LEAP_SECOND;
}
private static final TemporalQuery<Boolean> PARSED_LEAP_SECOND = t -> {
if (t instanceof Parsed) {
return ((Parsed) t).leapSecond;
} else {
return Boolean.FALSE;
}
};
//-----------------------------------------------------------------------
/** /**
* Constructor. * Constructor.
* *
* @param printerParser the printer/parser to use, not null * @param printerParser the printer/parser to use, not null
* @param locale the locale to use, not null * @param locale the locale to use, not null
* @param symbols the symbols to use, not null * @param decimalStyle the DecimalStyle to use, not null
* @param resolverStyle the resolver style to use, not null * @param resolverStyle the resolver style to use, not null
* @param resolverFields the fields to use during resolving, null for all fields * @param resolverFields the fields to use during resolving, null for all fields
* @param chrono the chronology to use, null for no override * @param chrono the chronology to use, null for no override
* @param zone the zone to use, null for no override * @param zone the zone to use, null for no override
*/ */
DateTimeFormatter(CompositePrinterParser printerParser, DateTimeFormatter(CompositePrinterParser printerParser,
Locale locale, DateTimeFormatSymbols symbols, Locale locale, DecimalStyle decimalStyle,
ResolverStyle resolverStyle, Set<TemporalField> resolverFields, ResolverStyle resolverStyle, Set<TemporalField> resolverFields,
Chronology chrono, ZoneId zone) { Chronology chrono, ZoneId zone) {
this.printerParser = Objects.requireNonNull(printerParser, "printerParser"); this.printerParser = Objects.requireNonNull(printerParser, "printerParser");
this.resolverFields = resolverFields; this.resolverFields = resolverFields;
this.locale = Objects.requireNonNull(locale, "locale"); this.locale = Objects.requireNonNull(locale, "locale");
this.symbols = Objects.requireNonNull(symbols, "symbols"); this.decimalStyle = Objects.requireNonNull(decimalStyle, "decimalStyle");
this.resolverStyle = Objects.requireNonNull(resolverStyle, "resolverStyle"); this.resolverStyle = Objects.requireNonNull(resolverStyle, "resolverStyle");
this.chrono = chrono; this.chrono = chrono;
this.zone = zone; this.zone = zone;
...@@ -1253,32 +1409,32 @@ public final class DateTimeFormatter { ...@@ -1253,32 +1409,32 @@ public final class DateTimeFormatter {
if (this.locale.equals(locale)) { if (this.locale.equals(locale)) {
return this; return this;
} }
return new DateTimeFormatter(printerParser, locale, symbols, resolverStyle, resolverFields, chrono, zone); return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone);
} }
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
/** /**
* Gets the set of symbols to be used during formatting. * Gets the DecimalStyle to be used during formatting.
* *
* @return the locale of this formatter, not null * @return the locale of this formatter, not null
*/ */
public DateTimeFormatSymbols getSymbols() { public DecimalStyle getDecimalStyle() {
return symbols; return decimalStyle;
} }
/** /**
* Returns a copy of this formatter with a new set of symbols. * Returns a copy of this formatter with a new DecimalStyle.
* <p> * <p>
* This instance is immutable and unaffected by this method call. * This instance is immutable and unaffected by this method call.
* *
* @param symbols the new symbols, not null * @param decimalStyle the new DecimalStyle, not null
* @return a formatter based on this formatter with the requested symbols, not null * @return a formatter based on this formatter with the requested DecimalStyle, not null
*/ */
public DateTimeFormatter withSymbols(DateTimeFormatSymbols symbols) { public DateTimeFormatter withDecimalStyle(DecimalStyle decimalStyle) {
if (this.symbols.equals(symbols)) { if (this.decimalStyle.equals(decimalStyle)) {
return this; return this;
} }
return new DateTimeFormatter(printerParser, locale, symbols, resolverStyle, resolverFields, chrono, zone); return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone);
} }
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
...@@ -1332,7 +1488,7 @@ public final class DateTimeFormatter { ...@@ -1332,7 +1488,7 @@ public final class DateTimeFormatter {
if (Objects.equals(this.chrono, chrono)) { if (Objects.equals(this.chrono, chrono)) {
return this; return this;
} }
return new DateTimeFormatter(printerParser, locale, symbols, resolverStyle, resolverFields, chrono, zone); return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone);
} }
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
...@@ -1389,7 +1545,7 @@ public final class DateTimeFormatter { ...@@ -1389,7 +1545,7 @@ public final class DateTimeFormatter {
if (Objects.equals(this.zone, zone)) { if (Objects.equals(this.zone, zone)) {
return this; return this;
} }
return new DateTimeFormatter(printerParser, locale, symbols, resolverStyle, resolverFields, chrono, zone); return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone);
} }
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
...@@ -1431,7 +1587,7 @@ public final class DateTimeFormatter { ...@@ -1431,7 +1587,7 @@ public final class DateTimeFormatter {
if (Objects.equals(this.resolverStyle, resolverStyle)) { if (Objects.equals(this.resolverStyle, resolverStyle)) {
return this; return this;
} }
return new DateTimeFormatter(printerParser, locale, symbols, resolverStyle, resolverFields, chrono, zone); return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone);
} }
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
...@@ -1495,7 +1651,7 @@ public final class DateTimeFormatter { ...@@ -1495,7 +1651,7 @@ public final class DateTimeFormatter {
return this; return this;
} }
fields = Collections.unmodifiableSet(fields); fields = Collections.unmodifiableSet(fields);
return new DateTimeFormatter(printerParser, locale, symbols, resolverStyle, fields, chrono, zone); return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, fields, chrono, zone);
} }
/** /**
...@@ -1543,7 +1699,7 @@ public final class DateTimeFormatter { ...@@ -1543,7 +1699,7 @@ public final class DateTimeFormatter {
return this; return this;
} }
resolverFields = Collections.unmodifiableSet(new HashSet<>(resolverFields)); resolverFields = Collections.unmodifiableSet(new HashSet<>(resolverFields));
return new DateTimeFormatter(printerParser, locale, symbols, resolverStyle, resolverFields, chrono, zone); return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone);
} }
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
......
...@@ -61,6 +61,7 @@ ...@@ -61,6 +61,7 @@
*/ */
package java.time.format; package java.time.format;
import java.time.Duration;
import java.time.ZoneId; import java.time.ZoneId;
import java.time.chrono.Chronology; import java.time.chrono.Chronology;
import java.time.chrono.IsoChronology; import java.time.chrono.IsoChronology;
...@@ -79,7 +80,7 @@ import java.util.Objects; ...@@ -79,7 +80,7 @@ import java.util.Objects;
* Once parsing is complete, the {@link #toParsed()} is used to obtain the data. * Once parsing is complete, the {@link #toParsed()} is used to obtain the data.
* It contains a method to resolve the separate parsed fields into meaningful values. * It contains a method to resolve the separate parsed fields into meaningful values.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This class is a mutable context intended for use from a single thread. * This class is a mutable context intended for use from a single thread.
* Usage of the class is thread-safe within standard parsing as a new instance of this class * Usage of the class is thread-safe within standard parsing as a new instance of this class
* is automatically created for each parse and parsing is single-threaded * is automatically created for each parse and parsing is single-threaded
...@@ -118,9 +119,13 @@ final class DateTimeParseContext { ...@@ -118,9 +119,13 @@ final class DateTimeParseContext {
/** /**
* Creates a copy of this context. * Creates a copy of this context.
* This retains the case sensitive and strict flags.
*/ */
DateTimeParseContext copy() { DateTimeParseContext copy() {
return new DateTimeParseContext(formatter); DateTimeParseContext newContext = new DateTimeParseContext(formatter);
newContext.caseSensitive = caseSensitive;
newContext.strict = strict;
return newContext;
} }
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
...@@ -128,7 +133,7 @@ final class DateTimeParseContext { ...@@ -128,7 +133,7 @@ final class DateTimeParseContext {
* Gets the locale. * Gets the locale.
* <p> * <p>
* This locale is used to control localization in the parse except * This locale is used to control localization in the parse except
* where localization is controlled by the symbols. * where localization is controlled by the DecimalStyle.
* *
* @return the locale, not null * @return the locale, not null
*/ */
...@@ -137,14 +142,14 @@ final class DateTimeParseContext { ...@@ -137,14 +142,14 @@ final class DateTimeParseContext {
} }
/** /**
* Gets the formatting symbols. * Gets the DecimalStyle.
* <p> * <p>
* The symbols control the localization of numeric parsing. * The DecimalStyle controls the numeric parsing.
* *
* @return the formatting symbols, not null * @return the DecimalStyle, not null
*/ */
DateTimeFormatSymbols getSymbols() { DecimalStyle getDecimalStyle() {
return formatter.getSymbols(); return formatter.getDecimalStyle();
} }
/** /**
...@@ -370,6 +375,13 @@ final class DateTimeParseContext { ...@@ -370,6 +375,13 @@ final class DateTimeParseContext {
currentParsed().zone = zone; currentParsed().zone = zone;
} }
/**
* Stores the parsed leap second.
*/
void setParsedLeapSecond() {
currentParsed().leapSecond = true;
}
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
/** /**
* Returns a string version of the context for debugging. * Returns a string version of the context for debugging.
......
...@@ -68,7 +68,7 @@ import java.time.DateTimeException; ...@@ -68,7 +68,7 @@ import java.time.DateTimeException;
* <p> * <p>
* This exception includes the text being parsed and the error index. * This exception includes the text being parsed and the error index.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This class is intended for use in a single thread. * This class is intended for use in a single thread.
* *
* @since 1.8 * @since 1.8
......
...@@ -85,7 +85,7 @@ import java.util.Objects; ...@@ -85,7 +85,7 @@ import java.util.Objects;
* <p> * <p>
* This class provides a single wrapper to items used in the format. * This class provides a single wrapper to items used in the format.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This class is a mutable context intended for use from a single thread. * This class is a mutable context intended for use from a single thread.
* Usage of the class is thread-safe within standard printing as the framework creates * Usage of the class is thread-safe within standard printing as the framework creates
* a new instance of the class for each format and printing is single-threaded. * a new instance of the class for each format and printing is single-threaded.
...@@ -234,7 +234,7 @@ final class DateTimePrintContext { ...@@ -234,7 +234,7 @@ final class DateTimePrintContext {
* Gets the locale. * Gets the locale.
* <p> * <p>
* This locale is used to control localization in the format output except * This locale is used to control localization in the format output except
* where localization is controlled by the symbols. * where localization is controlled by the DecimalStyle.
* *
* @return the locale, not null * @return the locale, not null
*/ */
...@@ -243,14 +243,14 @@ final class DateTimePrintContext { ...@@ -243,14 +243,14 @@ final class DateTimePrintContext {
} }
/** /**
* Gets the formatting symbols. * Gets the DecimalStyle.
* <p> * <p>
* The symbols control the localization of numeric output. * The DecimalStyle controls the localization of numeric output.
* *
* @return the formatting symbols, not null * @return the DecimalStyle, not null
*/ */
DateTimeFormatSymbols getSymbols() { DecimalStyle getDecimalStyle() {
return formatter.getSymbols(); return formatter.getDecimalStyle();
} }
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
......
...@@ -94,7 +94,7 @@ import sun.util.locale.provider.LocaleResources; ...@@ -94,7 +94,7 @@ import sun.util.locale.provider.LocaleResources;
/** /**
* A provider to obtain the textual form of a date-time field. * A provider to obtain the textual form of a date-time field.
* *
* <h3>Specification for implementors</h3> * @implSpec
* Implementations must be thread-safe. * Implementations must be thread-safe.
* Implementations should cache the textual information. * Implementations should cache the textual information.
* *
......
...@@ -62,34 +62,38 @@ ...@@ -62,34 +62,38 @@
package java.time.format; package java.time.format;
import java.text.DecimalFormatSymbols; import java.text.DecimalFormatSymbols;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Locale; import java.util.Locale;
import java.util.Objects; import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
/** /**
* Localized symbols used in date and time formatting. * Localized decimal style used in date and time formatting.
* <p> * <p>
* A significant part of dealing with dates and times is the localization. * A significant part of dealing with dates and times is the localization.
* This class acts as a central point for accessing the information. * This class acts as a central point for accessing the information.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This class is immutable and thread-safe. * This class is immutable and thread-safe.
* *
* @since 1.8 * @since 1.8
*/ */
public final class DateTimeFormatSymbols { public final class DecimalStyle {
/** /**
* The standard set of non-localized symbols. * The standard set of non-localized decimal style symbols.
* <p> * <p>
* This uses standard ASCII characters for zero, positive, negative and a dot for the decimal point. * This uses standard ASCII characters for zero, positive, negative and a dot for the decimal point.
*/ */
public static final DateTimeFormatSymbols STANDARD = new DateTimeFormatSymbols('0', '+', '-', '.'); public static final DecimalStyle STANDARD = new DecimalStyle('0', '+', '-', '.');
/** /**
* The cache of symbols instances. * The cache of DecimalStyle instances.
*/ */
private static final ConcurrentMap<Locale, DateTimeFormatSymbols> CACHE = new ConcurrentHashMap<>(16, 0.75f, 2); private static final ConcurrentMap<Locale, DecimalStyle> CACHE = new ConcurrentHashMap<>(16, 0.75f, 2);
/** /**
* The zero digit. * The zero digit.
...@@ -114,17 +118,20 @@ public final class DateTimeFormatSymbols { ...@@ -114,17 +118,20 @@ public final class DateTimeFormatSymbols {
* <p> * <p>
* The locale 'en_US' will always be present. * The locale 'en_US' will always be present.
* *
* @return an array of locales for which localization is supported * @return a Set of Locales for which localization is supported
*/ */
public static Locale[] getAvailableLocales() { public static Set<Locale> getAvailableLocales() {
return DecimalFormatSymbols.getAvailableLocales(); Locale[] l = DecimalFormatSymbols.getAvailableLocales();
Set<Locale> locales = new HashSet<>(l.length);
Collections.addAll(locales, l);
return locales;
} }
/** /**
* Obtains symbols for the default * Obtains the DecimalStyle for the default
* {@link java.util.Locale.Category#FORMAT FORMAT} locale. * {@link java.util.Locale.Category#FORMAT FORMAT} locale.
* <p> * <p>
* This method provides access to locale sensitive symbols. * This method provides access to locale sensitive decimal style symbols.
* <p> * <p>
* This is equivalent to calling * This is equivalent to calling
* {@link #of(Locale) * {@link #of(Locale)
...@@ -133,21 +140,21 @@ public final class DateTimeFormatSymbols { ...@@ -133,21 +140,21 @@ public final class DateTimeFormatSymbols {
* @see java.util.Locale.Category#FORMAT * @see java.util.Locale.Category#FORMAT
* @return the info, not null * @return the info, not null
*/ */
public static DateTimeFormatSymbols ofDefaultLocale() { public static DecimalStyle ofDefaultLocale() {
return of(Locale.getDefault(Locale.Category.FORMAT)); return of(Locale.getDefault(Locale.Category.FORMAT));
} }
/** /**
* Obtains symbols for the specified locale. * Obtains the DecimalStyle for the specified locale.
* <p> * <p>
* This method provides access to locale sensitive symbols. * This method provides access to locale sensitive decimal style symbols.
* *
* @param locale the locale, not null * @param locale the locale, not null
* @return the info, not null * @return the info, not null
*/ */
public static DateTimeFormatSymbols of(Locale locale) { public static DecimalStyle of(Locale locale) {
Objects.requireNonNull(locale, "locale"); Objects.requireNonNull(locale, "locale");
DateTimeFormatSymbols info = CACHE.get(locale); DecimalStyle info = CACHE.get(locale);
if (info == null) { if (info == null) {
info = create(locale); info = create(locale);
CACHE.putIfAbsent(locale, info); CACHE.putIfAbsent(locale, info);
...@@ -156,7 +163,7 @@ public final class DateTimeFormatSymbols { ...@@ -156,7 +163,7 @@ public final class DateTimeFormatSymbols {
return info; return info;
} }
private static DateTimeFormatSymbols create(Locale locale) { private static DecimalStyle create(Locale locale) {
DecimalFormatSymbols oldSymbols = DecimalFormatSymbols.getInstance(locale); DecimalFormatSymbols oldSymbols = DecimalFormatSymbols.getInstance(locale);
char zeroDigit = oldSymbols.getZeroDigit(); char zeroDigit = oldSymbols.getZeroDigit();
char positiveSign = '+'; char positiveSign = '+';
...@@ -165,7 +172,7 @@ public final class DateTimeFormatSymbols { ...@@ -165,7 +172,7 @@ public final class DateTimeFormatSymbols {
if (zeroDigit == '0' && negativeSign == '-' && decimalSeparator == '.') { if (zeroDigit == '0' && negativeSign == '-' && decimalSeparator == '.') {
return STANDARD; return STANDARD;
} }
return new DateTimeFormatSymbols(zeroDigit, positiveSign, negativeSign, decimalSeparator); return new DecimalStyle(zeroDigit, positiveSign, negativeSign, decimalSeparator);
} }
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
...@@ -177,7 +184,7 @@ public final class DateTimeFormatSymbols { ...@@ -177,7 +184,7 @@ public final class DateTimeFormatSymbols {
* @param negativeSignChar the character to use for the negative sign * @param negativeSignChar the character to use for the negative sign
* @param decimalPointChar the character to use for the decimal point * @param decimalPointChar the character to use for the decimal point
*/ */
private DateTimeFormatSymbols(char zeroChar, char positiveSignChar, char negativeSignChar, char decimalPointChar) { private DecimalStyle(char zeroChar, char positiveSignChar, char negativeSignChar, char decimalPointChar) {
this.zeroDigit = zeroChar; this.zeroDigit = zeroChar;
this.positiveSign = positiveSignChar; this.positiveSign = positiveSignChar;
this.negativeSign = negativeSignChar; this.negativeSign = negativeSignChar;
...@@ -207,11 +214,11 @@ public final class DateTimeFormatSymbols { ...@@ -207,11 +214,11 @@ public final class DateTimeFormatSymbols {
* @return a copy with a new character that represents zero, not null * @return a copy with a new character that represents zero, not null
*/ */
public DateTimeFormatSymbols withZeroDigit(char zeroDigit) { public DecimalStyle withZeroDigit(char zeroDigit) {
if (zeroDigit == this.zeroDigit) { if (zeroDigit == this.zeroDigit) {
return this; return this;
} }
return new DateTimeFormatSymbols(zeroDigit, positiveSign, negativeSign, decimalSeparator); return new DecimalStyle(zeroDigit, positiveSign, negativeSign, decimalSeparator);
} }
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
...@@ -236,11 +243,11 @@ public final class DateTimeFormatSymbols { ...@@ -236,11 +243,11 @@ public final class DateTimeFormatSymbols {
* @param positiveSign the character for the positive sign * @param positiveSign the character for the positive sign
* @return a copy with a new character that represents the positive sign, not null * @return a copy with a new character that represents the positive sign, not null
*/ */
public DateTimeFormatSymbols withPositiveSign(char positiveSign) { public DecimalStyle withPositiveSign(char positiveSign) {
if (positiveSign == this.positiveSign) { if (positiveSign == this.positiveSign) {
return this; return this;
} }
return new DateTimeFormatSymbols(zeroDigit, positiveSign, negativeSign, decimalSeparator); return new DecimalStyle(zeroDigit, positiveSign, negativeSign, decimalSeparator);
} }
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
...@@ -265,11 +272,11 @@ public final class DateTimeFormatSymbols { ...@@ -265,11 +272,11 @@ public final class DateTimeFormatSymbols {
* @param negativeSign the character for the negative sign * @param negativeSign the character for the negative sign
* @return a copy with a new character that represents the negative sign, not null * @return a copy with a new character that represents the negative sign, not null
*/ */
public DateTimeFormatSymbols withNegativeSign(char negativeSign) { public DecimalStyle withNegativeSign(char negativeSign) {
if (negativeSign == this.negativeSign) { if (negativeSign == this.negativeSign) {
return this; return this;
} }
return new DateTimeFormatSymbols(zeroDigit, positiveSign, negativeSign, decimalSeparator); return new DecimalStyle(zeroDigit, positiveSign, negativeSign, decimalSeparator);
} }
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
...@@ -294,11 +301,11 @@ public final class DateTimeFormatSymbols { ...@@ -294,11 +301,11 @@ public final class DateTimeFormatSymbols {
* @param decimalSeparator the character for the decimal point * @param decimalSeparator the character for the decimal point
* @return a copy with a new character that represents the decimal point, not null * @return a copy with a new character that represents the decimal point, not null
*/ */
public DateTimeFormatSymbols withDecimalSeparator(char decimalSeparator) { public DecimalStyle withDecimalSeparator(char decimalSeparator) {
if (decimalSeparator == this.decimalSeparator) { if (decimalSeparator == this.decimalSeparator) {
return this; return this;
} }
return new DateTimeFormatSymbols(zeroDigit, positiveSign, negativeSign, decimalSeparator); return new DecimalStyle(zeroDigit, positiveSign, negativeSign, decimalSeparator);
} }
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
...@@ -333,7 +340,7 @@ public final class DateTimeFormatSymbols { ...@@ -333,7 +340,7 @@ public final class DateTimeFormatSymbols {
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
/** /**
* Checks if these symbols equal another set of symbols. * Checks if this DecimalStyle is equal another DecimalStyle.
* *
* @param obj the object to check, null returns false * @param obj the object to check, null returns false
* @return true if this is equal to the other date * @return true if this is equal to the other date
...@@ -343,8 +350,8 @@ public final class DateTimeFormatSymbols { ...@@ -343,8 +350,8 @@ public final class DateTimeFormatSymbols {
if (this == obj) { if (this == obj) {
return true; return true;
} }
if (obj instanceof DateTimeFormatSymbols) { if (obj instanceof DecimalStyle) {
DateTimeFormatSymbols other = (DateTimeFormatSymbols) obj; DecimalStyle other = (DecimalStyle) obj;
return (zeroDigit == other.zeroDigit && positiveSign == other.positiveSign && return (zeroDigit == other.zeroDigit && positiveSign == other.positiveSign &&
negativeSign == other.negativeSign && decimalSeparator == other.decimalSeparator); negativeSign == other.negativeSign && decimalSeparator == other.decimalSeparator);
} }
...@@ -352,7 +359,7 @@ public final class DateTimeFormatSymbols { ...@@ -352,7 +359,7 @@ public final class DateTimeFormatSymbols {
} }
/** /**
* A hash code for these symbols. * A hash code for this DecimalStyle.
* *
* @return a suitable hash code * @return a suitable hash code
*/ */
...@@ -363,13 +370,13 @@ public final class DateTimeFormatSymbols { ...@@ -363,13 +370,13 @@ public final class DateTimeFormatSymbols {
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
/** /**
* Returns a string describing these symbols. * Returns a string describing this DecimalStyle.
* *
* @return a string description, not null * @return a string description, not null
*/ */
@Override @Override
public String toString() { public String toString() {
return "Symbols[" + zeroDigit + positiveSign + negativeSign + decimalSeparator + "]"; return "DecimalStyle[" + zeroDigit + positiveSign + negativeSign + decimalSeparator + "]";
} }
} }
...@@ -67,7 +67,7 @@ package java.time.format; ...@@ -67,7 +67,7 @@ package java.time.format;
* These styles are used when obtaining a date-time style from configuration. * These styles are used when obtaining a date-time style from configuration.
* See {@link DateTimeFormatter} and {@link DateTimeFormatterBuilder} for usage. * See {@link DateTimeFormatter} and {@link DateTimeFormatterBuilder} for usage.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This is an immutable and thread-safe enum. * This is an immutable and thread-safe enum.
* *
* @since 1.8 * @since 1.8
......
...@@ -80,6 +80,7 @@ import static java.time.temporal.ChronoField.SECOND_OF_MINUTE; ...@@ -80,6 +80,7 @@ import static java.time.temporal.ChronoField.SECOND_OF_MINUTE;
import java.time.DateTimeException; import java.time.DateTimeException;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalTime; import java.time.LocalTime;
import java.time.Period;
import java.time.ZoneId; import java.time.ZoneId;
import java.time.chrono.ChronoLocalDate; import java.time.chrono.ChronoLocalDate;
import java.time.chrono.Chronology; import java.time.chrono.Chronology;
...@@ -105,7 +106,7 @@ import java.util.Set; ...@@ -105,7 +106,7 @@ import java.util.Set;
* Once parsing is completed, this class can be used as the resultant {@code TemporalAccessor}. * Once parsing is completed, this class can be used as the resultant {@code TemporalAccessor}.
* In most cases, it is only exposed once the fields have been resolved. * In most cases, it is only exposed once the fields have been resolved.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This class is a mutable context intended for use from a single thread. * This class is a mutable context intended for use from a single thread.
* Usage of the class is thread-safe within standard parsing as a new instance of this class * Usage of the class is thread-safe within standard parsing as a new instance of this class
* is automatically created for each parse and parsing is single-threaded * is automatically created for each parse and parsing is single-threaded
...@@ -127,6 +128,10 @@ final class Parsed implements TemporalAccessor { ...@@ -127,6 +128,10 @@ final class Parsed implements TemporalAccessor {
* The parsed chronology. * The parsed chronology.
*/ */
Chronology chrono; Chronology chrono;
/**
* Whether a leap-second is parsed.
*/
boolean leapSecond;
/** /**
* The effective chronology. * The effective chronology.
*/ */
...@@ -143,6 +148,10 @@ final class Parsed implements TemporalAccessor { ...@@ -143,6 +148,10 @@ final class Parsed implements TemporalAccessor {
* The resolved time. * The resolved time.
*/ */
private LocalTime time; private LocalTime time;
/**
* The excess period from time-only parsing.
*/
Period excessDays = Period.ZERO;
/** /**
* Creates an instance. * Creates an instance.
...@@ -159,6 +168,7 @@ final class Parsed implements TemporalAccessor { ...@@ -159,6 +168,7 @@ final class Parsed implements TemporalAccessor {
cloned.fieldValues.putAll(this.fieldValues); cloned.fieldValues.putAll(this.fieldValues);
cloned.zone = this.zone; cloned.zone = this.zone;
cloned.chrono = this.chrono; cloned.chrono = this.chrono;
cloned.leapSecond = this.leapSecond;
return cloned; return cloned;
} }
...@@ -232,6 +242,7 @@ final class Parsed implements TemporalAccessor { ...@@ -232,6 +242,7 @@ final class Parsed implements TemporalAccessor {
resolveFields(); resolveFields();
resolveTimeLenient(); resolveTimeLenient();
crossCheck(); crossCheck();
resolvePeriod();
return this; return this;
} }
...@@ -308,36 +319,72 @@ final class Parsed implements TemporalAccessor { ...@@ -308,36 +319,72 @@ final class Parsed implements TemporalAccessor {
private void resolveTimeFields() { private void resolveTimeFields() {
// simplify fields // simplify fields
if (fieldValues.containsKey(CLOCK_HOUR_OF_DAY)) { if (fieldValues.containsKey(CLOCK_HOUR_OF_DAY)) {
// lenient allows anything, smart allows 0-24, strict allows 1-24
long ch = fieldValues.remove(CLOCK_HOUR_OF_DAY); long ch = fieldValues.remove(CLOCK_HOUR_OF_DAY);
if (resolverStyle == ResolverStyle.STRICT || (resolverStyle == ResolverStyle.SMART && ch != 0)) {
CLOCK_HOUR_OF_DAY.checkValidValue(ch);
}
updateCheckConflict(CLOCK_HOUR_OF_DAY, HOUR_OF_DAY, ch == 24 ? 0 : ch); updateCheckConflict(CLOCK_HOUR_OF_DAY, HOUR_OF_DAY, ch == 24 ? 0 : ch);
} }
if (fieldValues.containsKey(CLOCK_HOUR_OF_AMPM)) { if (fieldValues.containsKey(CLOCK_HOUR_OF_AMPM)) {
// lenient allows anything, smart allows 0-12, strict allows 1-12
long ch = fieldValues.remove(CLOCK_HOUR_OF_AMPM); long ch = fieldValues.remove(CLOCK_HOUR_OF_AMPM);
if (resolverStyle == ResolverStyle.STRICT || (resolverStyle == ResolverStyle.SMART && ch != 0)) {
CLOCK_HOUR_OF_AMPM.checkValidValue(ch);
}
updateCheckConflict(CLOCK_HOUR_OF_AMPM, HOUR_OF_AMPM, ch == 12 ? 0 : ch); updateCheckConflict(CLOCK_HOUR_OF_AMPM, HOUR_OF_AMPM, ch == 12 ? 0 : ch);
} }
if (fieldValues.containsKey(AMPM_OF_DAY) && fieldValues.containsKey(HOUR_OF_AMPM)) { if (fieldValues.containsKey(AMPM_OF_DAY) && fieldValues.containsKey(HOUR_OF_AMPM)) {
long ap = fieldValues.remove(AMPM_OF_DAY); long ap = fieldValues.remove(AMPM_OF_DAY);
long hap = fieldValues.remove(HOUR_OF_AMPM); long hap = fieldValues.remove(HOUR_OF_AMPM);
updateCheckConflict(AMPM_OF_DAY, HOUR_OF_DAY, ap * 12 + hap); if (resolverStyle == ResolverStyle.LENIENT) {
updateCheckConflict(AMPM_OF_DAY, HOUR_OF_DAY, Math.addExact(Math.multiplyExact(ap, 12), hap));
} else { // STRICT or SMART
AMPM_OF_DAY.checkValidValue(ap);
HOUR_OF_AMPM.checkValidValue(ap);
updateCheckConflict(AMPM_OF_DAY, HOUR_OF_DAY, ap * 12 + hap);
}
}
if (fieldValues.containsKey(NANO_OF_DAY)) {
long nod = fieldValues.remove(NANO_OF_DAY);
if (resolverStyle != ResolverStyle.LENIENT) {
NANO_OF_DAY.checkValidValue(nod);
}
updateCheckConflict(NANO_OF_DAY, HOUR_OF_DAY, nod / 3600_000_000_000L);
updateCheckConflict(NANO_OF_DAY, MINUTE_OF_HOUR, (nod / 60_000_000_000L) % 60);
updateCheckConflict(NANO_OF_DAY, SECOND_OF_MINUTE, (nod / 1_000_000_000L) % 60);
updateCheckConflict(NANO_OF_DAY, NANO_OF_SECOND, nod % 1_000_000_000L);
} }
if (fieldValues.containsKey(MICRO_OF_DAY)) { if (fieldValues.containsKey(MICRO_OF_DAY)) {
long cod = fieldValues.remove(MICRO_OF_DAY); long cod = fieldValues.remove(MICRO_OF_DAY);
if (resolverStyle != ResolverStyle.LENIENT) {
MICRO_OF_DAY.checkValidValue(cod);
}
updateCheckConflict(MICRO_OF_DAY, SECOND_OF_DAY, cod / 1_000_000L); updateCheckConflict(MICRO_OF_DAY, SECOND_OF_DAY, cod / 1_000_000L);
updateCheckConflict(MICRO_OF_DAY, MICRO_OF_SECOND, cod % 1_000_000L); updateCheckConflict(MICRO_OF_DAY, MICRO_OF_SECOND, cod % 1_000_000L);
} }
if (fieldValues.containsKey(MILLI_OF_DAY)) { if (fieldValues.containsKey(MILLI_OF_DAY)) {
long lod = fieldValues.remove(MILLI_OF_DAY); long lod = fieldValues.remove(MILLI_OF_DAY);
if (resolverStyle != ResolverStyle.LENIENT) {
MILLI_OF_DAY.checkValidValue(lod);
}
updateCheckConflict(MILLI_OF_DAY, SECOND_OF_DAY, lod / 1_000); updateCheckConflict(MILLI_OF_DAY, SECOND_OF_DAY, lod / 1_000);
updateCheckConflict(MILLI_OF_DAY, MILLI_OF_SECOND, lod % 1_000); updateCheckConflict(MILLI_OF_DAY, MILLI_OF_SECOND, lod % 1_000);
} }
if (fieldValues.containsKey(SECOND_OF_DAY)) { if (fieldValues.containsKey(SECOND_OF_DAY)) {
long sod = fieldValues.remove(SECOND_OF_DAY); long sod = fieldValues.remove(SECOND_OF_DAY);
if (resolverStyle != ResolverStyle.LENIENT) {
SECOND_OF_DAY.checkValidValue(sod);
}
updateCheckConflict(SECOND_OF_DAY, HOUR_OF_DAY, sod / 3600); updateCheckConflict(SECOND_OF_DAY, HOUR_OF_DAY, sod / 3600);
updateCheckConflict(SECOND_OF_DAY, MINUTE_OF_HOUR, (sod / 60) % 60); updateCheckConflict(SECOND_OF_DAY, MINUTE_OF_HOUR, (sod / 60) % 60);
updateCheckConflict(SECOND_OF_DAY, SECOND_OF_MINUTE, sod % 60); updateCheckConflict(SECOND_OF_DAY, SECOND_OF_MINUTE, sod % 60);
} }
if (fieldValues.containsKey(MINUTE_OF_DAY)) { if (fieldValues.containsKey(MINUTE_OF_DAY)) {
long mod = fieldValues.remove(MINUTE_OF_DAY); long mod = fieldValues.remove(MINUTE_OF_DAY);
if (resolverStyle != ResolverStyle.LENIENT) {
MINUTE_OF_DAY.checkValidValue(mod);
}
updateCheckConflict(MINUTE_OF_DAY, HOUR_OF_DAY, mod / 60); updateCheckConflict(MINUTE_OF_DAY, HOUR_OF_DAY, mod / 60);
updateCheckConflict(MINUTE_OF_DAY, MINUTE_OF_HOUR, mod % 60); updateCheckConflict(MINUTE_OF_DAY, MINUTE_OF_HOUR, mod % 60);
} }
...@@ -345,29 +392,34 @@ final class Parsed implements TemporalAccessor { ...@@ -345,29 +392,34 @@ final class Parsed implements TemporalAccessor {
// combine partial second fields strictly, leaving lenient expansion to later // combine partial second fields strictly, leaving lenient expansion to later
if (fieldValues.containsKey(NANO_OF_SECOND)) { if (fieldValues.containsKey(NANO_OF_SECOND)) {
long nos = fieldValues.get(NANO_OF_SECOND); long nos = fieldValues.get(NANO_OF_SECOND);
if (resolverStyle != ResolverStyle.LENIENT) {
NANO_OF_SECOND.checkValidValue(nos);
}
if (fieldValues.containsKey(MICRO_OF_SECOND)) { if (fieldValues.containsKey(MICRO_OF_SECOND)) {
long cos = fieldValues.remove(MICRO_OF_SECOND); long cos = fieldValues.remove(MICRO_OF_SECOND);
if (resolverStyle != ResolverStyle.LENIENT) {
MICRO_OF_SECOND.checkValidValue(cos);
}
nos = cos * 1000 + (nos % 1000); nos = cos * 1000 + (nos % 1000);
updateCheckConflict(MICRO_OF_SECOND, NANO_OF_SECOND, nos); updateCheckConflict(MICRO_OF_SECOND, NANO_OF_SECOND, nos);
} }
if (fieldValues.containsKey(MILLI_OF_SECOND)) { if (fieldValues.containsKey(MILLI_OF_SECOND)) {
long los = fieldValues.remove(MILLI_OF_SECOND); long los = fieldValues.remove(MILLI_OF_SECOND);
if (resolverStyle != ResolverStyle.LENIENT) {
MILLI_OF_SECOND.checkValidValue(los);
}
updateCheckConflict(MILLI_OF_SECOND, NANO_OF_SECOND, los * 1_000_000L + (nos % 1_000_000L)); updateCheckConflict(MILLI_OF_SECOND, NANO_OF_SECOND, los * 1_000_000L + (nos % 1_000_000L));
} }
} }
// convert to time if possible // convert to time if all four fields available (optimization)
if (fieldValues.containsKey(NANO_OF_DAY)) {
long nod = fieldValues.remove(NANO_OF_DAY);
updateCheckConflict(LocalTime.ofNanoOfDay(nod));
}
if (fieldValues.containsKey(HOUR_OF_DAY) && fieldValues.containsKey(MINUTE_OF_HOUR) && if (fieldValues.containsKey(HOUR_OF_DAY) && fieldValues.containsKey(MINUTE_OF_HOUR) &&
fieldValues.containsKey(SECOND_OF_MINUTE) && fieldValues.containsKey(NANO_OF_SECOND)) { fieldValues.containsKey(SECOND_OF_MINUTE) && fieldValues.containsKey(NANO_OF_SECOND)) {
int hodVal = HOUR_OF_DAY.checkValidIntValue(fieldValues.remove(HOUR_OF_DAY)); long hod = fieldValues.remove(HOUR_OF_DAY);
int mohVal = MINUTE_OF_HOUR.checkValidIntValue(fieldValues.remove(MINUTE_OF_HOUR)); long moh = fieldValues.remove(MINUTE_OF_HOUR);
int somVal = SECOND_OF_MINUTE.checkValidIntValue(fieldValues.remove(SECOND_OF_MINUTE)); long som = fieldValues.remove(SECOND_OF_MINUTE);
int nosVal = NANO_OF_SECOND.checkValidIntValue(fieldValues.remove(NANO_OF_SECOND)); long nos = fieldValues.remove(NANO_OF_SECOND);
updateCheckConflict(LocalTime.of(hodVal, mohVal, somVal, nosVal)); resolveTime(hod, moh, som, nos);
} }
} }
...@@ -377,7 +429,7 @@ final class Parsed implements TemporalAccessor { ...@@ -377,7 +429,7 @@ final class Parsed implements TemporalAccessor {
// which would break updateCheckConflict(field) // which would break updateCheckConflict(field)
if (time == null) { if (time == null) {
// can only get here if NANO_OF_SECOND not present // NANO_OF_SECOND merged with MILLI/MICRO above
if (fieldValues.containsKey(MILLI_OF_SECOND)) { if (fieldValues.containsKey(MILLI_OF_SECOND)) {
long los = fieldValues.remove(MILLI_OF_SECOND); long los = fieldValues.remove(MILLI_OF_SECOND);
if (fieldValues.containsKey(MICRO_OF_SECOND)) { if (fieldValues.containsKey(MICRO_OF_SECOND)) {
...@@ -395,43 +447,87 @@ final class Parsed implements TemporalAccessor { ...@@ -395,43 +447,87 @@ final class Parsed implements TemporalAccessor {
long cos = fieldValues.remove(MICRO_OF_SECOND); long cos = fieldValues.remove(MICRO_OF_SECOND);
fieldValues.put(NANO_OF_SECOND, cos * 1_000L); fieldValues.put(NANO_OF_SECOND, cos * 1_000L);
} }
}
// merge hour/minute/second/nano leniently // merge hour/minute/second/nano leniently
Long hod = fieldValues.get(HOUR_OF_DAY); Long hod = fieldValues.get(HOUR_OF_DAY);
if (hod != null) { if (hod != null) {
int hodVal = HOUR_OF_DAY.checkValidIntValue(hod); Long moh = fieldValues.get(MINUTE_OF_HOUR);
Long moh = fieldValues.get(MINUTE_OF_HOUR); Long som = fieldValues.get(SECOND_OF_MINUTE);
Long som = fieldValues.get(SECOND_OF_MINUTE); Long nos = fieldValues.get(NANO_OF_SECOND);
Long nos = fieldValues.get(NANO_OF_SECOND);
// check for invalid combinations that cannot be defaulted // check for invalid combinations that cannot be defaulted
if (time == null) {
if ((moh == null && (som != null || nos != null)) || if ((moh == null && (som != null || nos != null)) ||
(moh != null && som == null && nos != null)) { (moh != null && som == null && nos != null)) {
return; return;
} }
// default as necessary and build time
long mohVal = (moh != null ? moh : 0);
long somVal = (som != null ? som : 0);
long nosVal = (nos != null ? nos : 0);
resolveTime(hod, mohVal, somVal, nosVal);
fieldValues.remove(HOUR_OF_DAY);
fieldValues.remove(MINUTE_OF_HOUR);
fieldValues.remove(SECOND_OF_MINUTE);
fieldValues.remove(NANO_OF_SECOND);
}
}
// validate remaining
if (resolverStyle != ResolverStyle.LENIENT && fieldValues.size() > 0) {
for (Entry<TemporalField, Long> entry : fieldValues.entrySet()) {
TemporalField field = entry.getKey();
if (field instanceof ChronoField && field.isTimeBased()) {
((ChronoField) field).checkValidValue(entry.getValue());
}
} }
}
}
// default as necessary and build time private void resolveTime(long hod, long moh, long som, long nos) {
int mohVal = (moh != null ? MINUTE_OF_HOUR.checkValidIntValue(moh) : (time != null ? time.getMinute() : 0)); if (resolverStyle == ResolverStyle.LENIENT) {
int somVal = (som != null ? SECOND_OF_MINUTE.checkValidIntValue(som) : (time != null ? time.getSecond() : 0)); long totalNanos = Math.multiplyExact(hod, 3600_000_000_000L);
int nosVal = (nos != null ? NANO_OF_SECOND.checkValidIntValue(nos) : (time != null ? time.getNano() : 0)); totalNanos = Math.addExact(totalNanos, Math.multiplyExact(moh, 60_000_000_000L));
updateCheckConflict(LocalTime.of(hodVal, mohVal, somVal, nosVal)); totalNanos = Math.addExact(totalNanos, Math.multiplyExact(som, 1_000_000_000L));
fieldValues.remove(HOUR_OF_DAY); totalNanos = Math.addExact(totalNanos, nos);
fieldValues.remove(MINUTE_OF_HOUR); int excessDays = (int) Math.floorDiv(totalNanos, 86400_000_000_000L); // safe int cast
fieldValues.remove(SECOND_OF_MINUTE); long nod = Math.floorMod(totalNanos, 86400_000_000_000L);
fieldValues.remove(NANO_OF_SECOND); updateCheckConflict(LocalTime.ofNanoOfDay(nod), Period.ofDays(excessDays));
} else { // STRICT or SMART
int mohVal = MINUTE_OF_HOUR.checkValidIntValue(moh);
int nosVal = NANO_OF_SECOND.checkValidIntValue(nos);
// handle 24:00 end of day
if (resolverStyle == ResolverStyle.SMART && hod == 24 && mohVal == 0 && som == 0 && nosVal == 0) {
updateCheckConflict(LocalTime.MIDNIGHT, Period.ofDays(1));
} else {
int hodVal = HOUR_OF_DAY.checkValidIntValue(hod);
int somVal = SECOND_OF_MINUTE.checkValidIntValue(som);
updateCheckConflict(LocalTime.of(hodVal, mohVal, somVal, nosVal), Period.ZERO);
}
} }
} }
private void updateCheckConflict(LocalTime lt) { private void resolvePeriod() {
// add whole days if we have both date and time
if (date != null && time != null && excessDays.isZero() == false) {
date = date.plus(excessDays);
excessDays = Period.ZERO;
}
}
private void updateCheckConflict(LocalTime timeToSet, Period periodToSet) {
if (time != null) { if (time != null) {
if (lt != null && time.equals(lt) == false) { if (time.equals(timeToSet) == false) {
throw new DateTimeException("Conflict found: Fields resolved to two different times: " + time + " " + lt); throw new DateTimeException("Conflict found: Fields resolved to different times: " + time + " " + timeToSet);
}
if (excessDays.isZero() == false && periodToSet.isZero() == false && excessDays.equals(periodToSet) == false) {
throw new DateTimeException("Conflict found: Fields resolved to different excess periods: " + excessDays + " " + periodToSet);
} else {
excessDays = periodToSet;
} }
} else { } else {
time = lt; time = timeToSet;
excessDays = periodToSet;
} }
} }
......
...@@ -69,7 +69,7 @@ package java.time.format; ...@@ -69,7 +69,7 @@ package java.time.format;
* Phase 2 resolves the parsed field-value pairs into date and/or time objects. * Phase 2 resolves the parsed field-value pairs into date and/or time objects.
* This style is used to control how phase 2, resolving, happens. * This style is used to control how phase 2, resolving, happens.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This is an immutable and thread-safe enum. * This is an immutable and thread-safe enum.
* *
* @since 1.8 * @since 1.8
...@@ -96,10 +96,9 @@ public enum ResolverStyle { ...@@ -96,10 +96,9 @@ public enum ResolverStyle {
* behavior. Individual fields will interpret this differently. * behavior. Individual fields will interpret this differently.
* <p> * <p>
* For example, resolving year-month and day-of-month in the ISO calendar * For example, resolving year-month and day-of-month in the ISO calendar
* system using smart mode will ensure that the day-of-month is valid * system using smart mode will ensure that the day-of-month is from
* for the year-month, rejecting invalid values, with the exception that * 1 to 31, converting any value beyond the last valid day-of-month to be
* February 29th in a year other than a leap year will be converted to * the last valid day-of-month.
* February 28th.
*/ */
SMART, SMART,
/** /**
...@@ -110,6 +109,7 @@ public enum ResolverStyle { ...@@ -110,6 +109,7 @@ public enum ResolverStyle {
* <p> * <p>
* For example, lenient mode allows the month in the ISO calendar system * For example, lenient mode allows the month in the ISO calendar system
* to be outside the range 1 to 12. * to be outside the range 1 to 12.
* For example, month 15 is treated as being 3 months after month 12.
*/ */
LENIENT; LENIENT;
......
...@@ -68,7 +68,7 @@ package java.time.format; ...@@ -68,7 +68,7 @@ package java.time.format;
* to be controlled using this enum. * to be controlled using this enum.
* See {@link DateTimeFormatterBuilder} for usage. * See {@link DateTimeFormatterBuilder} for usage.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This is an immutable and thread-safe enum. * This is an immutable and thread-safe enum.
* *
* @since 1.8 * @since 1.8
......
...@@ -80,7 +80,7 @@ import java.util.Calendar; ...@@ -80,7 +80,7 @@ import java.util.Calendar;
* For example, the word used for a month when used alone in a date picker is different * For example, the word used for a month when used alone in a date picker is different
* to the word used for month in association with a day and year in a date. * to the word used for month in association with a day and year in a date.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This is immutable and thread-safe enum. * This is immutable and thread-safe enum.
*/ */
public enum TextStyle { public enum TextStyle {
......
...@@ -76,7 +76,7 @@ ...@@ -76,7 +76,7 @@
* Localization occurs by calling * Localization occurs by calling
* {@link java.time.format.DateTimeFormatter#withLocale(java.util.Locale) withLocale(Locale)} * {@link java.time.format.DateTimeFormatter#withLocale(java.util.Locale) withLocale(Locale)}
* on the formatter. Further customization is possible using * on the formatter. Further customization is possible using
* {@link java.time.format.DateTimeFormatSymbols DateTimeFormatSymbols}. * {@link java.time.format.DecimalStyle DecimalStyle}.
* </p> * </p>
* *
* <h3>Package specification</h3> * <h3>Package specification</h3>
......
...@@ -93,7 +93,7 @@ import sun.util.locale.provider.LocaleResources; ...@@ -93,7 +93,7 @@ import sun.util.locale.provider.LocaleResources;
* just with slightly different rules. * just with slightly different rules.
* The documentation of each field explains how it operates. * The documentation of each field explains how it operates.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This is a final, immutable and thread-safe enum. * This is a final, immutable and thread-safe enum.
* *
* @since 1.8 * @since 1.8
...@@ -115,6 +115,10 @@ public enum ChronoField implements TemporalField { ...@@ -115,6 +115,10 @@ public enum ChronoField implements TemporalField {
* object stores, using integer division to remove excess precision. * object stores, using integer division to remove excess precision.
* For example, if the {@code TemporalAccessor} stores time to millisecond precision, * For example, if the {@code TemporalAccessor} stores time to millisecond precision,
* then the nano-of-second must be divided by 1,000,000 before replacing the milli-of-second. * then the nano-of-second must be divided by 1,000,000 before replacing the milli-of-second.
* <p>
* When parsing this field it behaves equivalent to the following:
* The value is validated in strict and smart mode but not in lenient mode.
* The field is resolved in combination with {@code MILLI_OF_SECOND} and {@code MICRO_OF_SECOND}.
*/ */
NANO_OF_SECOND("NanoOfSecond", NANOS, SECONDS, ValueRange.of(0, 999_999_999)), NANO_OF_SECOND("NanoOfSecond", NANOS, SECONDS, ValueRange.of(0, 999_999_999)),
/** /**
...@@ -126,6 +130,11 @@ public enum ChronoField implements TemporalField { ...@@ -126,6 +130,11 @@ public enum ChronoField implements TemporalField {
* This field is used to represent the nano-of-day handling any fraction of the second. * This field is used to represent the nano-of-day handling any fraction of the second.
* Implementations of {@code TemporalAccessor} should provide a value for this field if * Implementations of {@code TemporalAccessor} should provide a value for this field if
* they can return a value for {@link #SECOND_OF_DAY} filling unknown precision with zero. * they can return a value for {@link #SECOND_OF_DAY} filling unknown precision with zero.
* <p>
* When parsing this field it behaves equivalent to the following:
* The value is validated in strict and smart mode but not in lenient mode.
* The value is split to form {@code NANO_OF_SECOND}, {@code SECOND_OF_MINUTE},
* {@code MINUTE_OF_HOUR} and {@code HOUR_OF_DAY} fields.
*/ */
NANO_OF_DAY("NanoOfDay", NANOS, DAYS, ValueRange.of(0, 86400L * 1000_000_000L - 1)), NANO_OF_DAY("NanoOfDay", NANOS, DAYS, ValueRange.of(0, 86400L * 1000_000_000L - 1)),
/** /**
...@@ -141,6 +150,11 @@ public enum ChronoField implements TemporalField { ...@@ -141,6 +150,11 @@ public enum ChronoField implements TemporalField {
* <p> * <p>
* When this field is used for setting a value, it should behave in the same way as * When this field is used for setting a value, it should behave in the same way as
* setting {@link #NANO_OF_SECOND} with the value multiplied by 1,000. * setting {@link #NANO_OF_SECOND} with the value multiplied by 1,000.
* <p>
* When parsing this field it behaves equivalent to the following:
* The value is validated in strict and smart mode but not in lenient mode.
* The field is resolved in combination with {@code MILLI_OF_SECOND} to produce
* {@code NANO_OF_SECOND}.
*/ */
MICRO_OF_SECOND("MicroOfSecond", MICROS, SECONDS, ValueRange.of(0, 999_999)), MICRO_OF_SECOND("MicroOfSecond", MICROS, SECONDS, ValueRange.of(0, 999_999)),
/** /**
...@@ -155,6 +169,11 @@ public enum ChronoField implements TemporalField { ...@@ -155,6 +169,11 @@ public enum ChronoField implements TemporalField {
* <p> * <p>
* When this field is used for setting a value, it should behave in the same way as * When this field is used for setting a value, it should behave in the same way as
* setting {@link #NANO_OF_DAY} with the value multiplied by 1,000. * setting {@link #NANO_OF_DAY} with the value multiplied by 1,000.
* <p>
* When parsing this field it behaves equivalent to the following:
* The value is validated in strict and smart mode but not in lenient mode.
* The value is split to form {@code MICRO_OF_SECOND}, {@code SECOND_OF_MINUTE},
* {@code MINUTE_OF_HOUR} and {@code HOUR_OF_DAY} fields.
*/ */
MICRO_OF_DAY("MicroOfDay", MICROS, DAYS, ValueRange.of(0, 86400L * 1000_000L - 1)), MICRO_OF_DAY("MicroOfDay", MICROS, DAYS, ValueRange.of(0, 86400L * 1000_000L - 1)),
/** /**
...@@ -170,6 +189,11 @@ public enum ChronoField implements TemporalField { ...@@ -170,6 +189,11 @@ public enum ChronoField implements TemporalField {
* <p> * <p>
* When this field is used for setting a value, it should behave in the same way as * When this field is used for setting a value, it should behave in the same way as
* setting {@link #NANO_OF_SECOND} with the value multiplied by 1,000,000. * setting {@link #NANO_OF_SECOND} with the value multiplied by 1,000,000.
* <p>
* When parsing this field it behaves equivalent to the following:
* The value is validated in strict and smart mode but not in lenient mode.
* The field is resolved in combination with {@code MICRO_OF_SECOND} to produce
* {@code NANO_OF_SECOND}.
*/ */
MILLI_OF_SECOND("MilliOfSecond", MILLIS, SECONDS, ValueRange.of(0, 999)), MILLI_OF_SECOND("MilliOfSecond", MILLIS, SECONDS, ValueRange.of(0, 999)),
/** /**
...@@ -184,6 +208,11 @@ public enum ChronoField implements TemporalField { ...@@ -184,6 +208,11 @@ public enum ChronoField implements TemporalField {
* <p> * <p>
* When this field is used for setting a value, it should behave in the same way as * When this field is used for setting a value, it should behave in the same way as
* setting {@link #NANO_OF_DAY} with the value multiplied by 1,000,000. * setting {@link #NANO_OF_DAY} with the value multiplied by 1,000,000.
* <p>
* When parsing this field it behaves equivalent to the following:
* The value is validated in strict and smart mode but not in lenient mode.
* The value is split to form {@code MILLI_OF_SECOND}, {@code SECOND_OF_MINUTE},
* {@code MINUTE_OF_HOUR} and {@code HOUR_OF_DAY} fields.
*/ */
MILLI_OF_DAY("MilliOfDay", MILLIS, DAYS, ValueRange.of(0, 86400L * 1000L - 1)), MILLI_OF_DAY("MilliOfDay", MILLIS, DAYS, ValueRange.of(0, 86400L * 1000L - 1)),
/** /**
...@@ -191,6 +220,9 @@ public enum ChronoField implements TemporalField { ...@@ -191,6 +220,9 @@ public enum ChronoField implements TemporalField {
* <p> * <p>
* This counts the second within the minute, from 0 to 59. * This counts the second within the minute, from 0 to 59.
* This field has the same meaning for all calendar systems. * This field has the same meaning for all calendar systems.
* <p>
* When parsing this field it behaves equivalent to the following:
* The value is validated in strict and smart mode but not in lenient mode.
*/ */
SECOND_OF_MINUTE("SecondOfMinute", SECONDS, MINUTES, ValueRange.of(0, 59), "second"), SECOND_OF_MINUTE("SecondOfMinute", SECONDS, MINUTES, ValueRange.of(0, 59), "second"),
/** /**
...@@ -198,6 +230,11 @@ public enum ChronoField implements TemporalField { ...@@ -198,6 +230,11 @@ public enum ChronoField implements TemporalField {
* <p> * <p>
* This counts the second within the day, from 0 to (24 * 60 * 60) - 1. * This counts the second within the day, from 0 to (24 * 60 * 60) - 1.
* This field has the same meaning for all calendar systems. * This field has the same meaning for all calendar systems.
* <p>
* When parsing this field it behaves equivalent to the following:
* The value is validated in strict and smart mode but not in lenient mode.
* The value is split to form {@code SECOND_OF_MINUTE}, {@code MINUTE_OF_HOUR}
* and {@code HOUR_OF_DAY} fields.
*/ */
SECOND_OF_DAY("SecondOfDay", SECONDS, DAYS, ValueRange.of(0, 86400L - 1)), SECOND_OF_DAY("SecondOfDay", SECONDS, DAYS, ValueRange.of(0, 86400L - 1)),
/** /**
...@@ -205,6 +242,9 @@ public enum ChronoField implements TemporalField { ...@@ -205,6 +242,9 @@ public enum ChronoField implements TemporalField {
* <p> * <p>
* This counts the minute within the hour, from 0 to 59. * This counts the minute within the hour, from 0 to 59.
* This field has the same meaning for all calendar systems. * This field has the same meaning for all calendar systems.
* <p>
* When parsing this field it behaves equivalent to the following:
* The value is validated in strict and smart mode but not in lenient mode.
*/ */
MINUTE_OF_HOUR("MinuteOfHour", MINUTES, HOURS, ValueRange.of(0, 59), "minute"), MINUTE_OF_HOUR("MinuteOfHour", MINUTES, HOURS, ValueRange.of(0, 59), "minute"),
/** /**
...@@ -212,6 +252,10 @@ public enum ChronoField implements TemporalField { ...@@ -212,6 +252,10 @@ public enum ChronoField implements TemporalField {
* <p> * <p>
* This counts the minute within the day, from 0 to (24 * 60) - 1. * This counts the minute within the day, from 0 to (24 * 60) - 1.
* This field has the same meaning for all calendar systems. * This field has the same meaning for all calendar systems.
* <p>
* When parsing this field it behaves equivalent to the following:
* The value is validated in strict and smart mode but not in lenient mode.
* The value is split to form {@code MINUTE_OF_HOUR} and {@code HOUR_OF_DAY} fields.
*/ */
MINUTE_OF_DAY("MinuteOfDay", MINUTES, DAYS, ValueRange.of(0, (24 * 60) - 1)), MINUTE_OF_DAY("MinuteOfDay", MINUTES, DAYS, ValueRange.of(0, (24 * 60) - 1)),
/** /**
...@@ -220,6 +264,12 @@ public enum ChronoField implements TemporalField { ...@@ -220,6 +264,12 @@ public enum ChronoField implements TemporalField {
* This counts the hour within the AM/PM, from 0 to 11. * This counts the hour within the AM/PM, from 0 to 11.
* This is the hour that would be observed on a standard 12-hour digital clock. * This is the hour that would be observed on a standard 12-hour digital clock.
* This field has the same meaning for all calendar systems. * This field has the same meaning for all calendar systems.
* <p>
* When parsing this field it behaves equivalent to the following:
* The value is validated from 0 to 11 in strict and smart mode.
* In lenient mode the value is not validated. It is combined with
* {@code AMPM_OF_DAY} to form {@code HOUR_OF_DAY} by multiplying
* the {AMPM_OF_DAY} value by 12.
*/ */
HOUR_OF_AMPM("HourOfAmPm", HOURS, HALF_DAYS, ValueRange.of(0, 11)), HOUR_OF_AMPM("HourOfAmPm", HOURS, HALF_DAYS, ValueRange.of(0, 11)),
/** /**
...@@ -228,6 +278,12 @@ public enum ChronoField implements TemporalField { ...@@ -228,6 +278,12 @@ public enum ChronoField implements TemporalField {
* This counts the hour within the AM/PM, from 1 to 12. * This counts the hour within the AM/PM, from 1 to 12.
* This is the hour that would be observed on a standard 12-hour analog wall clock. * This is the hour that would be observed on a standard 12-hour analog wall clock.
* This field has the same meaning for all calendar systems. * This field has the same meaning for all calendar systems.
* <p>
* When parsing this field it behaves equivalent to the following:
* The value is validated from 1 to 12 in strict mode and from
* 0 to 12 in smart mode. In lenient mode the value is not validated.
* The field is converted to an {@code HOUR_OF_AMPM} with the same value,
* unless the value is 12, in which case it is converted to 0.
*/ */
CLOCK_HOUR_OF_AMPM("ClockHourOfAmPm", HOURS, HALF_DAYS, ValueRange.of(1, 12)), CLOCK_HOUR_OF_AMPM("ClockHourOfAmPm", HOURS, HALF_DAYS, ValueRange.of(1, 12)),
/** /**
...@@ -236,6 +292,13 @@ public enum ChronoField implements TemporalField { ...@@ -236,6 +292,13 @@ public enum ChronoField implements TemporalField {
* This counts the hour within the day, from 0 to 23. * This counts the hour within the day, from 0 to 23.
* This is the hour that would be observed on a standard 24-hour digital clock. * This is the hour that would be observed on a standard 24-hour digital clock.
* This field has the same meaning for all calendar systems. * This field has the same meaning for all calendar systems.
* <p>
* When parsing this field it behaves equivalent to the following:
* The value is validated in strict and smart mode but not in lenient mode.
* The field is combined with {@code MINUTE_OF_HOUR}, {@code SECOND_OF_MINUTE} and
* {@code NANO_OF_SECOND} to produce a {@code LocalTime}.
* In lenient mode, any excess days are added to the parsed date, or
* made available via {@link java.time.format.DateTimeFormatter#parsedExcessDays()}.
*/ */
HOUR_OF_DAY("HourOfDay", HOURS, DAYS, ValueRange.of(0, 23), "hour"), HOUR_OF_DAY("HourOfDay", HOURS, DAYS, ValueRange.of(0, 23), "hour"),
/** /**
...@@ -244,6 +307,12 @@ public enum ChronoField implements TemporalField { ...@@ -244,6 +307,12 @@ public enum ChronoField implements TemporalField {
* This counts the hour within the AM/PM, from 1 to 24. * This counts the hour within the AM/PM, from 1 to 24.
* This is the hour that would be observed on a 24-hour analog wall clock. * This is the hour that would be observed on a 24-hour analog wall clock.
* This field has the same meaning for all calendar systems. * This field has the same meaning for all calendar systems.
* <p>
* When parsing this field it behaves equivalent to the following:
* The value is validated from 1 to 24 in strict mode and from
* 0 to 24 in smart mode. In lenient mode the value is not validated.
* The field is converted to an {@code HOUR_OF_DAY} with the same value,
* unless the value is 24, in which case it is converted to 0.
*/ */
CLOCK_HOUR_OF_DAY("ClockHourOfDay", HOURS, DAYS, ValueRange.of(1, 24)), CLOCK_HOUR_OF_DAY("ClockHourOfDay", HOURS, DAYS, ValueRange.of(1, 24)),
/** /**
...@@ -251,6 +320,12 @@ public enum ChronoField implements TemporalField { ...@@ -251,6 +320,12 @@ public enum ChronoField implements TemporalField {
* <p> * <p>
* This counts the AM/PM within the day, from 0 (AM) to 1 (PM). * This counts the AM/PM within the day, from 0 (AM) to 1 (PM).
* This field has the same meaning for all calendar systems. * This field has the same meaning for all calendar systems.
* <p>
* When parsing this field it behaves equivalent to the following:
* The value is validated from 0 to 1 in strict and smart mode.
* In lenient mode the value is not validated. It is combined with
* {@code HOUR_OF_AMPM} to form {@code HOUR_OF_DAY} by multiplying
* the {AMPM_OF_DAY} value by 12.
*/ */
AMPM_OF_DAY("AmPmOfDay", HALF_DAYS, DAYS, ValueRange.of(0, 1), "dayperiod"), AMPM_OF_DAY("AmPmOfDay", HALF_DAYS, DAYS, ValueRange.of(0, 1), "dayperiod"),
/** /**
......
...@@ -72,7 +72,7 @@ import java.time.chrono.ChronoZonedDateTime; ...@@ -72,7 +72,7 @@ import java.time.chrono.ChronoZonedDateTime;
* just with slightly different rules. * just with slightly different rules.
* The documentation of each unit explains how it operates. * The documentation of each unit explains how it operates.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This is a final, immutable and thread-safe enum. * This is a final, immutable and thread-safe enum.
* *
* @since 1.8 * @since 1.8
......
...@@ -146,7 +146,7 @@ import sun.util.locale.provider.LocaleResources; ...@@ -146,7 +146,7 @@ import sun.util.locale.provider.LocaleResources;
* <tr><th>2009-01-05</th><td>Monday</td><td>Week 2 of week-based-year 2009</td></tr> * <tr><th>2009-01-05</th><td>Monday</td><td>Week 2 of week-based-year 2009</td></tr>
* </table> * </table>
* *
* <h3>Specification for implementors</h3> * @implSpec
* <p> * <p>
* This class is immutable and thread-safe. * This class is immutable and thread-safe.
* *
......
...@@ -81,7 +81,7 @@ import java.util.Map; ...@@ -81,7 +81,7 @@ import java.util.Map;
* The fields are supported, and can be queried and set if {@code EPOCH_DAY} is available. * The fields are supported, and can be queried and set if {@code EPOCH_DAY} is available.
* The fields work with all chronologies. * The fields work with all chronologies.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This is an immutable and thread-safe class. * This is an immutable and thread-safe class.
* *
* @since 1.8 * @since 1.8
......
...@@ -119,7 +119,7 @@ import java.time.ZoneId; ...@@ -119,7 +119,7 @@ import java.time.ZoneId;
* days to months. * days to months.
* </ul><p> * </ul><p>
* *
* <h3>Specification for implementors</h3> * @implSpec
* This interface places no restrictions on the mutability of implementations, * This interface places no restrictions on the mutability of implementations,
* however immutability is strongly recommended. * however immutability is strongly recommended.
* All implementations must be {@link Comparable}. * All implementations must be {@link Comparable}.
...@@ -146,7 +146,7 @@ public interface Temporal extends TemporalAccessor { ...@@ -146,7 +146,7 @@ public interface Temporal extends TemporalAccessor {
* date = date.with(next(WEDNESDAY)); // static import from Adjusters and DayOfWeek * date = date.with(next(WEDNESDAY)); // static import from Adjusters and DayOfWeek
* </pre> * </pre>
* *
* <h3>Specification for implementors</h3> * @implSpec
* Implementations must not alter either this object. * Implementations must not alter either this object.
* Instead, an adjusted copy of the original must be returned. * Instead, an adjusted copy of the original must be returned.
* This provides equivalent, safe behavior for immutable and mutable implementations. * This provides equivalent, safe behavior for immutable and mutable implementations.
...@@ -177,7 +177,7 @@ public interface Temporal extends TemporalAccessor { ...@@ -177,7 +177,7 @@ public interface Temporal extends TemporalAccessor {
* In cases like this, the field is responsible for resolving the result. Typically it will choose * In cases like this, the field is responsible for resolving the result. Typically it will choose
* the previous valid date, which would be the last valid day of February in this example. * the previous valid date, which would be the last valid day of February in this example.
* *
* <h3>Specification for implementors</h3> * @implSpec
* Implementations must check and handle all fields defined in {@link ChronoField}. * Implementations must check and handle all fields defined in {@link ChronoField}.
* If the field is supported, then the adjustment must be performed. * If the field is supported, then the adjustment must be performed.
* If unsupported, then an {@code UnsupportedTemporalTypeException} must be thrown. * If unsupported, then an {@code UnsupportedTemporalTypeException} must be thrown.
...@@ -217,7 +217,7 @@ public interface Temporal extends TemporalAccessor { ...@@ -217,7 +217,7 @@ public interface Temporal extends TemporalAccessor {
* Note that calling {@code plus} followed by {@code minus} is not guaranteed to * Note that calling {@code plus} followed by {@code minus} is not guaranteed to
* return the same date-time. * return the same date-time.
* *
* <h3>Specification for implementors</h3> * @implSpec
* Implementations must not alter either this object. * Implementations must not alter either this object.
* Instead, an adjusted copy of the original must be returned. * Instead, an adjusted copy of the original must be returned.
* This provides equivalent, safe behavior for immutable and mutable implementations. * This provides equivalent, safe behavior for immutable and mutable implementations.
...@@ -247,12 +247,8 @@ public interface Temporal extends TemporalAccessor { ...@@ -247,12 +247,8 @@ public interface Temporal extends TemporalAccessor {
* a date representing the 31st January, then adding one month would be unclear. * a date representing the 31st January, then adding one month would be unclear.
* In cases like this, the field is responsible for resolving the result. Typically it will choose * In cases like this, the field is responsible for resolving the result. Typically it will choose
* the previous valid date, which would be the last valid day of February in this example. * the previous valid date, which would be the last valid day of February in this example.
* <p>
* If the implementation represents a date-time that has boundaries, such as {@code LocalTime},
* then the permitted units must include the boundary unit, but no multiples of the boundary unit.
* For example, {@code LocalTime} must accept {@code DAYS} but not {@code WEEKS} or {@code MONTHS}.
* *
* <h3>Specification for implementors</h3> * @implSpec
* Implementations must check and handle all units defined in {@link ChronoUnit}. * Implementations must check and handle all units defined in {@link ChronoUnit}.
* If the unit is supported, then the addition must be performed. * If the unit is supported, then the addition must be performed.
* If unsupported, then an {@code UnsupportedTemporalTypeException} must be thrown. * If unsupported, then an {@code UnsupportedTemporalTypeException} must be thrown.
...@@ -292,7 +288,7 @@ public interface Temporal extends TemporalAccessor { ...@@ -292,7 +288,7 @@ public interface Temporal extends TemporalAccessor {
* Note that calling {@code plus} followed by {@code minus} is not guaranteed to * Note that calling {@code plus} followed by {@code minus} is not guaranteed to
* return the same date-time. * return the same date-time.
* *
* <h3>Specification for implementors</h3> * @implSpec
* Implementations must not alter either this object. * Implementations must not alter either this object.
* Instead, an adjusted copy of the original must be returned. * Instead, an adjusted copy of the original must be returned.
* This provides equivalent, safe behavior for immutable and mutable implementations. * This provides equivalent, safe behavior for immutable and mutable implementations.
...@@ -322,12 +318,8 @@ public interface Temporal extends TemporalAccessor { ...@@ -322,12 +318,8 @@ public interface Temporal extends TemporalAccessor {
* a date representing the 31st March, then subtracting one month would be unclear. * a date representing the 31st March, then subtracting one month would be unclear.
* In cases like this, the field is responsible for resolving the result. Typically it will choose * In cases like this, the field is responsible for resolving the result. Typically it will choose
* the previous valid date, which would be the last valid day of February in this example. * the previous valid date, which would be the last valid day of February in this example.
* <p>
* If the implementation represents a date-time that has boundaries, such as {@code LocalTime},
* then the permitted units must include the boundary unit, but no multiples of the boundary unit.
* For example, {@code LocalTime} must accept {@code DAYS} but not {@code WEEKS} or {@code MONTHS}.
* *
* <h3>Specification for implementors</h3> * @implSpec
* Implementations must behave in a manor equivalent to the default method behavior. * Implementations must behave in a manor equivalent to the default method behavior.
* <p> * <p>
* Implementations must not alter either this object or the specified temporal object. * Implementations must not alter either this object or the specified temporal object.
...@@ -353,10 +345,10 @@ public interface Temporal extends TemporalAccessor { ...@@ -353,10 +345,10 @@ public interface Temporal extends TemporalAccessor {
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
/** /**
* Calculates the period between this temporal and another temporal in * Calculates the amount of time until another temporal in terms of the specified unit.
* terms of the specified unit.
* <p> * <p>
* This calculates the period between two temporals in terms of a single unit. * This calculates the amount of time between two temporal objects
* of the same type in terms of a single {@code TemporalUnit}.
* The start and end points are {@code this} and the specified temporal. * The start and end points are {@code this} and the specified temporal.
* The result will be negative if the end is before the start. * The result will be negative if the end is before the start.
* For example, the period in hours between two temporal objects can be * For example, the period in hours between two temporal objects can be
...@@ -385,7 +377,7 @@ public interface Temporal extends TemporalAccessor { ...@@ -385,7 +377,7 @@ public interface Temporal extends TemporalAccessor {
* long daysBetween = DAYS.between(start, end); * long daysBetween = DAYS.between(start, end);
* </pre> * </pre>
* *
* <h3>Specification for implementors</h3> * @implSpec
* Implementations must begin by checking to ensure that the input temporal * Implementations must begin by checking to ensure that the input temporal
* object is of the same observable type as the implementation. * object is of the same observable type as the implementation.
* They must then perform the calculation for all instances of {@link ChronoUnit}. * They must then perform the calculation for all instances of {@link ChronoUnit}.
...@@ -410,11 +402,11 @@ public interface Temporal extends TemporalAccessor { ...@@ -410,11 +402,11 @@ public interface Temporal extends TemporalAccessor {
* Neither this object, nor the specified temporal, may be altered. * Neither this object, nor the specified temporal, may be altered.
* *
* @param endTemporal the end temporal, of the same type as this object, not null * @param endTemporal the end temporal, of the same type as this object, not null
* @param unit the unit to measure the period in, not null * @param unit the unit to measure the amount in, not null
* @return the period between this temporal object and the specified one in terms of * @return the amount of time between this temporal object and the specified one
* the unit; positive if the specified object is later than this one, negative if * in terms of the unit; positive if the specified object is later than this one,
* it is earlier than this one * negative if it is earlier than this one
* @throws DateTimeException if the period cannot be calculated * @throws DateTimeException if the amount cannot be calculated
* @throws UnsupportedTemporalTypeException if the unit is not supported * @throws UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs * @throws ArithmeticException if numeric overflow occurs
*/ */
......
...@@ -94,7 +94,7 @@ import java.util.Objects; ...@@ -94,7 +94,7 @@ import java.util.Objects;
* of this interface may be in calendar systems other than ISO. * of this interface may be in calendar systems other than ISO.
* See {@link java.time.chrono.ChronoLocalDate} for a fuller discussion of the issues. * See {@link java.time.chrono.ChronoLocalDate} for a fuller discussion of the issues.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This interface places no restrictions on the mutability of implementations, * This interface places no restrictions on the mutability of implementations,
* however immutability is strongly recommended. * however immutability is strongly recommended.
* *
...@@ -109,7 +109,7 @@ public interface TemporalAccessor { ...@@ -109,7 +109,7 @@ public interface TemporalAccessor {
* If false, then calling the {@link #range(TemporalField) range} and {@link #get(TemporalField) get} * If false, then calling the {@link #range(TemporalField) range} and {@link #get(TemporalField) get}
* methods will throw an exception. * methods will throw an exception.
* *
* <h3>Specification for implementors</h3> * @implSpec
* Implementations must check and handle all fields defined in {@link ChronoField}. * Implementations must check and handle all fields defined in {@link ChronoField}.
* If the field is supported, then true is returned, otherwise false * If the field is supported, then true is returned, otherwise false
* <p> * <p>
...@@ -137,7 +137,7 @@ public interface TemporalAccessor { ...@@ -137,7 +137,7 @@ public interface TemporalAccessor {
* and it is important not to read too much into them. For example, there * and it is important not to read too much into them. For example, there
* could be values within the range that are invalid for the field. * could be values within the range that are invalid for the field.
* *
* <h3>Specification for implementors</h3> * @implSpec
* Implementations must check and handle all fields defined in {@link ChronoField}. * Implementations must check and handle all fields defined in {@link ChronoField}.
* If the field is supported, then the range of the field must be returned. * If the field is supported, then the range of the field must be returned.
* If unsupported, then an {@code UnsupportedTemporalTypeException} must be thrown. * If unsupported, then an {@code UnsupportedTemporalTypeException} must be thrown.
...@@ -183,7 +183,7 @@ public interface TemporalAccessor { ...@@ -183,7 +183,7 @@ public interface TemporalAccessor {
* If the date-time cannot return the value, because the field is unsupported or for * If the date-time cannot return the value, because the field is unsupported or for
* some other reason, an exception will be thrown. * some other reason, an exception will be thrown.
* *
* <h3>Specification for implementors</h3> * @implSpec
* Implementations must check and handle all fields defined in {@link ChronoField}. * Implementations must check and handle all fields defined in {@link ChronoField}.
* If the field is supported and has an {@code int} range, then the value of * If the field is supported and has an {@code int} range, then the value of
* the field must be returned. * the field must be returned.
...@@ -231,7 +231,7 @@ public interface TemporalAccessor { ...@@ -231,7 +231,7 @@ public interface TemporalAccessor {
* If the date-time cannot return the value, because the field is unsupported or for * If the date-time cannot return the value, because the field is unsupported or for
* some other reason, an exception will be thrown. * some other reason, an exception will be thrown.
* *
* <h3>Specification for implementors</h3> * @implSpec
* Implementations must check and handle all fields defined in {@link ChronoField}. * Implementations must check and handle all fields defined in {@link ChronoField}.
* If the field is supported, then the value of the field must be returned. * If the field is supported, then the value of the field must be returned.
* If unsupported, then an {@code UnsupportedTemporalTypeException} must be thrown. * If unsupported, then an {@code UnsupportedTemporalTypeException} must be thrown.
...@@ -265,7 +265,7 @@ public interface TemporalAccessor { ...@@ -265,7 +265,7 @@ public interface TemporalAccessor {
* {@code LocalDate::from} and {@code ZoneId::from}. * {@code LocalDate::from} and {@code ZoneId::from}.
* Additional implementations are provided as static methods on {@link TemporalQuery}. * Additional implementations are provided as static methods on {@link TemporalQuery}.
* *
* <h3>Specification for implementors</h3> * @implSpec
* The default implementation must behave equivalent to this code: * The default implementation must behave equivalent to this code:
* <pre> * <pre>
* if (query == TemporalQuery.zoneId() || * if (query == TemporalQuery.zoneId() ||
......
...@@ -97,7 +97,7 @@ import java.util.function.UnaryOperator; ...@@ -97,7 +97,7 @@ import java.util.function.UnaryOperator;
* <li>finding the next or previous day-of-week, such as "next Thursday" * <li>finding the next or previous day-of-week, such as "next Thursday"
* </ul> * </ul>
* *
* <h3>Specification for implementors</h3> * @implSpec
* This interface places no restrictions on the mutability of implementations, * This interface places no restrictions on the mutability of implementations,
* however immutability is strongly recommended. * however immutability is strongly recommended.
* <p> * <p>
...@@ -127,7 +127,7 @@ public interface TemporalAdjuster { ...@@ -127,7 +127,7 @@ public interface TemporalAdjuster {
* It is recommended to use the second approach, {@code with(TemporalAdjuster)}, * It is recommended to use the second approach, {@code with(TemporalAdjuster)},
* as it is a lot clearer to read in code. * as it is a lot clearer to read in code.
* *
* <h3>Specification for implementors</h3> * @implSpec
* The implementation must take the input object and adjust it. * The implementation must take the input object and adjust it.
* The implementation defines the logic of the adjustment and is responsible for * The implementation defines the logic of the adjustment and is responsible for
* documenting that logic. It may use any method on {@code Temporal} to * documenting that logic. It may use any method on {@code Temporal} to
...@@ -162,10 +162,10 @@ public interface TemporalAdjuster { ...@@ -162,10 +162,10 @@ public interface TemporalAdjuster {
* This is provided for convenience to make user-written adjusters simpler. * This is provided for convenience to make user-written adjusters simpler.
* <p> * <p>
* In general, user-written adjusters should be static constants: * In general, user-written adjusters should be static constants:
* <pre> * <pre>{@code
* static TemporalAdjuster TWO_DAYS_LATER = TemporalAdjuster.ofDateAdjuster( * static TemporalAdjuster TWO_DAYS_LATER = TemporalAdjuster.ofDateAdjuster(
* date -> date.plusDays(2)); * date -> date.plusDays(2));
* </pre> * }</pre>
* *
* @param dateBasedAdjuster the date-based adjuster, not null * @param dateBasedAdjuster the date-based adjuster, not null
* @return the temporal adjuster wrapping on the date adjuster, not null * @return the temporal adjuster wrapping on the date adjuster, not null
......
...@@ -90,7 +90,7 @@ import java.util.List; ...@@ -90,7 +90,7 @@ import java.util.List;
* used in application code. Instead, applications should create and pass * used in application code. Instead, applications should create and pass
* around instances of concrete types, such as {@code Period} and {@code Duration}. * around instances of concrete types, such as {@code Period} and {@code Duration}.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This interface places no restrictions on the mutability of implementations, * This interface places no restrictions on the mutability of implementations,
* however immutability is strongly recommended. * however immutability is strongly recommended.
* *
...@@ -104,7 +104,7 @@ public interface TemporalAmount { ...@@ -104,7 +104,7 @@ public interface TemporalAmount {
* value of the {@code TemporalAmount}. A value must be returned * value of the {@code TemporalAmount}. A value must be returned
* for each unit listed in {@code getUnits}. * for each unit listed in {@code getUnits}.
* *
* <h3>Specification for implementors</h3> * @implSpec
* Implementations may declare support for units not listed by {@link #getUnits()}. * Implementations may declare support for units not listed by {@link #getUnits()}.
* Typically, the implementation would define additional units * Typically, the implementation would define additional units
* as conversions for the convenience of developers. * as conversions for the convenience of developers.
...@@ -124,7 +124,7 @@ public interface TemporalAmount { ...@@ -124,7 +124,7 @@ public interface TemporalAmount {
* The units are ordered from longest duration to the shortest duration * The units are ordered from longest duration to the shortest duration
* of the unit. * of the unit.
* *
* <h3>Specification for implementors</h3> * @implSpec
* The list of units completely and uniquely represents the * The list of units completely and uniquely represents the
* state of the object without omissions, overlaps or duplication. * state of the object without omissions, overlaps or duplication.
* The units are in order from longest duration to shortest. * The units are in order from longest duration to shortest.
...@@ -150,7 +150,7 @@ public interface TemporalAmount { ...@@ -150,7 +150,7 @@ public interface TemporalAmount {
* It is recommended to use the second approach, {@code plus(TemporalAmount)}, * It is recommended to use the second approach, {@code plus(TemporalAmount)},
* as it is a lot clearer to read in code. * as it is a lot clearer to read in code.
* *
* <h3>Specification for implementors</h3> * @implSpec
* The implementation must take the input object and add to it. * The implementation must take the input object and add to it.
* The implementation defines the logic of the addition and is responsible for * The implementation defines the logic of the addition and is responsible for
* documenting that logic. It may use any method on {@code Temporal} to * documenting that logic. It may use any method on {@code Temporal} to
...@@ -192,7 +192,7 @@ public interface TemporalAmount { ...@@ -192,7 +192,7 @@ public interface TemporalAmount {
* It is recommended to use the second approach, {@code minus(TemporalAmount)}, * It is recommended to use the second approach, {@code minus(TemporalAmount)},
* as it is a lot clearer to read in code. * as it is a lot clearer to read in code.
* *
* <h3>Specification for implementors</h3> * @implSpec
* The implementation must take the input object and subtract from it. * The implementation must take the input object and subtract from it.
* The implementation defines the logic of the subtraction and is responsible for * The implementation defines the logic of the subtraction and is responsible for
* documenting that logic. It may use any method on {@code Temporal} to * documenting that logic. It may use any method on {@code Temporal} to
......
...@@ -82,7 +82,7 @@ import java.util.Objects; ...@@ -82,7 +82,7 @@ import java.util.Objects;
* If it is, then the date-time must handle it. * If it is, then the date-time must handle it.
* Otherwise, the method call is re-dispatched to the matching method in this interface. * Otherwise, the method call is re-dispatched to the matching method in this interface.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This interface must be implemented with care to ensure other classes operate correctly. * This interface must be implemented with care to ensure other classes operate correctly.
* All implementations that can be instantiated must be final, immutable and thread-safe. * All implementations that can be instantiated must be final, immutable and thread-safe.
* Implementations should be {@code Serializable} where possible. * Implementations should be {@code Serializable} where possible.
......
...@@ -96,7 +96,7 @@ import java.time.chrono.Chronology; ...@@ -96,7 +96,7 @@ import java.time.chrono.Chronology;
* {@code LocalDate::from} and {@code ZoneId::from}. * {@code LocalDate::from} and {@code ZoneId::from}.
* Additional common implementations are provided on this interface as static methods. * Additional common implementations are provided on this interface as static methods.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This interface places no restrictions on the mutability of implementations, * This interface places no restrictions on the mutability of implementations,
* however immutability is strongly recommended. * however immutability is strongly recommended.
* *
...@@ -124,7 +124,7 @@ public interface TemporalQuery<R> { ...@@ -124,7 +124,7 @@ public interface TemporalQuery<R> {
* It is recommended to use the second approach, {@code query(TemporalQuery)}, * It is recommended to use the second approach, {@code query(TemporalQuery)},
* as it is a lot clearer to read in code. * as it is a lot clearer to read in code.
* *
* <h3>Specification for implementors</h3> * @implSpec
* The implementation must take the input object and query it. * The implementation must take the input object and query it.
* The implementation defines the logic of the query and is responsible for * The implementation defines the logic of the query and is responsible for
* documenting that logic. * documenting that logic.
......
...@@ -83,7 +83,7 @@ import java.time.Period; ...@@ -83,7 +83,7 @@ import java.time.Period;
* If it is, then the date-time must handle it. * If it is, then the date-time must handle it.
* Otherwise, the method call is re-dispatched to the matching method in this interface. * Otherwise, the method call is re-dispatched to the matching method in this interface.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This interface must be implemented with care to ensure other classes operate correctly. * This interface must be implemented with care to ensure other classes operate correctly.
* All implementations that can be instantiated must be final, immutable and thread-safe. * All implementations that can be instantiated must be final, immutable and thread-safe.
* It is recommended to use an enum where possible. * It is recommended to use an enum where possible.
...@@ -197,19 +197,17 @@ public interface TemporalUnit { ...@@ -197,19 +197,17 @@ public interface TemporalUnit {
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
/** /**
* Calculates the period in terms of this unit between two temporal objects * Calculates the amount of time between two temporal objects.
* of the same type.
* <p> * <p>
* This calculates the period between two temporals in terms of this unit. * This calculates the amount in terms of this unit. The start and end
* The start and end points are supplied as temporal objects and must be * points are supplied as temporal objects and must be of the same type.
* of the same type.
* The result will be negative if the end is before the start. * The result will be negative if the end is before the start.
* For example, the period in hours between two temporal objects can be * For example, the amount in hours between two temporal objects can be
* calculated using {@code HOURS.between(startTime, endTime)}. * calculated using {@code HOURS.between(startTime, endTime)}.
* <p> * <p>
* The calculation returns a whole number, representing the number of * The calculation returns a whole number, representing the number of
* complete units between the two temporals. * complete units between the two temporals.
* For example, the period in hours between the times 11:30 and 13:29 * For example, the amount in hours between the times 11:30 and 13:29
* will only be one hour as it is one minute short of two hours. * will only be one hour as it is one minute short of two hours.
* <p> * <p>
* There are two equivalent ways of using this method. * There are two equivalent ways of using this method.
...@@ -237,9 +235,9 @@ public interface TemporalUnit { ...@@ -237,9 +235,9 @@ public interface TemporalUnit {
* *
* @param temporal1 the base temporal object, not null * @param temporal1 the base temporal object, not null
* @param temporal2 the other temporal object, not null * @param temporal2 the other temporal object, not null
* @return the period between temporal1 and temporal2 in terms of this unit; * @return the amount of time between temporal1 and temporal2 in terms of this unit;
* positive if temporal2 is later than temporal1, negative if earlier * positive if temporal2 is later than temporal1, negative if earlier
* @throws DateTimeException if the period cannot be calculated * @throws DateTimeException if the amount cannot be calculated
* @throws UnsupportedTemporalTypeException if the unit is not supported by the temporal * @throws UnsupportedTemporalTypeException if the unit is not supported by the temporal
* @throws ArithmeticException if numeric overflow occurs * @throws ArithmeticException if numeric overflow occurs
*/ */
......
...@@ -67,7 +67,7 @@ import java.time.DateTimeException; ...@@ -67,7 +67,7 @@ import java.time.DateTimeException;
* UnsupportedTemporalTypeException indicates that a ChronoField or ChronoUnit is * UnsupportedTemporalTypeException indicates that a ChronoField or ChronoUnit is
* not supported for a Temporal class. * not supported for a Temporal class.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This class is intended for use in a single thread. * This class is intended for use in a single thread.
* *
* @since 1.8 * @since 1.8
......
...@@ -79,7 +79,7 @@ import java.time.DateTimeException; ...@@ -79,7 +79,7 @@ import java.time.DateTimeException;
* <p> * <p>
* Instances of this class are not tied to a specific field. * Instances of this class are not tied to a specific field.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This class is immutable and thread-safe. * This class is immutable and thread-safe.
* *
* @since 1.8 * @since 1.8
......
...@@ -170,7 +170,8 @@ import sun.util.locale.provider.LocaleResources; ...@@ -170,7 +170,8 @@ import sun.util.locale.provider.LocaleResources;
* <tr><th>2009-01-05</th><td>Monday</td> * <tr><th>2009-01-05</th><td>Monday</td>
* <td>Week 2 of 2009</td><td>Week 1 of 2009</td></tr> * <td>Week 2 of 2009</td><td>Week 1 of 2009</td></tr>
* </table> * </table>
* <h3>Specification for implementors</h3> *
* @implSpec
* This class is immutable and thread-safe. * This class is immutable and thread-safe.
* *
* @since 1.8 * @since 1.8
...@@ -200,8 +201,6 @@ public final class WeekFields implements Serializable { ...@@ -200,8 +201,6 @@ public final class WeekFields implements Serializable {
* Note that the first week may start in the previous calendar year. * Note that the first week may start in the previous calendar year.
* Note also that the first few days of a calendar year may be in the * Note also that the first few days of a calendar year may be in the
* week-based-year corresponding to the previous calendar year. * week-based-year corresponding to the previous calendar year.
* <p>
* This field is an immutable and thread-safe singleton.
*/ */
public static final WeekFields ISO = new WeekFields(DayOfWeek.MONDAY, 4); public static final WeekFields ISO = new WeekFields(DayOfWeek.MONDAY, 4);
...@@ -211,8 +210,6 @@ public final class WeekFields implements Serializable { ...@@ -211,8 +210,6 @@ public final class WeekFields implements Serializable {
* <p> * <p>
* Defined as starting on Sunday and with a minimum of 1 day in the month. * Defined as starting on Sunday and with a minimum of 1 day in the month.
* This week definition is in use in the US and other European countries. * This week definition is in use in the US and other European countries.
* <p>
* This field is an immutable and thread-safe singleton.
*/ */
public static final WeekFields SUNDAY_START = WeekFields.of(DayOfWeek.SUNDAY, 1); public static final WeekFields SUNDAY_START = WeekFields.of(DayOfWeek.SUNDAY, 1);
...@@ -230,7 +227,7 @@ public final class WeekFields implements Serializable { ...@@ -230,7 +227,7 @@ public final class WeekFields implements Serializable {
* In that case, the week is set to the last week of the year * In that case, the week is set to the last week of the year
* with the same day-of-week. * with the same day-of-week.
* <p> * <p>
* This field is an immutable and thread-safe singleton. * This unit is an immutable and thread-safe singleton.
*/ */
public static final TemporalUnit WEEK_BASED_YEARS = IsoFields.WEEK_BASED_YEARS; public static final TemporalUnit WEEK_BASED_YEARS = IsoFields.WEEK_BASED_YEARS;
...@@ -247,22 +244,18 @@ public final class WeekFields implements Serializable { ...@@ -247,22 +244,18 @@ public final class WeekFields implements Serializable {
* The minimal number of days in the first week. * The minimal number of days in the first week.
*/ */
private final int minimalDays; private final int minimalDays;
/** /**
* The field used to access the computed DayOfWeek. * The field used to access the computed DayOfWeek.
*/ */
private transient final TemporalField dayOfWeek = ComputedDayOfField.ofDayOfWeekField(this); private transient final TemporalField dayOfWeek = ComputedDayOfField.ofDayOfWeekField(this);
/** /**
* The field used to access the computed WeekOfMonth. * The field used to access the computed WeekOfMonth.
*/ */
private transient final TemporalField weekOfMonth = ComputedDayOfField.ofWeekOfMonthField(this); private transient final TemporalField weekOfMonth = ComputedDayOfField.ofWeekOfMonthField(this);
/** /**
* The field used to access the computed WeekOfYear. * The field used to access the computed WeekOfYear.
*/ */
private transient final TemporalField weekOfYear = ComputedDayOfField.ofWeekOfYearField(this); private transient final TemporalField weekOfYear = ComputedDayOfField.ofWeekOfYearField(this);
/** /**
* The field that represents the week-of-week-based-year. * The field that represents the week-of-week-based-year.
* <p> * <p>
...@@ -271,7 +264,6 @@ public final class WeekFields implements Serializable { ...@@ -271,7 +264,6 @@ public final class WeekFields implements Serializable {
* This unit is an immutable and thread-safe singleton. * This unit is an immutable and thread-safe singleton.
*/ */
private transient final TemporalField weekOfWeekBasedYear = ComputedDayOfField.ofWeekOfWeekBasedYearField(this); private transient final TemporalField weekOfWeekBasedYear = ComputedDayOfField.ofWeekOfWeekBasedYearField(this);
/** /**
* The field that represents the week-based-year. * The field that represents the week-based-year.
* <p> * <p>
...@@ -281,6 +273,7 @@ public final class WeekFields implements Serializable { ...@@ -281,6 +273,7 @@ public final class WeekFields implements Serializable {
*/ */
private transient final TemporalField weekBasedYear = ComputedDayOfField.ofWeekBasedYearField(this); private transient final TemporalField weekBasedYear = ComputedDayOfField.ofWeekBasedYearField(this);
//-----------------------------------------------------------------------
/** /**
* Obtains an instance of {@code WeekFields} appropriate for a locale. * Obtains an instance of {@code WeekFields} appropriate for a locale.
* <p> * <p>
...@@ -359,8 +352,7 @@ public final class WeekFields implements Serializable { ...@@ -359,8 +352,7 @@ public final class WeekFields implements Serializable {
try { try {
return WeekFields.of(firstDayOfWeek, minimalDays); return WeekFields.of(firstDayOfWeek, minimalDays);
} catch (IllegalArgumentException iae) { } catch (IllegalArgumentException iae) {
throw new InvalidObjectException("Invalid serialized WeekFields: " throw new InvalidObjectException("Invalid serialized WeekFields: " + iae.getMessage());
+ iae.getMessage());
} }
} }
...@@ -394,21 +386,24 @@ public final class WeekFields implements Serializable { ...@@ -394,21 +386,24 @@ public final class WeekFields implements Serializable {
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
/** /**
* Returns a field to access the day of week, * Returns a field to access the day of week based on this {@code WeekFields}.
* computed based on this WeekFields.
* <p> * <p>
* The days of week are numbered from 1 to 7. * This is similar to {@link ChronoField#DAY_OF_WEEK} but uses values for
* Day number 1 is the {@link #getFirstDayOfWeek() first day-of-week}. * the day-of-week based on this {@code WeekFields}.
* The days are numbered from 1 to 7 where the
* {@link #getFirstDayOfWeek() first day-of-week} is assigned the value 1.
* <p>
* For example, if the first day-of-week is Sunday, then that will have the
* value 1, with other days ranging from Monday as 2 to Saturday as 7.
* *
* @return the field for day-of-week using this week definition, not null * @return a field providing access to the day-of-week with localized numbering, not null
*/ */
public TemporalField dayOfWeek() { public TemporalField dayOfWeek() {
return dayOfWeek; return dayOfWeek;
} }
/** /**
* Returns a field to access the week of month, * Returns a field to access the week of month based on this {@code WeekFields}.
* computed based on this WeekFields.
* <p> * <p>
* This represents the concept of the count of weeks within the month where weeks * This represents the concept of the count of weeks within the month where weeks
* start on a fixed day-of-week, such as Monday. * start on a fixed day-of-week, such as Monday.
...@@ -426,15 +421,15 @@ public final class WeekFields implements Serializable { ...@@ -426,15 +421,15 @@ public final class WeekFields implements Serializable {
* - if the 5th day of the month is a Monday, week two starts on the 5th and the 1st to 4th is in week one<br> * - if the 5th day of the month is a Monday, week two starts on the 5th and the 1st to 4th is in week one<br>
* <p> * <p>
* This field can be used with any calendar system. * This field can be used with any calendar system.
* @return a TemporalField to access the WeekOfMonth, not null *
* @return a field providing access to the week-of-month, not null
*/ */
public TemporalField weekOfMonth() { public TemporalField weekOfMonth() {
return weekOfMonth; return weekOfMonth;
} }
/** /**
* Returns a field to access the week of year, * Returns a field to access the week of year based on this {@code WeekFields}.
* computed based on this WeekFields.
* <p> * <p>
* This represents the concept of the count of weeks within the year where weeks * This represents the concept of the count of weeks within the year where weeks
* start on a fixed day-of-week, such as Monday. * start on a fixed day-of-week, such as Monday.
...@@ -452,15 +447,15 @@ public final class WeekFields implements Serializable { ...@@ -452,15 +447,15 @@ public final class WeekFields implements Serializable {
* - if the 5th day of the year is a Monday, week two starts on the 5th and the 1st to 4th is in week one<br> * - if the 5th day of the year is a Monday, week two starts on the 5th and the 1st to 4th is in week one<br>
* <p> * <p>
* This field can be used with any calendar system. * This field can be used with any calendar system.
* @return a TemporalField to access the WeekOfYear, not null *
* @return a field providing access to the week-of-year, not null
*/ */
public TemporalField weekOfYear() { public TemporalField weekOfYear() {
return weekOfYear; return weekOfYear;
} }
/** /**
* Returns a field to access the week of a week-based-year, * Returns a field to access the week of a week-based-year based on this {@code WeekFields}.
* computed based on this WeekFields.
* <p> * <p>
* This represents the concept of the count of weeks within the year where weeks * This represents the concept of the count of weeks within the year where weeks
* start on a fixed day-of-week, such as Monday and each week belongs to exactly one year. * start on a fixed day-of-week, such as Monday and each week belongs to exactly one year.
...@@ -482,15 +477,15 @@ public final class WeekFields implements Serializable { ...@@ -482,15 +477,15 @@ public final class WeekFields implements Serializable {
* the 1st to 4th is in week one<br> * the 1st to 4th is in week one<br>
* <p> * <p>
* This field can be used with any calendar system. * This field can be used with any calendar system.
* @return a TemporalField to access the week of week-based-year, not null *
* @return a field providing access to the week-of-week-based-year, not null
*/ */
public TemporalField weekOfWeekBasedYear() { public TemporalField weekOfWeekBasedYear() {
return weekOfWeekBasedYear; return weekOfWeekBasedYear;
} }
/** /**
* Returns a field to access the year of a week-based-year, * Returns a field to access the year of a week-based-year based on this {@code WeekFields}.
* computed based on this WeekFields.
* <p> * <p>
* This represents the concept of the year where weeks start on a fixed day-of-week, * This represents the concept of the year where weeks start on a fixed day-of-week,
* such as Monday and each week belongs to exactly one year. * such as Monday and each week belongs to exactly one year.
...@@ -504,14 +499,16 @@ public final class WeekFields implements Serializable { ...@@ -504,14 +499,16 @@ public final class WeekFields implements Serializable {
* is in the last week of the previous year. * is in the last week of the previous year.
* <p> * <p>
* This field can be used with any calendar system. * This field can be used with any calendar system.
* @return a TemporalField to access the year of week-based-year, not null *
* @return a field providing access to the week-based-year, not null
*/ */
public TemporalField weekBasedYear() { public TemporalField weekBasedYear() {
return weekBasedYear; return weekBasedYear;
} }
//-----------------------------------------------------------------------
/** /**
* Checks if this WeekFields is equal to the specified object. * Checks if this {@code WeekFields} is equal to the specified object.
* <p> * <p>
* The comparison is based on the entire state of the rules, which is * The comparison is based on the entire state of the rules, which is
* the first day-of-week and minimal days. * the first day-of-week and minimal days.
...@@ -531,7 +528,7 @@ public final class WeekFields implements Serializable { ...@@ -531,7 +528,7 @@ public final class WeekFields implements Serializable {
} }
/** /**
* A hash code for these rules. * A hash code for this {@code WeekFields}.
* *
* @return a suitable hash code * @return a suitable hash code
*/ */
...@@ -542,7 +539,7 @@ public final class WeekFields implements Serializable { ...@@ -542,7 +539,7 @@ public final class WeekFields implements Serializable {
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
/** /**
* A string representation of this definition. * A string representation of this {@code WeekFields} instance.
* *
* @return the string representation, not null * @return the string representation, not null
*/ */
...@@ -957,7 +954,6 @@ public final class WeekFields implements Serializable { ...@@ -957,7 +954,6 @@ public final class WeekFields implements Serializable {
/** /**
* Map the field range to a week range of a week year. * Map the field range to a week range of a week year.
* @param temporal the temporal * @param temporal the temporal
* @param field the field to get the range of
* @return the ValueRange with the range adjusted to weeks. * @return the ValueRange with the range adjusted to weeks.
*/ */
private ValueRange rangeWeekOfWeekBasedYear(TemporalAccessor temporal) { private ValueRange rangeWeekOfWeekBasedYear(TemporalAccessor temporal) {
......
...@@ -74,7 +74,7 @@ import java.time.ZoneOffset; ...@@ -74,7 +74,7 @@ import java.time.ZoneOffset;
/** /**
* The shared serialization delegate for this package. * The shared serialization delegate for this package.
* *
* <h3>Implementation notes</h3> * @implNote
* This class is mutable and should be created once per serialization. * This class is mutable and should be created once per serialization.
* *
* @serial include * @serial include
......
...@@ -89,7 +89,7 @@ import java.util.Objects; ...@@ -89,7 +89,7 @@ import java.util.Objects;
* An example would be when the offset changes from {@code +04:00} to {@code +03:00}. * An example would be when the offset changes from {@code +04:00} to {@code +03:00}.
* This might be described as 'the clocks will move back one hour tonight at 2am'. * This might be described as 'the clocks will move back one hour tonight at 2am'.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This class is immutable and thread-safe. * This class is immutable and thread-safe.
* *
* @since 1.8 * @since 1.8
......
...@@ -90,7 +90,7 @@ import java.util.Objects; ...@@ -90,7 +90,7 @@ import java.util.Objects;
* </ul><p> * </ul><p>
* These different rule types can be expressed and queried. * These different rule types can be expressed and queried.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This class is immutable and thread-safe. * This class is immutable and thread-safe.
* *
* @since 1.8 * @since 1.8
......
...@@ -100,7 +100,7 @@ import java.util.concurrent.ConcurrentMap; ...@@ -100,7 +100,7 @@ import java.util.concurrent.ConcurrentMap;
* Applications should treat the data provided as representing the best information * Applications should treat the data provided as representing the best information
* available to the implementation of this rule. * available to the implementation of this rule.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This class is immutable and thread-safe. * This class is immutable and thread-safe.
* *
* @since 1.8 * @since 1.8
......
...@@ -64,7 +64,7 @@ import java.time.DateTimeException; ...@@ -64,7 +64,7 @@ import java.time.DateTimeException;
* This exception is used to indicate a problems with the configured * This exception is used to indicate a problems with the configured
* time-zone rules. * time-zone rules.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This class is intended for use in a single thread. * This class is intended for use in a single thread.
* *
* @since 1.8 * @since 1.8
......
...@@ -111,7 +111,7 @@ import java.util.concurrent.CopyOnWriteArrayList; ...@@ -111,7 +111,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
* Each provider will provide the latest rules for each zone ID, but they * Each provider will provide the latest rules for each zone ID, but they
* may also provide the history of how the rules changed. * may also provide the history of how the rules changed.
* *
* <h3>Specification for implementors</h3> * @implSpec
* This interface is a service provider that can be called by multiple threads. * This interface is a service provider that can be called by multiple threads.
* Implementations must be immutable and thread-safe. * Implementations must be immutable and thread-safe.
* <p> * <p>
......
...@@ -249,11 +249,14 @@ class JapaneseImperialCalendar extends Calendar { ...@@ -249,11 +249,14 @@ class JapaneseImperialCalendar extends Calendar {
CalendarDate transitionDate = eras[i].getSinceDate(); CalendarDate transitionDate = eras[i].getSinceDate();
date.setDate(transitionDate.getYear(), BaseCalendar.JANUARY, 1); date.setDate(transitionDate.getYear(), BaseCalendar.JANUARY, 1);
long fdd = gcal.getFixedDate(date); long fdd = gcal.getFixedDate(date);
dayOfYear = Math.min((int)(fdd - fd), dayOfYear); if (fd != fdd) {
dayOfYear = Math.min((int)(fd - fdd) + 1, dayOfYear);
}
date.setDate(transitionDate.getYear(), BaseCalendar.DECEMBER, 31); date.setDate(transitionDate.getYear(), BaseCalendar.DECEMBER, 31);
fdd = gcal.getFixedDate(date) + 1; fdd = gcal.getFixedDate(date);
dayOfYear = Math.min((int)(fd - fdd), dayOfYear); if (fd != fdd) {
dayOfYear = Math.min((int)(fdd - fd) + 1, dayOfYear);
}
LocalGregorianCalendar.Date lgd = getCalendarDate(fd - 1); LocalGregorianCalendar.Date lgd = getCalendarDate(fd - 1);
int y = lgd.getYear(); int y = lgd.getYear();
// Unless the first year starts from January 1, the actual // Unless the first year starts from January 1, the actual
......
...@@ -269,7 +269,7 @@ public final class Objects { ...@@ -269,7 +269,7 @@ public final class Objects {
* Checks that the specified object reference is not {@code null} and * Checks that the specified object reference is not {@code null} and
* throws a customized {@link NullPointerException} if it is. * throws a customized {@link NullPointerException} if it is.
* *
* <p>Unlike the method {@link requireNonNull(Object, String}, * <p>Unlike the method {@link #requireNonNull(Object, String)},
* this method allows creation of the message to be deferred until * this method allows creation of the message to be deferred until
* after the null check is made. While this may confer a * after the null check is made. While this may confer a
* performance advantage in the non-null case, when deciding to * performance advantage in the non-null case, when deciding to
......
/* /*
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -643,9 +643,7 @@ final class Config { ...@@ -643,9 +643,7 @@ final class Config {
// //
private String parseLibrary(String keyword) throws IOException { private String parseLibrary(String keyword) throws IOException {
checkDup(keyword); String lib = parseStringEntry(keyword);
parseEquals();
String lib = parseLine();
lib = expand(lib); lib = expand(lib);
int i = lib.indexOf("/$ISA/"); int i = lib.indexOf("/$ISA/");
if (i != -1) { if (i != -1) {
......
/* /*
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -460,7 +460,7 @@ final class P11Cipher extends CipherSpi { ...@@ -460,7 +460,7 @@ final class P11Cipher extends CipherSpi {
} }
int result = inLen + bytesBuffered; int result = inLen + bytesBuffered;
if (blockSize != 0) { if (blockSize != 0 && blockMode != MODE_CTR) {
// minus the number of bytes in the last incomplete block. // minus the number of bytes in the last incomplete block.
result -= (result & (blockSize - 1)); result -= (result & (blockSize - 1));
} }
......
...@@ -1528,7 +1528,7 @@ public class PKCS11 { ...@@ -1528,7 +1528,7 @@ public class PKCS11 {
* *
* @exception Throwable If finalization fails. * @exception Throwable If finalization fails.
*/ */
public void finalize() throws Throwable { protected void finalize() throws Throwable {
disconnect(); disconnect();
} }
......
...@@ -246,16 +246,16 @@ public class LocalGregorianCalendar extends BaseCalendar { ...@@ -246,16 +246,16 @@ public class LocalGregorianCalendar extends BaseCalendar {
return false; return false;
} }
ldate.setNormalizedYear(era.getSinceDate().getYear() + ldate.getYear() - 1); ldate.setNormalizedYear(era.getSinceDate().getYear() + ldate.getYear() - 1);
// If it's not the last Era, validate the date. Date tmp = newCalendarDate(date.getZone());
if (era != eras[eras.length - 1]) { tmp.setEra(era).setDate(date.getYear(), date.getMonth(), date.getDayOfMonth());
Date tmp = newCalendarDate(date.getZone()); normalize(tmp);
tmp.setEra(era).setDate(date.getYear(), date.getMonth(), date.getDayOfMonth()); if (tmp.getEra() != era) {
normalize(tmp); return false;
if (tmp.getEra() != era) {
return false;
}
} }
} else { } else {
if (date.getYear() >= eras[0].getSinceDate().getYear()) {
return false;
}
ldate.setNormalizedYear(ldate.getYear()); ldate.setNormalizedYear(ldate.getYear());
} }
return super.validate(ldate); return super.validate(ldate);
......
...@@ -370,6 +370,8 @@ public class TCKInstant extends AbstractDateTimeTest { ...@@ -370,6 +370,8 @@ public class TCKInstant extends AbstractDateTimeTest {
{"Z"}, {"Z"},
{"1970-01-01T00:00:00"}, {"1970-01-01T00:00:00"},
{"1970-01-01T00:00:0Z"}, {"1970-01-01T00:00:0Z"},
{"1970-01-01T00:0:00Z"},
{"1970-01-01T0:00:00Z"},
{"1970-01-01T00:00:00.0000000000Z"}, {"1970-01-01T00:00:00.0000000000Z"},
}; };
} }
...@@ -2045,60 +2047,64 @@ public class TCKInstant extends AbstractDateTimeTest { ...@@ -2045,60 +2047,64 @@ public class TCKInstant extends AbstractDateTimeTest {
Object[][] data_toString() { Object[][] data_toString() {
return new Object[][] { return new Object[][] {
{Instant.ofEpochSecond(65L, 567), "1970-01-01T00:01:05.000000567Z"}, {Instant.ofEpochSecond(65L, 567), "1970-01-01T00:01:05.000000567Z"},
{Instant.ofEpochSecond(65L, 560), "1970-01-01T00:01:05.000000560Z"},
{Instant.ofEpochSecond(65L, 560000), "1970-01-01T00:01:05.000560Z"},
{Instant.ofEpochSecond(65L, 560000000), "1970-01-01T00:01:05.560Z"},
{Instant.ofEpochSecond(1, 0), "1970-01-01T00:00:01Z"}, {Instant.ofEpochSecond(1, 0), "1970-01-01T00:00:01Z"},
{Instant.ofEpochSecond(60, 0), "1970-01-01T00:01Z"}, {Instant.ofEpochSecond(60, 0), "1970-01-01T00:01:00Z"},
{Instant.ofEpochSecond(3600, 0), "1970-01-01T01:00Z"}, {Instant.ofEpochSecond(3600, 0), "1970-01-01T01:00:00Z"},
{Instant.ofEpochSecond(-1, 0), "1969-12-31T23:59:59Z"}, {Instant.ofEpochSecond(-1, 0), "1969-12-31T23:59:59Z"},
{LocalDateTime.of(0, 1, 2, 0, 0).toInstant(ZoneOffset.UTC), "0000-01-02T00:00Z"}, {LocalDateTime.of(0, 1, 2, 0, 0).toInstant(ZoneOffset.UTC), "0000-01-02T00:00:00Z"},
{LocalDateTime.of(0, 1, 1, 12, 30).toInstant(ZoneOffset.UTC), "0000-01-01T12:30Z"}, {LocalDateTime.of(0, 1, 1, 12, 30).toInstant(ZoneOffset.UTC), "0000-01-01T12:30:00Z"},
{LocalDateTime.of(0, 1, 1, 0, 0, 0, 1).toInstant(ZoneOffset.UTC), "0000-01-01T00:00:00.000000001Z"}, {LocalDateTime.of(0, 1, 1, 0, 0, 0, 1).toInstant(ZoneOffset.UTC), "0000-01-01T00:00:00.000000001Z"},
{LocalDateTime.of(0, 1, 1, 0, 0).toInstant(ZoneOffset.UTC), "0000-01-01T00:00Z"}, {LocalDateTime.of(0, 1, 1, 0, 0).toInstant(ZoneOffset.UTC), "0000-01-01T00:00:00Z"},
{LocalDateTime.of(-1, 12, 31, 23, 59, 59, 999_999_999).toInstant(ZoneOffset.UTC), "-0001-12-31T23:59:59.999999999Z"}, {LocalDateTime.of(-1, 12, 31, 23, 59, 59, 999_999_999).toInstant(ZoneOffset.UTC), "-0001-12-31T23:59:59.999999999Z"},
{LocalDateTime.of(-1, 12, 31, 12, 30).toInstant(ZoneOffset.UTC), "-0001-12-31T12:30Z"}, {LocalDateTime.of(-1, 12, 31, 12, 30).toInstant(ZoneOffset.UTC), "-0001-12-31T12:30:00Z"},
{LocalDateTime.of(-1, 12, 30, 12, 30).toInstant(ZoneOffset.UTC), "-0001-12-30T12:30Z"}, {LocalDateTime.of(-1, 12, 30, 12, 30).toInstant(ZoneOffset.UTC), "-0001-12-30T12:30:00Z"},
{LocalDateTime.of(-9999, 1, 2, 12, 30).toInstant(ZoneOffset.UTC), "-9999-01-02T12:30Z"}, {LocalDateTime.of(-9999, 1, 2, 12, 30).toInstant(ZoneOffset.UTC), "-9999-01-02T12:30:00Z"},
{LocalDateTime.of(-9999, 1, 1, 12, 30).toInstant(ZoneOffset.UTC), "-9999-01-01T12:30Z"}, {LocalDateTime.of(-9999, 1, 1, 12, 30).toInstant(ZoneOffset.UTC), "-9999-01-01T12:30:00Z"},
{LocalDateTime.of(-9999, 1, 1, 0, 0).toInstant(ZoneOffset.UTC), "-9999-01-01T00:00Z"}, {LocalDateTime.of(-9999, 1, 1, 0, 0).toInstant(ZoneOffset.UTC), "-9999-01-01T00:00:00Z"},
{LocalDateTime.of(-10000, 12, 31, 23, 59, 59, 999_999_999).toInstant(ZoneOffset.UTC), "-10000-12-31T23:59:59.999999999Z"}, {LocalDateTime.of(-10000, 12, 31, 23, 59, 59, 999_999_999).toInstant(ZoneOffset.UTC), "-10000-12-31T23:59:59.999999999Z"},
{LocalDateTime.of(-10000, 12, 31, 12, 30).toInstant(ZoneOffset.UTC), "-10000-12-31T12:30Z"}, {LocalDateTime.of(-10000, 12, 31, 12, 30).toInstant(ZoneOffset.UTC), "-10000-12-31T12:30:00Z"},
{LocalDateTime.of(-10000, 12, 30, 12, 30).toInstant(ZoneOffset.UTC), "-10000-12-30T12:30Z"}, {LocalDateTime.of(-10000, 12, 30, 12, 30).toInstant(ZoneOffset.UTC), "-10000-12-30T12:30:00Z"},
{LocalDateTime.of(-15000, 12, 31, 12, 30).toInstant(ZoneOffset.UTC), "-15000-12-31T12:30Z"}, {LocalDateTime.of(-15000, 12, 31, 12, 30).toInstant(ZoneOffset.UTC), "-15000-12-31T12:30:00Z"},
{LocalDateTime.of(-19999, 1, 2, 12, 30).toInstant(ZoneOffset.UTC), "-19999-01-02T12:30Z"}, {LocalDateTime.of(-19999, 1, 2, 12, 30).toInstant(ZoneOffset.UTC), "-19999-01-02T12:30:00Z"},
{LocalDateTime.of(-19999, 1, 1, 12, 30).toInstant(ZoneOffset.UTC), "-19999-01-01T12:30Z"}, {LocalDateTime.of(-19999, 1, 1, 12, 30).toInstant(ZoneOffset.UTC), "-19999-01-01T12:30:00Z"},
{LocalDateTime.of(-19999, 1, 1, 0, 0).toInstant(ZoneOffset.UTC), "-19999-01-01T00:00Z"}, {LocalDateTime.of(-19999, 1, 1, 0, 0).toInstant(ZoneOffset.UTC), "-19999-01-01T00:00:00Z"},
{LocalDateTime.of(-20000, 12, 31, 23, 59, 59, 999_999_999).toInstant(ZoneOffset.UTC), "-20000-12-31T23:59:59.999999999Z"}, {LocalDateTime.of(-20000, 12, 31, 23, 59, 59, 999_999_999).toInstant(ZoneOffset.UTC), "-20000-12-31T23:59:59.999999999Z"},
{LocalDateTime.of(-20000, 12, 31, 12, 30).toInstant(ZoneOffset.UTC), "-20000-12-31T12:30Z"}, {LocalDateTime.of(-20000, 12, 31, 12, 30).toInstant(ZoneOffset.UTC), "-20000-12-31T12:30:00Z"},
{LocalDateTime.of(-20000, 12, 30, 12, 30).toInstant(ZoneOffset.UTC), "-20000-12-30T12:30Z"}, {LocalDateTime.of(-20000, 12, 30, 12, 30).toInstant(ZoneOffset.UTC), "-20000-12-30T12:30:00Z"},
{LocalDateTime.of(-25000, 12, 31, 12, 30).toInstant(ZoneOffset.UTC), "-25000-12-31T12:30Z"}, {LocalDateTime.of(-25000, 12, 31, 12, 30).toInstant(ZoneOffset.UTC), "-25000-12-31T12:30:00Z"},
{LocalDateTime.of(9999, 12, 30, 12, 30).toInstant(ZoneOffset.UTC), "9999-12-30T12:30Z"}, {LocalDateTime.of(9999, 12, 30, 12, 30).toInstant(ZoneOffset.UTC), "9999-12-30T12:30:00Z"},
{LocalDateTime.of(9999, 12, 31, 12, 30).toInstant(ZoneOffset.UTC), "9999-12-31T12:30Z"}, {LocalDateTime.of(9999, 12, 31, 12, 30).toInstant(ZoneOffset.UTC), "9999-12-31T12:30:00Z"},
{LocalDateTime.of(9999, 12, 31, 23, 59, 59, 999_999_999).toInstant(ZoneOffset.UTC), "9999-12-31T23:59:59.999999999Z"}, {LocalDateTime.of(9999, 12, 31, 23, 59, 59, 999_999_999).toInstant(ZoneOffset.UTC), "9999-12-31T23:59:59.999999999Z"},
{LocalDateTime.of(10000, 1, 1, 0, 0).toInstant(ZoneOffset.UTC), "+10000-01-01T00:00Z"}, {LocalDateTime.of(10000, 1, 1, 0, 0).toInstant(ZoneOffset.UTC), "+10000-01-01T00:00:00Z"},
{LocalDateTime.of(10000, 1, 1, 12, 30).toInstant(ZoneOffset.UTC), "+10000-01-01T12:30Z"}, {LocalDateTime.of(10000, 1, 1, 12, 30).toInstant(ZoneOffset.UTC), "+10000-01-01T12:30:00Z"},
{LocalDateTime.of(10000, 1, 2, 12, 30).toInstant(ZoneOffset.UTC), "+10000-01-02T12:30Z"}, {LocalDateTime.of(10000, 1, 2, 12, 30).toInstant(ZoneOffset.UTC), "+10000-01-02T12:30:00Z"},
{LocalDateTime.of(15000, 12, 31, 12, 30).toInstant(ZoneOffset.UTC), "+15000-12-31T12:30Z"}, {LocalDateTime.of(15000, 12, 31, 12, 30).toInstant(ZoneOffset.UTC), "+15000-12-31T12:30:00Z"},
{LocalDateTime.of(19999, 12, 30, 12, 30).toInstant(ZoneOffset.UTC), "+19999-12-30T12:30Z"}, {LocalDateTime.of(19999, 12, 30, 12, 30).toInstant(ZoneOffset.UTC), "+19999-12-30T12:30:00Z"},
{LocalDateTime.of(19999, 12, 31, 12, 30).toInstant(ZoneOffset.UTC), "+19999-12-31T12:30Z"}, {LocalDateTime.of(19999, 12, 31, 12, 30).toInstant(ZoneOffset.UTC), "+19999-12-31T12:30:00Z"},
{LocalDateTime.of(19999, 12, 31, 23, 59, 59, 999_999_999).toInstant(ZoneOffset.UTC), "+19999-12-31T23:59:59.999999999Z"}, {LocalDateTime.of(19999, 12, 31, 23, 59, 59, 999_999_999).toInstant(ZoneOffset.UTC), "+19999-12-31T23:59:59.999999999Z"},
{LocalDateTime.of(20000, 1, 1, 0, 0).toInstant(ZoneOffset.UTC), "+20000-01-01T00:00Z"}, {LocalDateTime.of(20000, 1, 1, 0, 0).toInstant(ZoneOffset.UTC), "+20000-01-01T00:00:00Z"},
{LocalDateTime.of(20000, 1, 1, 12, 30).toInstant(ZoneOffset.UTC), "+20000-01-01T12:30Z"}, {LocalDateTime.of(20000, 1, 1, 12, 30).toInstant(ZoneOffset.UTC), "+20000-01-01T12:30:00Z"},
{LocalDateTime.of(20000, 1, 2, 12, 30).toInstant(ZoneOffset.UTC), "+20000-01-02T12:30Z"}, {LocalDateTime.of(20000, 1, 2, 12, 30).toInstant(ZoneOffset.UTC), "+20000-01-02T12:30:00Z"},
{LocalDateTime.of(25000, 12, 31, 12, 30).toInstant(ZoneOffset.UTC), "+25000-12-31T12:30Z"}, {LocalDateTime.of(25000, 12, 31, 12, 30).toInstant(ZoneOffset.UTC), "+25000-12-31T12:30:00Z"},
{LocalDateTime.of(-999_999_999, 1, 1, 12, 30).toInstant(ZoneOffset.UTC).minus(1, DAYS), "-1000000000-12-31T12:30Z"}, {LocalDateTime.of(-999_999_999, 1, 1, 12, 30).toInstant(ZoneOffset.UTC).minus(1, DAYS), "-1000000000-12-31T12:30:00Z"},
{LocalDateTime.of(999_999_999, 12, 31, 12, 30).toInstant(ZoneOffset.UTC).plus(1, DAYS), "+1000000000-01-01T12:30Z"}, {LocalDateTime.of(999_999_999, 12, 31, 12, 30).toInstant(ZoneOffset.UTC).plus(1, DAYS), "+1000000000-01-01T12:30:00Z"},
{Instant.MIN, "-1000000000-01-01T00:00Z"}, {Instant.MIN, "-1000000000-01-01T00:00:00Z"},
{Instant.MAX, "+1000000000-12-31T23:59:59.999999999Z"}, {Instant.MAX, "+1000000000-12-31T23:59:59.999999999Z"},
}; };
} }
......
...@@ -142,7 +142,7 @@ public class TCKLocalTime extends AbstractDateTimeTest { ...@@ -142,7 +142,7 @@ public class TCKLocalTime extends AbstractDateTimeTest {
private static final TemporalUnit[] INVALID_UNITS; private static final TemporalUnit[] INVALID_UNITS;
static { static {
EnumSet<ChronoUnit> set = EnumSet.range(WEEKS, FOREVER); EnumSet<ChronoUnit> set = EnumSet.range(DAYS, FOREVER);
INVALID_UNITS = (TemporalUnit[]) set.toArray(new TemporalUnit[set.size()]); INVALID_UNITS = (TemporalUnit[]) set.toArray(new TemporalUnit[set.size()]);
} }
...@@ -1122,14 +1122,6 @@ public class TCKLocalTime extends AbstractDateTimeTest { ...@@ -1122,14 +1122,6 @@ public class TCKLocalTime extends AbstractDateTimeTest {
} }
} }
@Test
public void test_plus_longTemporalUnit_multiples() {
assertEquals(TEST_12_30_40_987654321.plus(0, DAYS), TEST_12_30_40_987654321);
assertEquals(TEST_12_30_40_987654321.plus(1, DAYS), TEST_12_30_40_987654321);
assertEquals(TEST_12_30_40_987654321.plus(2, DAYS), TEST_12_30_40_987654321);
assertEquals(TEST_12_30_40_987654321.plus(-3, DAYS), TEST_12_30_40_987654321);
}
@Test(expectedExceptions=NullPointerException.class) @Test(expectedExceptions=NullPointerException.class)
public void test_plus_longTemporalUnit_null() { public void test_plus_longTemporalUnit_null() {
TEST_12_30_40_987654321.plus(1, (TemporalUnit) null); TEST_12_30_40_987654321.plus(1, (TemporalUnit) null);
...@@ -1556,14 +1548,6 @@ public class TCKLocalTime extends AbstractDateTimeTest { ...@@ -1556,14 +1548,6 @@ public class TCKLocalTime extends AbstractDateTimeTest {
} }
} }
@Test
public void test_minus_longTemporalUnit_long_multiples() {
assertEquals(TEST_12_30_40_987654321.minus(0, DAYS), TEST_12_30_40_987654321);
assertEquals(TEST_12_30_40_987654321.minus(1, DAYS), TEST_12_30_40_987654321);
assertEquals(TEST_12_30_40_987654321.minus(2, DAYS), TEST_12_30_40_987654321);
assertEquals(TEST_12_30_40_987654321.minus(-3, DAYS), TEST_12_30_40_987654321);
}
@Test(expectedExceptions=NullPointerException.class) @Test(expectedExceptions=NullPointerException.class)
public void test_minus_longTemporalUnit_null() { public void test_minus_longTemporalUnit_null() {
TEST_12_30_40_987654321.minus(1, (TemporalUnit) null); TEST_12_30_40_987654321.minus(1, (TemporalUnit) null);
......
...@@ -75,7 +75,13 @@ import static java.time.temporal.ChronoField.NANO_OF_SECOND; ...@@ -75,7 +75,13 @@ import static java.time.temporal.ChronoField.NANO_OF_SECOND;
import static java.time.temporal.ChronoField.OFFSET_SECONDS; import static java.time.temporal.ChronoField.OFFSET_SECONDS;
import static java.time.temporal.ChronoField.SECOND_OF_DAY; import static java.time.temporal.ChronoField.SECOND_OF_DAY;
import static java.time.temporal.ChronoField.SECOND_OF_MINUTE; import static java.time.temporal.ChronoField.SECOND_OF_MINUTE;
import static java.time.temporal.ChronoUnit.MONTHS;
import static java.time.temporal.ChronoUnit.DAYS; import static java.time.temporal.ChronoUnit.DAYS;
import static java.time.temporal.ChronoUnit.HOURS;
import static java.time.temporal.ChronoUnit.MINUTES;
import static java.time.temporal.ChronoUnit.MICROS;
import static java.time.temporal.ChronoUnit.MILLIS;
import static java.time.temporal.ChronoUnit.HALF_DAYS;
import static java.time.temporal.ChronoUnit.NANOS; import static java.time.temporal.ChronoUnit.NANOS;
import static java.time.temporal.ChronoUnit.SECONDS; import static java.time.temporal.ChronoUnit.SECONDS;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
...@@ -110,6 +116,7 @@ import java.time.temporal.TemporalAdjuster; ...@@ -110,6 +116,7 @@ import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalAmount; import java.time.temporal.TemporalAmount;
import java.time.temporal.TemporalField; import java.time.temporal.TemporalField;
import java.time.temporal.TemporalQuery; import java.time.temporal.TemporalQuery;
import java.time.temporal.TemporalUnit;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
...@@ -1030,6 +1037,56 @@ public class TCKOffsetTime extends AbstractDateTimeTest { ...@@ -1030,6 +1037,56 @@ public class TCKOffsetTime extends AbstractDateTimeTest {
assertEquals(test, base); assertEquals(test, base);
} }
//-----------------------------------------------------------------------
// periodUntil(Temporal, TemporalUnit)
//-----------------------------------------------------------------------
@DataProvider(name="periodUntilUnit")
Object[][] data_periodUntilUnit() {
return new Object[][] {
{OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(13, 1, 1), ZoneOffset.ofHours(1)), HALF_DAYS, 1},
{OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(2, 1, 1), ZoneOffset.ofHours(1)), HOURS, 1},
{OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(2, 1, 1), ZoneOffset.ofHours(1)), MINUTES, 60},
{OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(2, 1, 1), ZoneOffset.ofHours(1)), SECONDS, 3600},
{OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(2, 1, 1), ZoneOffset.ofHours(1)), MILLIS, 3600*1000},
{OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(2, 1, 1), ZoneOffset.ofHours(1)), MICROS, 3600*1000*1000L},
{OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(2, 1, 1), ZoneOffset.ofHours(1)), NANOS, 3600*1000*1000L*1000},
{OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(14, 1, 1), ZoneOffset.ofHours(2)), HALF_DAYS, 1},
{OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(3, 1, 1), ZoneOffset.ofHours(2)), HOURS, 1},
{OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(3, 1, 1), ZoneOffset.ofHours(2)), MINUTES, 60},
{OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(3, 1, 1), ZoneOffset.ofHours(2)), SECONDS, 3600},
{OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(3, 1, 1), ZoneOffset.ofHours(2)), MILLIS, 3600*1000},
{OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(3, 1, 1), ZoneOffset.ofHours(2)), MICROS, 3600*1000*1000L},
{OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1)), OffsetTime.of(LocalTime.of(3, 1, 1), ZoneOffset.ofHours(2)), NANOS, 3600*1000*1000L*1000},
};
}
@Test(dataProvider="periodUntilUnit")
public void test_periodUntil_TemporalUnit(OffsetTime offsetTime1, OffsetTime offsetTime2, TemporalUnit unit, long expected) {
long amount = offsetTime1.periodUntil(offsetTime2, unit);
assertEquals(amount, expected);
}
@Test(dataProvider="periodUntilUnit")
public void test_periodUntil_TemporalUnit_negated(OffsetTime offsetTime1, OffsetTime offsetTime2, TemporalUnit unit, long expected) {
long amount = offsetTime2.periodUntil(offsetTime1, unit);
assertEquals(amount, -expected);
}
@Test(expectedExceptions=DateTimeException.class)
public void test_periodUntil_InvalidType() {
OffsetTime offsetTime = OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1));
OffsetDateTime offsetDateTime = offsetTime.atDate(LocalDate.of(1980, 2, 10));
offsetTime.periodUntil(offsetDateTime, SECONDS);
}
@Test(expectedExceptions=DateTimeException.class)
public void test_periodUntil_InvalidTemporalUnit() {
OffsetTime offsetTime1 = OffsetTime.of(LocalTime.of(1, 1, 1), ZoneOffset.ofHours(1));
OffsetTime offsetTime2 = OffsetTime.of(LocalTime.of(2, 1, 1), ZoneOffset.ofHours(1));
offsetTime1.periodUntil(offsetTime2, MONTHS);
}
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
// format(DateTimeFormatter) // format(DateTimeFormatter)
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
......
...@@ -71,6 +71,7 @@ import static java.time.temporal.ChronoUnit.MONTHS; ...@@ -71,6 +71,7 @@ import static java.time.temporal.ChronoUnit.MONTHS;
import static java.time.temporal.ChronoUnit.WEEKS; import static java.time.temporal.ChronoUnit.WEEKS;
import static java.time.temporal.ChronoUnit.YEARS; import static java.time.temporal.ChronoUnit.YEARS;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail; import static org.testng.Assert.fail;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
...@@ -89,6 +90,7 @@ import java.time.Year; ...@@ -89,6 +90,7 @@ import java.time.Year;
import java.time.YearMonth; import java.time.YearMonth;
import java.time.ZoneId; import java.time.ZoneId;
import java.time.ZoneOffset; import java.time.ZoneOffset;
import java.time.chrono.IsoEra;
import java.time.chrono.IsoChronology; import java.time.chrono.IsoChronology;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException; import java.time.format.DateTimeParseException;
...@@ -525,6 +527,47 @@ public class TCKYear extends AbstractDateTimeTest { ...@@ -525,6 +527,47 @@ public class TCKYear extends AbstractDateTimeTest {
Year.of(Year.MIN_VALUE).plusYears(-1000); Year.of(Year.MIN_VALUE).plusYears(-1000);
} }
//-----------------------------------------------------------------------
// plus(long, TemporalUnit)
//-----------------------------------------------------------------------
@DataProvider(name="plus_long_TemporalUnit")
Object[][] data_plus_long_TemporalUnit() {
return new Object[][] {
{Year.of(1), 1, ChronoUnit.YEARS, Year.of(2), null},
{Year.of(1), -12, ChronoUnit.YEARS, Year.of(-11), null},
{Year.of(1), 0, ChronoUnit.YEARS, Year.of(1), null},
{Year.of(999999999), 0, ChronoUnit.YEARS, Year.of(999999999), null},
{Year.of(-999999999), 0, ChronoUnit.YEARS, Year.of(-999999999), null},
{Year.of(0), -999999999, ChronoUnit.YEARS, Year.of(-999999999), null},
{Year.of(0), 999999999, ChronoUnit.YEARS, Year.of(999999999), null},
{Year.of(-1), 1, ChronoUnit.ERAS, Year.of(2), null},
{Year.of(5), 1, ChronoUnit.CENTURIES, Year.of(105), null},
{Year.of(5), 1, ChronoUnit.DECADES, Year.of(15), null},
{Year.of(999999999), 1, ChronoUnit.YEARS, null, DateTimeException.class},
{Year.of(-999999999), -1, ChronoUnit.YEARS, null, DateTimeException.class},
{Year.of(1), 0, ChronoUnit.DAYS, null, DateTimeException.class},
{Year.of(1), 0, ChronoUnit.WEEKS, null, DateTimeException.class},
{Year.of(1), 0, ChronoUnit.MONTHS, null, DateTimeException.class},
};
}
@Test(groups={"tck"}, dataProvider="plus_long_TemporalUnit")
public void test_plus_long_TemporalUnit(Year base, long amount, TemporalUnit unit, Year expectedYear, Class expectedEx) {
if (expectedEx == null) {
assertEquals(base.plus(amount, unit), expectedYear);
} else {
try {
Year result = base.plus(amount, unit);
fail();
} catch (Exception ex) {
assertTrue(expectedEx.isInstance(ex));
}
}
}
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
// minus(Period) // minus(Period)
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
...@@ -616,6 +659,47 @@ public class TCKYear extends AbstractDateTimeTest { ...@@ -616,6 +659,47 @@ public class TCKYear extends AbstractDateTimeTest {
Year.of(Year.MIN_VALUE).minusYears(1000); Year.of(Year.MIN_VALUE).minusYears(1000);
} }
//-----------------------------------------------------------------------
// minus(long, TemporalUnit)
//-----------------------------------------------------------------------
@DataProvider(name="minus_long_TemporalUnit")
Object[][] data_minus_long_TemporalUnit() {
return new Object[][] {
{Year.of(1), 1, ChronoUnit.YEARS, Year.of(0), null},
{Year.of(1), -12, ChronoUnit.YEARS, Year.of(13), null},
{Year.of(1), 0, ChronoUnit.YEARS, Year.of(1), null},
{Year.of(999999999), 0, ChronoUnit.YEARS, Year.of(999999999), null},
{Year.of(-999999999), 0, ChronoUnit.YEARS, Year.of(-999999999), null},
{Year.of(0), -999999999, ChronoUnit.YEARS, Year.of(999999999), null},
{Year.of(0), 999999999, ChronoUnit.YEARS, Year.of(-999999999), null},
{Year.of(999999999), 1, ChronoUnit.ERAS, Year.of(-999999999 + 1), null},
{Year.of(105), 1, ChronoUnit.CENTURIES, Year.of(5), null},
{Year.of(15), 1, ChronoUnit.DECADES, Year.of(5), null},
{Year.of(-999999999), 1, ChronoUnit.YEARS, null, DateTimeException.class},
{Year.of(1), -999999999, ChronoUnit.YEARS, null, DateTimeException.class},
{Year.of(1), 0, ChronoUnit.DAYS, null, DateTimeException.class},
{Year.of(1), 0, ChronoUnit.WEEKS, null, DateTimeException.class},
{Year.of(1), 0, ChronoUnit.MONTHS, null, DateTimeException.class},
};
}
@Test(groups={"tck"}, dataProvider="minus_long_TemporalUnit")
public void test_minus_long_TemporalUnit(Year base, long amount, TemporalUnit unit, Year expectedYear, Class expectedEx) {
if (expectedEx == null) {
assertEquals(base.minus(amount, unit), expectedYear);
} else {
try {
Year result = base.minus(amount, unit);
fail();
} catch (Exception ex) {
assertTrue(expectedEx.isInstance(ex));
}
}
}
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
// adjustInto() // adjustInto()
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
...@@ -640,6 +724,49 @@ public class TCKYear extends AbstractDateTimeTest { ...@@ -640,6 +724,49 @@ public class TCKYear extends AbstractDateTimeTest {
test.adjustInto((LocalDate) null); test.adjustInto((LocalDate) null);
} }
//-----------------------------------------------------------------------
// with(TemporalAdjuster)
//-----------------------------------------------------------------------
@Test
public void test_with_TemporalAdjuster() {
Year base = Year.of(-10);
for (int i = -4; i <= 2104; i++) {
Temporal result = base.with(Year.of(i));
assertEquals(result, Year.of(i));
}
}
@Test(expectedExceptions=DateTimeException.class)
public void test_with_BadTemporalAdjuster() {
Year test = Year.of(1);
test.with(LocalTime.of(18, 1, 2));
}
//-----------------------------------------------------------------------
// with(TemporalField, long)
//-----------------------------------------------------------------------
@Test(groups={"tck"})
public void test_with() {
Year base = Year.of(5);
Year result = base.with(ChronoField.ERA, 0);
assertEquals(result, base.with(IsoEra.of(0)));
int prolepticYear = IsoChronology.INSTANCE.prolepticYear(IsoEra.of(0), 5);
assertEquals(result.get(ChronoField.ERA), 0);
assertEquals(result.get(ChronoField.YEAR), prolepticYear);
assertEquals(result.get(ChronoField.YEAR_OF_ERA), 5);
result = base.with(ChronoField.YEAR, 10);
assertEquals(result.get(ChronoField.ERA), base.get(ChronoField.ERA));
assertEquals(result.get(ChronoField.YEAR), 10);
assertEquals(result.get(ChronoField.YEAR_OF_ERA), 10);
result = base.with(ChronoField.YEAR_OF_ERA, 20);
assertEquals(result.get(ChronoField.ERA), base.get(ChronoField.ERA));
assertEquals(result.get(ChronoField.YEAR), 20);
assertEquals(result.get(ChronoField.YEAR_OF_ERA), 20);
}
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
// length() // length()
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
......
...@@ -81,6 +81,7 @@ import java.io.DataOutputStream; ...@@ -81,6 +81,7 @@ import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.time.Clock; import java.time.Clock;
import java.time.DateTimeException; import java.time.DateTimeException;
import java.time.Duration;
import java.time.Instant; import java.time.Instant;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
...@@ -98,6 +99,7 @@ import java.time.temporal.ChronoField; ...@@ -98,6 +99,7 @@ import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.time.temporal.JulianFields; import java.time.temporal.JulianFields;
import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAmount;
import java.time.temporal.TemporalField; import java.time.temporal.TemporalField;
import java.time.temporal.TemporalQuery; import java.time.temporal.TemporalQuery;
import java.time.temporal.TemporalUnit; import java.time.temporal.TemporalUnit;
...@@ -688,6 +690,106 @@ public class TCKYearMonth extends AbstractDateTimeTest { ...@@ -688,6 +690,106 @@ public class TCKYearMonth extends AbstractDateTimeTest {
test.plusMonths(-1); test.plusMonths(-1);
} }
//-----------------------------------------------------------------------
// plus(long, TemporalUnit)
//-----------------------------------------------------------------------
@DataProvider(name="plus_long_TemporalUnit")
Object[][] data_plus_long_TemporalUnit() {
return new Object[][] {
{YearMonth.of(1, 10), 1, ChronoUnit.YEARS, YearMonth.of(2, 10), null},
{YearMonth.of(1, 10), -12, ChronoUnit.YEARS, YearMonth.of(-11, 10), null},
{YearMonth.of(1, 10), 0, ChronoUnit.YEARS, YearMonth.of(1, 10), null},
{YearMonth.of(999999999, 12), 0, ChronoUnit.YEARS, YearMonth.of(999999999, 12), null},
{YearMonth.of(-999999999, 1), 0, ChronoUnit.YEARS, YearMonth.of(-999999999, 1), null},
{YearMonth.of(0, 1), -999999999, ChronoUnit.YEARS, YearMonth.of(-999999999, 1), null},
{YearMonth.of(0, 12), 999999999, ChronoUnit.YEARS, YearMonth.of(999999999, 12), null},
{YearMonth.of(1, 10), 1, ChronoUnit.MONTHS, YearMonth.of(1, 11), null},
{YearMonth.of(1, 10), -12, ChronoUnit.MONTHS, YearMonth.of(0, 10), null},
{YearMonth.of(1, 10), 0, ChronoUnit.MONTHS, YearMonth.of(1, 10), null},
{YearMonth.of(999999999, 12), 0, ChronoUnit.MONTHS, YearMonth.of(999999999, 12), null},
{YearMonth.of(-999999999, 1), 0, ChronoUnit.MONTHS, YearMonth.of(-999999999, 1), null},
{YearMonth.of(-999999999, 2), -1, ChronoUnit.MONTHS, YearMonth.of(-999999999, 1), null},
{YearMonth.of(999999999, 3), 9, ChronoUnit.MONTHS, YearMonth.of(999999999, 12), null},
{YearMonth.of(-1, 10), 1, ChronoUnit.ERAS, YearMonth.of(2, 10), null},
{YearMonth.of(5, 10), 1, ChronoUnit.CENTURIES, YearMonth.of(105, 10), null},
{YearMonth.of(5, 10), 1, ChronoUnit.DECADES, YearMonth.of(15, 10), null},
{YearMonth.of(999999999, 12), 1, ChronoUnit.MONTHS, null, DateTimeException.class},
{YearMonth.of(-999999999, 1), -1, ChronoUnit.MONTHS, null, DateTimeException.class},
{YearMonth.of(1, 1), 0, ChronoUnit.DAYS, null, DateTimeException.class},
{YearMonth.of(1, 1), 0, ChronoUnit.WEEKS, null, DateTimeException.class},
};
}
@Test(groups={"tck"}, dataProvider="plus_long_TemporalUnit")
public void test_plus_long_TemporalUnit(YearMonth base, long amount, TemporalUnit unit, YearMonth expectedYearMonth, Class expectedEx) {
if (expectedEx == null) {
assertEquals(base.plus(amount, unit), expectedYearMonth);
} else {
try {
YearMonth result = base.plus(amount, unit);
fail();
} catch (Exception ex) {
assertTrue(expectedEx.isInstance(ex));
}
}
}
//-----------------------------------------------------------------------
// plus(TemporalAmount)
//-----------------------------------------------------------------------
@DataProvider(name="plus_TemporalAmount")
Object[][] data_plus_TemporalAmount() {
return new Object[][] {
{YearMonth.of(1, 1), Period.ofYears(1), YearMonth.of(2, 1), null},
{YearMonth.of(1, 1), Period.ofYears(-12), YearMonth.of(-11, 1), null},
{YearMonth.of(1, 1), Period.ofYears(0), YearMonth.of(1, 1), null},
{YearMonth.of(999999999, 12), Period.ofYears(0), YearMonth.of(999999999, 12), null},
{YearMonth.of(-999999999, 1), Period.ofYears(0), YearMonth.of(-999999999, 1), null},
{YearMonth.of(0, 1), Period.ofYears(-999999999), YearMonth.of(-999999999, 1), null},
{YearMonth.of(0, 12), Period.ofYears(999999999), YearMonth.of(999999999, 12), null},
{YearMonth.of(1, 1), Period.ofMonths(1), YearMonth.of(1, 2), null},
{YearMonth.of(1, 1), Period.ofMonths(-12), YearMonth.of(0, 1), null},
{YearMonth.of(1, 1), Period.ofMonths(121), YearMonth.of(11, 2), null},
{YearMonth.of(1, 1), Period.ofMonths(0), YearMonth.of(1, 1), null},
{YearMonth.of(999999999, 12), Period.ofMonths(0), YearMonth.of(999999999, 12), null},
{YearMonth.of(-999999999, 1), Period.ofMonths(0), YearMonth.of(-999999999, 1), null},
{YearMonth.of(-999999999, 2), Period.ofMonths(-1), YearMonth.of(-999999999, 1), null},
{YearMonth.of(999999999, 11), Period.ofMonths(1), YearMonth.of(999999999, 12), null},
{YearMonth.of(1, 1), Period.ofYears(1).withMonths(2), YearMonth.of(2, 3), null},
{YearMonth.of(1, 1), Period.ofYears(-12).withMonths(-1), YearMonth.of(-12, 12), null},
{YearMonth.of(1, 1), Period.ofMonths(2).withYears(1), YearMonth.of(2, 3), null},
{YearMonth.of(1, 1), Period.ofMonths(-1).withYears(-12), YearMonth.of(-12, 12), null},
{YearMonth.of(1, 1), Period.ofDays(365), null, DateTimeException.class},
{YearMonth.of(1, 1), Duration.ofDays(365), null, DateTimeException.class},
{YearMonth.of(1, 1), Duration.ofHours(365*24), null, DateTimeException.class},
{YearMonth.of(1, 1), Duration.ofMinutes(365*24*60), null, DateTimeException.class},
{YearMonth.of(1, 1), Duration.ofSeconds(365*24*3600), null, DateTimeException.class},
{YearMonth.of(1, 1), Duration.ofNanos(365*24*3600*1000000000), null, DateTimeException.class},
};
}
@Test(groups={"tck"}, dataProvider="plus_TemporalAmount")
public void test_plus_TemporalAmount(YearMonth base, TemporalAmount temporalAmount, YearMonth expectedYearMonth, Class expectedEx) {
if (expectedEx == null) {
assertEquals(base.plus(temporalAmount), expectedYearMonth);
} else {
try {
YearMonth result = base.plus(temporalAmount);
fail();
} catch (Exception ex) {
assertTrue(expectedEx.isInstance(ex));
}
}
}
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
// minusYears() // minusYears()
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
...@@ -803,6 +905,106 @@ public class TCKYearMonth extends AbstractDateTimeTest { ...@@ -803,6 +905,106 @@ public class TCKYearMonth extends AbstractDateTimeTest {
test.minusMonths(1); test.minusMonths(1);
} }
//-----------------------------------------------------------------------
// minus(long, TemporalUnit)
//-----------------------------------------------------------------------
@DataProvider(name="minus_long_TemporalUnit")
Object[][] data_minus_long_TemporalUnit() {
return new Object[][] {
{YearMonth.of(1, 10), 1, ChronoUnit.YEARS, YearMonth.of(0, 10), null},
{YearMonth.of(1, 10), 12, ChronoUnit.YEARS, YearMonth.of(-11, 10), null},
{YearMonth.of(1, 10), 0, ChronoUnit.YEARS, YearMonth.of(1, 10), null},
{YearMonth.of(999999999, 12), 0, ChronoUnit.YEARS, YearMonth.of(999999999, 12), null},
{YearMonth.of(-999999999, 1), 0, ChronoUnit.YEARS, YearMonth.of(-999999999, 1), null},
{YearMonth.of(0, 1), 999999999, ChronoUnit.YEARS, YearMonth.of(-999999999, 1), null},
{YearMonth.of(0, 12), -999999999, ChronoUnit.YEARS, YearMonth.of(999999999, 12), null},
{YearMonth.of(1, 10), 1, ChronoUnit.MONTHS, YearMonth.of(1, 9), null},
{YearMonth.of(1, 10), 12, ChronoUnit.MONTHS, YearMonth.of(0, 10), null},
{YearMonth.of(1, 10), 0, ChronoUnit.MONTHS, YearMonth.of(1, 10), null},
{YearMonth.of(999999999, 12), 0, ChronoUnit.MONTHS, YearMonth.of(999999999, 12), null},
{YearMonth.of(-999999999, 1), 0, ChronoUnit.MONTHS, YearMonth.of(-999999999, 1), null},
{YearMonth.of(-999999999, 2), 1, ChronoUnit.MONTHS, YearMonth.of(-999999999, 1), null},
{YearMonth.of(999999999, 11), -1, ChronoUnit.MONTHS, YearMonth.of(999999999, 12), null},
{YearMonth.of(1, 10), 1, ChronoUnit.ERAS, YearMonth.of(0, 10), null},
{YearMonth.of(5, 10), 1, ChronoUnit.CENTURIES, YearMonth.of(-95, 10), null},
{YearMonth.of(5, 10), 1, ChronoUnit.DECADES, YearMonth.of(-5, 10), null},
{YearMonth.of(999999999, 12), -1, ChronoUnit.MONTHS, null, DateTimeException.class},
{YearMonth.of(-999999999, 1), 1, ChronoUnit.MONTHS, null, DateTimeException.class},
{YearMonth.of(1, 1), 0, ChronoUnit.DAYS, null, DateTimeException.class},
{YearMonth.of(1, 1), 0, ChronoUnit.WEEKS, null, DateTimeException.class},
};
}
@Test(groups={"tck"}, dataProvider="minus_long_TemporalUnit")
public void test_minus_long_TemporalUnit(YearMonth base, long amount, TemporalUnit unit, YearMonth expectedYearMonth, Class expectedEx) {
if (expectedEx == null) {
assertEquals(base.minus(amount, unit), expectedYearMonth);
} else {
try {
YearMonth result = base.minus(amount, unit);
fail();
} catch (Exception ex) {
assertTrue(expectedEx.isInstance(ex));
}
}
}
//-----------------------------------------------------------------------
// minus(TemporalAmount)
//-----------------------------------------------------------------------
@DataProvider(name="minus_TemporalAmount")
Object[][] data_minus_TemporalAmount() {
return new Object[][] {
{YearMonth.of(1, 1), Period.ofYears(1), YearMonth.of(0, 1), null},
{YearMonth.of(1, 1), Period.ofYears(-12), YearMonth.of(13, 1), null},
{YearMonth.of(1, 1), Period.ofYears(0), YearMonth.of(1, 1), null},
{YearMonth.of(999999999, 12), Period.ofYears(0), YearMonth.of(999999999, 12), null},
{YearMonth.of(-999999999, 1), Period.ofYears(0), YearMonth.of(-999999999, 1), null},
{YearMonth.of(0, 1), Period.ofYears(999999999), YearMonth.of(-999999999, 1), null},
{YearMonth.of(0, 12), Period.ofYears(-999999999), YearMonth.of(999999999, 12), null},
{YearMonth.of(1, 1), Period.ofMonths(1), YearMonth.of(0, 12), null},
{YearMonth.of(1, 1), Period.ofMonths(-12), YearMonth.of(2, 1), null},
{YearMonth.of(1, 1), Period.ofMonths(121), YearMonth.of(-10, 12), null},
{YearMonth.of(1, 1), Period.ofMonths(0), YearMonth.of(1, 1), null},
{YearMonth.of(999999999, 12), Period.ofMonths(0), YearMonth.of(999999999, 12), null},
{YearMonth.of(-999999999, 1), Period.ofMonths(0), YearMonth.of(-999999999, 1), null},
{YearMonth.of(-999999999, 2), Period.ofMonths(1), YearMonth.of(-999999999, 1), null},
{YearMonth.of(999999999, 11), Period.ofMonths(-1), YearMonth.of(999999999, 12), null},
{YearMonth.of(1, 1), Period.ofYears(1).withMonths(2), YearMonth.of(-1, 11), null},
{YearMonth.of(1, 1), Period.ofYears(-12).withMonths(-1), YearMonth.of(13, 2), null},
{YearMonth.of(1, 1), Period.ofMonths(2).withYears(1), YearMonth.of(-1, 11), null},
{YearMonth.of(1, 1), Period.ofMonths(-1).withYears(-12), YearMonth.of(13, 2), null},
{YearMonth.of(1, 1), Period.ofDays(365), null, DateTimeException.class},
{YearMonth.of(1, 1), Duration.ofDays(365), null, DateTimeException.class},
{YearMonth.of(1, 1), Duration.ofHours(365*24), null, DateTimeException.class},
{YearMonth.of(1, 1), Duration.ofMinutes(365*24*60), null, DateTimeException.class},
{YearMonth.of(1, 1), Duration.ofSeconds(365*24*3600), null, DateTimeException.class},
{YearMonth.of(1, 1), Duration.ofNanos(365*24*3600*1000000000), null, DateTimeException.class},
};
}
@Test(groups={"tck"}, dataProvider="minus_TemporalAmount")
public void test_minus_TemporalAmount(YearMonth base, TemporalAmount temporalAmount, YearMonth expectedYearMonth, Class expectedEx) {
if (expectedEx == null) {
assertEquals(base.minus(temporalAmount), expectedYearMonth);
} else {
try {
YearMonth result = base.minus(temporalAmount);
fail();
} catch (Exception ex) {
assertTrue(expectedEx.isInstance(ex));
}
}
}
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
// adjustInto() // adjustInto()
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
......
...@@ -73,8 +73,10 @@ import java.time.Instant; ...@@ -73,8 +73,10 @@ import java.time.Instant;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.LocalTime; import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZoneOffset; import java.time.ZoneOffset;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
import java.time.OffsetDateTime;
import java.time.temporal.ChronoField; import java.time.temporal.ChronoField;
import java.time.temporal.JulianFields; import java.time.temporal.JulianFields;
import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalAccessor;
...@@ -619,6 +621,45 @@ public class TCKZoneOffset extends AbstractDateTimeTest { ...@@ -619,6 +621,45 @@ public class TCKZoneOffset extends AbstractDateTimeTest {
assertEquals(offset2.hashCode() == offset2b.hashCode(), true); assertEquals(offset2.hashCode() == offset2b.hashCode(), true);
} }
//-----------------------------------------------------------------------
// adjustInto()
//-----------------------------------------------------------------------
@Test
public void test_adjustInto_ZonedDateTime() {
ZoneOffset base = ZoneOffset.ofHoursMinutesSeconds(1, 1, 1);
for (String zoneId : ZoneId.getAvailableZoneIds()) {
//Do not change offset of ZonedDateTime after adjustInto()
ZonedDateTime zonedDateTime_target = ZonedDateTime.of(LocalDate.of(1909, 2, 2), LocalTime.of(10, 10, 10), ZoneId.of(zoneId));
ZonedDateTime zonedDateTime_result = (ZonedDateTime)(base.adjustInto(zonedDateTime_target));
assertEquals(zonedDateTime_target.getOffset(), zonedDateTime_result.getOffset());
OffsetDateTime offsetDateTime_target = zonedDateTime_target.toOffsetDateTime();
OffsetDateTime offsetDateTime_result = (OffsetDateTime)(base.adjustInto(offsetDateTime_target));
assertEquals(base, offsetDateTime_result.getOffset());
}
}
@Test
public void test_adjustInto_OffsetDateTime() {
ZoneOffset base = ZoneOffset.ofHoursMinutesSeconds(1, 1, 1);
for (int i=-18; i<=18; i++) {
OffsetDateTime offsetDateTime_target = OffsetDateTime.of(LocalDate.of(1909, 2, 2), LocalTime.of(10, 10, 10), ZoneOffset.ofHours(i));
OffsetDateTime offsetDateTime_result = (OffsetDateTime)base.adjustInto(offsetDateTime_target);
assertEquals(base, offsetDateTime_result.getOffset());
//Do not change offset of ZonedDateTime after adjustInto()
ZonedDateTime zonedDateTime_target = offsetDateTime_target.toZonedDateTime();
ZonedDateTime zonedDateTime_result = (ZonedDateTime)(base.adjustInto(zonedDateTime_target));
assertEquals(zonedDateTime_target.getOffset(), zonedDateTime_result.getOffset());
}
}
@Test(expectedExceptions=DateTimeException.class)
public void test_adjustInto_dateOnly() {
ZoneOffset base = ZoneOffset.ofHoursMinutesSeconds(1, 1, 1);
base.adjustInto((LocalDate.of(1909, 2, 2)));
}
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
// toString() // toString()
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
......
...@@ -162,39 +162,30 @@ public class TCKChronology { ...@@ -162,39 +162,30 @@ public class TCKChronology {
@DataProvider(name = "calendarsystemtype") @DataProvider(name = "calendarsystemtype")
Object[][] data_CalendarType() { Object[][] data_CalendarType() {
return new Object[][] { return new Object[][] {
{HijrahChronology.INSTANCE, "islamic", "umalqura"}, {HijrahChronology.INSTANCE, "islamic-umalqura"},
{IsoChronology.INSTANCE, "iso8601", null}, {IsoChronology.INSTANCE, "iso8601"},
{JapaneseChronology.INSTANCE, "japanese", null}, {JapaneseChronology.INSTANCE, "japanese"},
{MinguoChronology.INSTANCE, "roc", null}, {MinguoChronology.INSTANCE, "roc"},
{ThaiBuddhistChronology.INSTANCE, "buddhist", null}, {ThaiBuddhistChronology.INSTANCE, "buddhist"},
}; };
} }
@Test(dataProvider = "calendarsystemtype") @Test(dataProvider = "calendarsystemtype")
public void test_getCalendarType(Chronology chrono, String calendarType, String variant) { public void test_getCalendarType(Chronology chrono, String calendarType) {
String type = calendarType; String type = calendarType;
if (variant != null) {
type += '-';
type += variant;
}
assertEquals(chrono.getCalendarType(), type); assertEquals(chrono.getCalendarType(), type);
} }
@Test(dataProvider = "calendarsystemtype") @Test(dataProvider = "calendarsystemtype")
public void test_lookupLocale(Chronology chrono, String calendarType, String variant) { public void test_lookupLocale(Chronology chrono, String calendarType) {
Locale.Builder builder = new Locale.Builder().setLanguage("en").setRegion("CA"); Locale.Builder builder = new Locale.Builder().setLanguage("en").setRegion("CA");
builder.setUnicodeLocaleKeyword("ca", calendarType); builder.setUnicodeLocaleKeyword("ca", calendarType);
if (variant != null) {
builder.setUnicodeLocaleKeyword("cv", variant);
}
Locale locale = builder.build(); Locale locale = builder.build();
assertEquals(Chronology.ofLocale(locale), chrono); assertEquals(Chronology.ofLocale(locale), chrono);
} }
/** /**
* Test lookup by calendarType of each chronology. * Test lookup by calendarType of each chronology.
* The calendarType is split on "-" to separate the calendar and variant.
* Verify that the calendar can be found by {@link java.time.chrono.Chronology#ofLocale}. * Verify that the calendar can be found by {@link java.time.chrono.Chronology#ofLocale}.
*/ */
@Test @Test
...@@ -202,15 +193,10 @@ public class TCKChronology { ...@@ -202,15 +193,10 @@ public class TCKChronology {
// Test that all available chronologies can be successfully found using ofLocale // Test that all available chronologies can be successfully found using ofLocale
Set<Chronology> chronos = Chronology.getAvailableChronologies(); Set<Chronology> chronos = Chronology.getAvailableChronologies();
for (Chronology chrono : chronos) { for (Chronology chrono : chronos) {
String[] split = chrono.getCalendarType().split("-");
Locale.Builder builder = new Locale.Builder().setLanguage("en").setRegion("CA"); Locale.Builder builder = new Locale.Builder().setLanguage("en").setRegion("CA");
builder.setUnicodeLocaleKeyword("ca", split[0]); builder.setUnicodeLocaleKeyword("ca", chrono.getCalendarType());
if (split.length > 1) {
builder.setUnicodeLocaleKeyword("cv", split[1]);
}
Locale locale = builder.build(); Locale locale = builder.build();
assertEquals(Chronology.ofLocale(locale), chrono, "Lookup by type and variant"); assertEquals(Chronology.ofLocale(locale), chrono, "Lookup by type");
} }
} }
...@@ -218,7 +204,6 @@ public class TCKChronology { ...@@ -218,7 +204,6 @@ public class TCKChronology {
public void test_lookupLocale() { public void test_lookupLocale() {
Locale.Builder builder = new Locale.Builder().setLanguage("en").setRegion("CA"); Locale.Builder builder = new Locale.Builder().setLanguage("en").setRegion("CA");
builder.setUnicodeLocaleKeyword("ca", "xxx"); builder.setUnicodeLocaleKeyword("ca", "xxx");
builder.setUnicodeLocaleKeyword("cv", "yyy");
Locale locale = builder.build(); Locale locale = builder.build();
Chronology.ofLocale(locale); Chronology.ofLocale(locale);
......
...@@ -93,7 +93,6 @@ public class TCKChronologySerialization { ...@@ -93,7 +93,6 @@ public class TCKChronologySerialization {
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
@Test(dataProvider="calendars") @Test(dataProvider="calendars")
public void test_ChronoSerialization(Chronology chrono) throws Exception { public void test_ChronoSerialization(Chronology chrono) throws Exception {
System.out.printf(" ChronoSerialization: %s%n", chrono);
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(baos); ObjectOutputStream out = new ObjectOutputStream(baos);
out.writeObject(chrono); out.writeObject(chrono);
......
...@@ -62,16 +62,20 @@ import static org.testng.Assert.assertFalse; ...@@ -62,16 +62,20 @@ import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue; import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail; import static org.testng.Assert.fail;
import java.time.Clock;
import java.time.DateTimeException; import java.time.DateTimeException;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.Month; import java.time.Month;
import java.time.Period; import java.time.Period;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.chrono.ChronoLocalDate; import java.time.chrono.ChronoLocalDate;
import java.time.chrono.Chronology; import java.time.chrono.Chronology;
import java.time.chrono.Era; import java.time.chrono.Era;
import java.time.chrono.HijrahChronology; import java.time.chrono.HijrahChronology;
import java.time.chrono.HijrahDate; import java.time.chrono.HijrahDate;
import java.time.chrono.HijrahEra;
import java.time.chrono.IsoChronology; import java.time.chrono.IsoChronology;
import java.time.chrono.MinguoChronology; import java.time.chrono.MinguoChronology;
import java.time.chrono.MinguoDate; import java.time.chrono.MinguoDate;
...@@ -119,8 +123,11 @@ public class TCKHijrahChronology { ...@@ -119,8 +123,11 @@ public class TCKHijrahChronology {
//{HijrahChronology.INSTANCE.date(1324, 7, 3), LocalDate.of(1906, 8, 23)}, //{HijrahChronology.INSTANCE.date(1324, 7, 3), LocalDate.of(1906, 8, 23)},
//{HijrahChronology.INSTANCE.date(1324, 7, 4), LocalDate.of(1906, 8, 24)}, //{HijrahChronology.INSTANCE.date(1324, 7, 4), LocalDate.of(1906, 8, 24)},
//{HijrahChronology.INSTANCE.date(1325, 1, 1), LocalDate.of(1907, 2, 13)}, //{HijrahChronology.INSTANCE.date(1325, 1, 1), LocalDate.of(1907, 2, 13)},
{HijrahChronology.INSTANCE.date(1434, 7, 1), LocalDate.of(2013, 5, 11)},
{HijrahChronology.INSTANCE.date(1434, 7, 1), LocalDate.of(2013, 5, 11)},
{HijrahChronology.INSTANCE.date(HijrahEra.AH, 1434, 7, 1), LocalDate.of(2013, 5, 11)},
{HijrahChronology.INSTANCE.dateYearDay(HijrahEra.AH, 1434, 178), LocalDate.of(2013, 5, 11)},
{HijrahChronology.INSTANCE.dateYearDay(1434, 178), LocalDate.of(2013, 5, 11)},
//{HijrahChronology.INSTANCE.date(1500, 3, 3), LocalDate.of(2079, 1, 5)}, //{HijrahChronology.INSTANCE.date(1500, 3, 3), LocalDate.of(2079, 1, 5)},
//{HijrahChronology.INSTANCE.date(1500, 10, 28), LocalDate.of(2079, 8, 25)}, //{HijrahChronology.INSTANCE.date(1500, 10, 28), LocalDate.of(2079, 8, 25)},
//{HijrahChronology.INSTANCE.date(1500, 10, 29), LocalDate.of(2079, 8, 26)}, //{HijrahChronology.INSTANCE.date(1500, 10, 29), LocalDate.of(2079, 8, 26)},
...@@ -142,6 +149,26 @@ public class TCKHijrahChronology { ...@@ -142,6 +149,26 @@ public class TCKHijrahChronology {
assertEquals(hijrahDate.get(DAY_OF_WEEK), iso.get(DAY_OF_WEEK), "Hijrah day of week should be same as ISO day of week"); assertEquals(hijrahDate.get(DAY_OF_WEEK), iso.get(DAY_OF_WEEK), "Hijrah day of week should be same as ISO day of week");
} }
@Test
public void test_dateNow(){
assertEquals(HijrahChronology.INSTANCE.dateNow(), HijrahDate.now()) ;
assertEquals(HijrahChronology.INSTANCE.dateNow(), HijrahDate.now(ZoneId.systemDefault())) ;
assertEquals(HijrahChronology.INSTANCE.dateNow(), HijrahDate.now(Clock.systemDefaultZone())) ;
assertEquals(HijrahChronology.INSTANCE.dateNow(), HijrahDate.now(Clock.systemDefaultZone().getZone())) ;
assertEquals(HijrahChronology.INSTANCE.dateNow(), HijrahChronology.INSTANCE.dateNow(ZoneId.systemDefault())) ;
assertEquals(HijrahChronology.INSTANCE.dateNow(), HijrahChronology.INSTANCE.dateNow(Clock.systemDefaultZone())) ;
assertEquals(HijrahChronology.INSTANCE.dateNow(), HijrahChronology.INSTANCE.dateNow(Clock.systemDefaultZone().getZone())) ;
ZoneId zoneId = ZoneId.of("Europe/Paris");
assertEquals(HijrahChronology.INSTANCE.dateNow(zoneId), HijrahChronology.INSTANCE.dateNow(Clock.system(zoneId))) ;
assertEquals(HijrahChronology.INSTANCE.dateNow(zoneId), HijrahChronology.INSTANCE.dateNow(Clock.system(zoneId).getZone())) ;
assertEquals(HijrahChronology.INSTANCE.dateNow(zoneId), HijrahDate.now(Clock.system(zoneId))) ;
assertEquals(HijrahChronology.INSTANCE.dateNow(zoneId), HijrahDate.now(Clock.system(zoneId).getZone())) ;
assertEquals(HijrahChronology.INSTANCE.dateNow(ZoneId.of(ZoneOffset.UTC.getId())), HijrahChronology.INSTANCE.dateNow(Clock.systemUTC())) ;
}
@DataProvider(name="badDates") @DataProvider(name="badDates")
Object[][] data_badDates() { Object[][] data_badDates() {
return new Object[][] { return new Object[][] {
......
...@@ -66,12 +66,15 @@ import static org.testng.Assert.assertFalse; ...@@ -66,12 +66,15 @@ import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue; import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail; import static org.testng.Assert.fail;
import java.time.Clock;
import java.time.DateTimeException; import java.time.DateTimeException;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.Month; import java.time.Month;
import java.time.Period; import java.time.Period;
import java.time.Year; import java.time.Year;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.chrono.ChronoLocalDate; import java.time.chrono.ChronoLocalDate;
import java.time.chrono.Chronology; import java.time.chrono.Chronology;
import java.time.chrono.Era; import java.time.chrono.Era;
...@@ -182,6 +185,16 @@ public class TCKJapaneseChronology { ...@@ -182,6 +185,16 @@ public class TCKJapaneseChronology {
{JapaneseChronology.INSTANCE.dateYearDay(1868, 60), LocalDate.of(1868, 2, 29)}, {JapaneseChronology.INSTANCE.dateYearDay(1868, 60), LocalDate.of(1868, 2, 29)},
{JapaneseChronology.INSTANCE.dateYearDay(1928, 60), LocalDate.of(1928, 2, 29)}, {JapaneseChronology.INSTANCE.dateYearDay(1928, 60), LocalDate.of(1928, 2, 29)},
{JapaneseChronology.INSTANCE.dateYearDay(1912, 60), LocalDate.of(1912, 2, 29)}, {JapaneseChronology.INSTANCE.dateYearDay(1912, 60), LocalDate.of(1912, 2, 29)},
{JapaneseDate.ofYearDay(1996, 60), LocalDate.of(1996, 2, 29)},
{JapaneseDate.ofYearDay(1868, 60), LocalDate.of(1868, 2, 29)},
{JapaneseDate.ofYearDay(1928, 60), LocalDate.of(1928, 2, 29)},
{JapaneseDate.ofYearDay(1912, 60), LocalDate.of(1912, 2, 29)},
{JapaneseChronology.INSTANCE.dateYearDay(JapaneseEra.HEISEI, 1996 - YDIFF_HEISEI, 60), LocalDate.of(1996, 2, 29)},
{JapaneseChronology.INSTANCE.dateYearDay(JapaneseEra.MEIJI, 1868 - YDIFF_MEIJI, 60), LocalDate.of(1868, 2, 29)},
{JapaneseChronology.INSTANCE.dateYearDay(JapaneseEra.SHOWA, 1928 - YDIFF_SHOWA, 60), LocalDate.of(1928, 2, 29)},
// {JapaneseChronology.INSTANCE.dateYearDay(JapaneseEra.TAISHO, 1916 - YDIFF_TAISHO, 60), LocalDate.of(1912, 2, 29)},
}; };
} }
...@@ -195,6 +208,26 @@ public class TCKJapaneseChronology { ...@@ -195,6 +208,26 @@ public class TCKJapaneseChronology {
assertEquals(JapaneseChronology.INSTANCE.date(iso), jdate); assertEquals(JapaneseChronology.INSTANCE.date(iso), jdate);
} }
@Test
public void test_dateNow(){
assertEquals(JapaneseChronology.INSTANCE.dateNow(), JapaneseDate.now()) ;
assertEquals(JapaneseChronology.INSTANCE.dateNow(), JapaneseDate.now(ZoneId.systemDefault())) ;
assertEquals(JapaneseChronology.INSTANCE.dateNow(), JapaneseDate.now(Clock.systemDefaultZone())) ;
assertEquals(JapaneseChronology.INSTANCE.dateNow(), JapaneseDate.now(Clock.systemDefaultZone().getZone())) ;
assertEquals(JapaneseChronology.INSTANCE.dateNow(), JapaneseChronology.INSTANCE.dateNow(ZoneId.systemDefault())) ;
assertEquals(JapaneseChronology.INSTANCE.dateNow(), JapaneseChronology.INSTANCE.dateNow(Clock.systemDefaultZone())) ;
assertEquals(JapaneseChronology.INSTANCE.dateNow(), JapaneseChronology.INSTANCE.dateNow(Clock.systemDefaultZone().getZone())) ;
ZoneId zoneId = ZoneId.of("Europe/Paris");
assertEquals(JapaneseChronology.INSTANCE.dateNow(zoneId), JapaneseChronology.INSTANCE.dateNow(Clock.system(zoneId))) ;
assertEquals(JapaneseChronology.INSTANCE.dateNow(zoneId), JapaneseChronology.INSTANCE.dateNow(Clock.system(zoneId).getZone())) ;
assertEquals(JapaneseChronology.INSTANCE.dateNow(zoneId), JapaneseDate.now(Clock.system(zoneId))) ;
assertEquals(JapaneseChronology.INSTANCE.dateNow(zoneId), JapaneseDate.now(Clock.system(zoneId).getZone())) ;
assertEquals(JapaneseChronology.INSTANCE.dateNow(ZoneId.of(ZoneOffset.UTC.getId())), JapaneseChronology.INSTANCE.dateNow(Clock.systemUTC())) ;
}
@DataProvider(name="badDates") @DataProvider(name="badDates")
Object[][] data_badDates() { Object[][] data_badDates() {
return new Object[][] { return new Object[][] {
...@@ -232,8 +265,6 @@ public class TCKJapaneseChronology { ...@@ -232,8 +265,6 @@ public class TCKJapaneseChronology {
return new Object[][] { return new Object[][] {
{2, JapaneseEra.HEISEI, 1, 1 + YDIFF_HEISEI, false}, {2, JapaneseEra.HEISEI, 1, 1 + YDIFF_HEISEI, false},
{2, JapaneseEra.HEISEI, 100, 100 + YDIFF_HEISEI, true}, {2, JapaneseEra.HEISEI, 100, 100 + YDIFF_HEISEI, true},
{2, JapaneseEra.HEISEI, 0, YDIFF_HEISEI, true},
{2, JapaneseEra.HEISEI, -10, -10 + YDIFF_HEISEI, false},
{-1, JapaneseEra.MEIJI, 1, 1 + YDIFF_MEIJI, true}, {-1, JapaneseEra.MEIJI, 1, 1 + YDIFF_MEIJI, true},
{-1, JapaneseEra.MEIJI, 4, 4 + YDIFF_MEIJI, false}, {-1, JapaneseEra.MEIJI, 4, 4 + YDIFF_MEIJI, false},
......
...@@ -66,12 +66,15 @@ import static org.testng.Assert.assertFalse; ...@@ -66,12 +66,15 @@ import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue; import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail; import static org.testng.Assert.fail;
import java.time.Clock;
import java.time.DateTimeException; import java.time.DateTimeException;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.Month; import java.time.Month;
import java.time.Period; import java.time.Period;
import java.time.Year; import java.time.Year;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.chrono.ChronoLocalDate; import java.time.chrono.ChronoLocalDate;
import java.time.chrono.Chronology; import java.time.chrono.Chronology;
import java.time.chrono.Era; import java.time.chrono.Era;
...@@ -177,6 +180,15 @@ public class TCKThaiBuddhistChronology { ...@@ -177,6 +180,15 @@ public class TCKThaiBuddhistChronology {
{ThaiBuddhistChronology.INSTANCE.dateYearDay(400 + YDIFF, 60), LocalDate.of(400, 2, 29)}, {ThaiBuddhistChronology.INSTANCE.dateYearDay(400 + YDIFF, 60), LocalDate.of(400, 2, 29)},
{ThaiBuddhistChronology.INSTANCE.dateYearDay(2000 + YDIFF, 60), LocalDate.of(2000, 2, 29)}, {ThaiBuddhistChronology.INSTANCE.dateYearDay(2000 + YDIFF, 60), LocalDate.of(2000, 2, 29)},
{ThaiBuddhistChronology.INSTANCE.dateYearDay(ThaiBuddhistEra.BE, 1916 + YDIFF, 60), LocalDate.of(1916, 2, 29)},
{ThaiBuddhistChronology.INSTANCE.dateYearDay(ThaiBuddhistEra.BEFORE_BE, -1907 - YDIFF, 60), LocalDate.of(1908, 2, 29)},
{ThaiBuddhistChronology.INSTANCE.dateYearDay(ThaiBuddhistEra.BE, 2000 + YDIFF, 60), LocalDate.of(2000, 2, 29)},
{ThaiBuddhistChronology.INSTANCE.dateYearDay(ThaiBuddhistEra.BE, 2400 + YDIFF, 60), LocalDate.of(2400, 2, 29)},
{ThaiBuddhistChronology.INSTANCE.date(ThaiBuddhistEra.BE, 1916 + YDIFF, 2, 29 ), LocalDate.of(1916, 2, 29)},
{ThaiBuddhistChronology.INSTANCE.date(ThaiBuddhistEra.BEFORE_BE, -1907 - YDIFF, 2, 29), LocalDate.of(1908, 2, 29)},
{ThaiBuddhistChronology.INSTANCE.date(ThaiBuddhistEra.BE, 2000 + YDIFF, 2, 29), LocalDate.of(2000, 2, 29)},
{ThaiBuddhistChronology.INSTANCE.date(ThaiBuddhistEra.BE, 2400 + YDIFF, 2, 29), LocalDate.of(2400, 2, 29)},
}; };
} }
...@@ -190,6 +202,26 @@ public class TCKThaiBuddhistChronology { ...@@ -190,6 +202,26 @@ public class TCKThaiBuddhistChronology {
assertEquals(ThaiBuddhistChronology.INSTANCE.date(iso), jdate); assertEquals(ThaiBuddhistChronology.INSTANCE.date(iso), jdate);
} }
@Test
public void test_dateNow(){
assertEquals(ThaiBuddhistChronology.INSTANCE.dateNow(), ThaiBuddhistDate.now()) ;
assertEquals(ThaiBuddhistChronology.INSTANCE.dateNow(), ThaiBuddhistDate.now(ZoneId.systemDefault())) ;
assertEquals(ThaiBuddhistChronology.INSTANCE.dateNow(), ThaiBuddhistDate.now(Clock.systemDefaultZone())) ;
assertEquals(ThaiBuddhistChronology.INSTANCE.dateNow(), ThaiBuddhistDate.now(Clock.systemDefaultZone().getZone())) ;
assertEquals(ThaiBuddhistChronology.INSTANCE.dateNow(), ThaiBuddhistChronology.INSTANCE.dateNow(ZoneId.systemDefault())) ;
assertEquals(ThaiBuddhistChronology.INSTANCE.dateNow(), ThaiBuddhistChronology.INSTANCE.dateNow(Clock.systemDefaultZone())) ;
assertEquals(ThaiBuddhistChronology.INSTANCE.dateNow(), ThaiBuddhistChronology.INSTANCE.dateNow(Clock.systemDefaultZone().getZone())) ;
ZoneId zoneId = ZoneId.of("Europe/Paris");
assertEquals(ThaiBuddhistChronology.INSTANCE.dateNow(zoneId), ThaiBuddhistChronology.INSTANCE.dateNow(Clock.system(zoneId))) ;
assertEquals(ThaiBuddhistChronology.INSTANCE.dateNow(zoneId), ThaiBuddhistChronology.INSTANCE.dateNow(Clock.system(zoneId).getZone())) ;
assertEquals(ThaiBuddhistChronology.INSTANCE.dateNow(zoneId), ThaiBuddhistDate.now(Clock.system(zoneId))) ;
assertEquals(ThaiBuddhistChronology.INSTANCE.dateNow(zoneId), ThaiBuddhistDate.now(Clock.system(zoneId).getZone())) ;
assertEquals(ThaiBuddhistChronology.INSTANCE.dateNow(ZoneId.of(ZoneOffset.UTC.getId())), ThaiBuddhistChronology.INSTANCE.dateNow(Clock.systemUTC())) ;
}
@DataProvider(name="badDates") @DataProvider(name="badDates")
Object[][] data_badDates() { Object[][] data_badDates() {
return new Object[][] { return new Object[][] {
......
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册