diff --git a/jdk/src/share/classes/java/time/DayOfWeek.java b/jdk/src/share/classes/java/time/DayOfWeek.java index d2a6f5aa541..b48482241df 100644 --- a/jdk/src/share/classes/java/time/DayOfWeek.java +++ b/jdk/src/share/classes/java/time/DayOfWeek.java @@ -61,7 +61,6 @@ */ package java.time; -import java.time.temporal.UnsupportedTemporalTypeException; import static java.time.temporal.ChronoField.DAY_OF_WEEK; import static java.time.temporal.ChronoUnit.DAYS; @@ -73,6 +72,7 @@ import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalAdjuster; import java.time.temporal.TemporalField; import java.time.temporal.TemporalQuery; +import java.time.temporal.UnsupportedTemporalTypeException; import java.time.temporal.ValueRange; import java.time.temporal.WeekFields; import java.util.Locale; @@ -339,7 +339,7 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster { if (field == DAY_OF_WEEK) { return getValue(); } else if (field instanceof ChronoField) { - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.getFrom(this); } diff --git a/jdk/src/share/classes/java/time/Duration.java b/jdk/src/share/classes/java/time/Duration.java index 52b225e6e69..ab7da66f83a 100644 --- a/jdk/src/share/classes/java/time/Duration.java +++ b/jdk/src/share/classes/java/time/Duration.java @@ -459,9 +459,9 @@ public final class Duration */ public static Duration between(Temporal startInclusive, Temporal endExclusive) { try { - return ofNanos(startInclusive.periodUntil(endExclusive, NANOS)); + return ofNanos(startInclusive.until(endExclusive, NANOS)); } catch (DateTimeException | ArithmeticException ex) { - long secs = startInclusive.periodUntil(endExclusive, SECONDS); + long secs = startInclusive.until(endExclusive, SECONDS); long nanos; try { nanos = endExclusive.getLong(NANO_OF_SECOND) - startInclusive.getLong(NANO_OF_SECOND); @@ -523,7 +523,7 @@ public final class Duration } else if (unit == NANOS) { return nanos; } else { - throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName()); + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } } diff --git a/jdk/src/share/classes/java/time/Instant.java b/jdk/src/share/classes/java/time/Instant.java index 6dc24646945..aeecdbed524 100644 --- a/jdk/src/share/classes/java/time/Instant.java +++ b/jdk/src/share/classes/java/time/Instant.java @@ -69,6 +69,7 @@ import static java.time.temporal.ChronoField.INSTANT_SECONDS; import static java.time.temporal.ChronoField.MICRO_OF_SECOND; import static java.time.temporal.ChronoField.MILLI_OF_SECOND; import static java.time.temporal.ChronoField.NANO_OF_SECOND; +import static java.time.temporal.ChronoUnit.DAYS; import static java.time.temporal.ChronoUnit.NANOS; import java.io.DataInput; @@ -418,8 +419,9 @@ public final class Instant * Checks if the specified field is supported. *

* This checks if this instant can be queried for the specified field. - * If false, then calling the {@link #range(TemporalField) range} and - * {@link #get(TemporalField) get} methods will throw an exception. + * If false, then calling the {@link #range(TemporalField) range}, + * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)} + * methods will throw an exception. *

* If the field is a {@link ChronoField} then the query is implemented here. * The supported fields are: @@ -447,6 +449,44 @@ public final class Instant return field != null && field.isSupportedBy(this); } + /** + * Checks if the specified unit is supported. + *

+ * This checks if the specified unit can be added to, or subtracted from, this date-time. + * If false, then calling the {@link #plus(long, TemporalUnit)} and + * {@link #minus(long, TemporalUnit) minus} methods will throw an exception. + *

+ * If the unit is a {@link ChronoUnit} then the query is implemented here. + * The supported units are: + *

+ * All other {@code ChronoUnit} instances will return false. + *

+ * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)} + * passing {@code this} as the argument. + * Whether the unit is supported is determined by the unit. + * + * @param unit the unit to check, null returns false + * @return true if the unit can be added/subtracted, false if not + */ + @Override + public boolean isSupported(TemporalUnit unit) { + if (unit instanceof ChronoUnit) { + return unit.isTimeBased() || unit == DAYS; + } + return unit != null && unit.isSupportedBy(this); + } + + //----------------------------------------------------------------------- /** * Gets the range of valid values for the specified field. *

@@ -511,7 +551,7 @@ public final class Instant case MILLI_OF_SECOND: return nanos / 1000_000; case INSTANT_SECONDS: INSTANT_SECONDS.checkValidIntValue(seconds); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return range(field).checkValidIntValue(field.getFrom(this), field); } @@ -548,7 +588,7 @@ public final class Instant case MILLI_OF_SECOND: return nanos / 1000_000; case INSTANT_SECONDS: return seconds; } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.getFrom(this); } @@ -665,7 +705,7 @@ public final class Instant case NANO_OF_SECOND: return (newValue != nanos ? create(seconds, (int) newValue) : this); case INSTANT_SECONDS: return (newValue != seconds ? create(newValue, nanos) : this); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.adjustInto(this, newValue); } @@ -807,7 +847,7 @@ public final class Instant case HALF_DAYS: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_DAY / 2)); case DAYS: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_DAY)); } - throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName()); + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } return unit.addTo(this, amountToAdd); } @@ -1053,14 +1093,14 @@ public final class Instant * complete units between the two instants. * The {@code Temporal} passed to this method must be an {@code Instant}. * For example, the amount in days between two dates can be calculated - * using {@code startInstant.periodUntil(endInstant, SECONDS)}. + * using {@code startInstant.until(endInstant, SECONDS)}. *

* There are two equivalent ways of using this method. * The first is to invoke this method. * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}: *

      *   // these two lines are equivalent
-     *   amount = start.periodUntil(end, SECONDS);
+     *   amount = start.until(end, SECONDS);
      *   amount = SECONDS.between(start, end);
      * 
* The choice should be made based on which makes the code more readable. @@ -1085,7 +1125,7 @@ public final class Instant * @throws ArithmeticException if numeric overflow occurs */ @Override - public long periodUntil(Temporal endInstant, TemporalUnit unit) { + public long until(Temporal endInstant, TemporalUnit unit) { if (endInstant instanceof Instant == false) { Objects.requireNonNull(endInstant, "endInstant"); throw new DateTimeException("Unable to calculate amount as objects are of two different types"); @@ -1103,7 +1143,7 @@ public final class Instant case HALF_DAYS: return secondsUntil(end) / (12 * SECONDS_PER_HOUR); case DAYS: return secondsUntil(end) / (SECONDS_PER_DAY); } - throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName()); + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } return unit.between(this, endInstant); } diff --git a/jdk/src/share/classes/java/time/LocalDate.java b/jdk/src/share/classes/java/time/LocalDate.java index ede6d8326b9..d96f5b1fd1e 100644 --- a/jdk/src/share/classes/java/time/LocalDate.java +++ b/jdk/src/share/classes/java/time/LocalDate.java @@ -127,7 +127,7 @@ import java.util.Objects; * @since 1.8 */ public final class LocalDate - implements Temporal, TemporalAdjuster, ChronoLocalDate, Serializable { + implements Temporal, TemporalAdjuster, ChronoLocalDate, Serializable { /** * The minimum supported {@code LocalDate}, '-999999999-01-01'. @@ -466,8 +466,9 @@ public final class LocalDate * Checks if the specified field is supported. *

* This checks if this date can be queried for the specified field. - * If false, then calling the {@link #range(TemporalField) range} and - * {@link #get(TemporalField) get} methods will throw an exception. + * If false, then calling the {@link #range(TemporalField) range}, + * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)} + * methods will throw an exception. *

* If the field is a {@link ChronoField} then the query is implemented here. * The supported fields are: @@ -501,6 +502,41 @@ public final class LocalDate return ChronoLocalDate.super.isSupported(field); } + /** + * Checks if the specified unit is supported. + *

+ * This checks if the specified unit can be added to, or subtracted from, this date-time. + * If false, then calling the {@link #plus(long, TemporalUnit)} and + * {@link #minus(long, TemporalUnit) minus} methods will throw an exception. + *

+ * If the unit is a {@link ChronoUnit} then the query is implemented here. + * The supported units are: + *

+ * All other {@code ChronoUnit} instances will return false. + *

+ * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)} + * passing {@code this} as the argument. + * Whether the unit is supported is determined by the unit. + * + * @param unit the unit to check, null returns false + * @return true if the unit can be added/subtracted, false if not + */ + @Override // override for Javadoc + public boolean isSupported(TemporalUnit unit) { + return ChronoLocalDate.super.isSupported(unit); + } + + //----------------------------------------------------------------------- /** * Gets the range of valid values for the specified field. *

@@ -538,7 +574,7 @@ public final class LocalDate } return field.range(); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.rangeRefinedBy(this); } @@ -631,7 +667,7 @@ public final class LocalDate case YEAR: return year; case ERA: return (year >= 1 ? 1 : 0); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } private long getProlepticMonth() { @@ -988,7 +1024,7 @@ public final class LocalDate case YEAR: return withYear((int) newValue); case ERA: return (getLong(ERA) == newValue ? this : withYear(1 - year)); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.adjustInto(this, newValue); } @@ -1187,7 +1223,7 @@ public final class LocalDate case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000)); case ERAS: return with(ERA, Math.addExact(getLong(ERA), amountToAdd)); } - throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName()); + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } return unit.addTo(this, amountToAdd); } @@ -1497,7 +1533,7 @@ public final class LocalDate * The result will be negative if the end is before the start. * The {@code Temporal} passed to this method must be a {@code LocalDate}. * For example, the amount in days between two dates can be calculated - * using {@code startDate.periodUntil(endDate, DAYS)}. + * using {@code startDate.until(endDate, DAYS)}. *

* The calculation returns a whole number, representing the number of * complete units between the two dates. @@ -1509,7 +1545,7 @@ public final class LocalDate * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}: *

      *   // these two lines are equivalent
-     *   amount = start.periodUntil(end, MONTHS);
+     *   amount = start.until(end, MONTHS);
      *   amount = MONTHS.between(start, end);
      * 
* The choice should be made based on which makes the code more readable. @@ -1534,7 +1570,7 @@ public final class LocalDate * @throws ArithmeticException if numeric overflow occurs */ @Override - public long periodUntil(Temporal endDate, TemporalUnit unit) { + public long until(Temporal endDate, TemporalUnit unit) { Objects.requireNonNull(unit, "unit"); if (endDate instanceof LocalDate == false) { Objects.requireNonNull(endDate, "endDate"); @@ -1552,7 +1588,7 @@ public final class LocalDate case MILLENNIA: return monthsUntil(end) / 12000; case ERAS: return end.getLong(ERA) - getLong(ERA); } - throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName()); + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } return unit.between(this, endDate); } @@ -1591,7 +1627,7 @@ public final class LocalDate * The second is to use {@link Period#between(LocalDate, LocalDate)}: *
      *   // these two lines are equivalent
-     *   period = start.periodUntil(end);
+     *   period = start.until(end);
      *   period = Period.between(start, end);
      * 
* The choice should be made based on which makes the code more readable. @@ -1600,7 +1636,7 @@ public final class LocalDate * @return the period between this date and the end date, not null */ @Override - public Period periodUntil(ChronoLocalDate endDate) { + public Period until(ChronoLocalDate endDate) { LocalDate end = LocalDate.from(endDate); long totalMonths = end.getProlepticMonth() - this.getProlepticMonth(); // safe int days = end.day - this.day; @@ -1803,7 +1839,7 @@ public final class LocalDate * @return the comparator value, negative if less, positive if greater */ @Override // override for Javadoc and performance - public int compareTo(ChronoLocalDate other) { + public int compareTo(ChronoLocalDate other) { if (other instanceof LocalDate) { return compareTo0((LocalDate) other); } @@ -1843,7 +1879,7 @@ public final class LocalDate * @return true if this date is after the specified date */ @Override // override for Javadoc and performance - public boolean isAfter(ChronoLocalDate other) { + public boolean isAfter(ChronoLocalDate other) { if (other instanceof LocalDate) { return compareTo0((LocalDate) other) > 0; } @@ -1872,7 +1908,7 @@ public final class LocalDate * @return true if this date is before the specified date */ @Override // override for Javadoc and performance - public boolean isBefore(ChronoLocalDate other) { + public boolean isBefore(ChronoLocalDate other) { if (other instanceof LocalDate) { return compareTo0((LocalDate) other) < 0; } @@ -1901,7 +1937,7 @@ public final class LocalDate * @return true if this date is equal to the specified date */ @Override // override for Javadoc and performance - public boolean isEqual(ChronoLocalDate other) { + public boolean isEqual(ChronoLocalDate other) { if (other instanceof LocalDate) { return compareTo0((LocalDate) other) == 0; } diff --git a/jdk/src/share/classes/java/time/LocalDateTime.java b/jdk/src/share/classes/java/time/LocalDateTime.java index 6e6c87bc2ff..d68d6f52537 100644 --- a/jdk/src/share/classes/java/time/LocalDateTime.java +++ b/jdk/src/share/classes/java/time/LocalDateTime.java @@ -515,8 +515,9 @@ public final class LocalDateTime * Checks if the specified field is supported. *

* This checks if this date-time can be queried for the specified field. - * If false, then calling the {@link #range(TemporalField) range} and - * {@link #get(TemporalField) get} methods will throw an exception. + * If false, then calling the {@link #range(TemporalField) range}, + * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)} + * methods will throw an exception. *

* If the field is a {@link ChronoField} then the query is implemented here. * The supported fields are: @@ -569,6 +570,48 @@ public final class LocalDateTime return field != null && field.isSupportedBy(this); } + /** + * Checks if the specified unit is supported. + *

+ * This checks if the specified unit can be added to, or subtracted from, this date-time. + * If false, then calling the {@link #plus(long, TemporalUnit)} and + * {@link #minus(long, TemporalUnit) minus} methods will throw an exception. + *

+ * If the unit is a {@link ChronoUnit} then the query is implemented here. + * The supported units are: + *

+ * All other {@code ChronoUnit} instances will return false. + *

+ * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)} + * passing {@code this} as the argument. + * Whether the unit is supported is determined by the unit. + * + * @param unit the unit to check, null returns false + * @return true if the unit can be added/subtracted, false if not + */ + @Override // override for Javadoc + public boolean isSupported(TemporalUnit unit) { + return ChronoLocalDateTime.super.isSupported(unit); + } + + //----------------------------------------------------------------------- /** * Gets the range of valid values for the specified field. *

@@ -1570,7 +1613,7 @@ public final class LocalDateTime * The result will be negative if the end is before the start. * The {@code Temporal} passed to this method must be a {@code LocalDateTime}. * For example, the amount in days between two date-times can be calculated - * using {@code startDateTime.periodUntil(endDateTime, DAYS)}. + * using {@code startDateTime.until(endDateTime, DAYS)}. *

* The calculation returns a whole number, representing the number of * complete units between the two date-times. @@ -1582,7 +1625,7 @@ public final class LocalDateTime * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}: *

      *   // these two lines are equivalent
-     *   amount = start.periodUntil(end, MONTHS);
+     *   amount = start.until(end, MONTHS);
      *   amount = MONTHS.between(start, end);
      * 
* The choice should be made based on which makes the code more readable. @@ -1609,18 +1652,17 @@ public final class LocalDateTime * @throws ArithmeticException if numeric overflow occurs */ @Override - public long periodUntil(Temporal endDateTime, TemporalUnit unit) { + public long until(Temporal endDateTime, TemporalUnit unit) { if (endDateTime instanceof LocalDateTime == false) { Objects.requireNonNull(endDateTime, "endDateTime"); throw new DateTimeException("Unable to calculate amount as objects are of two different types"); } LocalDateTime end = (LocalDateTime) endDateTime; if (unit instanceof ChronoUnit) { - ChronoUnit f = (ChronoUnit) unit; - if (f.isTimeUnit()) { + if (unit.isTimeBased()) { long amount = date.daysUntil(end.date); if (amount == 0) { - return time.periodUntil(end.time, unit); + return time.until(end.time, unit); } long timePart = end.time.toNanoOfDay() - time.toNanoOfDay(); if (amount > 0) { @@ -1630,7 +1672,7 @@ public final class LocalDateTime amount++; // safe timePart -= NANOS_PER_DAY; // safe } - switch (f) { + switch ((ChronoUnit) unit) { case NANOS: amount = Math.multiplyExact(amount, NANOS_PER_DAY); break; @@ -1667,7 +1709,7 @@ public final class LocalDateTime } else if (endDate.isBefore(date) && end.time.isAfter(time)) { endDate = endDate.plusDays(1); } - return date.periodUntil(endDate, unit); + return date.until(endDate, unit); } return unit.between(this, endDateTime); } diff --git a/jdk/src/share/classes/java/time/LocalTime.java b/jdk/src/share/classes/java/time/LocalTime.java index 41b1a927560..2bace6e7bc9 100644 --- a/jdk/src/share/classes/java/time/LocalTime.java +++ b/jdk/src/share/classes/java/time/LocalTime.java @@ -470,8 +470,9 @@ public final class LocalTime * Checks if the specified field is supported. *

* This checks if this time can be queried for the specified field. - * If false, then calling the {@link #range(TemporalField) range} and - * {@link #get(TemporalField) get} methods will throw an exception. + * If false, then calling the {@link #range(TemporalField) range}, + * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)} + * methods will throw an exception. *

* If the field is a {@link ChronoField} then the query is implemented here. * The supported fields are: @@ -510,6 +511,43 @@ public final class LocalTime return field != null && field.isSupportedBy(this); } + /** + * Checks if the specified unit is supported. + *

+ * This checks if the specified unit can be added to, or subtracted from, this date-time. + * If false, then calling the {@link #plus(long, TemporalUnit)} and + * {@link #minus(long, TemporalUnit) minus} methods will throw an exception. + *

+ * If the unit is a {@link ChronoUnit} then the query is implemented here. + * The supported units are: + *

+ * All other {@code ChronoUnit} instances will return false. + *

+ * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)} + * passing {@code this} as the argument. + * Whether the unit is supported is determined by the unit. + * + * @param unit the unit to check, null returns false + * @return true if the unit can be added/subtracted, false if not + */ + @Override // override for Javadoc + public boolean isSupported(TemporalUnit unit) { + if (unit instanceof ChronoUnit) { + return unit.isTimeBased(); + } + return unit != null && unit.isSupportedBy(this); + } + + //----------------------------------------------------------------------- /** * Gets the range of valid values for the specified field. *

@@ -628,7 +666,7 @@ public final class LocalTime case CLOCK_HOUR_OF_DAY: return (hour == 0 ? 24 : hour); case AMPM_OF_DAY: return hour / 12; } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } //----------------------------------------------------------------------- @@ -803,7 +841,7 @@ public final class LocalTime case CLOCK_HOUR_OF_DAY: return withHour((int) (newValue == 24 ? 0 : newValue)); case AMPM_OF_DAY: return plusHours((newValue - (hour / 12)) * 12); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.adjustInto(this, newValue); } @@ -995,8 +1033,7 @@ public final class LocalTime @Override public LocalTime plus(long amountToAdd, TemporalUnit unit) { if (unit instanceof ChronoUnit) { - ChronoUnit f = (ChronoUnit) unit; - switch (f) { + switch ((ChronoUnit) unit) { case NANOS: return plusNanos(amountToAdd); case MICROS: return plusNanos((amountToAdd % MICROS_PER_DAY) * 1000); case MILLIS: return plusNanos((amountToAdd % MILLIS_PER_DAY) * 1000_000); @@ -1005,7 +1042,7 @@ public final class LocalTime case HOURS: return plusHours(amountToAdd); case HALF_DAYS: return plusHours((amountToAdd % 2) * 12); } - throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName()); + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } return unit.addTo(this, amountToAdd); } @@ -1295,7 +1332,7 @@ public final class LocalTime * The result will be negative if the end is before the start. * The {@code Temporal} passed to this method must be a {@code LocalTime}. * For example, the amount in hours between two times can be calculated - * using {@code startTime.periodUntil(endTime, HOURS)}. + * using {@code startTime.until(endTime, HOURS)}. *

* The calculation returns a whole number, representing the number of * complete units between the two times. @@ -1307,7 +1344,7 @@ public final class LocalTime * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}: *

      *   // these two lines are equivalent
-     *   amount = start.periodUntil(end, MINUTES);
+     *   amount = start.until(end, MINUTES);
      *   amount = MINUTES.between(start, end);
      * 
* The choice should be made based on which makes the code more readable. @@ -1332,7 +1369,7 @@ public final class LocalTime * @throws ArithmeticException if numeric overflow occurs */ @Override - public long periodUntil(Temporal endTime, TemporalUnit unit) { + public long until(Temporal endTime, TemporalUnit unit) { if (endTime instanceof LocalTime == false) { Objects.requireNonNull(endTime, "endTime"); throw new DateTimeException("Unable to calculate amount as objects are of two different types"); @@ -1349,7 +1386,7 @@ public final class LocalTime case HOURS: return nanosUntil / NANOS_PER_HOUR; case HALF_DAYS: return nanosUntil / (12 * NANOS_PER_HOUR); } - throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName()); + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } return unit.between(this, endTime); } diff --git a/jdk/src/share/classes/java/time/Month.java b/jdk/src/share/classes/java/time/Month.java index 272e8f96b36..85d12d8f136 100644 --- a/jdk/src/share/classes/java/time/Month.java +++ b/jdk/src/share/classes/java/time/Month.java @@ -61,7 +61,6 @@ */ package java.time; -import java.time.temporal.UnsupportedTemporalTypeException; import static java.time.temporal.ChronoField.MONTH_OF_YEAR; import static java.time.temporal.ChronoUnit.MONTHS; @@ -75,6 +74,7 @@ import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalAdjuster; import java.time.temporal.TemporalField; import java.time.temporal.TemporalQuery; +import java.time.temporal.UnsupportedTemporalTypeException; import java.time.temporal.ValueRange; import java.util.Locale; @@ -370,7 +370,7 @@ public enum Month implements TemporalAccessor, TemporalAdjuster { if (field == MONTH_OF_YEAR) { return getValue(); } else if (field instanceof ChronoField) { - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.getFrom(this); } diff --git a/jdk/src/share/classes/java/time/MonthDay.java b/jdk/src/share/classes/java/time/MonthDay.java index 4204ef74a7d..06aa0437af8 100644 --- a/jdk/src/share/classes/java/time/MonthDay.java +++ b/jdk/src/share/classes/java/time/MonthDay.java @@ -438,7 +438,7 @@ public final class MonthDay case DAY_OF_MONTH: return day; case MONTH_OF_YEAR: return month; } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.getFrom(this); } diff --git a/jdk/src/share/classes/java/time/OffsetDateTime.java b/jdk/src/share/classes/java/time/OffsetDateTime.java index b053085a9f5..5641154cf3e 100644 --- a/jdk/src/share/classes/java/time/OffsetDateTime.java +++ b/jdk/src/share/classes/java/time/OffsetDateTime.java @@ -65,6 +65,7 @@ import static java.time.temporal.ChronoField.EPOCH_DAY; import static java.time.temporal.ChronoField.INSTANT_SECONDS; import static java.time.temporal.ChronoField.NANO_OF_DAY; import static java.time.temporal.ChronoField.OFFSET_SECONDS; +import static java.time.temporal.ChronoUnit.FOREVER; import static java.time.temporal.ChronoUnit.NANOS; import java.io.IOException; @@ -137,25 +138,40 @@ public final class OffsetDateTime public static final OffsetDateTime MAX = LocalDateTime.MAX.atOffset(ZoneOffset.MIN); /** - * Comparator for two {@code OffsetDateTime} instances based solely on the instant. + * Gets a comparator that compares two {@code OffsetDateTime} instances + * based solely on the instant. *

* This method differs from the comparison in {@link #compareTo} in that it * only compares the underlying instant. * + * @return a comparator that compares in time-line order + * * @see #isAfter * @see #isBefore * @see #isEqual */ - public static final Comparator INSTANT_COMPARATOR = new Comparator() { - @Override - public int compare(OffsetDateTime datetime1, OffsetDateTime datetime2) { - int cmp = Long.compare(datetime1.toEpochSecond(), datetime2.toEpochSecond()); - if (cmp == 0) { - cmp = Long.compare(datetime1.toLocalTime().toNanoOfDay(), datetime2.toLocalTime().toNanoOfDay()); - } - return cmp; + public static Comparator timeLineOrder() { + return OffsetDateTime::compareInstant; + } + + /** + * Compares this {@code OffsetDateTime} to another date-time. + * The comparison is based on the instant. + * + * @param datetime1 the first date-time to compare, not null + * @param datetime2 the other date-time to compare to, not null + * @return the comparator value, negative if less, positive if greater + */ + private static int compareInstant(OffsetDateTime datetime1, OffsetDateTime datetime2) { + if (datetime1.getOffset().equals(datetime2.getOffset())) { + return datetime1.toLocalDateTime().compareTo(datetime2.toLocalDateTime()); } - }; + int cmp = Long.compare(datetime1.toEpochSecond(), datetime2.toEpochSecond()); + if (cmp == 0) { + cmp = datetime1.toLocalTime().getNano() - datetime2.toLocalTime().getNano(); + } + return cmp; + } /** * Serialization version. @@ -406,8 +422,9 @@ public final class OffsetDateTime * Checks if the specified field is supported. *

* This checks if this date-time can be queried for the specified field. - * If false, then calling the {@link #range(TemporalField) range} and - * {@link #get(TemporalField) get} methods will throw an exception. + * If false, then calling the {@link #range(TemporalField) range}, + * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)} + * methods will throw an exception. *

* If the field is a {@link ChronoField} then the query is implemented here. * The supported fields are: @@ -458,6 +475,51 @@ public final class OffsetDateTime return field instanceof ChronoField || (field != null && field.isSupportedBy(this)); } + /** + * Checks if the specified unit is supported. + *

+ * This checks if the specified unit can be added to, or subtracted from, this date-time. + * If false, then calling the {@link #plus(long, TemporalUnit)} and + * {@link #minus(long, TemporalUnit) minus} methods will throw an exception. + *

+ * If the unit is a {@link ChronoUnit} then the query is implemented here. + * The supported units are: + *

+ * All other {@code ChronoUnit} instances will return false. + *

+ * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)} + * passing {@code this} as the argument. + * Whether the unit is supported is determined by the unit. + * + * @param unit the unit to check, null returns false + * @return true if the unit can be added/subtracted, false if not + */ + @Override // override for Javadoc + public boolean isSupported(TemporalUnit unit) { + if (unit instanceof ChronoUnit) { + return unit != FOREVER; + } + return unit != null && unit.isSupportedBy(this); + } + + //----------------------------------------------------------------------- /** * Gets the range of valid values for the specified field. *

@@ -1528,7 +1590,7 @@ public final class OffsetDateTime * 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. * For example, the period in days between two date-times can be calculated - * using {@code startDateTime.periodUntil(endDateTime, DAYS)}. + * using {@code startDateTime.until(endDateTime, DAYS)}. *

* The {@code Temporal} passed to this method must be an {@code OffsetDateTime}. * If the offset differs between the two date-times, the specified @@ -1544,7 +1606,7 @@ public final class OffsetDateTime * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}: *

      *   // these two lines are equivalent
-     *   amount = start.periodUntil(end, MONTHS);
+     *   amount = start.until(end, MONTHS);
      *   amount = MONTHS.between(start, end);
      * 
* The choice should be made based on which makes the code more readable. @@ -1571,7 +1633,7 @@ public final class OffsetDateTime * @throws ArithmeticException if numeric overflow occurs */ @Override - public long periodUntil(Temporal endDateTime, TemporalUnit unit) { + public long until(Temporal endDateTime, TemporalUnit unit) { if (endDateTime instanceof OffsetDateTime == false) { Objects.requireNonNull(endDateTime, "endDateTime"); throw new DateTimeException("Unable to calculate amount as objects are of two different types"); @@ -1579,7 +1641,7 @@ public final class OffsetDateTime if (unit instanceof ChronoUnit) { OffsetDateTime end = (OffsetDateTime) endDateTime; end = end.withOffsetSameInstant(offset); - return dateTime.periodUntil(end.dateTime, unit); + return dateTime.until(end.dateTime, unit); } return unit.between(this, endDateTime); } @@ -1724,15 +1786,9 @@ public final class OffsetDateTime */ @Override public int compareTo(OffsetDateTime other) { - if (getOffset().equals(other.getOffset())) { - return toLocalDateTime().compareTo(other.toLocalDateTime()); - } - int cmp = Long.compare(toEpochSecond(), other.toEpochSecond()); + int cmp = compareInstant(this, other); if (cmp == 0) { - cmp = toLocalTime().getNano() - other.toLocalTime().getNano(); - if (cmp == 0) { - cmp = toLocalDateTime().compareTo(other.toLocalDateTime()); - } + cmp = toLocalDateTime().compareTo(other.toLocalDateTime()); } return cmp; } diff --git a/jdk/src/share/classes/java/time/OffsetTime.java b/jdk/src/share/classes/java/time/OffsetTime.java index ff990696942..2872cff4b26 100644 --- a/jdk/src/share/classes/java/time/OffsetTime.java +++ b/jdk/src/share/classes/java/time/OffsetTime.java @@ -348,8 +348,9 @@ public final class OffsetTime * Checks if the specified field is supported. *

* This checks if this time can be queried for the specified field. - * If false, then calling the {@link #range(TemporalField) range} and - * {@link #get(TemporalField) get} methods will throw an exception. + * If false, then calling the {@link #range(TemporalField) range}, + * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)} + * methods will throw an exception. *

* If the field is a {@link ChronoField} then the query is implemented here. * The supported fields are: @@ -389,6 +390,43 @@ public final class OffsetTime return field != null && field.isSupportedBy(this); } + /** + * Checks if the specified unit is supported. + *

+ * This checks if the specified unit can be added to, or subtracted from, this date-time. + * If false, then calling the {@link #plus(long, TemporalUnit)} and + * {@link #minus(long, TemporalUnit) minus} methods will throw an exception. + *

+ * If the unit is a {@link ChronoUnit} then the query is implemented here. + * The supported units are: + *

+ * All other {@code ChronoUnit} instances will return false. + *

+ * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)} + * passing {@code this} as the argument. + * Whether the unit is supported is determined by the unit. + * + * @param unit the unit to check, null returns false + * @return true if the unit can be added/subtracted, false if not + */ + @Override // override for Javadoc + public boolean isSupported(TemporalUnit unit) { + if (unit instanceof ChronoUnit) { + return unit.isTimeBased(); + } + return unit != null && unit.isSupportedBy(this); + } + + //----------------------------------------------------------------------- /** * Gets the range of valid values for the specified field. *

@@ -1084,7 +1122,7 @@ public final class OffsetTime * The start and end points are {@code this} and the specified time. * The result will be negative if the end is before the start. * For example, the period in hours between two times can be calculated - * using {@code startTime.periodUntil(endTime, HOURS)}. + * using {@code startTime.until(endTime, HOURS)}. *

* The {@code Temporal} passed to this method must be an {@code OffsetTime}. * If the offset differs between the two times, then the specified @@ -1100,7 +1138,7 @@ public final class OffsetTime * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}: *

      *   // these two lines are equivalent
-     *   amount = start.periodUntil(end, MINUTES);
+     *   amount = start.until(end, MINUTES);
      *   amount = MINUTES.between(start, end);
      * 
* The choice should be made based on which makes the code more readable. @@ -1125,7 +1163,7 @@ public final class OffsetTime * @throws ArithmeticException if numeric overflow occurs */ @Override - public long periodUntil(Temporal endTime, TemporalUnit unit) { + public long until(Temporal endTime, TemporalUnit unit) { if (endTime instanceof OffsetTime == false) { Objects.requireNonNull(endTime, "endTime"); throw new DateTimeException("Unable to calculate amount as objects are of two different types"); @@ -1142,7 +1180,7 @@ public final class OffsetTime case HOURS: return nanosUntil / NANOS_PER_HOUR; case HALF_DAYS: return nanosUntil / (12 * NANOS_PER_HOUR); } - throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName()); + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } return unit.between(this, endTime); } diff --git a/jdk/src/share/classes/java/time/Period.java b/jdk/src/share/classes/java/time/Period.java index b2748f089ce..45980d08740 100644 --- a/jdk/src/share/classes/java/time/Period.java +++ b/jdk/src/share/classes/java/time/Period.java @@ -139,7 +139,7 @@ public final class Period * The pattern for parsing. */ private final static Pattern PATTERN = - Pattern.compile("([-+]?)P(?:([-+]?[0-9]+)Y)?(?:([-+]?[0-9]+)M)?(?:([-+]?[0-9]+)D)?", Pattern.CASE_INSENSITIVE); + Pattern.compile("([-+]?)P(?:([-+]?[0-9]+)Y)?(?:([-+]?[0-9]+)M)?(?:([-+]?[0-9]+)W)?(?:([-+]?[0-9]+)D)?", Pattern.CASE_INSENSITIVE); /** * The set of supported units. */ @@ -186,6 +186,20 @@ public final class Period return create(0, months, 0); } + /** + * Obtains a {@code Period} representing a number of weeks. + *

+ * The resulting period will be day-based, with the amount of days + * equal to the number of weeks multiplied by 7. + * The years and months units will be zero. + * + * @param weeks the number of weeks, positive or negative + * @return the period, with the input weeks converted to days, not null + */ + public static Period ofWeeks(int weeks) { + return create(0, 0, Math.multiplyExact(weeks, 7)); + } + /** * Obtains a {@code Period} representing a number of days. *

@@ -257,22 +271,36 @@ public final class Period * Obtains a {@code Period} from a text string such as {@code PnYnMnD}. *

* This will parse the string produced by {@code toString()} which is - * based on the ISO-8601 period format {@code PnYnMnD}. + * based on the ISO-8601 period formats {@code PnYnMnD} and {@code PnW}. *

* The string starts with an optional sign, denoted by the ASCII negative * or positive symbol. If negative, the whole period is negated. * The ASCII letter "P" is next in upper or lower case. - * There are then three sections, each consisting of a number and a suffix. - * At least one of the three sections must be present. - * The sections have suffixes in ASCII of "Y", "M" and "D" for - * years, months and days, accepted in upper or lower case. + * There are then four sections, each consisting of a number and a suffix. + * At least one of the four sections must be present. + * The sections have suffixes in ASCII of "Y", "M", "W" and "D" for + * years, months, weeks and days, accepted in upper or lower case. * The suffixes must occur in order. * The number part of each section must consist of ASCII digits. * The number may be prefixed by the ASCII negative or positive symbol. * The number must parse to an {@code int}. *

* The leading plus/minus sign, and negative values for other units are - * not part of the ISO-8601 standard. + * not part of the ISO-8601 standard. In addition, ISO-8601 does not + * permit mixing between the {@code PnYnMnD} and {@code PnW} formats. + * Any week-based input is multiplied by 7 and treated as a number of days. + *

+ * For example, the following are valid inputs: + *

+     *   "P2Y"             -- Period.ofYears(2)
+     *   "P3M"             -- Period.ofMonths(3)
+     *   "P4W"             -- Period.ofWeeks(4)
+     *   "P5D"             -- Period.ofDays(5)
+     *   "P1Y2M3D"         -- Period.of(1, 2, 3)
+     *   "P1Y2M3W4D"       -- Period.of(1, 2, 25)
+     *   "P-1Y2M"          -- Period.of(-1, 2, 0)
+     *   "-P1Y2M"          -- Period.of(-1, -2, 0)
+     * 
* * @param text the text to parse, not null * @return the parsed period, not null @@ -285,14 +313,18 @@ public final class Period int negate = ("-".equals(matcher.group(1)) ? -1 : 1); String yearMatch = matcher.group(2); String monthMatch = matcher.group(3); - String dayMatch = matcher.group(4); - if (yearMatch != null || monthMatch != null || dayMatch != null) { + String weekMatch = matcher.group(4); + String dayMatch = matcher.group(5); + if (yearMatch != null || monthMatch != null || dayMatch != null || weekMatch != null) { try { - return create(parseNumber(text, yearMatch, negate), - parseNumber(text, monthMatch, negate), - parseNumber(text, dayMatch, negate)); + int years = parseNumber(text, yearMatch, negate); + int months = parseNumber(text, monthMatch, negate); + int weeks = parseNumber(text, weekMatch, negate); + int days = parseNumber(text, dayMatch, negate); + days = Math.addExact(days, Math.multiplyExact(weeks, 7)); + return create(years, months, days); } catch (NumberFormatException ex) { - throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Period", text, 0).initCause(ex); + throw new DateTimeParseException("Text cannot be parsed to a Period", text, 0, ex); } } } @@ -307,7 +339,7 @@ public final class Period try { return Math.multiplyExact(val, negate); } catch (ArithmeticException ex) { - throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Period", text, 0).initCause(ex); + throw new DateTimeParseException("Text cannot be parsed to a Period", text, 0, ex); } } @@ -329,10 +361,10 @@ public final class Period * @param startDate the start date, inclusive, not null * @param endDate the end date, exclusive, not null * @return the period between this date and the end date, not null - * @see ChronoLocalDate#periodUntil(ChronoLocalDate) + * @see ChronoLocalDate#until(ChronoLocalDate) */ public static Period between(LocalDate startDate, LocalDate endDate) { - return startDate.periodUntil(endDate); + return startDate.until(endDate); } //----------------------------------------------------------------------- @@ -386,7 +418,7 @@ public final class Period } else if (unit == ChronoUnit.DAYS) { return getDays(); } else { - throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName()); + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } } diff --git a/jdk/src/share/classes/java/time/Year.java b/jdk/src/share/classes/java/time/Year.java index c2d9974d79a..fb180d859cb 100644 --- a/jdk/src/share/classes/java/time/Year.java +++ b/jdk/src/share/classes/java/time/Year.java @@ -64,6 +64,10 @@ package java.time; import static java.time.temporal.ChronoField.ERA; import static java.time.temporal.ChronoField.YEAR; import static java.time.temporal.ChronoField.YEAR_OF_ERA; +import static java.time.temporal.ChronoUnit.CENTURIES; +import static java.time.temporal.ChronoUnit.DECADES; +import static java.time.temporal.ChronoUnit.ERAS; +import static java.time.temporal.ChronoUnit.MILLENNIA; import static java.time.temporal.ChronoUnit.YEARS; import java.io.DataInput; @@ -329,8 +333,9 @@ public final class Year * Checks if the specified field is supported. *

* This checks if this year can be queried for the specified field. - * If false, then calling the {@link #range(TemporalField) range} and - * {@link #get(TemporalField) get} methods will throw an exception. + * If false, then calling the {@link #range(TemporalField) range}, + * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)} + * methods will throw an exception. *

* If the field is a {@link ChronoField} then the query is implemented here. * The supported fields are: @@ -357,6 +362,41 @@ public final class Year return field != null && field.isSupportedBy(this); } + /** + * Checks if the specified unit is supported. + *

+ * This checks if the specified unit can be added to, or subtracted from, this date-time. + * If false, then calling the {@link #plus(long, TemporalUnit)} and + * {@link #minus(long, TemporalUnit) minus} methods will throw an exception. + *

+ * If the unit is a {@link ChronoUnit} then the query is implemented here. + * The supported units are: + *

+ * All other {@code ChronoUnit} instances will return false. + *

+ * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)} + * passing {@code this} as the argument. + * Whether the unit is supported is determined by the unit. + * + * @param unit the unit to check, null returns false + * @return true if the unit can be added/subtracted, false if not + */ + @Override + public boolean isSupported(TemporalUnit unit) { + if (unit instanceof ChronoUnit) { + return unit == YEARS || unit == DECADES || unit == CENTURIES || unit == MILLENNIA || unit == ERAS; + } + return unit != null && unit.isSupportedBy(this); + } + + //----------------------------------------------------------------------- /** * Gets the range of valid values for the specified field. *

@@ -450,7 +490,7 @@ public final class Year case YEAR: return year; case ERA: return (year < 1 ? 0 : 1); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.getFrom(this); } @@ -575,7 +615,7 @@ public final class Year case YEAR: return Year.of((int) newValue); case ERA: return (getLong(ERA) == newValue ? this : Year.of(1 - year)); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.adjustInto(this, newValue); } @@ -664,7 +704,7 @@ public final class Year case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000)); case ERAS: return with(ERA, Math.addExact(getLong(ERA), amountToAdd)); } - throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName()); + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } return unit.addTo(this, amountToAdd); } @@ -821,7 +861,7 @@ public final class Year * The result will be negative if the end is before the start. * The {@code Temporal} passed to this method must be a {@code Year}. * For example, the period in decades between two year can be calculated - * using {@code startYear.periodUntil(endYear, DECADES)}. + * using {@code startYear.until(endYear, DECADES)}. *

* The calculation returns a whole number, representing the number of * complete units between the two years. @@ -833,7 +873,7 @@ public final class Year * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}: *

      *   // these two lines are equivalent
-     *   amount = start.periodUntil(end, YEARS);
+     *   amount = start.until(end, YEARS);
      *   amount = YEARS.between(start, end);
      * 
* The choice should be made based on which makes the code more readable. @@ -858,7 +898,7 @@ public final class Year * @throws ArithmeticException if numeric overflow occurs */ @Override - public long periodUntil(Temporal endYear, TemporalUnit unit) { + public long until(Temporal endYear, TemporalUnit unit) { if (endYear instanceof Year == false) { Objects.requireNonNull(endYear, "endYear"); throw new DateTimeException("Unable to calculate amount as objects are of two different types"); @@ -873,7 +913,7 @@ public final class Year case MILLENNIA: return yearsUntil / 1000; case ERAS: return end.getLong(ERA) - getLong(ERA); } - throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName()); + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } return unit.between(this, endYear); } diff --git a/jdk/src/share/classes/java/time/YearMonth.java b/jdk/src/share/classes/java/time/YearMonth.java index 855774eed1a..1d974095336 100644 --- a/jdk/src/share/classes/java/time/YearMonth.java +++ b/jdk/src/share/classes/java/time/YearMonth.java @@ -66,7 +66,12 @@ import static java.time.temporal.ChronoField.MONTH_OF_YEAR; import static java.time.temporal.ChronoField.PROLEPTIC_MONTH; import static java.time.temporal.ChronoField.YEAR; import static java.time.temporal.ChronoField.YEAR_OF_ERA; +import static java.time.temporal.ChronoUnit.CENTURIES; +import static java.time.temporal.ChronoUnit.DECADES; +import static java.time.temporal.ChronoUnit.ERAS; +import static java.time.temporal.ChronoUnit.MILLENNIA; import static java.time.temporal.ChronoUnit.MONTHS; +import static java.time.temporal.ChronoUnit.YEARS; import java.io.DataInput; import java.io.DataOutput; @@ -313,8 +318,9 @@ public final class YearMonth * Checks if the specified field is supported. *

* This checks if this year-month can be queried for the specified field. - * If false, then calling the {@link #range(TemporalField) range} and - * {@link #get(TemporalField) get} methods will throw an exception. + * If false, then calling the {@link #range(TemporalField) range}, + * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)} + * methods will throw an exception. *

* If the field is a {@link ChronoField} then the query is implemented here. * The supported fields are: @@ -344,6 +350,42 @@ public final class YearMonth return field != null && field.isSupportedBy(this); } + /** + * Checks if the specified unit is supported. + *

+ * This checks if the specified unit can be added to, or subtracted from, this date-time. + * If false, then calling the {@link #plus(long, TemporalUnit)} and + * {@link #minus(long, TemporalUnit) minus} methods will throw an exception. + *

+ * If the unit is a {@link ChronoUnit} then the query is implemented here. + * The supported units are: + *

+ * All other {@code ChronoUnit} instances will return false. + *

+ * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)} + * passing {@code this} as the argument. + * Whether the unit is supported is determined by the unit. + * + * @param unit the unit to check, null returns false + * @return true if the unit can be added/subtracted, false if not + */ + @Override + public boolean isSupported(TemporalUnit unit) { + if (unit instanceof ChronoUnit) { + return unit == MONTHS || unit == YEARS || unit == DECADES || unit == CENTURIES || unit == MILLENNIA || unit == ERAS; + } + return unit != null && unit.isSupportedBy(this); + } + + //----------------------------------------------------------------------- /** * Gets the range of valid values for the specified field. *

@@ -440,7 +482,7 @@ public final class YearMonth case YEAR: return year; case ERA: return (year < 1 ? 0 : 1); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.getFrom(this); } @@ -639,7 +681,7 @@ public final class YearMonth case YEAR: return withYear((int) newValue); case ERA: return (getLong(ERA) == newValue ? this : withYear(1 - year)); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.adjustInto(this, newValue); } @@ -761,7 +803,7 @@ public final class YearMonth case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000)); case ERAS: return with(ERA, Math.addExact(getLong(ERA), amountToAdd)); } - throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName()); + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } return unit.addTo(this, amountToAdd); } @@ -952,7 +994,7 @@ public final class YearMonth * The result will be negative if the end is before the start. * The {@code Temporal} passed to this method must be a {@code YearMonth}. * For example, the period in years between two year-months can be calculated - * using {@code startYearMonth.periodUntil(endYearMonth, YEARS)}. + * using {@code startYearMonth.until(endYearMonth, YEARS)}. *

* The calculation returns a whole number, representing the number of * complete units between the two year-months. @@ -964,7 +1006,7 @@ public final class YearMonth * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}: *

      *   // these two lines are equivalent
-     *   amount = start.periodUntil(end, MONTHS);
+     *   amount = start.until(end, MONTHS);
      *   amount = MONTHS.between(start, end);
      * 
* The choice should be made based on which makes the code more readable. @@ -989,7 +1031,7 @@ public final class YearMonth * @throws ArithmeticException if numeric overflow occurs */ @Override - public long periodUntil(Temporal endYearMonth, TemporalUnit unit) { + public long until(Temporal endYearMonth, TemporalUnit unit) { if (endYearMonth instanceof YearMonth == false) { Objects.requireNonNull(endYearMonth, "endYearMonth"); throw new DateTimeException("Unable to calculate amount as objects are of two different types"); @@ -1005,7 +1047,7 @@ public final class YearMonth case MILLENNIA: return monthsUntil / 12000; case ERAS: return end.getLong(ERA) - getLong(ERA); } - throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName()); + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } return unit.between(this, endYearMonth); } diff --git a/jdk/src/share/classes/java/time/ZoneId.java b/jdk/src/share/classes/java/time/ZoneId.java index 026f73ef512..dcde85ae884 100644 --- a/jdk/src/share/classes/java/time/ZoneId.java +++ b/jdk/src/share/classes/java/time/ZoneId.java @@ -400,6 +400,36 @@ public abstract class ZoneId implements Serializable { return of(zoneId, true); } + /** + * Obtains an instance of {@code ZoneId} wrapping an offset. + *

+ * If the prefix is "GMT", "UTC", or "UT" a {@code ZoneId} + * with the prefix and the non-zero offset is returned. + * If the prefix is empty {@code ""} the {@code ZoneOffset} is returned. + * + * @param prefix the time-zone ID, not null + * @param offset the offset, not null + * @return the zone ID, not null + * @throws IllegalArgumentException if the prefix is not one of + * "GMT", "UTC", or "UT", or "" + */ + public static ZoneId ofOffset(String prefix, ZoneOffset offset) { + Objects.requireNonNull(prefix, "prefix"); + Objects.requireNonNull(offset, "offset"); + if (prefix.length() == 0) { + return offset; + } + + if (!prefix.equals("GMT") && !prefix.equals("UTC") && !prefix.equals("UT")) { + throw new IllegalArgumentException("prefix should be GMT, UTC or UT, is: " + prefix); + } + + if (offset.getTotalSeconds() != 0) { + prefix = prefix.concat(offset.getId()); + } + return new ZoneRegion(prefix, offset.getRules()); + } + /** * Parses the ID, taking a flag to indicate whether {@code ZoneRulesException} * should be thrown or not, used in deserialization. @@ -433,7 +463,7 @@ public abstract class ZoneId implements Serializable { private static ZoneId ofWithPrefix(String zoneId, int prefixLength, boolean checkAvailable) { String prefix = zoneId.substring(0, prefixLength); if (zoneId.length() == prefixLength) { - return ZoneRegion.ofPrefixedOffset(prefix, ZoneOffset.UTC); + return ofOffset(prefix, ZoneOffset.UTC); } if (zoneId.charAt(prefixLength) != '+' && zoneId.charAt(prefixLength) != '-') { return ZoneRegion.ofId(zoneId, checkAvailable); // drop through to ZoneRulesProvider @@ -441,9 +471,9 @@ public abstract class ZoneId implements Serializable { try { ZoneOffset offset = ZoneOffset.of(zoneId.substring(prefixLength)); if (offset == ZoneOffset.UTC) { - return ZoneRegion.ofPrefixedOffset(prefix, offset); + return ofOffset(prefix, offset); } - return ZoneRegion.ofPrefixedOffset(prefix + offset.toString(), offset); + return ofOffset(prefix, offset); } catch (DateTimeException ex) { throw new DateTimeException("Invalid ID for offset-based ZoneId: " + zoneId, ex); } diff --git a/jdk/src/share/classes/java/time/ZoneOffset.java b/jdk/src/share/classes/java/time/ZoneOffset.java index 4bbc4e4fa84..c5e4d056ee8 100644 --- a/jdk/src/share/classes/java/time/ZoneOffset.java +++ b/jdk/src/share/classes/java/time/ZoneOffset.java @@ -61,7 +61,6 @@ */ package java.time; -import java.time.temporal.UnsupportedTemporalTypeException; import static java.time.LocalTime.MINUTES_PER_HOUR; import static java.time.LocalTime.SECONDS_PER_HOUR; import static java.time.LocalTime.SECONDS_PER_MINUTE; @@ -79,6 +78,7 @@ import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalAdjuster; import java.time.temporal.TemporalField; import java.time.temporal.TemporalQuery; +import java.time.temporal.UnsupportedTemporalTypeException; import java.time.temporal.ValueRange; import java.time.zone.ZoneRules; import java.util.Objects; @@ -581,7 +581,7 @@ public final class ZoneOffset if (field == OFFSET_SECONDS) { return totalSeconds; } else if (field instanceof ChronoField) { - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return range(field).checkValidIntValue(getLong(field), field); } @@ -613,7 +613,7 @@ public final class ZoneOffset if (field == OFFSET_SECONDS) { return totalSeconds; } else if (field instanceof ChronoField) { - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.getFrom(this); } diff --git a/jdk/src/share/classes/java/time/ZoneRegion.java b/jdk/src/share/classes/java/time/ZoneRegion.java index af6a5405a69..66d30709d98 100644 --- a/jdk/src/share/classes/java/time/ZoneRegion.java +++ b/jdk/src/share/classes/java/time/ZoneRegion.java @@ -66,7 +66,6 @@ import java.time.zone.ZoneRules; import java.time.zone.ZoneRulesException; import java.time.zone.ZoneRulesProvider; import java.util.Objects; -import java.util.regex.Pattern; /** * A geographical region where the same time-zone rules apply. @@ -153,19 +152,6 @@ final class ZoneRegion extends ZoneId implements Serializable { } } - /** - * Obtains an instance of {@code ZoneId} wrapping an offset. - *

- * For example, zone IDs like 'UTC', 'GMT', 'UT' and 'UTC+01:30' will be setup here. - * - * @param zoneId the time-zone ID, not null - * @param offset the offset, not null - * @return the zone ID, not null - */ - static ZoneRegion ofPrefixedOffset(String zoneId, ZoneOffset offset) { - return new ZoneRegion(zoneId, offset.getRules()); - } - //------------------------------------------------------------------------- /** * Constructor. diff --git a/jdk/src/share/classes/java/time/ZonedDateTime.java b/jdk/src/share/classes/java/time/ZonedDateTime.java index e7ed5551d33..151470ecf93 100644 --- a/jdk/src/share/classes/java/time/ZonedDateTime.java +++ b/jdk/src/share/classes/java/time/ZonedDateTime.java @@ -642,8 +642,9 @@ public final class ZonedDateTime * Checks if the specified field is supported. *

* This checks if this date-time can be queried for the specified field. - * If false, then calling the {@link #range(TemporalField) range} and - * {@link #get(TemporalField) get} methods will throw an exception. + * If false, then calling the {@link #range(TemporalField) range}, + * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)} + * methods will throw an exception. *

* If the field is a {@link ChronoField} then the query is implemented here. * The supported fields are: @@ -694,6 +695,48 @@ public final class ZonedDateTime return field instanceof ChronoField || (field != null && field.isSupportedBy(this)); } + /** + * Checks if the specified unit is supported. + *

+ * This checks if the specified unit can be added to, or subtracted from, this date-time. + * If false, then calling the {@link #plus(long, TemporalUnit)} and + * {@link #minus(long, TemporalUnit) minus} methods will throw an exception. + *

+ * If the unit is a {@link ChronoUnit} then the query is implemented here. + * The supported units are: + *

+ * All other {@code ChronoUnit} instances will return false. + *

+ * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)} + * passing {@code this} as the argument. + * Whether the unit is supported is determined by the unit. + * + * @param unit the unit to check, null returns false + * @return true if the unit can be added/subtracted, false if not + */ + @Override // override for Javadoc + public boolean isSupported(TemporalUnit unit) { + return ChronoZonedDateTime.super.isSupported(unit); + } + + //----------------------------------------------------------------------- /** * Gets the range of valid values for the specified field. *

@@ -1540,8 +1583,7 @@ public final class ZonedDateTime @Override public ZonedDateTime plus(long amountToAdd, TemporalUnit unit) { if (unit instanceof ChronoUnit) { - ChronoUnit u = (ChronoUnit) unit; - if (u.isDateUnit()) { + if (unit.isDateBased()) { return resolveLocal(dateTime.plus(amountToAdd, unit)); } else { return resolveInstant(dateTime.plus(amountToAdd, unit)); @@ -1990,7 +2032,7 @@ public final class ZonedDateTime * 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. * For example, the period in days between two date-times can be calculated - * using {@code startDateTime.periodUntil(endDateTime, DAYS)}. + * using {@code startDateTime.until(endDateTime, DAYS)}. *

* The {@code Temporal} passed to this method must be a {@code ZonedDateTime}. * If the time-zone differs between the two zoned date-times, the specified @@ -2006,7 +2048,7 @@ public final class ZonedDateTime * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}: *

      *   // these two lines are equivalent
-     *   amount = start.periodUntil(end, MONTHS);
+     *   amount = start.until(end, MONTHS);
      *   amount = MONTHS.between(start, end);
      * 
* The choice should be made based on which makes the code more readable. @@ -2047,7 +2089,7 @@ public final class ZonedDateTime * @throws ArithmeticException if numeric overflow occurs */ @Override - public long periodUntil(Temporal endDateTime, TemporalUnit unit) { + public long until(Temporal endDateTime, TemporalUnit unit) { if (endDateTime instanceof ZonedDateTime == false) { Objects.requireNonNull(endDateTime, "endDateTime"); throw new DateTimeException("Unable to calculate amount as objects are of two different types"); @@ -2055,11 +2097,10 @@ public final class ZonedDateTime if (unit instanceof ChronoUnit) { ZonedDateTime end = (ZonedDateTime) endDateTime; end = end.withZoneSameInstant(zone); - ChronoUnit u = (ChronoUnit) unit; - if (u.isDateUnit()) { - return dateTime.periodUntil(end.dateTime, unit); + if (unit.isDateBased()) { + return dateTime.until(end.dateTime, unit); } else { - return toOffsetDateTime().periodUntil(end.toOffsetDateTime(), unit); + return toOffsetDateTime().until(end.toOffsetDateTime(), unit); } } return unit.between(this, endDateTime); diff --git a/jdk/src/share/classes/java/time/chrono/ChronoDateImpl.java b/jdk/src/share/classes/java/time/chrono/ChronoDateImpl.java index 14e2bf58f2a..99ba58f05b9 100644 --- a/jdk/src/share/classes/java/time/chrono/ChronoDateImpl.java +++ b/jdk/src/share/classes/java/time/chrono/ChronoDateImpl.java @@ -67,6 +67,8 @@ import java.time.DateTimeException; import java.time.temporal.ChronoUnit; import java.time.temporal.Temporal; import java.time.temporal.TemporalAdjuster; +import java.time.temporal.TemporalAmount; +import java.time.temporal.TemporalField; import java.time.temporal.TemporalUnit; import java.time.temporal.UnsupportedTemporalTypeException; import java.time.temporal.ValueRange; @@ -96,12 +98,12 @@ import java.util.Objects; * // Enumerate the list of available calendars and print today for each * Set<Chronology> chronos = Chronology.getAvailableChronologies(); * for (Chronology chrono : chronos) { - * ChronoLocalDate<?> date = chrono.dateNow(); + * ChronoLocalDate date = chrono.dateNow(); * System.out.printf(" %20s: %s%n", chrono.getID(), date.toString()); * } * * // Print the Hijrah date and calendar - * ChronoLocalDate<?> date = Chronology.of("Hijrah").dateNow(); + * ChronoLocalDate date = Chronology.of("Hijrah").dateNow(); * int day = date.get(ChronoField.DAY_OF_MONTH); * int dow = date.get(ChronoField.DAY_OF_WEEK); * int month = date.get(ChronoField.MONTH_OF_YEAR); @@ -110,10 +112,10 @@ import java.util.Objects; * dow, day, month, year); * // Print today's date and the last day of the year - * ChronoLocalDate<?> now1 = Chronology.of("Hijrah").dateNow(); - * ChronoLocalDate<?> first = now1.with(ChronoField.DAY_OF_MONTH, 1) + * ChronoLocalDate now1 = Chronology.of("Hijrah").dateNow(); + * ChronoLocalDate first = now1.with(ChronoField.DAY_OF_MONTH, 1) * .with(ChronoField.MONTH_OF_YEAR, 1); - * ChronoLocalDate<?> last = first.plus(1, ChronoUnit.YEARS) + * ChronoLocalDate last = first.plus(1, ChronoUnit.YEARS) * .minus(1, ChronoUnit.DAYS); * System.out.printf(" Today is %s: start: %s; end: %s%n", last.getChronology().getID(), * first, last); @@ -138,22 +140,61 @@ import java.util.Objects; * @param the ChronoLocalDate of this date-time * @since 1.8 */ -abstract class ChronoDateImpl> - implements ChronoLocalDate, Temporal, TemporalAdjuster, Serializable { +abstract class ChronoDateImpl + implements ChronoLocalDate, Temporal, TemporalAdjuster, Serializable { /** * Serialization version. */ private static final long serialVersionUID = 6282433883239719096L; + /** + * Casts the {@code Temporal} to {@code ChronoLocalDate} ensuring it bas the specified chronology. + * + * @param chrono the chronology to check for, not null + * @param temporal a date-time to cast, not null + * @return the date-time checked and cast to {@code ChronoLocalDate}, not null + * @throws ClassCastException if the date-time cannot be cast to ChronoLocalDate + * or the chronology is not equal this Chronology + */ + static D ensureValid(Chronology chrono, Temporal temporal) { + @SuppressWarnings("unchecked") + D other = (D) temporal; + if (chrono.equals(other.getChronology()) == false) { + throw new ClassCastException("Chronology mismatch, expected: " + chrono.getId() + ", actual: " + other.getChronology().getId()); + } + return other; + } + + //----------------------------------------------------------------------- /** * Creates an instance. */ ChronoDateImpl() { } + @Override + @SuppressWarnings("unchecked") + public D with(TemporalAdjuster adjuster) { + return (D) ChronoLocalDate.super.with(adjuster); + } + + @Override + @SuppressWarnings("unchecked") + public D with(TemporalField field, long value) { + return (D) ChronoLocalDate.super.with(field, value); + } + //----------------------------------------------------------------------- @Override + @SuppressWarnings("unchecked") + public D plus(TemporalAmount amount) { + return (D) ChronoLocalDate.super.plus(amount); + } + + //----------------------------------------------------------------------- + @Override + @SuppressWarnings("unchecked") public D plus(long amountToAdd, TemporalUnit unit) { if (unit instanceof ChronoUnit) { ChronoUnit f = (ChronoUnit) unit; @@ -167,9 +208,21 @@ abstract class ChronoDateImpl> case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000)); case ERAS: return with(ERA, Math.addExact(getLong(ERA), amountToAdd)); } - throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName()); + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } - return ChronoLocalDate.super.plus(amountToAdd, unit); + return (D) ChronoLocalDate.super.plus(amountToAdd, unit); + } + + @Override + @SuppressWarnings("unchecked") + public D minus(TemporalAmount amount) { + return (D) ChronoLocalDate.super.minus(amount); + } + + @Override + @SuppressWarnings("unchecked") + public D minus(long amountToSubtract, TemporalUnit unit) { + return (D) ChronoLocalDate.super.minus(amountToSubtract, unit); } //----------------------------------------------------------------------- @@ -254,6 +307,7 @@ abstract class ChronoDateImpl> * @return a date based on this one with the years subtracted, not null * @throws DateTimeException if the result exceeds the supported date range */ + @SuppressWarnings("unchecked") D minusYears(long yearsToSubtract) { return (yearsToSubtract == Long.MIN_VALUE ? ((ChronoDateImpl)plusYears(Long.MAX_VALUE)).plusYears(1) : plusYears(-yearsToSubtract)); } @@ -274,6 +328,7 @@ abstract class ChronoDateImpl> * @return a date based on this one with the months subtracted, not null * @throws DateTimeException if the result exceeds the supported date range */ + @SuppressWarnings("unchecked") D minusMonths(long monthsToSubtract) { return (monthsToSubtract == Long.MIN_VALUE ? ((ChronoDateImpl)plusMonths(Long.MAX_VALUE)).plusMonths(1) : plusMonths(-monthsToSubtract)); } @@ -293,6 +348,7 @@ abstract class ChronoDateImpl> * @return a date based on this one with the weeks subtracted, not null * @throws DateTimeException if the result exceeds the supported date range */ + @SuppressWarnings("unchecked") D minusWeeks(long weeksToSubtract) { return (weeksToSubtract == Long.MIN_VALUE ? ((ChronoDateImpl)plusWeeks(Long.MAX_VALUE)).plusWeeks(1) : plusWeeks(-weeksToSubtract)); } @@ -310,6 +366,7 @@ abstract class ChronoDateImpl> * @return a date based on this one with the days subtracted, not null * @throws DateTimeException if the result exceeds the supported date range */ + @SuppressWarnings("unchecked") D minusDays(long daysToSubtract) { return (daysToSubtract == Long.MIN_VALUE ? ((ChronoDateImpl)plusDays(Long.MAX_VALUE)).plusDays(1) : plusDays(-daysToSubtract)); } @@ -321,13 +378,13 @@ abstract class ChronoDateImpl> * @throws ArithmeticException {@inheritDoc} */ @Override - public long periodUntil(Temporal endDateTime, TemporalUnit unit) { + public long until(Temporal endDateTime, TemporalUnit unit) { Objects.requireNonNull(endDateTime, "endDateTime"); Objects.requireNonNull(unit, "unit"); if (endDateTime instanceof ChronoLocalDate == false) { 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) { throw new DateTimeException("Unable to calculate amount as objects have different chronologies"); } @@ -342,16 +399,16 @@ abstract class ChronoDateImpl> case MILLENNIA: return monthsUntil(end) / 12000; case ERAS: return end.getLong(ERA) - getLong(ERA); } - throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName()); + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } return unit.between(this, endDateTime); } - private long daysUntil(ChronoLocalDate end) { + private long daysUntil(ChronoLocalDate end) { return end.toEpochDay() - toEpochDay(); // no overflow } - private long monthsUntil(ChronoLocalDate end) { + private long monthsUntil(ChronoLocalDate end) { ValueRange range = getChronology().range(MONTH_OF_YEAR); if (range.getMaximum() != 12) { throw new IllegalStateException("ChronoDateImpl only supports Chronologies with 12 months per year"); @@ -367,7 +424,7 @@ abstract class ChronoDateImpl> return true; } if (obj instanceof ChronoLocalDate) { - return compareTo((ChronoLocalDate) obj) == 0; + return compareTo((ChronoLocalDate) obj) == 0; } return false; } diff --git a/jdk/src/share/classes/java/time/chrono/ChronoLocalDate.java b/jdk/src/share/classes/java/time/chrono/ChronoLocalDate.java index 31c08260d6e..923e8960b0f 100644 --- a/jdk/src/share/classes/java/time/chrono/ChronoLocalDate.java +++ b/jdk/src/share/classes/java/time/chrono/ChronoLocalDate.java @@ -242,11 +242,10 @@ import java.util.Objects; * Additional calendar systems may be added to the system. * See {@link Chronology} for more details. * - * @param the concrete type for the date * @since 1.8 */ -public interface ChronoLocalDate> - extends Temporal, TemporalAdjuster, Comparable> { +public interface ChronoLocalDate + extends Temporal, TemporalAdjuster, Comparable { /** * Gets a comparator that compares {@code ChronoLocalDate} in @@ -263,7 +262,7 @@ public interface ChronoLocalDate> * @see #isBefore * @see #isEqual */ - static Comparator> timeLineOrder() { + static Comparator timeLineOrder() { return Chronology.DATE_ORDER; } @@ -289,9 +288,9 @@ public interface ChronoLocalDate> * @throws DateTimeException if unable to convert to a {@code ChronoLocalDate} * @see Chronology#date(TemporalAccessor) */ - static ChronoLocalDate from(TemporalAccessor temporal) { + static ChronoLocalDate from(TemporalAccessor temporal) { if (temporal instanceof ChronoLocalDate) { - return (ChronoLocalDate) temporal; + return (ChronoLocalDate) temporal; } Chronology chrono = temporal.query(TemporalQuery.chronology()); if (chrono == null) { @@ -367,6 +366,25 @@ public interface ChronoLocalDate> return (isLeapYear() ? 366 : 365); } + /** + * Checks if the specified field is supported. + *

+ * This checks if the specified field can be queried on this date. + * If false, then calling the {@link #range(TemporalField) range}, + * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)} + * methods will throw an exception. + *

+ * The set of supported fields is defined by the chronology and normally includes + * all {@code ChronoField} date fields. + *

+ * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)} + * passing {@code this} as the argument. + * Whether the field is supported is determined by the field. + * + * @param field the field to check, null returns false + * @return true if the field can be queried, false if not + */ @Override default boolean isSupported(TemporalField field) { if (field instanceof ChronoField) { @@ -375,6 +393,32 @@ public interface ChronoLocalDate> return field != null && field.isSupportedBy(this); } + /** + * Checks if the specified unit is supported. + *

+ * This checks if the specified unit can be added to or subtracted from this date. + * If false, then calling the {@link #plus(long, TemporalUnit)} and + * {@link #minus(long, TemporalUnit) minus} methods will throw an exception. + *

+ * The set of supported units is defined by the chronology and normally includes + * all {@code ChronoUnit} date units except {@code FOREVER}. + *

+ * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)} + * passing {@code this} as the argument. + * Whether the unit is supported is determined by the unit. + * + * @param unit the unit to check, null returns false + * @return true if the unit can be added/subtracted, false if not + */ + @Override + default boolean isSupported(TemporalUnit unit) { + if (unit instanceof ChronoUnit) { + return unit.isDateBased(); + } + return unit != null && unit.isSupportedBy(this); + } + //----------------------------------------------------------------------- // override for covariant return type /** @@ -383,8 +427,8 @@ public interface ChronoLocalDate> * @throws ArithmeticException {@inheritDoc} */ @Override - default D with(TemporalAdjuster adjuster) { - return (D) getChronology().ensureChronoLocalDate(Temporal.super.with(adjuster)); + default ChronoLocalDate with(TemporalAdjuster adjuster) { + return ChronoDateImpl.ensureValid(getChronology(), Temporal.super.with(adjuster)); } /** @@ -394,11 +438,11 @@ public interface ChronoLocalDate> * @throws ArithmeticException {@inheritDoc} */ @Override - default D with(TemporalField field, long newValue) { + default ChronoLocalDate with(TemporalField field, long newValue) { if (field instanceof ChronoField) { - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } - return (D) getChronology().ensureChronoLocalDate(field.adjustInto(this, newValue)); + return ChronoDateImpl.ensureValid(getChronology(), field.adjustInto(this, newValue)); } /** @@ -407,8 +451,8 @@ public interface ChronoLocalDate> * @throws ArithmeticException {@inheritDoc} */ @Override - default D plus(TemporalAmount amount) { - return (D) getChronology().ensureChronoLocalDate(Temporal.super.plus(amount)); + default ChronoLocalDate plus(TemporalAmount amount) { + return ChronoDateImpl.ensureValid(getChronology(), Temporal.super.plus(amount)); } /** @@ -417,11 +461,11 @@ public interface ChronoLocalDate> * @throws ArithmeticException {@inheritDoc} */ @Override - default D plus(long amountToAdd, TemporalUnit unit) { + default ChronoLocalDate plus(long amountToAdd, TemporalUnit unit) { if (unit instanceof ChronoUnit) { - throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName()); + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } - return (D) getChronology().ensureChronoLocalDate(unit.addTo(this, amountToAdd)); + return ChronoDateImpl.ensureValid(getChronology(), unit.addTo(this, amountToAdd)); } /** @@ -430,8 +474,8 @@ public interface ChronoLocalDate> * @throws ArithmeticException {@inheritDoc} */ @Override - default D minus(TemporalAmount amount) { - return (D) getChronology().ensureChronoLocalDate(Temporal.super.minus(amount)); + default ChronoLocalDate minus(TemporalAmount amount) { + return ChronoDateImpl.ensureValid(getChronology(), Temporal.super.minus(amount)); } /** @@ -441,8 +485,8 @@ public interface ChronoLocalDate> * @throws ArithmeticException {@inheritDoc} */ @Override - default D minus(long amountToSubtract, TemporalUnit unit) { - return (D) getChronology().ensureChronoLocalDate(Temporal.super.minus(amountToSubtract, unit)); + default ChronoLocalDate minus(long amountToSubtract, TemporalUnit unit) { + return ChronoDateImpl.ensureValid(getChronology(), Temporal.super.minus(amountToSubtract, unit)); } //----------------------------------------------------------------------- @@ -522,14 +566,14 @@ public interface ChronoLocalDate> * The calculation returns a whole number, representing the number of * complete units between the two dates. * For example, the amount in days between two dates can be calculated - * using {@code startDate.periodUntil(endDate, DAYS)}. + * using {@code startDate.until(endDate, DAYS)}. *

* There are two equivalent ways of using this method. * The first is to invoke this method. * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}: *

      *   // these two lines are equivalent
-     *   amount = start.periodUntil(end, MONTHS);
+     *   amount = start.until(end, MONTHS);
      *   amount = MONTHS.between(start, end);
      * 
* The choice should be made based on which makes the code more readable. @@ -555,7 +599,7 @@ public interface ChronoLocalDate> * @throws ArithmeticException if numeric overflow occurs */ @Override // override for Javadoc - long periodUntil(Temporal endDate, TemporalUnit unit); + long until(Temporal endDate, TemporalUnit unit); /** * Calculates the period between this date and another date as a {@code Period}. @@ -575,7 +619,7 @@ public interface ChronoLocalDate> * @throws DateTimeException if the period cannot be calculated * @throws ArithmeticException if numeric overflow occurs */ - Period periodUntil(ChronoLocalDate endDate); + Period until(ChronoLocalDate endDate); /** * Formats this date using the specified formatter. @@ -606,8 +650,9 @@ public interface ChronoLocalDate> * @param localTime the local time to use, not null * @return the local date-time formed from this date and the specified time, not null */ - default ChronoLocalDateTime atTime(LocalTime localTime) { - return (ChronoLocalDateTime)ChronoLocalDateTimeImpl.of(this, localTime); + @SuppressWarnings("unchecked") + default ChronoLocalDateTime atTime(LocalTime localTime) { + return ChronoLocalDateTimeImpl.of(this, localTime); } //----------------------------------------------------------------------- @@ -656,7 +701,7 @@ public interface ChronoLocalDate> * @return the comparator value, negative if less, positive if greater */ @Override - default int compareTo(ChronoLocalDate other) { + default int compareTo(ChronoLocalDate other) { int cmp = Long.compare(toEpochDay(), other.toEpochDay()); if (cmp == 0) { cmp = getChronology().compareTo(other.getChronology()); @@ -678,7 +723,7 @@ public interface ChronoLocalDate> * @param other the other date to compare to, not null * @return true if this is after the specified date */ - default boolean isAfter(ChronoLocalDate other) { + default boolean isAfter(ChronoLocalDate other) { return this.toEpochDay() > other.toEpochDay(); } @@ -696,7 +741,7 @@ public interface ChronoLocalDate> * @param other the other date to compare to, not null * @return true if this is before the specified date */ - default boolean isBefore(ChronoLocalDate other) { + default boolean isBefore(ChronoLocalDate other) { return this.toEpochDay() < other.toEpochDay(); } @@ -714,7 +759,7 @@ public interface ChronoLocalDate> * @param other the other date to compare to, not null * @return true if the underlying date is equal to the specified date */ - default boolean isEqual(ChronoLocalDate other) { + default boolean isEqual(ChronoLocalDate other) { return this.toEpochDay() == other.toEpochDay(); } diff --git a/jdk/src/share/classes/java/time/chrono/ChronoLocalDateTime.java b/jdk/src/share/classes/java/time/chrono/ChronoLocalDateTime.java index f0a893a4c95..be93f0e036a 100644 --- a/jdk/src/share/classes/java/time/chrono/ChronoLocalDateTime.java +++ b/jdk/src/share/classes/java/time/chrono/ChronoLocalDateTime.java @@ -63,6 +63,7 @@ package java.time.chrono; import static java.time.temporal.ChronoField.EPOCH_DAY; import static java.time.temporal.ChronoField.NANO_OF_DAY; +import static java.time.temporal.ChronoUnit.FOREVER; import static java.time.temporal.ChronoUnit.NANOS; import java.time.DateTimeException; @@ -73,6 +74,7 @@ import java.time.ZoneId; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoField; +import java.time.temporal.ChronoUnit; import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalAdjuster; @@ -114,7 +116,7 @@ import java.util.Objects; * @param the concrete type for the date of this date-time * @since 1.8 */ -public interface ChronoLocalDateTime> +public interface ChronoLocalDateTime extends Temporal, TemporalAdjuster, Comparable> { /** @@ -191,9 +193,54 @@ public interface ChronoLocalDateTime> */ LocalTime toLocalTime(); - @Override // Override to provide javadoc + /** + * Checks if the specified field is supported. + *

+ * This checks if the specified field can be queried on this date-time. + * If false, then calling the {@link #range(TemporalField) range}, + * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)} + * methods will throw an exception. + *

+ * The set of supported fields is defined by the chronology and normally includes + * all {@code ChronoField} date and time fields. + *

+ * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)} + * passing {@code this} as the argument. + * Whether the field is supported is determined by the field. + * + * @param field the field to check, null returns false + * @return true if the field can be queried, false if not + */ + @Override boolean isSupported(TemporalField field); + /** + * Checks if the specified unit is supported. + *

+ * This checks if the specified unit can be added to or subtracted from this date-time. + * If false, then calling the {@link #plus(long, TemporalUnit)} and + * {@link #minus(long, TemporalUnit) minus} methods will throw an exception. + *

+ * The set of supported units is defined by the chronology and normally includes + * all {@code ChronoUnit} units except {@code FOREVER}. + *

+ * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)} + * passing {@code this} as the argument. + * Whether the unit is supported is determined by the unit. + * + * @param unit the unit to check, null returns false + * @return true if the unit can be added/subtracted, false if not + */ + @Override + default boolean isSupported(TemporalUnit unit) { + if (unit instanceof ChronoUnit) { + return unit != FOREVER; + } + return unit != null && unit.isSupportedBy(this); + } + //----------------------------------------------------------------------- // override for covariant return type /** @@ -203,7 +250,7 @@ public interface ChronoLocalDateTime> */ @Override default ChronoLocalDateTime with(TemporalAdjuster adjuster) { - return (ChronoLocalDateTime)(toLocalDate().getChronology().ensureChronoLocalDateTime(Temporal.super.with(adjuster))); + return ChronoLocalDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.with(adjuster)); } /** @@ -221,7 +268,7 @@ public interface ChronoLocalDateTime> */ @Override default ChronoLocalDateTime plus(TemporalAmount amount) { - return (ChronoLocalDateTime)(toLocalDate().getChronology().ensureChronoLocalDateTime(Temporal.super.plus(amount))); + return ChronoLocalDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.plus(amount)); } /** @@ -239,7 +286,7 @@ public interface ChronoLocalDateTime> */ @Override default ChronoLocalDateTime minus(TemporalAmount amount) { - return (ChronoLocalDateTime)(toLocalDate().getChronology().ensureChronoLocalDateTime(Temporal.super.minus(amount))); + return ChronoLocalDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.minus(amount)); } /** @@ -249,7 +296,7 @@ public interface ChronoLocalDateTime> */ @Override default ChronoLocalDateTime minus(long amountToSubtract, TemporalUnit unit) { - return (ChronoLocalDateTime)(toLocalDate().getChronology().ensureChronoLocalDateTime(Temporal.super.minus(amountToSubtract, unit))); + return ChronoLocalDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.minus(amountToSubtract, unit)); } //----------------------------------------------------------------------- diff --git a/jdk/src/share/classes/java/time/chrono/ChronoLocalDateTimeImpl.java b/jdk/src/share/classes/java/time/chrono/ChronoLocalDateTimeImpl.java index 1f7195bc6f7..14f7bd927c2 100644 --- a/jdk/src/share/classes/java/time/chrono/ChronoLocalDateTimeImpl.java +++ b/jdk/src/share/classes/java/time/chrono/ChronoLocalDateTimeImpl.java @@ -98,7 +98,7 @@ import java.util.Objects; * @param the concrete type for the date of this date-time * @since 1.8 */ -final class ChronoLocalDateTimeImpl> +final class ChronoLocalDateTimeImpl implements ChronoLocalDateTime, Temporal, TemporalAdjuster, Serializable { /** @@ -171,9 +171,27 @@ final class ChronoLocalDateTimeImpl> * @param time the local time, not null * @return the local date-time, not null */ - @SuppressWarnings("rawtypes") - static ChronoLocalDateTimeImpl of(ChronoLocalDate date, LocalTime time) { - return new ChronoLocalDateTimeImpl(date, time); + static ChronoLocalDateTimeImpl of(R date, LocalTime time) { + return new ChronoLocalDateTimeImpl<>(date, time); + } + + /** + * Casts the {@code Temporal} to {@code ChronoLocalDateTime} ensuring it bas the specified chronology. + * + * @param chrono the chronology to check for, not null + * @param temporal a date-time to cast, not null + * @return the date-time checked and cast to {@code ChronoLocalDateTime}, not null + * @throws ClassCastException if the date-time cannot be cast to ChronoLocalDateTimeImpl + * or the chronology is not equal this Chronology + */ + static ChronoLocalDateTimeImpl ensureValid(Chronology chrono, Temporal temporal) { + @SuppressWarnings("unchecked") + ChronoLocalDateTimeImpl other = (ChronoLocalDateTimeImpl) temporal; + if (chrono.equals(other.toLocalDate().getChronology()) == false) { + throw new ClassCastException("Chronology mismatch, required: " + chrono.getId() + + ", actual: " + other.toLocalDate().getChronology().getId()); + } + return other; } /** @@ -202,7 +220,7 @@ final class ChronoLocalDateTimeImpl> return this; } // Validate that the new Temporal is a ChronoLocalDate (and not something else) - D cd = (D) date.getChronology().ensureChronoLocalDate(newDate); + D cd = ChronoDateImpl.ensureValid(date.getChronology(), newDate); return new ChronoLocalDateTimeImpl<>(cd, newTime); } @@ -260,13 +278,13 @@ final class ChronoLocalDateTimeImpl> public ChronoLocalDateTimeImpl with(TemporalAdjuster adjuster) { if (adjuster instanceof ChronoLocalDate) { // The Chronology is checked in with(date,time) - return with((ChronoLocalDate) adjuster, time); + return with((ChronoLocalDate) adjuster, time); } else if (adjuster instanceof LocalTime) { return with(date, (LocalTime) adjuster); } else if (adjuster instanceof ChronoLocalDateTimeImpl) { - return (ChronoLocalDateTimeImpl)(date.getChronology().ensureChronoLocalDateTime((ChronoLocalDateTimeImpl) adjuster)); + return ChronoLocalDateTimeImpl.ensureValid(date.getChronology(), (ChronoLocalDateTimeImpl) adjuster); } - return (ChronoLocalDateTimeImpl)(date.getChronology().ensureChronoLocalDateTime((ChronoLocalDateTimeImpl) adjuster.adjustInto(this))); + return ChronoLocalDateTimeImpl.ensureValid(date.getChronology(), (ChronoLocalDateTimeImpl) adjuster.adjustInto(this)); } @Override @@ -279,7 +297,7 @@ final class ChronoLocalDateTimeImpl> return with(date.with(field, newValue), time); } } - return (ChronoLocalDateTimeImpl)(date.getChronology().ensureChronoLocalDateTime(field.adjustInto(this, newValue))); + return ChronoLocalDateTimeImpl.ensureValid(date.getChronology(), field.adjustInto(this, newValue)); } //----------------------------------------------------------------------- @@ -298,7 +316,7 @@ final class ChronoLocalDateTimeImpl> } return with(date.plus(amountToAdd, unit), time); } - return (ChronoLocalDateTimeImpl)(date.getChronology().ensureChronoLocalDateTime(unit.addTo(this, amountToAdd))); + return ChronoLocalDateTimeImpl.ensureValid(date.getChronology(), unit.addTo(this, amountToAdd)); } private ChronoLocalDateTimeImpl plusDays(long days) { @@ -322,7 +340,7 @@ final class ChronoLocalDateTimeImpl> } //----------------------------------------------------------------------- - private ChronoLocalDateTimeImpl plusWithOverflow(ChronoLocalDate newDate, long hours, long minutes, long seconds, long nanos) { + private ChronoLocalDateTimeImpl plusWithOverflow(D newDate, long hours, long minutes, long seconds, long nanos) { // 9223372036854775808 long, 2147483648 int if ((hours | minutes | seconds | nanos) == 0) { return with(newDate, time); @@ -351,7 +369,7 @@ final class ChronoLocalDateTimeImpl> //----------------------------------------------------------------------- @Override - public long periodUntil(Temporal endDateTime, TemporalUnit unit) { + public long until(Temporal endDateTime, TemporalUnit unit) { if (endDateTime instanceof ChronoLocalDateTime == false) { throw new DateTimeException("Unable to calculate amount as objects are of two different types"); } @@ -361,10 +379,9 @@ final class ChronoLocalDateTimeImpl> throw new DateTimeException("Unable to calculate amount as objects have different chronologies"); } if (unit instanceof ChronoUnit) { - ChronoUnit f = (ChronoUnit) unit; - if (f.isTimeUnit()) { + if (unit.isTimeBased()) { long amount = end.getLong(EPOCH_DAY) - date.getLong(EPOCH_DAY); - switch (f) { + switch ((ChronoUnit) unit) { case NANOS: amount = Math.multiplyExact(amount, NANOS_PER_DAY); break; case MICROS: amount = Math.multiplyExact(amount, MICROS_PER_DAY); break; case MILLIS: amount = Math.multiplyExact(amount, MILLIS_PER_DAY); break; @@ -373,13 +390,13 @@ final class ChronoLocalDateTimeImpl> case HOURS: amount = Math.multiplyExact(amount, HOURS_PER_DAY); break; case HALF_DAYS: amount = Math.multiplyExact(amount, 2); break; } - return Math.addExact(amount, time.periodUntil(end.toLocalTime(), unit)); + return Math.addExact(amount, time.until(end.toLocalTime(), unit)); } - D endDate = end.toLocalDate(); + ChronoLocalDate endDate = end.toLocalDate(); if (end.toLocalTime().isBefore(time)) { endDate = endDate.minus(1, ChronoUnit.DAYS); } - return date.periodUntil(endDate, unit); + return date.until(endDate, unit); } return unit.between(this, endDateTime); } @@ -404,7 +421,7 @@ final class ChronoLocalDateTimeImpl> } static ChronoLocalDateTime readExternal(ObjectInput in) throws IOException, ClassNotFoundException { - ChronoLocalDate date = (ChronoLocalDate) in.readObject(); + ChronoLocalDate date = (ChronoLocalDate) in.readObject(); LocalTime time = (LocalTime) in.readObject(); return date.atTime(time); } diff --git a/jdk/src/share/classes/java/time/chrono/ChronoZonedDateTime.java b/jdk/src/share/classes/java/time/chrono/ChronoZonedDateTime.java index d838a36ec29..dd911fcd789 100644 --- a/jdk/src/share/classes/java/time/chrono/ChronoZonedDateTime.java +++ b/jdk/src/share/classes/java/time/chrono/ChronoZonedDateTime.java @@ -63,6 +63,7 @@ package java.time.chrono; import static java.time.temporal.ChronoField.INSTANT_SECONDS; import static java.time.temporal.ChronoField.OFFSET_SECONDS; +import static java.time.temporal.ChronoUnit.FOREVER; import static java.time.temporal.ChronoUnit.NANOS; import java.time.DateTimeException; @@ -73,6 +74,7 @@ import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoField; +import java.time.temporal.ChronoUnit; import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalAdjuster; @@ -115,7 +117,7 @@ import java.util.Objects; * @param the concrete type for the date of this date-time * @since 1.8 */ -public interface ChronoZonedDateTime> +public interface ChronoZonedDateTime extends Temporal, Comparable> { /** @@ -338,9 +340,54 @@ public interface ChronoZonedDateTime> */ ChronoZonedDateTime withZoneSameInstant(ZoneId zone); - @Override // Override to provide javadoc + /** + * Checks if the specified field is supported. + *

+ * This checks if the specified field can be queried on this date-time. + * If false, then calling the {@link #range(TemporalField) range}, + * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)} + * methods will throw an exception. + *

+ * The set of supported fields is defined by the chronology and normally includes + * all {@code ChronoField} fields. + *

+ * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)} + * passing {@code this} as the argument. + * Whether the field is supported is determined by the field. + * + * @param field the field to check, null returns false + * @return true if the field can be queried, false if not + */ + @Override boolean isSupported(TemporalField field); + /** + * Checks if the specified unit is supported. + *

+ * This checks if the specified unit can be added to or subtracted from this date-time. + * If false, then calling the {@link #plus(long, TemporalUnit)} and + * {@link #minus(long, TemporalUnit) minus} methods will throw an exception. + *

+ * The set of supported units is defined by the chronology and normally includes + * all {@code ChronoUnit} units except {@code FOREVER}. + *

+ * If the unit is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)} + * passing {@code this} as the argument. + * Whether the unit is supported is determined by the unit. + * + * @param unit the unit to check, null returns false + * @return true if the unit can be added/subtracted, false if not + */ + @Override + default boolean isSupported(TemporalUnit unit) { + if (unit instanceof ChronoUnit) { + return unit != FOREVER; + } + return unit != null && unit.isSupportedBy(this); + } + //----------------------------------------------------------------------- // override for covariant return type /** @@ -350,7 +397,7 @@ public interface ChronoZonedDateTime> */ @Override default ChronoZonedDateTime with(TemporalAdjuster adjuster) { - return (ChronoZonedDateTime)(toLocalDate().getChronology().ensureChronoZonedDateTime(Temporal.super.with(adjuster))); + return ChronoZonedDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.with(adjuster)); } /** @@ -368,7 +415,7 @@ public interface ChronoZonedDateTime> */ @Override default ChronoZonedDateTime plus(TemporalAmount amount) { - return (ChronoZonedDateTime)(toLocalDate().getChronology().ensureChronoZonedDateTime(Temporal.super.plus(amount))); + return ChronoZonedDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.plus(amount)); } /** @@ -386,7 +433,7 @@ public interface ChronoZonedDateTime> */ @Override default ChronoZonedDateTime minus(TemporalAmount amount) { - return (ChronoZonedDateTime)(toLocalDate().getChronology().ensureChronoZonedDateTime(Temporal.super.minus(amount))); + return ChronoZonedDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.minus(amount)); } /** @@ -396,7 +443,7 @@ public interface ChronoZonedDateTime> */ @Override default ChronoZonedDateTime minus(long amountToSubtract, TemporalUnit unit) { - return (ChronoZonedDateTime)(toLocalDate().getChronology().ensureChronoZonedDateTime(Temporal.super.minus(amountToSubtract, unit))); + return ChronoZonedDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.minus(amountToSubtract, unit)); } //----------------------------------------------------------------------- diff --git a/jdk/src/share/classes/java/time/chrono/ChronoZonedDateTimeImpl.java b/jdk/src/share/classes/java/time/chrono/ChronoZonedDateTimeImpl.java index 835ec932184..a39ed298d37 100644 --- a/jdk/src/share/classes/java/time/chrono/ChronoZonedDateTimeImpl.java +++ b/jdk/src/share/classes/java/time/chrono/ChronoZonedDateTimeImpl.java @@ -101,7 +101,7 @@ import java.util.Objects; * @param the concrete type for the date of this date-time * @since 1.8 */ -final class ChronoZonedDateTimeImpl> +final class ChronoZonedDateTimeImpl implements ChronoZonedDateTime, Serializable { /** @@ -131,7 +131,7 @@ final class ChronoZonedDateTimeImpl> * @param preferredOffset the zone offset, null if no preference * @return the zoned date-time, not null */ - static > ChronoZonedDateTime ofBest( + static ChronoZonedDateTime ofBest( ChronoLocalDateTimeImpl localDateTime, ZoneId zone, ZoneOffset preferredOffset) { Objects.requireNonNull(localDateTime, "localDateTime"); Objects.requireNonNull(zone, "zone"); @@ -167,14 +167,13 @@ final class ChronoZonedDateTimeImpl> * @param zone the zone identifier, not null * @return the zoned date-time, not null */ - @SuppressWarnings("rawtypes") static ChronoZonedDateTimeImpl ofInstant(Chronology chrono, Instant instant, ZoneId zone) { ZoneRules rules = zone.getRules(); ZoneOffset offset = rules.getOffset(instant); Objects.requireNonNull(offset, "offset"); // protect against bad ZoneRules LocalDateTime ldt = LocalDateTime.ofEpochSecond(instant.getEpochSecond(), instant.getNano(), offset); - ChronoLocalDateTimeImpl cldt = (ChronoLocalDateTimeImpl) chrono.localDateTime(ldt); - return new ChronoZonedDateTimeImpl(cldt, offset, zone); + ChronoLocalDateTimeImpl cldt = (ChronoLocalDateTimeImpl)chrono.localDateTime(ldt); + return new ChronoZonedDateTimeImpl<>(cldt, offset, zone); } /** @@ -184,10 +183,30 @@ final class ChronoZonedDateTimeImpl> * @param zone the time-zone to use, validated not null * @return the zoned date-time, validated not null */ + @SuppressWarnings("unchecked") private ChronoZonedDateTimeImpl create(Instant instant, ZoneId zone) { return (ChronoZonedDateTimeImpl)ofInstant(toLocalDate().getChronology(), instant, zone); } + /** + * Casts the {@code Temporal} to {@code ChronoZonedDateTimeImpl} ensuring it bas the specified chronology. + * + * @param chrono the chronology to check for, not null + * @param temporal a date-time to cast, not null + * @return the date-time checked and cast to {@code ChronoZonedDateTimeImpl}, not null + * @throws ClassCastException if the date-time cannot be cast to ChronoZonedDateTimeImpl + * or the chronology is not equal this Chronology + */ + static ChronoZonedDateTimeImpl ensureValid(Chronology chrono, Temporal temporal) { + @SuppressWarnings("unchecked") + ChronoZonedDateTimeImpl other = (ChronoZonedDateTimeImpl) temporal; + if (chrono.equals(other.toLocalDate().getChronology()) == false) { + throw new ClassCastException("Chronology mismatch, required: " + chrono.getId() + + ", actual: " + other.toLocalDate().getChronology().getId()); + } + return other; + } + //----------------------------------------------------------------------- /** * Constructor. @@ -271,7 +290,7 @@ final class ChronoZonedDateTimeImpl> } return ofBest(dateTime.with(field, newValue), zone, offset); } - return (ChronoZonedDateTime)(toLocalDate().getChronology().ensureChronoZonedDateTime(field.adjustInto(this, newValue))); + return ChronoZonedDateTimeImpl.ensureValid(toLocalDate().getChronology(), field.adjustInto(this, newValue)); } //----------------------------------------------------------------------- @@ -280,12 +299,12 @@ final class ChronoZonedDateTimeImpl> if (unit instanceof ChronoUnit) { return with(dateTime.plus(amountToAdd, unit)); } - return (ChronoZonedDateTime)(toLocalDate().getChronology().ensureChronoZonedDateTime(unit.addTo(this, amountToAdd))); /// TODO: Generics replacement Risk! + return ChronoZonedDateTimeImpl.ensureValid(toLocalDate().getChronology(), unit.addTo(this, amountToAdd)); /// TODO: Generics replacement Risk! } //----------------------------------------------------------------------- @Override - public long periodUntil(Temporal endDateTime, TemporalUnit unit) { + public long until(Temporal endDateTime, TemporalUnit unit) { if (endDateTime instanceof ChronoZonedDateTime == false) { throw new DateTimeException("Unable to calculate amount as objects are of two different types"); } @@ -296,7 +315,7 @@ final class ChronoZonedDateTimeImpl> } if (unit instanceof ChronoUnit) { end = end.withZoneSameInstant(offset); - return dateTime.periodUntil(end.toLocalDateTime(), unit); + return dateTime.until(end.toLocalDateTime(), unit); } return unit.between(this, endDateTime); } diff --git a/jdk/src/share/classes/java/time/chrono/Chronology.java b/jdk/src/share/classes/java/time/chrono/Chronology.java index e5daae76464..561e2f794fa 100644 --- a/jdk/src/share/classes/java/time/chrono/Chronology.java +++ b/jdk/src/share/classes/java/time/chrono/Chronology.java @@ -74,6 +74,9 @@ import static java.time.temporal.ChronoField.MONTH_OF_YEAR; import static java.time.temporal.ChronoField.PROLEPTIC_MONTH; import static java.time.temporal.ChronoField.YEAR; import static java.time.temporal.ChronoField.YEAR_OF_ERA; +import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.MONTHS; +import static java.time.temporal.ChronoUnit.WEEKS; import static java.time.temporal.TemporalAdjuster.nextOrSame; import java.io.DataInput; @@ -88,14 +91,16 @@ import java.time.DayOfWeek; import java.time.Instant; import java.time.LocalDate; import java.time.LocalTime; +import java.time.Month; +import java.time.Year; import java.time.ZoneId; import java.time.format.DateTimeFormatterBuilder; import java.time.format.ResolverStyle; import java.time.format.TextStyle; import java.time.temporal.ChronoField; -import java.time.temporal.ChronoUnit; import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalAdjuster; import java.time.temporal.TemporalField; import java.time.temporal.TemporalQuery; import java.time.temporal.UnsupportedTemporalTypeException; @@ -188,8 +193,8 @@ public abstract class Chronology implements Comparable { /** * ChronoLocalDate order constant. */ - static final Comparator> DATE_ORDER = - (Comparator> & Serializable) (date1, date2) -> { + static final Comparator DATE_ORDER = + (Comparator & Serializable) (date1, date2) -> { return Long.compare(date1.toEpochDay(), date2.toEpochDay()); }; /** @@ -480,60 +485,6 @@ public abstract class Chronology implements Comparable { protected Chronology() { } - //----------------------------------------------------------------------- - /** - * Casts the {@code Temporal} to {@code ChronoLocalDate} with the same chronology. - * - * @param temporal a date-time to cast, not null - * @return the date-time checked and cast to {@code ChronoLocalDate}, not null - * @throws ClassCastException if the date-time cannot be cast to ChronoLocalDate - * or the chronology is not equal this Chronology - */ - ChronoLocalDate ensureChronoLocalDate(Temporal temporal) { - @SuppressWarnings("unchecked") - ChronoLocalDate other = (ChronoLocalDate) temporal; - if (this.equals(other.getChronology()) == false) { - throw new ClassCastException("Chronology mismatch, expected: " + getId() + ", actual: " + other.getChronology().getId()); - } - return other; - } - - /** - * Casts the {@code Temporal} to {@code ChronoLocalDateTime} with the same chronology. - * - * @param temporal a date-time to cast, not null - * @return the date-time checked and cast to {@code ChronoLocalDateTime}, not null - * @throws ClassCastException if the date-time cannot be cast to ChronoLocalDateTimeImpl - * or the chronology is not equal this Chronology - */ - ChronoLocalDateTimeImpl ensureChronoLocalDateTime(Temporal temporal) { - @SuppressWarnings("unchecked") - ChronoLocalDateTimeImpl other = (ChronoLocalDateTimeImpl) temporal; - if (this.equals(other.toLocalDate().getChronology()) == false) { - throw new ClassCastException("Chronology mismatch, required: " + getId() - + ", supplied: " + other.toLocalDate().getChronology().getId()); - } - return other; - } - - /** - * Casts the {@code Temporal} to {@code ChronoZonedDateTimeImpl} with the same chronology. - * - * @param temporal a date-time to cast, not null - * @return the date-time checked and cast to {@code ChronoZonedDateTimeImpl}, not null - * @throws ClassCastException if the date-time cannot be cast to ChronoZonedDateTimeImpl - * or the chronology is not equal this Chronology - */ - ChronoZonedDateTimeImpl ensureChronoZonedDateTime(Temporal temporal) { - @SuppressWarnings("unchecked") - ChronoZonedDateTimeImpl other = (ChronoZonedDateTimeImpl) temporal; - if (this.equals(other.toLocalDate().getChronology()) == false) { - throw new ClassCastException("Chronology mismatch, required: " + getId() - + ", supplied: " + other.toLocalDate().getChronology().getId()); - } - return other; - } - //----------------------------------------------------------------------- /** * Gets the ID of the chronology. @@ -574,7 +525,7 @@ public abstract class Chronology implements Comparable { * @throws DateTimeException if unable to create the date * @throws ClassCastException if the {@code era} is not of the correct type for the chronology */ - public ChronoLocalDate date(Era era, int yearOfEra, int month, int dayOfMonth) { + public ChronoLocalDate date(Era era, int yearOfEra, int month, int dayOfMonth) { return date(prolepticYear(era, yearOfEra), month, dayOfMonth); } @@ -588,7 +539,7 @@ public abstract class Chronology implements Comparable { * @return the local date in this chronology, not null * @throws DateTimeException if unable to create the date */ - public abstract ChronoLocalDate date(int prolepticYear, int month, int dayOfMonth); + public abstract ChronoLocalDate date(int prolepticYear, int month, int dayOfMonth); /** * Obtains a local date in this chronology from the era, year-of-era and @@ -601,7 +552,7 @@ public abstract class Chronology implements Comparable { * @throws DateTimeException if unable to create the date * @throws ClassCastException if the {@code era} is not of the correct type for the chronology */ - public ChronoLocalDate dateYearDay(Era era, int yearOfEra, int dayOfYear) { + public ChronoLocalDate dateYearDay(Era era, int yearOfEra, int dayOfYear) { return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear); } @@ -614,7 +565,7 @@ public abstract class Chronology implements Comparable { * @return the local date in this chronology, not null * @throws DateTimeException if unable to create the date */ - public abstract ChronoLocalDate dateYearDay(int prolepticYear, int dayOfYear); + public abstract ChronoLocalDate dateYearDay(int prolepticYear, int dayOfYear); /** * Obtains a local date in this chronology from the epoch-day. @@ -626,7 +577,7 @@ public abstract class Chronology implements Comparable { * @return the local date in this chronology, not null * @throws DateTimeException if unable to create the date */ - public abstract ChronoLocalDate dateEpochDay(long epochDay); + public abstract ChronoLocalDate dateEpochDay(long epochDay); //----------------------------------------------------------------------- /** @@ -643,7 +594,7 @@ public abstract class Chronology implements Comparable { * @return the current local date using the system clock and default time-zone, not null * @throws DateTimeException if unable to create the date */ - public ChronoLocalDate dateNow() { + public ChronoLocalDate dateNow() { return dateNow(Clock.systemDefaultZone()); } @@ -660,7 +611,7 @@ public abstract class Chronology implements Comparable { * @return the current local date using the system clock, not null * @throws DateTimeException if unable to create the date */ - public ChronoLocalDate dateNow(ZoneId zone) { + public ChronoLocalDate dateNow(ZoneId zone) { return dateNow(Clock.system(zone)); } @@ -675,7 +626,7 @@ public abstract class Chronology implements Comparable { * @return the current local date, not null * @throws DateTimeException if unable to create the date */ - public ChronoLocalDate dateNow(Clock clock) { + public ChronoLocalDate dateNow(Clock clock) { Objects.requireNonNull(clock, "clock"); return date(LocalDate.now(clock)); } @@ -699,7 +650,7 @@ public abstract class Chronology implements Comparable { * @throws DateTimeException if unable to create the date * @see ChronoLocalDate#from(TemporalAccessor) */ - public abstract ChronoLocalDate date(TemporalAccessor temporal); + public abstract ChronoLocalDate date(TemporalAccessor temporal); /** * Obtains a local date-time in this chronology from another temporal object. @@ -722,7 +673,7 @@ public abstract class Chronology implements Comparable { * @throws DateTimeException if unable to create the date-time * @see ChronoLocalDateTime#from(TemporalAccessor) */ - public ChronoLocalDateTime localDateTime(TemporalAccessor temporal) { + public ChronoLocalDateTime localDateTime(TemporalAccessor temporal) { try { return date(temporal).atTime(LocalTime.from(temporal)); } catch (DateTimeException ex) { @@ -754,7 +705,7 @@ public abstract class Chronology implements Comparable { * @throws DateTimeException if unable to create the date-time * @see ChronoZonedDateTime#from(TemporalAccessor) */ - public ChronoZonedDateTime zonedDateTime(TemporalAccessor temporal) { + public ChronoZonedDateTime zonedDateTime(TemporalAccessor temporal) { try { ZoneId zone = ZoneId.from(temporal); try { @@ -762,8 +713,7 @@ public abstract class Chronology implements Comparable { return zonedDateTime(instant, zone); } catch (DateTimeException ex1) { - @SuppressWarnings("rawtypes") - ChronoLocalDateTimeImpl cldt = ensureChronoLocalDateTime(localDateTime(temporal)); + ChronoLocalDateTimeImpl cldt = ChronoLocalDateTimeImpl.ensureValid(this, localDateTime(temporal)); return ChronoZonedDateTimeImpl.ofBest(cldt, zone, null); } } catch (DateTimeException ex) { @@ -781,7 +731,7 @@ public abstract class Chronology implements Comparable { * @return the zoned date-time, not null * @throws DateTimeException if the result exceeds the supported range */ - public ChronoZonedDateTime zonedDateTime(Instant instant, ZoneId zone) { + public ChronoZonedDateTime zonedDateTime(Instant instant, ZoneId zone) { return ChronoZonedDateTimeImpl.ofInstant(this, instant, zone); } @@ -929,11 +879,82 @@ public abstract class Chronology implements Comparable { * As such, {@code ChronoField} date fields are resolved here in the * context of a specific chronology. *

+ * {@code ChronoField} instances are resolved by this method, which may + * be overridden in subclasses. + *

    + *
  • {@code EPOCH_DAY} - If present, this is converted to a date and + * all other date fields are then cross-checked against the date. + *
  • {@code PROLEPTIC_MONTH} - If present, then it is split into the + * {@code YEAR} and {@code MONTH_OF_YEAR}. If the mode is strict or smart + * then the field is validated. + *
  • {@code YEAR_OF_ERA} and {@code ERA} - If both are present, then they + * are combined to form a {@code YEAR}. In lenient mode, the {@code YEAR_OF_ERA} + * range is not validated, in smart and strict mode it is. The {@code ERA} is + * validated for range in all three modes. If only the {@code YEAR_OF_ERA} is + * present, and the mode is smart or lenient, then the last available era + * is assumed. In strict mode, no era is assumed and the {@code YEAR_OF_ERA} is + * left untouched. If only the {@code ERA} is present, then it is left untouched. + *
  • {@code YEAR}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} - + * If all three are present, then they are combined to form a date. + * In all three modes, the {@code YEAR} is validated. + * If the mode is smart or strict, then the month and day are validated. + * If the mode is lenient, then the date is combined in a manner equivalent to + * creating a date on the first day of the first month in the requested year, + * then adding the difference in months, then the difference in days. + * If the mode is smart, and the day-of-month is greater than the maximum for + * the year-month, then the day-of-month is adjusted to the last day-of-month. + * If the mode is strict, then the three fields must form a valid date. + *
  • {@code YEAR} and {@code DAY_OF_YEAR} - + * If both are present, then they are combined to form a date. + * In all three modes, the {@code YEAR} is validated. + * If the mode is lenient, then the date is combined in a manner equivalent to + * creating a date on the first day of the requested year, then adding + * the difference in days. + * If the mode is smart or strict, then the two fields must form a valid date. + *
  • {@code YEAR}, {@code MONTH_OF_YEAR}, {@code ALIGNED_WEEK_OF_MONTH} and + * {@code ALIGNED_DAY_OF_WEEK_IN_MONTH} - + * If all four are present, then they are combined to form a date. + * In all three modes, the {@code YEAR} is validated. + * If the mode is lenient, then the date is combined in a manner equivalent to + * creating a date on the first day of the first month in the requested year, then adding + * the difference in months, then the difference in weeks, then in days. + * If the mode is smart or strict, then the all four fields are validated to + * their outer ranges. The date is then combined in a manner equivalent to + * creating a date on the first day of the requested year and month, then adding + * the amount in weeks and days to reach their values. If the mode is strict, + * the date is additionally validated to check that the day and week adjustment + * did not change the month. + *
  • {@code YEAR}, {@code MONTH_OF_YEAR}, {@code ALIGNED_WEEK_OF_MONTH} and + * {@code DAY_OF_WEEK} - If all four are present, then they are combined to + * form a date. The approach is the same as described above for + * years, months and weeks in {@code ALIGNED_DAY_OF_WEEK_IN_MONTH}. + * The day-of-week is adjusted as the next or same matching day-of-week once + * the years, months and weeks have been handled. + *
  • {@code YEAR}, {@code ALIGNED_WEEK_OF_YEAR} and {@code ALIGNED_DAY_OF_WEEK_IN_YEAR} - + * If all three are present, then they are combined to form a date. + * In all three modes, the {@code YEAR} is validated. + * If the mode is lenient, then the date is combined in a manner equivalent to + * creating a date on the first day of the requested year, then adding + * the difference in weeks, then in days. + * If the mode is smart or strict, then the all three fields are validated to + * their outer ranges. The date is then combined in a manner equivalent to + * creating a date on the first day of the requested year, then adding + * the amount in weeks and days to reach their values. If the mode is strict, + * the date is additionally validated to check that the day and week adjustment + * did not change the year. + *
  • {@code YEAR}, {@code ALIGNED_WEEK_OF_YEAR} and {@code DAY_OF_WEEK} - + * If all three are present, then they are combined to form a date. + * The approach is the same as described above for years and weeks in + * {@code ALIGNED_DAY_OF_WEEK_IN_YEAR}. The day-of-week is adjusted as the + * next or same matching day-of-week once the years and weeks have been handled. + *
+ *

* The default implementation is suitable for most calendar systems. * If {@link ChronoField#YEAR_OF_ERA} is found without an {@link ChronoField#ERA} * then the last era in {@link #eras()} is used. * The implementation assumes a 7 day week, that the first day-of-month - * has the value 1, and that first day-of-year has the value 1. + * has the value 1, that first day-of-year has the value 1, and that the + * first of the month and year always exists. * * @param fieldValues the map of fields to values, which can be updated, not null * @param resolverStyle the requested type of resolve, not null @@ -941,99 +962,214 @@ public abstract class Chronology implements Comparable { * @throws DateTimeException if the date cannot be resolved, typically * because of a conflict in the input data */ - public ChronoLocalDate resolveDate(Map fieldValues, ResolverStyle resolverStyle) { + public ChronoLocalDate resolveDate(Map fieldValues, ResolverStyle resolverStyle) { // check epoch-day before inventing era if (fieldValues.containsKey(EPOCH_DAY)) { return dateEpochDay(fieldValues.remove(EPOCH_DAY)); } // fix proleptic month before inventing era - Long pMonth = fieldValues.remove(PROLEPTIC_MONTH); - if (pMonth != null) { - // first day-of-month is likely to be safest for setting proleptic-month - // cannot add to year zero, as not all chronologies have a year zero - ChronoLocalDate chronoDate = dateNow() - .with(DAY_OF_MONTH, 1).with(PROLEPTIC_MONTH, pMonth); - addFieldValue(fieldValues, MONTH_OF_YEAR, chronoDate.get(MONTH_OF_YEAR)); - addFieldValue(fieldValues, YEAR, chronoDate.get(YEAR)); - } + resolveProlepticMonth(fieldValues, resolverStyle); // invent era if necessary to resolve year-of-era - Long yoeLong = fieldValues.remove(YEAR_OF_ERA); - if (yoeLong != null) { - Long eraLong = fieldValues.remove(ERA); - int yoe = range(YEAR_OF_ERA).checkValidIntValue(yoeLong, YEAR_OF_ERA); - if (eraLong != null) { - Era eraObj = eraOf(Math.toIntExact(eraLong)); - addFieldValue(fieldValues, YEAR, prolepticYear(eraObj, yoe)); - } else if (fieldValues.containsKey(YEAR)) { - int year = range(YEAR).checkValidIntValue(fieldValues.get(YEAR), YEAR); - ChronoLocalDate chronoDate = dateYearDay(year, 1); - addFieldValue(fieldValues, YEAR, prolepticYear(chronoDate.getEra(), yoe)); - } else { - List eras = eras(); - if (eras.isEmpty()) { - addFieldValue(fieldValues, YEAR, yoe); - } else { - Era eraObj = eras.get(eras.size() - 1); - addFieldValue(fieldValues, YEAR, prolepticYear(eraObj, yoe)); - } - } + ChronoLocalDate resolved = resolveYearOfEra(fieldValues, resolverStyle); + if (resolved != null) { + return resolved; } // build date if (fieldValues.containsKey(YEAR)) { if (fieldValues.containsKey(MONTH_OF_YEAR)) { if (fieldValues.containsKey(DAY_OF_MONTH)) { - int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR); - int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR); - int dom = range(DAY_OF_MONTH).checkValidIntValue(fieldValues.remove(DAY_OF_MONTH), DAY_OF_MONTH); - return date(y, moy, dom); + return resolveYMD(fieldValues, resolverStyle); } if (fieldValues.containsKey(ALIGNED_WEEK_OF_MONTH)) { if (fieldValues.containsKey(ALIGNED_DAY_OF_WEEK_IN_MONTH)) { - int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR); - int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR); - int aw = range(ALIGNED_WEEK_OF_MONTH).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), ALIGNED_WEEK_OF_MONTH); - int ad = range(ALIGNED_DAY_OF_WEEK_IN_MONTH).checkValidIntValue(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_MONTH), ALIGNED_DAY_OF_WEEK_IN_MONTH); - ChronoLocalDate chronoDate = date(y, moy, 1); - return chronoDate.plus((aw - 1) * 7 + (ad - 1), ChronoUnit.DAYS); + return resolveYMAA(fieldValues, resolverStyle); } if (fieldValues.containsKey(DAY_OF_WEEK)) { - int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR); - int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR); - int aw = range(ALIGNED_WEEK_OF_MONTH).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), ALIGNED_WEEK_OF_MONTH); - int dow = range(DAY_OF_WEEK).checkValidIntValue(fieldValues.remove(DAY_OF_WEEK), DAY_OF_WEEK); - ChronoLocalDate chronoDate = date(y, moy, 1); - return chronoDate.plus((aw - 1) * 7, ChronoUnit.DAYS).with(nextOrSame(DayOfWeek.of(dow))); + return resolveYMAD(fieldValues, resolverStyle); } } } if (fieldValues.containsKey(DAY_OF_YEAR)) { - int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR); - int doy = range(DAY_OF_YEAR).checkValidIntValue(fieldValues.remove(DAY_OF_YEAR), DAY_OF_YEAR); - return dateYearDay(y, doy); + return resolveYD(fieldValues, resolverStyle); } if (fieldValues.containsKey(ALIGNED_WEEK_OF_YEAR)) { if (fieldValues.containsKey(ALIGNED_DAY_OF_WEEK_IN_YEAR)) { - int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR); - int aw = range(ALIGNED_WEEK_OF_YEAR).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), ALIGNED_WEEK_OF_YEAR); - int ad = range(ALIGNED_DAY_OF_WEEK_IN_YEAR).checkValidIntValue(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_YEAR), ALIGNED_DAY_OF_WEEK_IN_YEAR); - ChronoLocalDate chronoDate = dateYearDay(y, 1); - return chronoDate.plus((aw - 1) * 7 + (ad - 1), ChronoUnit.DAYS); + return resolveYAA(fieldValues, resolverStyle); } if (fieldValues.containsKey(DAY_OF_WEEK)) { - int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR); - int aw = range(ALIGNED_WEEK_OF_YEAR).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), ALIGNED_WEEK_OF_YEAR); - int dow = range(DAY_OF_WEEK).checkValidIntValue(fieldValues.remove(DAY_OF_WEEK), DAY_OF_WEEK); - ChronoLocalDate chronoDate = dateYearDay(y, 1); - return chronoDate.plus((aw - 1) * 7, ChronoUnit.DAYS).with(nextOrSame(DayOfWeek.of(dow))); + return resolveYAD(fieldValues, resolverStyle); } } } return null; } + void resolveProlepticMonth(Map fieldValues, ResolverStyle resolverStyle) { + Long pMonth = fieldValues.remove(PROLEPTIC_MONTH); + if (pMonth != null) { + if (resolverStyle != ResolverStyle.LENIENT) { + PROLEPTIC_MONTH.checkValidValue(pMonth); + } + // first day-of-month is likely to be safest for setting proleptic-month + // cannot add to year zero, as not all chronologies have a year zero + ChronoLocalDate chronoDate = dateNow() + .with(DAY_OF_MONTH, 1).with(PROLEPTIC_MONTH, pMonth); + addFieldValue(fieldValues, MONTH_OF_YEAR, chronoDate.get(MONTH_OF_YEAR)); + addFieldValue(fieldValues, YEAR, chronoDate.get(YEAR)); + } + } + + ChronoLocalDate resolveYearOfEra(Map fieldValues, ResolverStyle resolverStyle) { + Long yoeLong = fieldValues.remove(YEAR_OF_ERA); + if (yoeLong != null) { + Long eraLong = fieldValues.remove(ERA); + int yoe; + if (resolverStyle != ResolverStyle.LENIENT) { + yoe = range(YEAR_OF_ERA).checkValidIntValue(yoeLong, YEAR_OF_ERA); + } else { + yoe = Math.toIntExact(yoeLong); + } + if (eraLong != null) { + Era eraObj = eraOf(range(ERA).checkValidIntValue(eraLong, ERA)); + addFieldValue(fieldValues, YEAR, prolepticYear(eraObj, yoe)); + } else { + if (fieldValues.containsKey(YEAR)) { + int year = range(YEAR).checkValidIntValue(fieldValues.get(YEAR), YEAR); + ChronoLocalDate chronoDate = dateYearDay(year, 1); + addFieldValue(fieldValues, YEAR, prolepticYear(chronoDate.getEra(), yoe)); + } else if (resolverStyle == ResolverStyle.STRICT) { + // do not invent era if strict + // reinstate the field removed earlier, no cross-check issues + fieldValues.put(YEAR_OF_ERA, yoeLong); + } else { + List eras = eras(); + if (eras.isEmpty()) { + addFieldValue(fieldValues, YEAR, yoe); + } else { + Era eraObj = eras.get(eras.size() - 1); + addFieldValue(fieldValues, YEAR, prolepticYear(eraObj, yoe)); + } + } + } + } else if (fieldValues.containsKey(ERA)) { + range(ERA).checkValidValue(fieldValues.get(ERA), ERA); // always validated + } + return null; + } + + ChronoLocalDate resolveYMD(Map fieldValues, ResolverStyle resolverStyle) { + int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR); + if (resolverStyle == ResolverStyle.LENIENT) { + long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1); + long days = Math.subtractExact(fieldValues.remove(DAY_OF_MONTH), 1); + return date(y, 1, 1).plus(months, MONTHS).plus(days, DAYS); + } + int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR); + ValueRange domRange = range(DAY_OF_MONTH); + int dom = domRange.checkValidIntValue(fieldValues.remove(DAY_OF_MONTH), DAY_OF_MONTH); + if (resolverStyle == ResolverStyle.SMART) { // previous valid + try { + return date(y, moy, dom); + } catch (DateTimeException ex) { + return date(y, moy, 1).with(TemporalAdjuster.lastDayOfMonth()); + } + } + return date(y, moy, dom); + } + + ChronoLocalDate resolveYD(Map fieldValues, ResolverStyle resolverStyle) { + int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR); + if (resolverStyle == ResolverStyle.LENIENT) { + long days = Math.subtractExact(fieldValues.remove(DAY_OF_YEAR), 1); + return dateYearDay(y, 1).plus(days, DAYS); + } + int doy = range(DAY_OF_YEAR).checkValidIntValue(fieldValues.remove(DAY_OF_YEAR), DAY_OF_YEAR); + return dateYearDay(y, doy); // smart is same as strict + } + + ChronoLocalDate resolveYMAA(Map fieldValues, ResolverStyle resolverStyle) { + int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR); + if (resolverStyle == ResolverStyle.LENIENT) { + long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1); + long weeks = Math.subtractExact(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), 1); + long days = Math.subtractExact(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_MONTH), 1); + return date(y, 1, 1).plus(months, MONTHS).plus(weeks, WEEKS).plus(days, DAYS); + } + int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR); + int aw = range(ALIGNED_WEEK_OF_MONTH).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), ALIGNED_WEEK_OF_MONTH); + int ad = range(ALIGNED_DAY_OF_WEEK_IN_MONTH).checkValidIntValue(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_MONTH), ALIGNED_DAY_OF_WEEK_IN_MONTH); + ChronoLocalDate date = date(y, moy, 1).plus((aw - 1) * 7 + (ad - 1), DAYS); + if (resolverStyle == ResolverStyle.STRICT && date.get(MONTH_OF_YEAR) != moy) { + throw new DateTimeException("Strict mode rejected resolved date as it is in a different month"); + } + return date; + } + + ChronoLocalDate resolveYMAD(Map fieldValues, ResolverStyle resolverStyle) { + int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR); + if (resolverStyle == ResolverStyle.LENIENT) { + long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1); + long weeks = Math.subtractExact(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), 1); + long dow = Math.subtractExact(fieldValues.remove(DAY_OF_WEEK), 1); + return resolveAligned(date(y, 1, 1), months, weeks, dow); + } + int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR); + int aw = range(ALIGNED_WEEK_OF_MONTH).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), ALIGNED_WEEK_OF_MONTH); + int dow = range(DAY_OF_WEEK).checkValidIntValue(fieldValues.remove(DAY_OF_WEEK), DAY_OF_WEEK); + ChronoLocalDate date = date(y, moy, 1).plus((aw - 1) * 7, DAYS).with(nextOrSame(DayOfWeek.of(dow))); + if (resolverStyle == ResolverStyle.STRICT && date.get(MONTH_OF_YEAR) != moy) { + throw new DateTimeException("Strict mode rejected resolved date as it is in a different month"); + } + return date; + } + + ChronoLocalDate resolveYAA(Map fieldValues, ResolverStyle resolverStyle) { + int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR); + if (resolverStyle == ResolverStyle.LENIENT) { + long weeks = Math.subtractExact(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), 1); + long days = Math.subtractExact(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_YEAR), 1); + return dateYearDay(y, 1).plus(weeks, WEEKS).plus(days, DAYS); + } + int aw = range(ALIGNED_WEEK_OF_YEAR).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), ALIGNED_WEEK_OF_YEAR); + int ad = range(ALIGNED_DAY_OF_WEEK_IN_YEAR).checkValidIntValue(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_YEAR), ALIGNED_DAY_OF_WEEK_IN_YEAR); + ChronoLocalDate date = dateYearDay(y, 1).plus((aw - 1) * 7 + (ad - 1), DAYS); + if (resolverStyle == ResolverStyle.STRICT && date.get(YEAR) != y) { + throw new DateTimeException("Strict mode rejected resolved date as it is in a different year"); + } + return date; + } + + ChronoLocalDate resolveYAD(Map fieldValues, ResolverStyle resolverStyle) { + int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR); + if (resolverStyle == ResolverStyle.LENIENT) { + long weeks = Math.subtractExact(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), 1); + long dow = Math.subtractExact(fieldValues.remove(DAY_OF_WEEK), 1); + return resolveAligned(dateYearDay(y, 1), 0, weeks, dow); + } + int aw = range(ALIGNED_WEEK_OF_YEAR).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), ALIGNED_WEEK_OF_YEAR); + int dow = range(DAY_OF_WEEK).checkValidIntValue(fieldValues.remove(DAY_OF_WEEK), DAY_OF_WEEK); + ChronoLocalDate date = dateYearDay(y, 1).plus((aw - 1) * 7, DAYS).with(nextOrSame(DayOfWeek.of(dow))); + if (resolverStyle == ResolverStyle.STRICT && date.get(YEAR) != y) { + throw new DateTimeException("Strict mode rejected resolved date as it is in a different year"); + } + return date; + } + + ChronoLocalDate resolveAligned(ChronoLocalDate base, long months, long weeks, long dow) { + ChronoLocalDate date = base.plus(months, MONTHS).plus(weeks, WEEKS); + if (dow > 7) { + date = date.plus((dow - 1) / 7, WEEKS); + dow = ((dow - 1) % 7) + 1; + } else if (dow < 1) { + date = date.plus(Math.subtractExact(dow, 7) / 7, WEEKS); + dow = ((dow + 6) % 7) + 1; + } + return date.with(nextOrSame(DayOfWeek.of((int) dow))); + } + /** * Adds a field-value pair to the map, checking for conflicts. *

diff --git a/jdk/src/share/classes/java/time/chrono/Era.java b/jdk/src/share/classes/java/time/chrono/Era.java index 330346dcc36..0fd31c9887d 100644 --- a/jdk/src/share/classes/java/time/chrono/Era.java +++ b/jdk/src/share/classes/java/time/chrono/Era.java @@ -238,7 +238,7 @@ public interface Era extends TemporalAccessor, TemporalAdjuster { if (field == ERA) { return getValue(); } else if (field instanceof ChronoField) { - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.getFrom(this); } diff --git a/jdk/src/share/classes/java/time/chrono/HijrahChronology.java b/jdk/src/share/classes/java/time/chrono/HijrahChronology.java index 63dfc1c213b..c5061b05a32 100644 --- a/jdk/src/share/classes/java/time/chrono/HijrahChronology.java +++ b/jdk/src/share/classes/java/time/chrono/HijrahChronology.java @@ -71,8 +71,10 @@ import java.time.DateTimeException; import java.time.Instant; import java.time.LocalDate; import java.time.ZoneId; +import java.time.format.ResolverStyle; import java.time.temporal.ChronoField; import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalField; import java.time.temporal.ValueRange; import java.util.Arrays; import java.util.HashMap; @@ -115,7 +117,7 @@ import sun.util.logging.PlatformLogger; * * Hijrah-umalqura * islamic-umalqura - * ca-islamic-cv-umalqura + * ca-islamic-umalqura * Islamic - Umm Al-Qura calendar of Saudi Arabia * * @@ -126,10 +128,10 @@ import sun.util.logging.PlatformLogger; *

* Selecting the chronology from the locale uses {@link Chronology#ofLocale} * to find the Chronology based on Locale supported BCP 47 extension mechanism - * to request a specific calendar ("ca") and variant ("cv"). For example, + * to request a specific calendar ("ca"). For example, *

*
- *      Locale locale = Locale.forLanguageTag("en-US-u-ca-islamic-cv-umalqura");
+ *      Locale locale = Locale.forLanguageTag("en-US-u-ca-islamic-umalqura");
  *      Chronology chrono = Chronology.ofLocale(locale);
  * 
* @@ -472,11 +474,16 @@ public final class HijrahChronology extends Chronology implements Serializable { * @param prolepticYear the proleptic-year * @param dayOfYear the day-of-year * @return the Hijrah local date, not null - * @throws DateTimeException if unable to create the date + * @throws DateTimeException if the value of the year is out of range, + * or if the day-of-year is invalid for the year */ @Override public HijrahDate dateYearDay(int prolepticYear, int dayOfYear) { - return HijrahDate.of(this, prolepticYear, 1, 1).plusDays(dayOfYear - 1); // TODO better + HijrahDate date = HijrahDate.of(this, prolepticYear, 1, 1); + if (dayOfYear > date.lengthOfYear()) { + throw new DateTimeException("Invalid dayOfYear: " + dayOfYear); + } + return date.plusDays(dayOfYear - 1); } /** @@ -515,16 +522,19 @@ public final class HijrahChronology extends Chronology implements Serializable { } @Override + @SuppressWarnings("unchecked") public ChronoLocalDateTime localDateTime(TemporalAccessor temporal) { return (ChronoLocalDateTime) super.localDateTime(temporal); } @Override + @SuppressWarnings("unchecked") public ChronoZonedDateTime zonedDateTime(TemporalAccessor temporal) { return (ChronoZonedDateTime) super.zonedDateTime(temporal); } @Override + @SuppressWarnings("unchecked") public ChronoZonedDateTime zonedDateTime(Instant instant, ZoneId zone) { return (ChronoZonedDateTime) super.zonedDateTime(instant, zone); } @@ -550,7 +560,7 @@ public final class HijrahChronology extends Chronology implements Serializable { } @Override - public Era eraOf(int eraValue) { + public HijrahEra eraOf(int eraValue) { switch (eraValue) { case 1: return HijrahEra.AH; @@ -580,6 +590,8 @@ public final class HijrahChronology extends Chronology implements Serializable { case YEAR: case YEAR_OF_ERA: return ValueRange.of(getMinimumYear(), getMaximumYear()); + case ERA: + return ValueRange.of(1, 1); default: return field.range(); } @@ -587,6 +599,13 @@ public final class HijrahChronology extends Chronology implements Serializable { return field.range(); } + //----------------------------------------------------------------------- + @Override // override for return type + public HijrahDate resolveDate(Map fieldValues, ResolverStyle resolverStyle) { + return (HijrahDate) super.resolveDate(fieldValues, resolverStyle); + } + + //----------------------------------------------------------------------- /** * Check the validity of a year. * diff --git a/jdk/src/share/classes/java/time/chrono/HijrahDate.java b/jdk/src/share/classes/java/time/chrono/HijrahDate.java index 3c01e94b980..ef40b6dc948 100644 --- a/jdk/src/share/classes/java/time/chrono/HijrahDate.java +++ b/jdk/src/share/classes/java/time/chrono/HijrahDate.java @@ -109,7 +109,7 @@ import java.time.temporal.ValueRange; */ public final class HijrahDate extends ChronoDateImpl - implements ChronoLocalDate, Serializable { + implements ChronoLocalDate, Serializable { /** * Serialization version. @@ -204,7 +204,7 @@ public final class HijrahDate * @throws DateTimeException if the current date cannot be obtained */ public static HijrahDate now(Clock clock) { - return HijrahChronology.INSTANCE.date(LocalDate.now(clock)); + return HijrahDate.ofEpochDay(HijrahChronology.INSTANCE, LocalDate.now(clock).toEpochDay()); } /** @@ -349,7 +349,7 @@ public final class HijrahDate } return getChronology().range(f); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.rangeRefinedBy(this); } @@ -372,7 +372,7 @@ public final class HijrahDate case YEAR: return prolepticYear; case ERA: return getEraValue(); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.getFrom(this); } @@ -393,7 +393,7 @@ public final class HijrahDate case ALIGNED_DAY_OF_WEEK_IN_MONTH: return plusDays(newValue - getLong(ALIGNED_DAY_OF_WEEK_IN_MONTH)); case ALIGNED_DAY_OF_WEEK_IN_YEAR: return plusDays(newValue - getLong(ALIGNED_DAY_OF_WEEK_IN_YEAR)); case DAY_OF_MONTH: return resolvePreviousValid(prolepticYear, monthOfYear, nvalue); - case DAY_OF_YEAR: return resolvePreviousValid(prolepticYear, ((nvalue - 1) / 30) + 1, ((nvalue - 1) % 30) + 1); + case DAY_OF_YEAR: return plusDays(Math.min(nvalue, lengthOfYear()) - getDayOfYear()); case EPOCH_DAY: return new HijrahDate(chrono, newValue); case ALIGNED_WEEK_OF_MONTH: return plusDays((newValue - getLong(ALIGNED_WEEK_OF_MONTH)) * 7); case ALIGNED_WEEK_OF_YEAR: return plusDays((newValue - getLong(ALIGNED_WEEK_OF_YEAR)) * 7); @@ -403,9 +403,9 @@ public final class HijrahDate case YEAR: return resolvePreviousValid(nvalue, monthOfYear, dayOfMonth); case ERA: return resolvePreviousValid(1 - prolepticYear, monthOfYear, dayOfMonth); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } - return ChronoLocalDate.super.with(field, newValue); + return super.with(field, newValue); } private HijrahDate resolvePreviousValid(int prolepticYear, int month, int day) { @@ -479,7 +479,7 @@ public final class HijrahDate * @return the day-of-year */ private int getDayOfYear() { - return chrono.getDayOfYear(prolepticYear, monthOfYear); + return chrono.getDayOfYear(prolepticYear, monthOfYear) + dayOfMonth; } /** @@ -575,12 +575,13 @@ public final class HijrahDate } @Override // for javadoc and covariant return type + @SuppressWarnings("unchecked") public final ChronoLocalDateTime atTime(LocalTime localTime) { - return super.atTime(localTime); + return (ChronoLocalDateTime)super.atTime(localTime); } @Override - public Period periodUntil(ChronoLocalDate endDate) { + public Period until(ChronoLocalDate endDate) { // TODO: untested HijrahDate end = getChronology().date(endDate); long totalMonths = (end.prolepticYear - this.prolepticYear) * 12 + (end.monthOfYear - this.monthOfYear); // safe @@ -622,7 +623,7 @@ public final class HijrahDate return this; } - static ChronoLocalDate readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + static HijrahDate readExternal(ObjectInput in) throws IOException, ClassNotFoundException { HijrahChronology chrono = (HijrahChronology) in.readObject(); int year = in.readInt(); int month = in.readByte(); diff --git a/jdk/src/share/classes/java/time/chrono/IsoChronology.java b/jdk/src/share/classes/java/time/chrono/IsoChronology.java index 66b0dc10d23..a2f6badeaa5 100644 --- a/jdk/src/share/classes/java/time/chrono/IsoChronology.java +++ b/jdk/src/share/classes/java/time/chrono/IsoChronology.java @@ -61,25 +61,16 @@ */ package java.time.chrono; -import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH; -import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR; -import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH; -import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR; import static java.time.temporal.ChronoField.DAY_OF_MONTH; -import static java.time.temporal.ChronoField.DAY_OF_WEEK; -import static java.time.temporal.ChronoField.DAY_OF_YEAR; -import static java.time.temporal.ChronoField.EPOCH_DAY; import static java.time.temporal.ChronoField.ERA; import static java.time.temporal.ChronoField.MONTH_OF_YEAR; import static java.time.temporal.ChronoField.PROLEPTIC_MONTH; import static java.time.temporal.ChronoField.YEAR; import static java.time.temporal.ChronoField.YEAR_OF_ERA; -import static java.time.temporal.TemporalAdjuster.nextOrSame; import java.io.Serializable; import java.time.Clock; import java.time.DateTimeException; -import java.time.DayOfWeek; import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; @@ -398,7 +389,7 @@ public final class IsoChronology extends Chronology implements Serializable { } @Override - public Era eraOf(int eraValue) { + public IsoEra eraOf(int eraValue) { return IsoEra.of(eraValue); } @@ -421,7 +412,7 @@ public final class IsoChronology extends Chronology implements Serializable { * as follows. *
    *
  • {@code EPOCH_DAY} - If present, this is converted to a {@code LocalDate} - * all other date fields are then cross-checked against the date + * and all other date fields are then cross-checked against the date. *
  • {@code PROLEPTIC_MONTH} - If present, then it is split into the * {@code YEAR} and {@code MONTH_OF_YEAR}. If the mode is strict or smart * then the field is validated. @@ -430,7 +421,7 @@ public final class IsoChronology extends Chronology implements Serializable { * range is not validated, in smart and strict mode it is. The {@code ERA} is * validated for range in all three modes. If only the {@code YEAR_OF_ERA} is * present, and the mode is smart or lenient, then the current era (CE/AD) - * is assumed. In strict mode, no ers is assumed and the {@code YEAR_OF_ERA} is + * is assumed. In strict mode, no era is assumed and the {@code YEAR_OF_ERA} is * left untouched. If only the {@code ERA} is present, then it is left untouched. *
  • {@code YEAR}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} - * If all three are present, then they are combined to form a {@code LocalDate}. @@ -495,48 +486,11 @@ public final class IsoChronology extends Chronology implements Serializable { */ @Override // override for performance public LocalDate resolveDate(Map fieldValues, ResolverStyle resolverStyle) { - // check epoch-day before inventing era - if (fieldValues.containsKey(EPOCH_DAY)) { - return LocalDate.ofEpochDay(fieldValues.remove(EPOCH_DAY)); - } - - // fix proleptic month before inventing era - resolveProlepticMonth(fieldValues, resolverStyle); - - // invent era if necessary to resolve year-of-era - resolveYearOfEra(fieldValues, resolverStyle); - - // build date - if (fieldValues.containsKey(YEAR)) { - if (fieldValues.containsKey(MONTH_OF_YEAR)) { - if (fieldValues.containsKey(DAY_OF_MONTH)) { - return resolveYMD(fieldValues, resolverStyle); - } - if (fieldValues.containsKey(ALIGNED_WEEK_OF_MONTH)) { - if (fieldValues.containsKey(ALIGNED_DAY_OF_WEEK_IN_MONTH)) { - return resolveYMAA(fieldValues, resolverStyle); - } - if (fieldValues.containsKey(DAY_OF_WEEK)) { - return resolveYMAD(fieldValues, resolverStyle); - } - } - } - if (fieldValues.containsKey(DAY_OF_YEAR)) { - return resolveYD(fieldValues, resolverStyle); - } - if (fieldValues.containsKey(ALIGNED_WEEK_OF_YEAR)) { - if (fieldValues.containsKey(ALIGNED_DAY_OF_WEEK_IN_YEAR)) { - return resolveYAA(fieldValues, resolverStyle); - } - if (fieldValues.containsKey(DAY_OF_WEEK)) { - return resolveYAD(fieldValues, resolverStyle); - } - } - } - return null; + return (LocalDate) super.resolveDate(fieldValues, resolverStyle); } - private void resolveProlepticMonth(Map fieldValues, ResolverStyle resolverStyle) { + @Override // override for better proleptic algorithm + void resolveProlepticMonth(Map fieldValues, ResolverStyle resolverStyle) { Long pMonth = fieldValues.remove(PROLEPTIC_MONTH); if (pMonth != null) { if (resolverStyle != ResolverStyle.LENIENT) { @@ -547,7 +501,8 @@ public final class IsoChronology extends Chronology implements Serializable { } } - private void resolveYearOfEra(Map fieldValues, ResolverStyle resolverStyle) { + @Override // override for enhanced behaviour + LocalDate resolveYearOfEra(Map fieldValues, ResolverStyle resolverStyle) { Long yoeLong = fieldValues.remove(YEAR_OF_ERA); if (yoeLong != null) { if (resolverStyle != ResolverStyle.LENIENT) { @@ -575,10 +530,14 @@ public final class IsoChronology extends Chronology implements Serializable { } else { throw new DateTimeException("Invalid value for era: " + era); } + } else if (fieldValues.containsKey(ERA)) { + ERA.checkValidValue(fieldValues.get(ERA)); // always validated } + return null; } - private LocalDate resolveYMD(Map fieldValues, ResolverStyle resolverStyle) { + @Override // override for performance + LocalDate resolveYMD(Map fieldValues, ResolverStyle resolverStyle) { int y = YEAR.checkValidIntValue(fieldValues.remove(YEAR)); if (resolverStyle == ResolverStyle.LENIENT) { long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1); @@ -598,96 +557,6 @@ public final class IsoChronology extends Chronology implements Serializable { return LocalDate.of(y, moy, dom); } - private LocalDate resolveYD(Map fieldValues, ResolverStyle resolverStyle) { - int y = YEAR.checkValidIntValue(fieldValues.remove(YEAR)); - if (resolverStyle == ResolverStyle.LENIENT) { - long days = Math.subtractExact(fieldValues.remove(DAY_OF_YEAR), 1); - return LocalDate.of(y, 1, 1).plusDays(days); - } - int doy = DAY_OF_YEAR.checkValidIntValue(fieldValues.remove(DAY_OF_YEAR)); - return LocalDate.ofYearDay(y, doy); // smart is same as strict - } - - private LocalDate resolveYMAA(Map fieldValues, ResolverStyle resolverStyle) { - int y = YEAR.checkValidIntValue(fieldValues.remove(YEAR)); - if (resolverStyle == ResolverStyle.LENIENT) { - long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1); - long weeks = Math.subtractExact(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), 1); - long days = Math.subtractExact(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_MONTH), 1); - return LocalDate.of(y, 1, 1).plusMonths(months).plusWeeks(weeks).plusDays(days); - } - int moy = MONTH_OF_YEAR.checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR)); - int aw = ALIGNED_WEEK_OF_MONTH.checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_MONTH)); - int ad = ALIGNED_DAY_OF_WEEK_IN_MONTH.checkValidIntValue(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_MONTH)); - LocalDate date = LocalDate.of(y, moy, 1).plusDays((aw - 1) * 7 + (ad - 1)); - if (resolverStyle == ResolverStyle.STRICT && date.getMonthValue() != moy) { - throw new DateTimeException("Strict mode rejected resolved date as it is in a different month"); - } - return date; - } - - private LocalDate resolveYMAD(Map fieldValues, ResolverStyle resolverStyle) { - int y = YEAR.checkValidIntValue(fieldValues.remove(YEAR)); - if (resolverStyle == ResolverStyle.LENIENT) { - long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1); - long weeks = Math.subtractExact(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), 1); - long dow = Math.subtractExact(fieldValues.remove(DAY_OF_WEEK), 1); - return resolveAligned(y, months, weeks, dow); - } - int moy = MONTH_OF_YEAR.checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR)); - int aw = ALIGNED_WEEK_OF_MONTH.checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_MONTH)); - int dow = DAY_OF_WEEK.checkValidIntValue(fieldValues.remove(DAY_OF_WEEK)); - LocalDate date = LocalDate.of(y, moy, 1).plusDays((aw - 1) * 7).with(nextOrSame(DayOfWeek.of(dow))); - if (resolverStyle == ResolverStyle.STRICT && date.getMonthValue() != moy) { - throw new DateTimeException("Strict mode rejected resolved date as it is in a different month"); - } - return date; - } - - private LocalDate resolveYAA(Map fieldValues, ResolverStyle resolverStyle) { - int y = YEAR.checkValidIntValue(fieldValues.remove(YEAR)); - if (resolverStyle == ResolverStyle.LENIENT) { - long weeks = Math.subtractExact(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), 1); - long days = Math.subtractExact(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_YEAR), 1); - return LocalDate.of(y, 1, 1).plusWeeks(weeks).plusDays(days); - } - int aw = ALIGNED_WEEK_OF_YEAR.checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_YEAR)); - int ad = ALIGNED_DAY_OF_WEEK_IN_YEAR.checkValidIntValue(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_YEAR)); - LocalDate date = LocalDate.of(y, 1, 1).plusDays((aw - 1) * 7 + (ad - 1)); - if (resolverStyle == ResolverStyle.STRICT && date.getYear() != y) { - throw new DateTimeException("Strict mode rejected resolved date as it is in a different year"); - } - return date; - } - - private LocalDate resolveYAD(Map fieldValues, ResolverStyle resolverStyle) { - int y = YEAR.checkValidIntValue(fieldValues.remove(YEAR)); - if (resolverStyle == ResolverStyle.LENIENT) { - long weeks = Math.subtractExact(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), 1); - long dow = Math.subtractExact(fieldValues.remove(DAY_OF_WEEK), 1); - return resolveAligned(y, 0, weeks, dow); - } - int aw = ALIGNED_WEEK_OF_YEAR.checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_YEAR)); - int dow = DAY_OF_WEEK.checkValidIntValue(fieldValues.remove(DAY_OF_WEEK)); - LocalDate date = LocalDate.of(y, 1, 1).plusDays((aw - 1) * 7).with(nextOrSame(DayOfWeek.of(dow))); - if (resolverStyle == ResolverStyle.STRICT && date.getYear() != y) { - throw new DateTimeException("Strict mode rejected resolved date as it is in a different year"); - } - return date; - } - - private LocalDate resolveAligned(int y, long months, long weeks, long dow) { - LocalDate date = LocalDate.of(y, 1, 1).plusMonths(months).plusWeeks(weeks); - if (dow > 7) { - date = date.plusWeeks((dow - 1) / 7); - dow = ((dow - 1) % 7) + 1; - } else if (dow < 1) { - date = date.plusWeeks(Math.subtractExact(dow, 7) / 7); - dow = ((dow + 6) % 7) + 1; - } - return date.with(nextOrSame(DayOfWeek.of((int) dow))); - } - //----------------------------------------------------------------------- @Override public ValueRange range(ChronoField field) { diff --git a/jdk/src/share/classes/java/time/chrono/JapaneseChronology.java b/jdk/src/share/classes/java/time/chrono/JapaneseChronology.java index 1aead71b8ad..68a12755ea3 100644 --- a/jdk/src/share/classes/java/time/chrono/JapaneseChronology.java +++ b/jdk/src/share/classes/java/time/chrono/JapaneseChronology.java @@ -56,6 +56,15 @@ */ package java.time.chrono; +import static java.time.temporal.ChronoField.DAY_OF_MONTH; +import static java.time.temporal.ChronoField.DAY_OF_YEAR; +import static java.time.temporal.ChronoField.ERA; +import static java.time.temporal.ChronoField.MONTH_OF_YEAR; +import static java.time.temporal.ChronoField.YEAR; +import static java.time.temporal.ChronoField.YEAR_OF_ERA; +import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.MONTHS; + import java.io.Serializable; import java.time.Clock; import java.time.DateTimeException; @@ -63,13 +72,18 @@ import java.time.Instant; import java.time.LocalDate; import java.time.Year; import java.time.ZoneId; +import java.time.format.ResolverStyle; import java.time.temporal.ChronoField; import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalAdjuster; +import java.time.temporal.TemporalField; +import java.time.temporal.UnsupportedTemporalTypeException; import java.time.temporal.ValueRange; import java.util.Arrays; import java.util.Calendar; import java.util.List; import java.util.Locale; +import java.util.Map; import sun.util.calendar.CalendarSystem; import sun.util.calendar.LocalGregorianCalendar; @@ -82,8 +96,22 @@ import sun.util.calendar.LocalGregorianCalendar; * The Japanese Imperial calendar system is the same as the ISO calendar system * apart from the era-based year numbering. *

    - * 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. + * Japan introduced the Gregorian calendar starting with Meiji 6. + * Only Meiji and later eras are supported; + * dates before Meiji 6, January 1 are not supported. + *

    + * The supported {@code ChronoField} instances are: + *

      + *
    • {@code DAY_OF_WEEK} + *
    • {@code DAY_OF_MONTH} + *
    • {@code DAY_OF_YEAR} + *
    • {@code EPOCH_DAY} + *
    • {@code MONTH_OF_YEAR} + *
    • {@code PROLEPTIC_MONTH} + *
    • {@code YEAR_OF_ERA} + *
    • {@code YEAR} + *
    • {@code ERA} + *
    * * @implSpec * This class is immutable and thread-safe. @@ -91,7 +119,6 @@ import sun.util.calendar.LocalGregorianCalendar; * @since 1.8 */ public final class JapaneseChronology extends Chronology implements Serializable { - // TODO: definition for unknown era may break requirement that year-of-era >= 1 static final LocalGregorianCalendar JCAL = (LocalGregorianCalendar) CalendarSystem.forName("japanese"); @@ -152,6 +179,16 @@ public final class JapaneseChronology extends Chronology implements Serializable /** * Obtains a local date in Japanese calendar system from the * era, year-of-era, month-of-year and day-of-month fields. + *

    + * The Japanese month and day-of-month are the same as those in the + * ISO calendar system. They are not reset when the era changes. + * For example: + *

    +     *  6th Jan Showa 64 = ISO 1989-01-06
    +     *  7th Jan Showa 64 = ISO 1989-01-07
    +     *  8th Jan Heisei 1 = ISO 1989-01-08
    +     *  9th Jan Heisei 1 = ISO 1989-01-09
    +     * 
    * * @param era the Japanese era, not null * @param yearOfEra the year-of-era @@ -172,6 +209,9 @@ public final class JapaneseChronology extends Chronology implements Serializable /** * Obtains a local date in Japanese calendar system from the * proleptic-year, month-of-year and day-of-month fields. + *

    + * The Japanese proleptic year, month and day-of-month are the same as those + * in the ISO calendar system. They are not reset when the era changes. * * @param prolepticYear the proleptic-year * @param month the month-of-year @@ -187,6 +227,17 @@ public final class JapaneseChronology extends Chronology implements Serializable /** * Obtains a local date in Japanese calendar system from the * era, year-of-era and day-of-year fields. + *

    + * The day-of-year in this factory is expressed relative to the start of the year-of-era. + * This definition changes the normal meaning of day-of-year only in those years + * where the year-of-era is reset to one due to a change in the era. + * For example: + *

    +     *  6th Jan Showa 64 = day-of-year 6
    +     *  7th Jan Showa 64 = day-of-year 7
    +     *  8th Jan Heisei 1 = day-of-year 1
    +     *  9th Jan Heisei 1 = day-of-year 2
    +     * 
    * * @param era the Japanese era, not null * @param yearOfEra the year-of-era @@ -203,6 +254,10 @@ public final class JapaneseChronology extends Chronology implements Serializable /** * Obtains a local date in Japanese calendar system from the * proleptic-year and day-of-year fields. + *

    + * The day-of-year in this factory is expressed relative to the start of the proleptic year. + * The Japanese proleptic year and day-of-year are the same as those in the ISO calendar system. + * They are not reset when the era changes. * * @param prolepticYear the proleptic-year * @param dayOfYear the day-of-year @@ -211,8 +266,7 @@ public final class JapaneseChronology extends Chronology implements Serializable */ @Override public JapaneseDate dateYearDay(int prolepticYear, int dayOfYear) { - LocalDate date = LocalDate.ofYearDay(prolepticYear, dayOfYear); - return date(prolepticYear, date.getMonthValue(), date.getDayOfMonth()); + return new JapaneseDate(LocalDate.ofYearDay(prolepticYear, dayOfYear)); } /** @@ -290,15 +344,6 @@ public final class JapaneseChronology extends Chronology implements Serializable 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; int gregorianYear = jera.getPrivateEra().getSinceDate().getYear() + yearOfEra - 1; if (yearOfEra == 1) { @@ -320,14 +365,13 @@ public final class JapaneseChronology extends Chronology implements Serializable * See the description of each Era for the numeric values of: * {@link JapaneseEra#HEISEI}, {@link JapaneseEra#SHOWA},{@link JapaneseEra#TAISHO}, * {@link JapaneseEra#MEIJI}), only Meiji and later eras are supported. - * Prior to Meiji {@link JapaneseEra#SEIREKI} is used. * * @param eraValue the era value * @return the Japanese {@code Era} for the given numeric era value * @throws DateTimeException if {@code eraValue} is invalid */ @Override - public Era eraOf(int eraValue) { + public JapaneseEra eraOf(int eraValue) { return JapaneseEra.of(eraValue); } @@ -346,49 +390,117 @@ public final class JapaneseChronology extends Chronology implements Serializable @Override public ValueRange range(ChronoField field) { switch (field) { - case YEAR: - case DAY_OF_MONTH: - case DAY_OF_WEEK: - case MICRO_OF_DAY: - case MICRO_OF_SECOND: - case HOUR_OF_DAY: - case HOUR_OF_AMPM: - case MINUTE_OF_DAY: - case MINUTE_OF_HOUR: - case SECOND_OF_DAY: - case SECOND_OF_MINUTE: - case MILLI_OF_DAY: - case MILLI_OF_SECOND: - case NANO_OF_DAY: - case NANO_OF_SECOND: - case CLOCK_HOUR_OF_DAY: - case CLOCK_HOUR_OF_AMPM: - case EPOCH_DAY: - case PROLEPTIC_MONTH: - case MONTH_OF_YEAR: - return field.range(); - case ERA: - return ValueRange.of(JapaneseEra.SEIREKI.getValue(), - getCurrentEra().getValue()); - } - Calendar jcal = Calendar.getInstance(LOCALE); - int fieldIndex; - switch (field) { + case ALIGNED_DAY_OF_WEEK_IN_MONTH: + case ALIGNED_DAY_OF_WEEK_IN_YEAR: + case ALIGNED_WEEK_OF_MONTH: + case ALIGNED_WEEK_OF_YEAR: + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); case YEAR_OF_ERA: { + Calendar jcal = Calendar.getInstance(LOCALE); int startYear = getCurrentEra().getPrivateEra().getSinceDate().getYear(); - return ValueRange.of(Year.MIN_VALUE, jcal.getGreatestMinimum(Calendar.YEAR), + return ValueRange.of(1, jcal.getGreatestMinimum(Calendar.YEAR), jcal.getLeastMaximum(Calendar.YEAR) + 1, // +1 due to the different definitions Year.MAX_VALUE - startYear); } - case DAY_OF_YEAR: - fieldIndex = Calendar.DAY_OF_YEAR; - break; + case DAY_OF_YEAR: { + Calendar jcal = Calendar.getInstance(LOCALE); + int fieldIndex = Calendar.DAY_OF_YEAR; + return ValueRange.of(jcal.getMinimum(fieldIndex), jcal.getGreatestMinimum(fieldIndex), + jcal.getLeastMaximum(fieldIndex), jcal.getMaximum(fieldIndex)); + } + case YEAR: + return ValueRange.of(JapaneseDate.MEIJI_6_ISODATE.getYear(), Year.MAX_VALUE); + case ERA: + return ValueRange.of(JapaneseEra.MEIJI.getValue(), getCurrentEra().getValue()); default: - // TODO: review the remaining fields - throw new UnsupportedOperationException("Unimplementable field: " + field); + return field.range(); } - return ValueRange.of(jcal.getMinimum(fieldIndex), jcal.getGreatestMinimum(fieldIndex), - jcal.getLeastMaximum(fieldIndex), jcal.getMaximum(fieldIndex)); + } + + //----------------------------------------------------------------------- + @Override // override for return type + public JapaneseDate resolveDate(Map fieldValues, ResolverStyle resolverStyle) { + return (JapaneseDate) super.resolveDate(fieldValues, resolverStyle); + } + + @Override // override for special Japanese behavior + ChronoLocalDate resolveYearOfEra(Map fieldValues, ResolverStyle resolverStyle) { + // validate era and year-of-era + Long eraLong = fieldValues.get(ERA); + JapaneseEra era = null; + if (eraLong != null) { + era = eraOf(range(ERA).checkValidIntValue(eraLong, ERA)); // always validated + } + Long yoeLong = fieldValues.get(YEAR_OF_ERA); + int yoe = 0; + if (yoeLong != null) { + yoe = range(YEAR_OF_ERA).checkValidIntValue(yoeLong, YEAR_OF_ERA); // always validated + } + // if only year-of-era and no year then invent era unless strict + if (era == null && yoeLong != null && fieldValues.containsKey(YEAR) == false && resolverStyle != ResolverStyle.STRICT) { + era = JapaneseEra.values()[JapaneseEra.values().length - 1]; + } + // if both present, then try to create date + if (yoeLong != null && era != null) { + if (fieldValues.containsKey(MONTH_OF_YEAR)) { + if (fieldValues.containsKey(DAY_OF_MONTH)) { + return resolveYMD(era, yoe, fieldValues, resolverStyle); + } + } + if (fieldValues.containsKey(DAY_OF_YEAR)) { + return resolveYD(era, yoe, fieldValues, resolverStyle); + } + } + return null; + } + + private int prolepticYearLenient(JapaneseEra era, int yearOfEra) { + return era.getPrivateEra().getSinceDate().getYear() + yearOfEra - 1; + } + + private ChronoLocalDate resolveYMD(JapaneseEra era, int yoe, Map fieldValues, ResolverStyle resolverStyle) { + fieldValues.remove(ERA); + fieldValues.remove(YEAR_OF_ERA); + if (resolverStyle == ResolverStyle.LENIENT) { + int y = prolepticYearLenient(era, yoe); + long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1); + long days = Math.subtractExact(fieldValues.remove(DAY_OF_MONTH), 1); + return date(y, 1, 1).plus(months, MONTHS).plus(days, DAYS); + } + int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR); + int dom = range(DAY_OF_MONTH).checkValidIntValue(fieldValues.remove(DAY_OF_MONTH), DAY_OF_MONTH); + if (resolverStyle == ResolverStyle.SMART) { // previous valid + if (yoe < 1) { + throw new DateTimeException("Invalid YearOfEra: " + yoe); + } + int y = prolepticYearLenient(era, yoe); + JapaneseDate result; + try { + result = date(y, moy, dom); + } catch (DateTimeException ex) { + result = date(y, moy, 1).with(TemporalAdjuster.lastDayOfMonth()); + } + // handle the era being changed + // only allow if the new date is in the same Jan-Dec as the era change + // determine by ensuring either original yoe or result yoe is 1 + if (result.getEra() != era && result.get(YEAR_OF_ERA) > 1 && yoe > 1) { + throw new DateTimeException("Invalid YearOfEra for Era: " + era + " " + yoe); + } + return result; + } + return date(era, yoe, moy, dom); + } + + private ChronoLocalDate resolveYD(JapaneseEra era, int yoe, Map fieldValues, ResolverStyle resolverStyle) { + fieldValues.remove(ERA); + fieldValues.remove(YEAR_OF_ERA); + if (resolverStyle == ResolverStyle.LENIENT) { + int y = prolepticYearLenient(era, yoe); + long days = Math.subtractExact(fieldValues.remove(DAY_OF_YEAR), 1); + return dateYearDay(y, 1).plus(days, DAYS); + } + int doy = range(DAY_OF_YEAR).checkValidIntValue(fieldValues.remove(DAY_OF_YEAR), DAY_OF_YEAR); + return dateYearDay(era, yoe, doy); // smart is same as strict } } diff --git a/jdk/src/share/classes/java/time/chrono/JapaneseDate.java b/jdk/src/share/classes/java/time/chrono/JapaneseDate.java index 646315b3d80..e49a8f33c75 100644 --- a/jdk/src/share/classes/java/time/chrono/JapaneseDate.java +++ b/jdk/src/share/classes/java/time/chrono/JapaneseDate.java @@ -56,9 +56,15 @@ */ package java.time.chrono; +import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH; +import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR; +import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH; +import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR; import static java.time.temporal.ChronoField.DAY_OF_MONTH; +import static java.time.temporal.ChronoField.DAY_OF_YEAR; import static java.time.temporal.ChronoField.MONTH_OF_YEAR; import static java.time.temporal.ChronoField.YEAR; +import static java.time.temporal.ChronoField.YEAR_OF_ERA; import java.io.DataInput; import java.io.DataOutput; @@ -96,6 +102,10 @@ import sun.util.calendar.LocalGregorianCalendar; * apart from the era-based year numbering. The proleptic-year is defined to be * equal to the ISO proleptic-year. *

    + * Japan introduced the Gregorian calendar starting with Meiji 6. + * Only Meiji and later eras are supported; + * dates before Meiji 6, January 1 are not supported. + *

    * For example, the Japanese year "Heisei 24" corresponds to ISO year "2012".
    * Calling {@code japaneseDate.get(YEAR_OF_ERA)} will return 24.
    * Calling {@code japaneseDate.get(YEAR)} will return 2012.
    @@ -109,7 +119,7 @@ import sun.util.calendar.LocalGregorianCalendar; */ public final class JapaneseDate extends ChronoDateImpl - implements ChronoLocalDate, Serializable { + implements ChronoLocalDate, Serializable { /** * Serialization version. @@ -129,6 +139,11 @@ public final class JapaneseDate */ private transient int yearOfEra; + /** + * The first day supported by the JapaneseChronology is Meiji 6, January 1st. + */ + final static LocalDate MEIJI_6_ISODATE = LocalDate.of(1873, 1, 1); + //----------------------------------------------------------------------- /** * Obtains the current {@code JapaneseDate} from the system clock in the default time-zone. @@ -173,7 +188,7 @@ public final class JapaneseDate * @throws DateTimeException if the current date cannot be obtained */ public static JapaneseDate now(Clock clock) { - return JapaneseChronology.INSTANCE.date(LocalDate.now(clock)); + return new JapaneseDate(LocalDate.now(clock)); } /** @@ -182,6 +197,16 @@ public final class JapaneseDate *

    * This returns a {@code JapaneseDate} with the specified fields. * The day must be valid for the year and month, otherwise an exception will be thrown. + *

    + * The Japanese month and day-of-month are the same as those in the + * ISO calendar system. They are not reset when the era changes. + * For example: + *

    +     *  6th Jan Showa 64 = ISO 1989-01-06
    +     *  7th Jan Showa 64 = ISO 1989-01-07
    +     *  8th Jan Heisei 1 = ISO 1989-01-08
    +     *  9th Jan Heisei 1 = ISO 1989-01-09
    +     * 
    * * @param era the Japanese era, not null * @param yearOfEra the Japanese year-of-era @@ -192,11 +217,15 @@ public final class JapaneseDate * or if the day-of-month is invalid for the month-year, * or if the date is not a Japanese era */ - public static JapaneseDate of(Era era, int yearOfEra, int month, int dayOfMonth) { - if (era instanceof JapaneseEra == false) { - throw new ClassCastException("Era must be JapaneseEra"); + public static JapaneseDate of(JapaneseEra era, int yearOfEra, int month, int dayOfMonth) { + Objects.requireNonNull(era, "era"); + LocalGregorianCalendar.Date jdate = JapaneseChronology.JCAL.newCalendarDate(null); + jdate.setEra(era.getPrivateEra()).setDate(yearOfEra, month, dayOfMonth); + if (!JapaneseChronology.JCAL.validate(jdate)) { + throw new DateTimeException("year, month, and day not valid for Era"); } - return JapaneseDate.of((JapaneseEra) era, yearOfEra, month, dayOfMonth); + LocalDate date = LocalDate.of(jdate.getNormalizedYear(), month, dayOfMonth); + return new JapaneseDate(era, yearOfEra, date); } /** @@ -205,6 +234,9 @@ public final class JapaneseDate *

    * This returns a {@code JapaneseDate} with the specified fields. * The day must be valid for the year and month, otherwise an exception will be thrown. + *

    + * The Japanese proleptic year, month and day-of-month are the same as those + * in the ISO calendar system. They are not reset when the era changes. * * @param prolepticYear the Japanese proleptic-year * @param month the Japanese month-of-year, from 1 to 12 @@ -219,23 +251,31 @@ public final class JapaneseDate /** * Obtains a {@code JapaneseDate} representing a date in the Japanese calendar - * system from the proleptic-year and day-of-year fields. + * system from the era, year-of-era and day-of-year fields. *

    * This returns a {@code JapaneseDate} with the specified fields. * The day must be valid for the year, otherwise an exception will be thrown. + *

    + * The day-of-year in this factory is expressed relative to the start of the year-of-era. + * This definition changes the normal meaning of day-of-year only in those years + * where the year-of-era is reset to one due to a change in the era. + * For example: + *

    +     *  6th Jan Showa 64 = day-of-year 6
    +     *  7th Jan Showa 64 = day-of-year 7
    +     *  8th Jan Heisei 1 = day-of-year 1
    +     *  9th Jan Heisei 1 = day-of-year 2
    +     * 
    * - * @param prolepticYear the chronology proleptic-year + * @param era the Japanese era, not null + * @param yearOfEra the Japanese year-of-era * @param dayOfYear the chronology day-of-year, from 1 to 366 * @return the date in Japanese calendar system, not null * @throws DateTimeException if the value of any field is out of range, * or if the day-of-year is invalid for the year */ - public static JapaneseDate ofYearDay(int prolepticYear, int dayOfYear) { - LocalDate date = LocalDate.ofYearDay(prolepticYear, dayOfYear); - return of(prolepticYear, date.getMonthValue(), date.getDayOfMonth()); - } - static JapaneseDate ofYearDay(JapaneseEra era, int yearOfEra, int dayOfYear) { + Objects.requireNonNull(era, "era"); CalendarDate firstDay = era.getPrivateEra().getSinceDate(); LocalGregorianCalendar.Date jdate = JapaneseChronology.JCAL.newCalendarDate(null); jdate.setEra(era.getPrivateEra()); @@ -253,32 +293,6 @@ public final class JapaneseDate return new JapaneseDate(era, yearOfEra, localdate); } - /** - * 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. - *

    - * This returns a {@code JapaneseDate} with the specified fields. - * The day must be valid for the year and month, otherwise an exception will be thrown. - * - * @param era the Japanese era, not null - * @param yearOfEra the Japanese year-of-era - * @param month the Japanese month-of-year, from 1 to 12 - * @param dayOfMonth the Japanese day-of-month, from 1 to 31 - * @return the date in Japanese calendar system, not null - * @throws DateTimeException if the value of any field is out of range, - * or if the day-of-month is invalid for the month-year - */ - static JapaneseDate of(JapaneseEra era, int yearOfEra, int month, int dayOfMonth) { - Objects.requireNonNull(era, "era"); - LocalGregorianCalendar.Date jdate = JapaneseChronology.JCAL.newCalendarDate(null); - jdate.setEra(era.getPrivateEra()).setDate(yearOfEra, month, dayOfMonth); - if (!JapaneseChronology.JCAL.validate(jdate)) { - throw new DateTimeException("year, month, and day not valid for Era"); - } - LocalDate date = LocalDate.of(jdate.getNormalizedYear(), month, dayOfMonth); - return new JapaneseDate(era, yearOfEra, date); - } - /** * Obtains a {@code JapaneseDate} from a temporal object. *

    @@ -307,6 +321,9 @@ public final class JapaneseDate * @param isoDate the standard local date, validated not null */ JapaneseDate(LocalDate isoDate) { + if (isoDate.isBefore(MEIJI_6_ISODATE)) { + throw new DateTimeException("JapaneseDate before Meiji 6 is not supported"); + } LocalGregorianCalendar.Date jdate = toPrivateJapaneseDate(isoDate); this.era = JapaneseEra.toJapaneseEra(jdate.getEra()); this.yearOfEra = jdate.getYear(); @@ -322,6 +339,9 @@ public final class JapaneseDate * @param isoDate the standard local date, validated not null */ JapaneseDate(JapaneseEra era, int year, LocalDate isoDate) { + if (isoDate.isBefore(MEIJI_6_ISODATE)) { + throw new DateTimeException("JapaneseDate before Meiji 6 is not supported"); + } this.era = era; this.yearOfEra = year; this.isoDate = isoDate; @@ -366,55 +386,99 @@ public final class JapaneseDate return isoDate.lengthOfMonth(); } + @Override + public int lengthOfYear() { + Calendar jcal = Calendar.getInstance(JapaneseChronology.LOCALE); + jcal.set(Calendar.ERA, era.getValue() + JapaneseEra.ERA_OFFSET); + jcal.set(yearOfEra, isoDate.getMonthValue() - 1, isoDate.getDayOfMonth()); + return jcal.getActualMaximum(Calendar.DAY_OF_YEAR); + } + //----------------------------------------------------------------------- + /** + * Checks if the specified field is supported. + *

    + * This checks if this date can be queried for the specified field. + * If false, then calling the {@link #range(TemporalField) range} and + * {@link #get(TemporalField) get} methods will throw an exception. + *

    + * If the field is a {@link ChronoField} then the query is implemented here. + * The supported fields are: + *

      + *
    • {@code DAY_OF_WEEK} + *
    • {@code DAY_OF_MONTH} + *
    • {@code DAY_OF_YEAR} + *
    • {@code EPOCH_DAY} + *
    • {@code MONTH_OF_YEAR} + *
    • {@code PROLEPTIC_MONTH} + *
    • {@code YEAR_OF_ERA} + *
    • {@code YEAR} + *
    • {@code ERA} + *
    + * All other {@code ChronoField} instances will return false. + *

    + * If the field is not a {@code ChronoField}, then the result of this method + * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)} + * passing {@code this} as the argument. + * Whether the field is supported is determined by the field. + * + * @param field the field to check, null returns false + * @return true if the field is supported on this date, false if not + */ + @Override + public boolean isSupported(TemporalField field) { + if (field == ALIGNED_DAY_OF_WEEK_IN_MONTH || field == ALIGNED_DAY_OF_WEEK_IN_YEAR || + field == ALIGNED_WEEK_OF_MONTH || field == ALIGNED_WEEK_OF_YEAR) { + return false; + } + return ChronoLocalDate.super.isSupported(field); + } + @Override public ValueRange range(TemporalField field) { if (field instanceof ChronoField) { if (isSupported(field)) { ChronoField f = (ChronoField) field; switch (f) { - case DAY_OF_MONTH: - case ALIGNED_WEEK_OF_MONTH: - return isoDate.range(field); - case DAY_OF_YEAR: - return actualRange(Calendar.DAY_OF_YEAR); - case YEAR_OF_ERA: - return actualRange(Calendar.YEAR); + case DAY_OF_MONTH: return ValueRange.of(1, lengthOfMonth()); + case DAY_OF_YEAR: return ValueRange.of(1, lengthOfYear()); + case YEAR_OF_ERA: { + Calendar jcal = Calendar.getInstance(JapaneseChronology.LOCALE); + jcal.set(Calendar.ERA, era.getValue() + JapaneseEra.ERA_OFFSET); + jcal.set(yearOfEra, isoDate.getMonthValue() - 1, isoDate.getDayOfMonth()); + return ValueRange.of(1, jcal.getActualMaximum(Calendar.YEAR)); + } } return getChronology().range(f); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.rangeRefinedBy(this); } - private ValueRange actualRange(int calendarField) { - Calendar jcal = Calendar.getInstance(JapaneseChronology.LOCALE); - jcal.set(Calendar.ERA, era.getValue() + JapaneseEra.ERA_OFFSET); // TODO: cannot calculate this way for SEIREKI - jcal.set(yearOfEra, isoDate.getMonthValue() - 1, isoDate.getDayOfMonth()); - return ValueRange.of(jcal.getActualMinimum(calendarField), - jcal.getActualMaximum(calendarField)); - } - @Override public long getLong(TemporalField field) { if (field instanceof ChronoField) { // same as ISO: - // DAY_OF_WEEK, ALIGNED_DAY_OF_WEEK_IN_MONTH, DAY_OF_MONTH, EPOCH_DAY, - // ALIGNED_WEEK_OF_MONTH, MONTH_OF_YEAR, PROLEPTIC_MONTH, YEAR + // DAY_OF_WEEK, DAY_OF_MONTH, EPOCH_DAY, MONTH_OF_YEAR, PROLEPTIC_MONTH, YEAR // // calendar specific fields - // ALIGNED_DAY_OF_WEEK_IN_YEAR, DAY_OF_YEAR, ALIGNED_WEEK_OF_YEAR, YEAR_OF_ERA, ERA + // DAY_OF_YEAR, YEAR_OF_ERA, ERA switch ((ChronoField) field) { + case ALIGNED_DAY_OF_WEEK_IN_MONTH: + case ALIGNED_DAY_OF_WEEK_IN_YEAR: + case ALIGNED_WEEK_OF_MONTH: + case ALIGNED_WEEK_OF_YEAR: + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); case YEAR_OF_ERA: return yearOfEra; case ERA: return era.getValue(); - case DAY_OF_YEAR: { - LocalGregorianCalendar.Date jdate = toPrivateJapaneseDate(isoDate); - return JapaneseChronology.JCAL.getDayOfYear(jdate); - } - // TODO: ALIGNED_DAY_OF_WEEK_IN_YEAR and ALIGNED_WEEK_OF_YEAR ??? + case DAY_OF_YEAR: + Calendar jcal = Calendar.getInstance(JapaneseChronology.LOCALE); + jcal.set(Calendar.ERA, era.getValue() + JapaneseEra.ERA_OFFSET); + jcal.set(yearOfEra, isoDate.getMonthValue() - 1, isoDate.getDayOfMonth()); + return jcal.get(Calendar.DAY_OF_YEAR); } return isoDate.getLong(field); } @@ -444,7 +508,7 @@ public final class JapaneseDate public JapaneseDate with(TemporalField field, long newValue) { if (field instanceof ChronoField) { ChronoField f = (ChronoField) field; - if (getLong(f) == newValue) { + if (getLong(f) == newValue) { // getLong() validates for supported fields return this; } switch (f) { @@ -464,10 +528,9 @@ public final class JapaneseDate } } // YEAR, PROLEPTIC_MONTH and others are same as ISO - // TODO: review other fields, such as WEEK_OF_YEAR return with(isoDate.with(field, newValue)); } - return ChronoLocalDate.super.with(field, newValue); + return super.with(field, newValue); } /** @@ -592,13 +655,14 @@ public final class JapaneseDate } @Override // for javadoc and covariant return type + @SuppressWarnings("unchecked") public final ChronoLocalDateTime atTime(LocalTime localTime) { - return super.atTime(localTime); + return (ChronoLocalDateTime)super.atTime(localTime); } @Override - public Period periodUntil(ChronoLocalDate endDate) { - return isoDate.periodUntil(endDate); + public Period until(ChronoLocalDate endDate) { + return isoDate.until(endDate); } @Override // override for performance @@ -624,14 +688,6 @@ public final class JapaneseDate return getChronology().getId().hashCode() ^ isoDate.hashCode(); } - @Override - public String toString() { - if (era == JapaneseEra.SEIREKI) { - return getChronology().getId() + " " + isoDate.toString(); - } - return super.toString(); - } - //----------------------------------------------------------------------- private Object writeReplace() { return new Ser(Ser.JAPANESE_DATE_TYPE, this); diff --git a/jdk/src/share/classes/java/time/chrono/JapaneseEra.java b/jdk/src/share/classes/java/time/chrono/JapaneseEra.java index 17635793b08..ba9fb434bf9 100644 --- a/jdk/src/share/classes/java/time/chrono/JapaneseEra.java +++ b/jdk/src/share/classes/java/time/chrono/JapaneseEra.java @@ -61,6 +61,7 @@ */ package java.time.chrono; +import static java.time.chrono.JapaneseDate.MEIJI_6_ISODATE; import static java.time.temporal.ChronoField.ERA; import java.io.DataInput; @@ -84,12 +85,9 @@ import sun.util.calendar.CalendarDate; * An era in the Japanese Imperial calendar system. *

    * This class defines the valid eras for the Japanese chronology. - * Only Meiji (1868-09-08 - 1912-07-29) and later eras are supported. - * Japan introduced the Gregorian calendar since Meiji 6. The dates - * between Meiji 1 - 5 are not historically correct. - * The older eras are recognized as Seireki (Western calendar) era, - * and the year of era of Seireki is proleptic Gregorian year. - * (The Julian to Gregorian transition is not supported.) + * Japan introduced the Gregorian calendar starting with Meiji 6. + * Only Meiji and later eras are supported; + * dates before Meiji 6, January 1 are not supported. * * @implSpec * This class is immutable and thread-safe. @@ -100,16 +98,11 @@ public final class JapaneseEra implements Era, Serializable { // The offset value to 0-based index from the era value. - // i.e., getValue() + ERA_OFFSET == 0-based index; except that -999 is mapped to zero + // i.e., getValue() + ERA_OFFSET == 0-based index static final int ERA_OFFSET = 2; static final sun.util.calendar.Era[] ERA_CONFIG; - /** - * The singleton instance for the before Meiji era ( - 1868-09-07) - * which has the value -999. - */ - public static final JapaneseEra SEIREKI = new JapaneseEra(-999, LocalDate.MIN); /** * The singleton instance for the 'Meiji' era (1868-09-08 - 1912-07-29) * which has the value -1. @@ -144,17 +137,13 @@ public final class JapaneseEra private static final JapaneseEra[] KNOWN_ERAS; static { - sun.util.calendar.Era[] sunEras = JapaneseChronology.JCAL.getEras(); - ERA_CONFIG = new sun.util.calendar.Era[sunEras.length + 1]; - for (int i = 1; i < ERA_CONFIG.length; i++) { - ERA_CONFIG[i] = sunEras[i - 1]; - } + ERA_CONFIG = JapaneseChronology.JCAL.getEras(); + KNOWN_ERAS = new JapaneseEra[ERA_CONFIG.length]; - KNOWN_ERAS[0] = SEIREKI; - KNOWN_ERAS[1] = MEIJI; - KNOWN_ERAS[2] = TAISHO; - KNOWN_ERAS[3] = SHOWA; - KNOWN_ERAS[4] = HEISEI; + KNOWN_ERAS[0] = MEIJI; + KNOWN_ERAS[1] = TAISHO; + KNOWN_ERAS[2] = SHOWA; + KNOWN_ERAS[3] = HEISEI; for (int i = N_ERA_CONSTANTS; i < ERA_CONFIG.length; i++) { CalendarDate date = ERA_CONFIG[i].getSinceDate(); LocalDate isoDate = LocalDate.of(date.getYear(), date.getMonth(), date.getDayOfMonth()); @@ -203,10 +192,8 @@ public final class JapaneseEra //----------------------------------------------------------------------- /** * Returns the Sun private Era instance corresponding to this {@code JapaneseEra}. - * SEIREKI doesn't have its corresponding one. * - * @return the Sun private Era instance for this {@code JapaneseEra}, - * or null for SEIREKI. + * @return the Sun private Era instance for this {@code JapaneseEra}. */ sun.util.calendar.Era getPrivateEra() { return ERA_CONFIG[ordinal(eraValue)]; @@ -218,16 +205,14 @@ public final class JapaneseEra *

    * The {@link #SHOWA} era that contains 1970-01-01 (ISO calendar system) has the value 1 * Later era is numbered 2 ({@link #HEISEI}). Earlier eras are numbered 0 ({@link #TAISHO}), - * -1 ({@link #MEIJI}), only Meiji and later eras are supported. The prior to Meiji, - * {@link #SEIREKI} is used. + * -1 ({@link #MEIJI}), only Meiji and later eras are supported. * * @param japaneseEra the era to represent * @return the {@code JapaneseEra} singleton, not null * @throws DateTimeException if the value is invalid */ public static JapaneseEra of(int japaneseEra) { - if (japaneseEra != SEIREKI.eraValue && - (japaneseEra < MEIJI.eraValue || japaneseEra > HEISEI.eraValue)) { + if (japaneseEra < MEIJI.eraValue || japaneseEra > HEISEI.eraValue) { throw new DateTimeException("Invalid era: " + japaneseEra); } return KNOWN_ERAS[ordinal(japaneseEra)]; @@ -276,22 +261,25 @@ public final class JapaneseEra * @return the Era singleton, never null */ static JapaneseEra from(LocalDate date) { + if (date.isBefore(MEIJI_6_ISODATE)) { + throw new DateTimeException("JapaneseDate before Meiji 6 are not supported"); + } for (int i = KNOWN_ERAS.length - 1; i > 0; i--) { JapaneseEra era = KNOWN_ERAS[i]; if (date.compareTo(era.since) >= 0) { return era; } } - return SEIREKI; + return null; } static JapaneseEra toJapaneseEra(sun.util.calendar.Era privateEra) { - for (int i = ERA_CONFIG.length - 1; i > 0; i--) { + for (int i = ERA_CONFIG.length - 1; i >= 0; i--) { if (ERA_CONFIG[i].equals(privateEra)) { return KNOWN_ERAS[i]; } } - return SEIREKI; + return null; } static sun.util.calendar.Era privateEraFrom(LocalDate isoDate) { @@ -306,13 +294,13 @@ public final class JapaneseEra /** * Returns the index into the arrays from the Era value. - * the eraValue is a valid Era number, -999, -1..2. + * the eraValue is a valid Era number, -1..2. * * @param eraValue the era value to convert to the index * @return the index of the current Era */ private static int ordinal(int eraValue) { - return (eraValue == SEIREKI.eraValue) ? 0 : eraValue + ERA_OFFSET; + return eraValue + ERA_OFFSET - 1; } //----------------------------------------------------------------------- @@ -321,7 +309,7 @@ public final class JapaneseEra *

    * The {@link #SHOWA} era that contains 1970-01-01 (ISO calendar system) has the value 1. * Later eras are numbered from 2 ({@link #HEISEI}). - * Earlier eras are numbered 0 ({@link #TAISHO}), -1 ({@link #MEIJI}), and -999 ({@link #SEIREKI}). + * Earlier eras are numbered 0 ({@link #TAISHO}), -1 ({@link #MEIJI})). * * @return the era value */ @@ -374,11 +362,7 @@ public final class JapaneseEra } String getName() { - int index = ordinal(getValue()); - if (index == 0) { - return "Seireki"; - } - return ERA_CONFIG[index].getName(); + return ERA_CONFIG[ordinal(getValue())].getName(); } @Override diff --git a/jdk/src/share/classes/java/time/chrono/MinguoChronology.java b/jdk/src/share/classes/java/time/chrono/MinguoChronology.java index 1c9c2e34c16..088588004c3 100644 --- a/jdk/src/share/classes/java/time/chrono/MinguoChronology.java +++ b/jdk/src/share/classes/java/time/chrono/MinguoChronology.java @@ -65,12 +65,15 @@ import java.time.DateTimeException; import java.time.Instant; import java.time.LocalDate; import java.time.ZoneId; +import java.time.format.ResolverStyle; import java.time.temporal.ChronoField; import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalField; import java.time.temporal.ValueRange; import java.util.Arrays; import java.util.List; import java.util.Locale; +import java.util.Map; /** * The Minguo calendar system. @@ -253,16 +256,19 @@ public final class MinguoChronology extends Chronology implements Serializable { } @Override + @SuppressWarnings("unchecked") public ChronoLocalDateTime localDateTime(TemporalAccessor temporal) { return (ChronoLocalDateTime)super.localDateTime(temporal); } @Override + @SuppressWarnings("unchecked") public ChronoZonedDateTime zonedDateTime(TemporalAccessor temporal) { return (ChronoZonedDateTime)super.zonedDateTime(temporal); } @Override + @SuppressWarnings("unchecked") public ChronoZonedDateTime zonedDateTime(Instant instant, ZoneId zone) { return (ChronoZonedDateTime)super.zonedDateTime(instant, zone); } @@ -292,7 +298,7 @@ public final class MinguoChronology extends Chronology implements Serializable { } @Override - public Era eraOf(int eraValue) { + public MinguoEra eraOf(int eraValue) { return MinguoEra.of(eraValue); } @@ -321,4 +327,10 @@ public final class MinguoChronology extends Chronology implements Serializable { return field.range(); } + //----------------------------------------------------------------------- + @Override // override for return type + public MinguoDate resolveDate(Map fieldValues, ResolverStyle resolverStyle) { + return (MinguoDate) super.resolveDate(fieldValues, resolverStyle); + } + } diff --git a/jdk/src/share/classes/java/time/chrono/MinguoDate.java b/jdk/src/share/classes/java/time/chrono/MinguoDate.java index b6a5582ef98..e15b0e90a15 100644 --- a/jdk/src/share/classes/java/time/chrono/MinguoDate.java +++ b/jdk/src/share/classes/java/time/chrono/MinguoDate.java @@ -96,7 +96,7 @@ import java.util.Objects; */ public final class MinguoDate extends ChronoDateImpl - implements ChronoLocalDate, Serializable { + implements ChronoLocalDate, Serializable { /** * Serialization version. @@ -152,7 +152,7 @@ public final class MinguoDate * @throws DateTimeException if the current date cannot be obtained */ public static MinguoDate now(Clock clock) { - return MinguoChronology.INSTANCE.date(LocalDate.now(clock)); + return new MinguoDate(LocalDate.now(clock)); } /** @@ -264,7 +264,7 @@ public final class MinguoDate } return getChronology().range(f); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.rangeRefinedBy(this); } @@ -325,7 +325,7 @@ public final class MinguoDate } return with(isoDate.with(field, newValue)); } - return ChronoLocalDate.super.with(field, newValue); + return super.with(field, newValue); } /** @@ -369,6 +369,11 @@ public final class MinguoDate return with(isoDate.plusMonths(months)); } + @Override + MinguoDate plusWeeks(long weeksToAdd) { + return super.plusWeeks(weeksToAdd); + } + @Override MinguoDate plusDays(long days) { return with(isoDate.plusDays(days)); @@ -384,11 +389,6 @@ public final class MinguoDate return super.minus(amountToAdd, unit); } - @Override - MinguoDate plusWeeks(long weeksToAdd) { - return super.plusWeeks(weeksToAdd); - } - @Override MinguoDate minusYears(long yearsToSubtract) { return super.minusYears(yearsToSubtract); @@ -414,13 +414,14 @@ public final class MinguoDate } @Override // for javadoc and covariant return type + @SuppressWarnings("unchecked") public final ChronoLocalDateTime atTime(LocalTime localTime) { - return super.atTime(localTime); + return (ChronoLocalDateTime)super.atTime(localTime); } @Override - public Period periodUntil(ChronoLocalDate endDate) { - return isoDate.periodUntil(endDate); + public Period until(ChronoLocalDate endDate) { + return isoDate.until(endDate); } @Override // override for performance @@ -458,7 +459,7 @@ public final class MinguoDate out.writeByte(get(DAY_OF_MONTH)); } - static ChronoLocalDate readExternal(DataInput in) throws IOException { + static MinguoDate readExternal(DataInput in) throws IOException { int year = in.readInt(); int month = in.readByte(); int dayOfMonth = in.readByte(); diff --git a/jdk/src/share/classes/java/time/chrono/ThaiBuddhistChronology.java b/jdk/src/share/classes/java/time/chrono/ThaiBuddhistChronology.java index 27c98a6f079..04f59ceb93c 100644 --- a/jdk/src/share/classes/java/time/chrono/ThaiBuddhistChronology.java +++ b/jdk/src/share/classes/java/time/chrono/ThaiBuddhistChronology.java @@ -65,13 +65,16 @@ import java.time.DateTimeException; import java.time.Instant; import java.time.LocalDate; import java.time.ZoneId; +import java.time.format.ResolverStyle; import java.time.temporal.ChronoField; import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalField; import java.time.temporal.ValueRange; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Locale; +import java.util.Map; /** * The Thai Buddhist calendar system. @@ -289,16 +292,19 @@ public final class ThaiBuddhistChronology extends Chronology implements Serializ } @Override + @SuppressWarnings("unchecked") public ChronoLocalDateTime localDateTime(TemporalAccessor temporal) { return (ChronoLocalDateTime)super.localDateTime(temporal); } @Override + @SuppressWarnings("unchecked") public ChronoZonedDateTime zonedDateTime(TemporalAccessor temporal) { return (ChronoZonedDateTime)super.zonedDateTime(temporal); } @Override + @SuppressWarnings("unchecked") public ChronoZonedDateTime zonedDateTime(Instant instant, ZoneId zone) { return (ChronoZonedDateTime)super.zonedDateTime(instant, zone); } @@ -328,7 +334,7 @@ public final class ThaiBuddhistChronology extends Chronology implements Serializ } @Override - public Era eraOf(int eraValue) { + public ThaiBuddhistEra eraOf(int eraValue) { return ThaiBuddhistEra.of(eraValue); } @@ -357,4 +363,10 @@ public final class ThaiBuddhistChronology extends Chronology implements Serializ return field.range(); } + //----------------------------------------------------------------------- + @Override // override for return type + public ThaiBuddhistDate resolveDate(Map fieldValues, ResolverStyle resolverStyle) { + return (ThaiBuddhistDate) super.resolveDate(fieldValues, resolverStyle); + } + } diff --git a/jdk/src/share/classes/java/time/chrono/ThaiBuddhistDate.java b/jdk/src/share/classes/java/time/chrono/ThaiBuddhistDate.java index 973c7b8ab0f..67799ad5af8 100644 --- a/jdk/src/share/classes/java/time/chrono/ThaiBuddhistDate.java +++ b/jdk/src/share/classes/java/time/chrono/ThaiBuddhistDate.java @@ -96,7 +96,7 @@ import java.util.Objects; */ public final class ThaiBuddhistDate extends ChronoDateImpl - implements ChronoLocalDate, Serializable { + implements ChronoLocalDate, Serializable { /** * Serialization version. @@ -152,7 +152,7 @@ public final class ThaiBuddhistDate * @throws DateTimeException if the current date cannot be obtained */ public static ThaiBuddhistDate now(Clock clock) { - return ThaiBuddhistChronology.INSTANCE.date(LocalDate.now(clock)); + return new ThaiBuddhistDate(LocalDate.now(clock)); } /** @@ -264,7 +264,7 @@ public final class ThaiBuddhistDate } return getChronology().range(f); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.rangeRefinedBy(this); } @@ -325,7 +325,7 @@ public final class ThaiBuddhistDate } return with(isoDate.with(field, newValue)); } - return ChronoLocalDate.super.with(field, newValue); + return super.with(field, newValue); } /** @@ -414,13 +414,14 @@ public final class ThaiBuddhistDate } @Override // for javadoc and covariant return type + @SuppressWarnings("unchecked") public final ChronoLocalDateTime atTime(LocalTime localTime) { - return super.atTime(localTime); + return (ChronoLocalDateTime) super.atTime(localTime); } @Override - public Period periodUntil(ChronoLocalDate endDate) { - return isoDate.periodUntil(endDate); + public Period until(ChronoLocalDate endDate) { + return isoDate.until(endDate); } @Override // override for performance diff --git a/jdk/src/share/classes/java/time/chrono/package-info.java b/jdk/src/share/classes/java/time/chrono/package-info.java index 4f2a3f6e78c..9273a770f82 100644 --- a/jdk/src/share/classes/java/time/chrono/package-info.java +++ b/jdk/src/share/classes/java/time/chrono/package-info.java @@ -103,7 +103,7 @@ * // Enumerate the list of available calendars and print todays date for each. * Set<Chronology> chronos = Chronology.getAvailableChronologies(); * for (Chronology chrono : chronos) { - * ChronoLocalDate<?> date = chrono.dateNow(); + * ChronoLocalDate date = chrono.dateNow(); * System.out.printf(" %20s: %s%n", chrono.getId(), date.toString()); * } * @@ -113,7 +113,7 @@ *

    *
      *   // Print the Thai Buddhist date
    - *       ChronoLocalDate<?> now1 = Chronology.of("ThaiBuddhist").dateNow();
    + *       ChronoLocalDate now1 = Chronology.of("ThaiBuddhist").dateNow();
      *       int day = now1.get(ChronoField.DAY_OF_MONTH);
      *       int dow = now1.get(ChronoField.DAY_OF_WEEK);
      *       int month = now1.get(ChronoField.MONTH_OF_YEAR);
    @@ -121,10 +121,10 @@
      *       System.out.printf("  Today is %s %s %d-%s-%d%n", now1.getChronology().getId(),
      *                 dow, day, month, year);
      *   // Print today's date and the last day of the year for the Thai Buddhist Calendar.
    - *       ChronoLocalDate<?> first = now1
    + *       ChronoLocalDate first = now1
      *                 .with(ChronoField.DAY_OF_MONTH, 1)
      *                 .with(ChronoField.MONTH_OF_YEAR, 1);
    - *       ChronoLocalDate<?> last = first
    + *       ChronoLocalDate last = first
      *                 .plus(1, ChronoUnit.YEARS)
      *                 .minus(1, ChronoUnit.DAYS);
      *       System.out.printf("  %s: 1st of year: %s; end of year: %s%n", last.getChronology().getId(),
    diff --git a/jdk/src/share/classes/java/time/format/DateTimeFormatter.java b/jdk/src/share/classes/java/time/format/DateTimeFormatter.java
    index 2552f96e5ad..0c0a5979b14 100644
    --- a/jdk/src/share/classes/java/time/format/DateTimeFormatter.java
    +++ b/jdk/src/share/classes/java/time/format/DateTimeFormatter.java
    @@ -265,7 +265,7 @@ import java.util.Set;
      * 

    * For example: *

    - *  DateTimeFormatter formatter = DateTimeFormatter.pattern("yyyy MM dd");
    + *  DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd");
      *  String text = date.toString(formatter);
      *  LocalDate date = LocalDate.parse(text, formatter);
      * 
    @@ -460,7 +460,7 @@ import java.util.Set; *
  • The {@code ChronoField} time fields are resolved. * This is documented on {@link ChronoField} and is the same for all chronologies. *
  • Any fields that are not {@code ChronoField} are processed. - * This is achieved using {@link TemporalField#resolve(TemporalAccessor, long, ResolverStyle)}. + * This is achieved using {@link TemporalField#resolve(Map, Chronology, ZoneId, ResolverStyle)}. * Documentation about field resolution is located in the implementation * of {@code TemporalField}. *
  • The {@code ChronoField} date and time fields are re-resolved. diff --git a/jdk/src/share/classes/java/time/format/DateTimeFormatterBuilder.java b/jdk/src/share/classes/java/time/format/DateTimeFormatterBuilder.java index cec07840439..f4983b48861 100644 --- a/jdk/src/share/classes/java/time/format/DateTimeFormatterBuilder.java +++ b/jdk/src/share/classes/java/time/format/DateTimeFormatterBuilder.java @@ -77,7 +77,6 @@ import java.math.BigInteger; import java.math.RoundingMode; import java.text.ParsePosition; import java.time.DateTimeException; -import java.time.Duration; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; @@ -962,12 +961,9 @@ public final class DateTimeFormatterBuilder { *
          *   "Europe/London"           -- ZoneId.of("Europe/London")
          *   "Z"                       -- ZoneOffset.UTC
    -     *   "UT"                      -- ZoneOffset.UTC
    -     *   "UTC"                     -- ZoneOffset.UTC
    -     *   "GMT"                     -- ZoneOffset.UTC
    -     *   "UT0"                     -- ZoneOffset.UTC
    -     *   "UTC0"                    -- ZoneOffset.UTC
    -     *   "GMT0"                    -- ZoneOffset.UTC
    +     *   "UT"                      -- ZoneId.of("UT")
    +     *   "UTC"                     -- ZoneId.of("UTC")
    +     *   "GMT"                     -- ZoneId.of("GMT")
          *   "+01:30"                  -- ZoneOffset.of("+01:30")
          *   "UT+01:30"                -- ZoneOffset.of("+01:30")
          *   "UTC+01:30"               -- ZoneOffset.of("+01:30")
    @@ -1016,12 +1012,9 @@ public final class DateTimeFormatterBuilder {
          * 
          *   "Europe/London"           -- ZoneId.of("Europe/London")
          *   "Z"                       -- ZoneOffset.UTC
    -     *   "UT"                      -- ZoneOffset.UTC
    -     *   "UTC"                     -- ZoneOffset.UTC
    -     *   "GMT"                     -- ZoneOffset.UTC
    -     *   "UT0"                     -- ZoneOffset.UTC
    -     *   "UTC0"                    -- ZoneOffset.UTC
    -     *   "GMT0"                    -- ZoneOffset.UTC
    +     *   "UT"                      -- ZoneId.of("UT")
    +     *   "UTC"                     -- ZoneId.of("UTC")
    +     *   "GMT"                     -- ZoneId.of("GMT")
          *   "+01:30"                  -- ZoneOffset.of("+01:30")
          *   "UT+01:30"                -- ZoneOffset.of("+01:30")
          *   "UTC+01:30"               -- ZoneOffset.of("+01:30")
    @@ -1077,16 +1070,13 @@ public final class DateTimeFormatterBuilder {
          * 
          *   "Europe/London"           -- ZoneId.of("Europe/London")
          *   "Z"                       -- ZoneOffset.UTC
    -     *   "UT"                      -- ZoneOffset.UTC
    -     *   "UTC"                     -- ZoneOffset.UTC
    -     *   "GMT"                     -- ZoneOffset.UTC
    -     *   "UT0"                     -- ZoneOffset.UTC
    -     *   "UTC0"                    -- ZoneOffset.UTC
    -     *   "GMT0"                    -- ZoneOffset.UTC
    +     *   "UT"                      -- ZoneId.of("UT")
    +     *   "UTC"                     -- ZoneId.of("UTC")
    +     *   "GMT"                     -- ZoneId.of("GMT")
          *   "+01:30"                  -- ZoneOffset.of("+01:30")
    -     *   "UT+01:30"                -- ZoneOffset.of("+01:30")
    -     *   "UTC+01:30"               -- ZoneOffset.of("+01:30")
    -     *   "GMT+01:30"               -- ZoneOffset.of("+01:30")
    +     *   "UT+01:30"                -- ZoneOffset.of("UT+01:30")
    +     *   "UTC+01:30"               -- ZoneOffset.of("UTC+01:30")
    +     *   "GMT+01:30"               -- ZoneOffset.of("GMT+01:30")
          * 
    *

    * Note that this method is is identical to {@code appendZoneId()} except @@ -2530,7 +2520,7 @@ public final class DateTimeFormatterBuilder { DecimalStyle decimalStyle = context.getDecimalStyle(); String str = (value == Long.MIN_VALUE ? "9223372036854775808" : Long.toString(Math.abs(value))); if (str.length() > maxWidth) { - throw new DateTimeException("Field " + field.getName() + + throw new DateTimeException("Field " + field + " cannot be printed as the value " + value + " exceeds the maximum print width of " + maxWidth); } @@ -2555,7 +2545,7 @@ public final class DateTimeFormatterBuilder { buf.append(decimalStyle.getNegativeSign()); break; case NOT_NEGATIVE: - throw new DateTimeException("Field " + field.getName() + + throw new DateTimeException("Field " + field + " cannot be printed as the value " + value + " cannot be negative according to the SignStyle"); } @@ -2699,12 +2689,12 @@ public final class DateTimeFormatterBuilder { @Override public String toString() { if (minWidth == 1 && maxWidth == 19 && signStyle == SignStyle.NORMAL) { - return "Value(" + field.getName() + ")"; + return "Value(" + field + ")"; } if (minWidth == maxWidth && signStyle == SignStyle.NOT_NEGATIVE) { - return "Value(" + field.getName() + "," + minWidth + ")"; + return "Value(" + field + "," + minWidth + ")"; } - return "Value(" + field.getName() + "," + minWidth + "," + maxWidth + "," + signStyle + ")"; + return "Value(" + field + "," + minWidth + "," + maxWidth + "," + signStyle + ")"; } } @@ -2817,7 +2807,7 @@ public final class DateTimeFormatterBuilder { @Override public String toString() { - return "ReducedValue(" + field.getName() + "," + minWidth + "," + maxWidth + "," + baseValue + ")"; + return "ReducedValue(" + field + "," + minWidth + "," + maxWidth + "," + baseValue + ")"; } } @@ -2842,7 +2832,7 @@ public final class DateTimeFormatterBuilder { FractionPrinterParser(TemporalField field, int minWidth, int maxWidth, boolean decimalPoint) { Objects.requireNonNull(field, "field"); if (field.range().isFixed() == false) { - throw new IllegalArgumentException("Field must have a fixed set of values: " + field.getName()); + throw new IllegalArgumentException("Field must have a fixed set of values: " + field); } if (minWidth < 0 || minWidth > 9) { throw new IllegalArgumentException("Minimum width must be from 0 to 9 inclusive but was " + minWidth); @@ -2984,7 +2974,7 @@ public final class DateTimeFormatterBuilder { @Override public String toString() { String decimal = (decimalPoint ? ",DecimalPoint" : ""); - return "Fraction(" + field.getName() + "," + minWidth + "," + maxWidth + decimal + ")"; + return "Fraction(" + field + "," + minWidth + "," + maxWidth + decimal + ")"; } } @@ -3079,9 +3069,9 @@ public final class DateTimeFormatterBuilder { @Override public String toString() { if (textStyle == TextStyle.FULL) { - return "Text(" + field.getName() + ")"; + return "Text(" + field + ")"; } - return "Text(" + field.getName() + "," + textStyle + ")"; + return "Text(" + field + "," + textStyle + ")"; } } @@ -3756,17 +3746,17 @@ public final class DateTimeFormatterBuilder { // handle fixed time-zone IDs char nextChar = text.charAt(position); if (nextChar == '+' || nextChar == '-') { - return parseOffsetBased(context, text, position, OffsetIdPrinterParser.INSTANCE_ID_Z); + return parseOffsetBased(context, text, position, position, OffsetIdPrinterParser.INSTANCE_ID_Z); } else if (length >= position + 2) { char nextNextChar = text.charAt(position + 1); if (context.charEquals(nextChar, 'U') && context.charEquals(nextNextChar, 'T')) { if (length >= position + 3 && context.charEquals(text.charAt(position + 2), 'C')) { - return parseOffsetBased(context, text, position + 3, OffsetIdPrinterParser.INSTANCE_ID_ZERO); + return parseOffsetBased(context, text, position, position + 3, OffsetIdPrinterParser.INSTANCE_ID_ZERO); } - return parseOffsetBased(context, text, position + 2, OffsetIdPrinterParser.INSTANCE_ID_ZERO); + return parseOffsetBased(context, text, position, position + 2, OffsetIdPrinterParser.INSTANCE_ID_ZERO); } else if (context.charEquals(nextChar, 'G') && length >= position + 3 && context.charEquals(nextNextChar, 'M') && context.charEquals(text.charAt(position + 2), 'T')) { - return parseOffsetBased(context, text, position + 3, OffsetIdPrinterParser.INSTANCE_ID_ZERO); + return parseOffsetBased(context, text, position, position + 3, OffsetIdPrinterParser.INSTANCE_ID_ZERO); } } @@ -3785,20 +3775,49 @@ public final class DateTimeFormatterBuilder { return ppos.getIndex(); } - private int parseOffsetBased(DateTimeParseContext context, CharSequence text, int position, OffsetIdPrinterParser parser) { - DateTimeParseContext newContext = context.copy(); - int endPos = parser.parse(newContext, text, position); - if (endPos < 0) { - if (parser == OffsetIdPrinterParser.INSTANCE_ID_Z) { - return ~position; - } - context.setParsed(ZoneOffset.UTC); + /** + * Parse an offset following a prefix and set the ZoneId if it is valid. + * To matching the parsing of ZoneId.of the values are not normalized + * to ZoneOffsets. + * + * @param context the parse context + * @param text the input text + * @param prefixPos start of the prefix + * @param position start of text after the prefix + * @param parser parser for the value after the prefix + * @return the position after the parse + */ + private int parseOffsetBased(DateTimeParseContext context, CharSequence text, int prefixPos, int position, OffsetIdPrinterParser parser) { + String prefix = text.toString().substring(prefixPos, position).toUpperCase(); + if (position >= text.length()) { + context.setParsed(ZoneId.of(prefix)); return position; } - int offset = (int) newContext.getParsed(OFFSET_SECONDS).longValue(); - ZoneId zone = ZoneOffset.ofTotalSeconds(offset); - context.setParsed(zone); - return endPos; + + // '0' or 'Z' after prefix is not part of a valid ZoneId; use bare prefix + if (text.charAt(position) == '0' || + context.charEquals(text.charAt(position), 'Z')) { + context.setParsed(ZoneId.of(prefix)); + return position; + } + + DateTimeParseContext newContext = context.copy(); + int endPos = parser.parse(newContext, text, position); + try { + if (endPos < 0) { + if (parser == OffsetIdPrinterParser.INSTANCE_ID_Z) { + return ~prefixPos; + } + context.setParsed(ZoneId.of(prefix)); + return position; + } + int offset = (int) newContext.getParsed(OFFSET_SECONDS).longValue(); + ZoneOffset zoneOffset = ZoneOffset.ofTotalSeconds(offset); + context.setParsed(ZoneId.ofOffset(prefix, zoneOffset)); + return endPos; + } catch (DateTimeException dte) { + return ~prefixPos; + } } @Override diff --git a/jdk/src/share/classes/java/time/format/DateTimePrintContext.java b/jdk/src/share/classes/java/time/format/DateTimePrintContext.java index 3e3f90fb5eb..e744bb7d946 100644 --- a/jdk/src/share/classes/java/time/format/DateTimePrintContext.java +++ b/jdk/src/share/classes/java/time/format/DateTimePrintContext.java @@ -157,7 +157,7 @@ final class DateTimePrintContext { } } final ZoneId effectiveZone = (overrideZone != null ? overrideZone : temporalZone); - final ChronoLocalDate effectiveDate; + final ChronoLocalDate effectiveDate; if (overrideChrono != null) { if (temporal.isSupported(EPOCH_DAY)) { effectiveDate = effectiveChrono.date(temporal); diff --git a/jdk/src/share/classes/java/time/format/Parsed.java b/jdk/src/share/classes/java/time/format/Parsed.java index b0a7fe810d9..42223d6c1d9 100644 --- a/jdk/src/share/classes/java/time/format/Parsed.java +++ b/jdk/src/share/classes/java/time/format/Parsed.java @@ -143,7 +143,7 @@ final class Parsed implements TemporalAccessor { /** * The resolved date. */ - private ChronoLocalDate date; + private ChronoLocalDate date; /** * The resolved time. */ @@ -197,7 +197,7 @@ final class Parsed implements TemporalAccessor { return time.getLong(field); } if (field instanceof ChronoField) { - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.getFrom(this); } @@ -255,42 +255,34 @@ final class Parsed implements TemporalAccessor { // if any other fields, handle them // any lenient date resolution should return epoch-day if (fieldValues.size() > 0) { - boolean changed = false; + int changedCount = 0; outer: - while (true) { + while (changedCount < 50) { for (Map.Entry entry : fieldValues.entrySet()) { TemporalField targetField = entry.getKey(); - Map changes = targetField.resolve(this, entry.getValue(), resolverStyle); - if (changes != null) { - changed = true; - resolveFieldsMakeChanges(targetField, changes); - fieldValues.remove(targetField); // helps avoid infinite loops + ChronoLocalDate resolvedDate = targetField.resolve(fieldValues, chrono, zone, resolverStyle); + if (resolvedDate != null) { + updateCheckConflict(resolvedDate); + changedCount++; + continue outer; // have to restart to avoid concurrent modification + } else if (fieldValues.containsKey(targetField) == false) { + changedCount++; continue outer; // have to restart to avoid concurrent modification } } break; } + if (changedCount == 50) { // catch infinite loops + throw new DateTimeException("One of the parsed fields has an incorrectly implemented resolve method"); + } // if something changed then have to redo ChronoField resolve - if (changed) { + if (changedCount > 0) { resolveDateFields(); resolveTimeFields(); } } } - private void resolveFieldsMakeChanges(TemporalField targetField, Map changes) { - for (Map.Entry change : changes.entrySet()) { - TemporalField changeField = change.getKey(); - Long changeValue = change.getValue(); - Objects.requireNonNull(changeField, "changeField"); - if (changeValue != null) { - updateCheckConflict(targetField, changeField, changeValue); - } else { - fieldValues.remove(changeField); - } - } - } - private void updateCheckConflict(TemporalField targetField, TemporalField changeField, Long changeValue) { Long old = fieldValues.put(changeField, changeValue); if (old != null && old.longValue() != changeValue.longValue()) { @@ -305,7 +297,7 @@ final class Parsed implements TemporalAccessor { updateCheckConflict(chrono.resolveDate(fieldValues, resolverStyle)); } - private void updateCheckConflict(ChronoLocalDate cld) { + private void updateCheckConflict(ChronoLocalDate cld) { if (date != null) { if (cld != null && date.equals(cld) == false) { throw new DateTimeException("Conflict found: Fields resolved to two different dates: " + date + " " + cld); diff --git a/jdk/src/share/classes/java/time/temporal/ChronoField.java b/jdk/src/share/classes/java/time/temporal/ChronoField.java index ac4522bb60b..fe3254e60ab 100644 --- a/jdk/src/share/classes/java/time/temporal/ChronoField.java +++ b/jdk/src/share/classes/java/time/temporal/ChronoField.java @@ -403,6 +403,12 @@ public enum ChronoField implements TemporalField { * Non-ISO calendar systems should implement this field using the most recognized * day-of-year values for users of the calendar system. * Normally, this is a count of days from 1 to the length of the year. + *

    + * Note that a non-ISO calendar system may have year numbering system that changes + * at a different point to the natural reset in the month numbering. An example + * of this is the Japanese calendar system where a change of era, which resets + * the year number to 1, can happen on any date. The era and year reset also cause + * the day-of-year to be reset to 1, but not the month-of-year or day-of-month. */ DAY_OF_YEAR("DayOfYear", DAYS, YEARS, ValueRange.of(1, 365, 366)), /** @@ -559,12 +565,11 @@ public enum ChronoField implements TemporalField { *

    * This represents the concept of the sequential count of seconds where * 1970-01-01T00:00Z (ISO) is zero. - * This field may be used with {@link #NANO_OF_DAY} to represent the fraction of the day. + * This field may be used with {@link #NANO_OF_SECOND} to represent the fraction of the second. *

    * An {@link Instant} represents an instantaneous point on the time-line. - * On their own they have no elements which allow a local date-time to be obtained. - * Only when paired with an offset or time-zone can the local date or time be found. - * This field allows the seconds part of the instant to be queried. + * On their own, an instant has insufficient information to allow a local date-time to be obtained. + * Only when paired with an offset or time-zone can the local date or time be calculated. *

    * This field is strictly defined to have the same meaning in all calendar systems. * This is necessary to ensure interoperation between calendars. @@ -608,24 +613,18 @@ public enum ChronoField implements TemporalField { this.displayNameKey = displayNameKey; } - //----------------------------------------------------------------------- - @Override - public String getName() { - return name; - } - @Override public String getDisplayName(Locale locale) { Objects.requireNonNull(locale, "locale"); if (displayNameKey == null) { - return getName(); + return name; } LocaleResources lr = LocaleProviderAdapter.getResourceBundleBased() .getLocaleResources(locale); ResourceBundle rb = lr.getJavaTimeFormatData(); String key = "field." + displayNameKey; - return rb.containsKey(key) ? rb.getString(key) : getName(); + return rb.containsKey(key) ? rb.getString(key) : name; } @Override @@ -748,7 +747,7 @@ public enum ChronoField implements TemporalField { //----------------------------------------------------------------------- @Override public String toString() { - return getName(); + return name; } } diff --git a/jdk/src/share/classes/java/time/temporal/ChronoUnit.java b/jdk/src/share/classes/java/time/temporal/ChronoUnit.java index 661960c28fb..19a37e46f4c 100644 --- a/jdk/src/share/classes/java/time/temporal/ChronoUnit.java +++ b/jdk/src/share/classes/java/time/temporal/ChronoUnit.java @@ -57,9 +57,6 @@ package java.time.temporal; import java.time.Duration; -import java.time.chrono.ChronoLocalDate; -import java.time.chrono.ChronoLocalDateTime; -import java.time.chrono.ChronoZonedDateTime; /** * A standard set of date periods units. @@ -200,12 +197,6 @@ public enum ChronoUnit implements TemporalUnit { this.duration = estimatedDuration; } - //----------------------------------------------------------------------- - @Override - public String getName() { - return name; - } - //----------------------------------------------------------------------- /** * Gets the estimated duration of this unit in the ISO calendar system. @@ -233,41 +224,40 @@ public enum ChronoUnit implements TemporalUnit { */ @Override public boolean isDurationEstimated() { - return isDateUnit(); + return this.compareTo(DAYS) >= 0; } //----------------------------------------------------------------------- /** * Checks if this unit is a date unit. + *

    + * All units from days to eras inclusive are date-based. + * Time-based units and {@code FOREVER} return false. * * @return true if a date unit, false if a time unit */ - public boolean isDateUnit() { - return this.compareTo(DAYS) >= 0; + @Override + public boolean isDateBased() { + return this.compareTo(DAYS) >= 0 && this != FOREVER; } /** * Checks if this unit is a time unit. + *

    + * All units from nanos to half-days inclusive are time-based. + * Date-based units and {@code FOREVER} return false. * * @return true if a time unit, false if a date unit */ - public boolean isTimeUnit() { + @Override + public boolean isTimeBased() { return this.compareTo(DAYS) < 0; } //----------------------------------------------------------------------- @Override public boolean isSupportedBy(Temporal temporal) { - if (this == FOREVER) { - return false; - } - if (temporal instanceof ChronoLocalDate) { - return isDateUnit(); - } - if (temporal instanceof ChronoLocalDateTime || temporal instanceof ChronoZonedDateTime) { - return true; - } - return TemporalUnit.super.isSupportedBy(temporal); + return temporal.isSupported(this); } @SuppressWarnings("unchecked") @@ -279,13 +269,13 @@ public enum ChronoUnit implements TemporalUnit { //----------------------------------------------------------------------- @Override public long between(Temporal temporal1, Temporal temporal2) { - return temporal1.periodUntil(temporal2, this); + return temporal1.until(temporal2, this); } //----------------------------------------------------------------------- @Override public String toString() { - return getName(); + return name; } } diff --git a/jdk/src/share/classes/java/time/temporal/IsoFields.java b/jdk/src/share/classes/java/time/temporal/IsoFields.java index e335c434d23..eae057afb2a 100644 --- a/jdk/src/share/classes/java/time/temporal/IsoFields.java +++ b/jdk/src/share/classes/java/time/temporal/IsoFields.java @@ -71,6 +71,8 @@ import static java.time.temporal.ChronoUnit.YEARS; import java.time.Duration; import java.time.LocalDate; +import java.time.ZoneId; +import java.time.chrono.ChronoLocalDate; import java.time.chrono.Chronology; import java.time.chrono.IsoChronology; import java.time.format.ResolverStyle; @@ -288,10 +290,6 @@ public final class IsoFields { */ private static enum Field implements TemporalField { DAY_OF_QUARTER { - @Override - public String getName() { - return "DayOfQuarter"; - } @Override public TemporalUnit getBaseUnit() { return DAYS; @@ -344,17 +342,21 @@ public final class IsoFields { return (R) temporal.with(DAY_OF_YEAR, temporal.getLong(DAY_OF_YEAR) + (newValue - curValue)); } @Override - public Map resolve(TemporalAccessor temporal, long doq, ResolverStyle resolverStyle) { - if ((temporal.isSupported(YEAR) && temporal.isSupported(QUARTER_OF_YEAR)) == false) { + public ChronoLocalDate resolve( + Map fieldValues, Chronology chronology, ZoneId zone, ResolverStyle resolverStyle) { + Long yearLong = fieldValues.get(YEAR); + Long qoyLong = fieldValues.get(QUARTER_OF_YEAR); + if (yearLong == null || qoyLong == null) { return null; } - int y = temporal.get(YEAR); // validated + int y = YEAR.checkValidIntValue(yearLong); // always validate + long doq = fieldValues.get(DAY_OF_QUARTER); LocalDate date; if (resolverStyle == ResolverStyle.LENIENT) { - long qoy = temporal.getLong(QUARTER_OF_YEAR); // unvalidated - date = LocalDate.of(y, 1, 1).plusMonths(Math.multiplyExact(Math.subtractExact(qoy, 1), 3)); + date = LocalDate.of(y, 1, 1).plusMonths(Math.multiplyExact(Math.subtractExact(qoyLong, 1), 3)); + doq = Math.subtractExact(doq, 1); } else { - int qoy = temporal.get(QUARTER_OF_YEAR); // validated + int qoy = QUARTER_OF_YEAR.range().checkValidIntValue(qoyLong, QUARTER_OF_YEAR); // validated date = LocalDate.of(y, ((qoy - 1) * 3) + 1, 1); if (doq < 1 || doq > 90) { if (resolverStyle == ResolverStyle.STRICT) { @@ -363,20 +365,19 @@ public final class IsoFields { range().checkValidValue(doq, this); // allow 1-92 rolling into next quarter } } + doq--; } - long epochDay = Math.addExact(date.toEpochDay(), Math.subtractExact(doq, 1)); - Map result = new HashMap<>(4, 1.0f); - result.put(EPOCH_DAY, epochDay); - result.put(YEAR, null); - result.put(QUARTER_OF_YEAR, null); - return result; + fieldValues.remove(this); + fieldValues.remove(YEAR); + fieldValues.remove(QUARTER_OF_YEAR); + return date.plusDays(doq); + } + @Override + public String toString() { + return "DayOfQuarter"; } }, QUARTER_OF_YEAR { - @Override - public String getName() { - return "QuarterOfYear"; - } @Override public TemporalUnit getBaseUnit() { return QUARTER_YEARS; @@ -409,20 +410,19 @@ public final class IsoFields { range().checkValidValue(newValue, this); // strictly check from 1 to 4 return (R) temporal.with(MONTH_OF_YEAR, temporal.getLong(MONTH_OF_YEAR) + (newValue - curValue) * 3); } + @Override + public String toString() { + return "QuarterOfYear"; + } }, WEEK_OF_WEEK_BASED_YEAR { - @Override - public String getName() { - return "WeekOfWeekBasedYear"; - } - @Override public String getDisplayName(Locale locale) { Objects.requireNonNull(locale, "locale"); LocaleResources lr = LocaleProviderAdapter.getResourceBundleBased() .getLocaleResources(locale); ResourceBundle rb = lr.getJavaTimeFormatData(); - return rb.containsKey("field.week") ? rb.getString("field.week") : getName(); + return rb.containsKey("field.week") ? rb.getString("field.week") : toString(); } @Override @@ -463,14 +463,18 @@ public final class IsoFields { return (R) temporal.plus(Math.subtractExact(newValue, getFrom(temporal)), WEEKS); } @Override - public Map resolve(TemporalAccessor temporal, long wowby, ResolverStyle resolverStyle) { - if ((temporal.isSupported(WEEK_BASED_YEAR) && temporal.isSupported(DAY_OF_WEEK)) == false) { + public ChronoLocalDate resolve( + Map fieldValues, Chronology chronology, ZoneId zone, ResolverStyle resolverStyle) { + Long wbyLong = fieldValues.get(WEEK_BASED_YEAR); + Long dowLong = fieldValues.get(DAY_OF_WEEK); + if (wbyLong == null || dowLong == null) { return null; } - int wby = temporal.get(WEEK_BASED_YEAR); // validated + int wby = WEEK_BASED_YEAR.range().checkValidIntValue(wbyLong, WEEK_BASED_YEAR); // always validate + long wowby = fieldValues.get(WEEK_OF_WEEK_BASED_YEAR); LocalDate date = LocalDate.of(wby, 1, 4); if (resolverStyle == ResolverStyle.LENIENT) { - long dow = temporal.getLong(DAY_OF_WEEK); // unvalidated + long dow = dowLong; // unvalidated if (dow > 7) { date = date.plusWeeks((dow - 1) / 7); dow = ((dow - 1) % 7) + 1; @@ -480,7 +484,7 @@ public final class IsoFields { } date = date.plusWeeks(Math.subtractExact(wowby, 1)).with(DAY_OF_WEEK, dow); } else { - int dow = temporal.get(DAY_OF_WEEK); // validated + int dow = DAY_OF_WEEK.checkValidIntValue(dowLong); // validated if (wowby < 1 || wowby > 52) { if (resolverStyle == ResolverStyle.STRICT) { getWeekRange(date).checkValidValue(wowby, this); // only allow exact range @@ -490,18 +494,17 @@ public final class IsoFields { } date = date.plusWeeks(wowby - 1).with(DAY_OF_WEEK, dow); } - Map result = new HashMap<>(2, 1.0f); - result.put(EPOCH_DAY, date.toEpochDay()); - result.put(WEEK_BASED_YEAR, null); - result.put(DAY_OF_WEEK, null); - return result; + fieldValues.remove(this); + fieldValues.remove(WEEK_BASED_YEAR); + fieldValues.remove(DAY_OF_WEEK); + return date; + } + @Override + public String toString() { + return "WeekOfWeekBasedYear"; } }, WEEK_BASED_YEAR { - @Override - public String getName() { - return "WeekBasedYear"; - } @Override public TemporalUnit getBaseUnit() { return WEEK_BASED_YEARS; @@ -537,6 +540,10 @@ public final class IsoFields { date = date.withDayOfYear(180).withYear(newVal).with(WEEK_OF_WEEK_BASED_YEAR, week); return (R) date.with(date); } + @Override + public String toString() { + return "WeekBasedYear"; + } }; @Override @@ -545,13 +552,13 @@ public final class IsoFields { } @Override - public ValueRange rangeRefinedBy(TemporalAccessor temporal) { - return range(); + public boolean isTimeBased() { + return false; } @Override - public String toString() { - return getName(); + public ValueRange rangeRefinedBy(TemporalAccessor temporal) { + return range(); } //------------------------------------------------------------------------- @@ -635,11 +642,6 @@ public final class IsoFields { this.duration = estimatedDuration; } - @Override - public String getName() { - return name; - } - @Override public Duration getDuration() { return duration; @@ -650,6 +652,16 @@ public final class IsoFields { return true; } + @Override + public boolean isDateBased() { + return true; + } + + @Override + public boolean isTimeBased() { + return false; + } + @Override public boolean isSupportedBy(Temporal temporal) { return temporal.isSupported(EPOCH_DAY); @@ -658,7 +670,7 @@ public final class IsoFields { @SuppressWarnings("unchecked") @Override public R addTo(R temporal, long amount) { - switch(this) { + switch (this) { case WEEK_BASED_YEARS: return (R) temporal.with(WEEK_BASED_YEAR, Math.addExact(temporal.get(WEEK_BASED_YEAR), amount)); @@ -678,7 +690,7 @@ public final class IsoFields { return Math.subtractExact(temporal2.getLong(WEEK_BASED_YEAR), temporal1.getLong(WEEK_BASED_YEAR)); case QUARTER_YEARS: - return temporal1.periodUntil(temporal2, MONTHS) / 3; + return temporal1.until(temporal2, MONTHS) / 3; default: throw new IllegalStateException("Unreachable"); } @@ -686,8 +698,7 @@ public final class IsoFields { @Override public String toString() { - return getName(); - + return name; } } } diff --git a/jdk/src/share/classes/java/time/temporal/JulianFields.java b/jdk/src/share/classes/java/time/temporal/JulianFields.java index 95400addcaa..326f20d222f 100644 --- a/jdk/src/share/classes/java/time/temporal/JulianFields.java +++ b/jdk/src/share/classes/java/time/temporal/JulianFields.java @@ -66,6 +66,9 @@ import static java.time.temporal.ChronoUnit.DAYS; import static java.time.temporal.ChronoUnit.FOREVER; import java.time.DateTimeException; +import java.time.ZoneId; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.Chronology; import java.time.format.ResolverStyle; import java.util.Collections; import java.util.Map; @@ -232,11 +235,6 @@ public final class JulianFields { } //----------------------------------------------------------------------- - @Override - public String getName() { - return name; - } - @Override public TemporalUnit getBaseUnit() { return baseUnit; @@ -252,6 +250,11 @@ public final class JulianFields { return true; } + @Override + public boolean isTimeBased() { + return false; + } + @Override public ValueRange range() { return range; @@ -287,15 +290,14 @@ public final class JulianFields { //----------------------------------------------------------------------- @Override - public Map resolve(TemporalAccessor temporal, long value, ResolverStyle resolverStyle) { - long epochDay; + public ChronoLocalDate resolve( + Map fieldValues, Chronology chronology, ZoneId zone, ResolverStyle resolverStyle) { + long value = fieldValues.remove(this); if (resolverStyle == ResolverStyle.LENIENT) { - epochDay = Math.subtractExact(value, offset); - } else { - range().checkValidValue(value, this); - epochDay = value - offset; + return chronology.dateEpochDay(Math.subtractExact(value, offset)); } - return Collections.singletonMap(EPOCH_DAY, epochDay); + range().checkValidValue(value, this); + return chronology.dateEpochDay(value - offset); } //----------------------------------------------------------------------- diff --git a/jdk/src/share/classes/java/time/temporal/Temporal.java b/jdk/src/share/classes/java/time/temporal/Temporal.java index 1928186b285..af8424c1560 100644 --- a/jdk/src/share/classes/java/time/temporal/Temporal.java +++ b/jdk/src/share/classes/java/time/temporal/Temporal.java @@ -62,7 +62,6 @@ package java.time.temporal; import java.time.DateTimeException; -import java.time.ZoneId; /** * Framework-level interface defining read-write access to a temporal object, @@ -81,7 +80,8 @@ import java.time.ZoneId; * See {@link ChronoField} for the standard set of fields. *

    * Two pieces of date/time information cannot be represented by numbers, - * the {@linkplain java.time.chrono.Chronology chronology} and the {@linkplain ZoneId time-zone}. + * the {@linkplain java.time.chrono.Chronology chronology} and the + * {@linkplain java.time.ZoneId time-zone}. * These can be accessed via {@link #query(TemporalQuery) queries} using * the static methods defined on {@link TemporalQuery}. *

    @@ -128,6 +128,29 @@ import java.time.ZoneId; */ public interface Temporal extends TemporalAccessor { + /** + * Checks if the specified unit is supported. + *

    + * This checks if the specified unit can be added to, or subtracted from, this date-time. + * If false, then calling the {@link #plus(long, TemporalUnit)} and + * {@link #minus(long, TemporalUnit) minus} methods will throw an exception. + * + * @implSpec + * Implementations must check and handle all units defined in {@link ChronoUnit}. + * If the unit is supported, then true must be returned, otherwise false must be returned. + *

    + * If the field is not a {@code ChronoUnit}, then the result of this method + * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)} + * passing {@code this} as the argument. + *

    + * Implementations must ensure that no observable state is altered when this + * read-only method is invoked. + * + * @param unit the unit to check, null returns false + * @return true if the unit can be added/subtracted, false if not + */ + boolean isSupported(TemporalUnit unit); + /** * Returns an adjusted object of the same type as this object with the adjustment made. *

    @@ -352,7 +375,7 @@ public interface Temporal extends TemporalAccessor { * The start and end points are {@code this} and the specified temporal. * The result will be negative if the end is before the start. * For example, the period in hours between two temporal objects can be - * calculated using {@code startTime.periodUntil(endTime, HOURS)}. + * calculated using {@code startTime.until(endTime, HOURS)}. *

    * The calculation returns a whole number, representing the number of * complete units between the two temporals. @@ -364,7 +387,7 @@ public interface Temporal extends TemporalAccessor { * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}: *

          *   // these two lines are equivalent
    -     *   temporal = start.periodUntil(end, unit);
    +     *   temporal = start.until(end, unit);
          *   temporal = unit.between(start, end);
          * 
    * The choice should be made based on which makes the code more readable. @@ -372,7 +395,7 @@ public interface Temporal extends TemporalAccessor { * For example, this method allows the number of days between two dates to * be calculated: *
    -     *  long daysBetween = start.periodUntil(end, DAYS);
    +     *  long daysBetween = start.until(end, DAYS);
          *  // or alternatively
          *  long daysBetween = DAYS.between(start, end);
          * 
    @@ -399,7 +422,8 @@ public interface Temporal extends TemporalAccessor { * return unit.between(this, endTemporal); *
    *

    - * Neither this object, nor the specified temporal, may be altered. + * Implementations must ensure that no observable state is altered when this + * read-only method is invoked. * * @param endTemporal the end temporal, of the same type as this object, not null * @param unit the unit to measure the amount in, not null @@ -410,6 +434,6 @@ public interface Temporal extends TemporalAccessor { * @throws UnsupportedTemporalTypeException if the unit is not supported * @throws ArithmeticException if numeric overflow occurs */ - long periodUntil(Temporal endTemporal, TemporalUnit unit); + long until(Temporal endTemporal, TemporalUnit unit); } diff --git a/jdk/src/share/classes/java/time/temporal/TemporalAccessor.java b/jdk/src/share/classes/java/time/temporal/TemporalAccessor.java index a212be85981..343447e36b9 100644 --- a/jdk/src/share/classes/java/time/temporal/TemporalAccessor.java +++ b/jdk/src/share/classes/java/time/temporal/TemporalAccessor.java @@ -62,7 +62,6 @@ package java.time.temporal; import java.time.DateTimeException; -import java.time.ZoneId; import java.util.Objects; /** @@ -80,7 +79,8 @@ import java.util.Objects; * See {@link ChronoField} for the standard set of fields. *

    * Two pieces of date/time information cannot be represented by numbers, - * the {@linkplain java.time.chrono.Chronology chronology} and the {@linkplain ZoneId time-zone}. + * the {@linkplain java.time.chrono.Chronology chronology} and the + * {@linkplain java.time.ZoneId time-zone}. * These can be accessed via {@linkplain #query(TemporalQuery) queries} using * the static methods defined on {@link TemporalQuery}. *

    @@ -111,13 +111,14 @@ public interface TemporalAccessor { * * @implSpec * 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 must be returned, otherwise false must be returned. *

    * If the field is not a {@code ChronoField}, then the result of this method * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)} * passing {@code this} as the argument. *

    - * Implementations must not alter either this object. + * Implementations must ensure that no observable state is altered when this + * read-only method is invoked. * * @param field the field to check, null returns false * @return true if this date-time can be queried for the field, false if not @@ -146,7 +147,8 @@ public interface TemporalAccessor { * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessorl)} * passing {@code this} as the argument. *

    - * Implementations must not alter either this object. + * Implementations must ensure that no observable state is altered when this + * read-only method is invoked. *

    * The default implementation must behave equivalent to this code: *

    @@ -154,7 +156,7 @@ public interface TemporalAccessor {
          *    if (isSupported(field)) {
          *      return field.range();
          *    }
    -     *    throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
    +     *    throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
          *  }
          *  return field.rangeRefinedBy(this);
          * 
    @@ -169,7 +171,7 @@ public interface TemporalAccessor { if (isSupported(field)) { return field.range(); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } Objects.requireNonNull(field, "field"); return field.rangeRefinedBy(this); @@ -193,7 +195,8 @@ public interface TemporalAccessor { * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} * passing {@code this} as the argument. *

    - * Implementations must not alter this object. + * Implementations must ensure that no observable state is altered when this + * read-only method is invoked. *

    * The default implementation must behave equivalent to this code: *

    @@ -240,7 +243,8 @@ public interface TemporalAccessor {
          * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
          * passing {@code this} as the argument.
          * 

    - * Implementations must not alter either this object. + * Implementations must ensure that no observable state is altered when this + * read-only method is invoked. * * @param field the field to get, not null * @return the value for the field @@ -291,6 +295,9 @@ public interface TemporalAccessor { * } * return TemporalAccessor.super.query(query); *

    + *

    + * Implementations must ensure that no observable state is altered when this + * read-only method is invoked. * * @param the type of the result * @param query the query to invoke, not null diff --git a/jdk/src/share/classes/java/time/temporal/TemporalField.java b/jdk/src/share/classes/java/time/temporal/TemporalField.java index cce2dfbd4de..e4d6b407783 100644 --- a/jdk/src/share/classes/java/time/temporal/TemporalField.java +++ b/jdk/src/share/classes/java/time/temporal/TemporalField.java @@ -62,6 +62,9 @@ package java.time.temporal; import java.time.DateTimeException; +import java.time.ZoneId; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.Chronology; import java.time.format.ResolverStyle; import java.util.Locale; import java.util.Map; @@ -92,30 +95,20 @@ import java.util.Objects; */ public interface TemporalField { - /** - * Gets a descriptive name for the field. - *

    - * The should be of the format 'BaseOfRange', such as 'MonthOfYear', - * unless the field has a range of {@code FOREVER}, when only - * the base unit is mentioned, such as 'Year' or 'Era'. - * - * @return the name, not null - */ - String getName(); - /** * Gets the display name for the field in the requested locale. *

    - * If there is no display name for the locale the value of {@code getName} - * is returned. + * If there is no display name for the locale then a suitable default must be returned. + *

    + * The default implementation must check the locale is not null + * and return {@code toString()}. * * @param locale the locale to use, not null - * @return the display name for the locale or the value of {@code getName}, - * not null + * @return the display name for the locale or a suitable default, not null */ default String getDisplayName(Locale locale) { - Objects.requireNonNull(locale, "local"); - return getName(); + Objects.requireNonNull(locale, "locale"); + return toString(); } /** @@ -164,28 +157,24 @@ public interface TemporalField { *

    * A field is date-based if it can be derived from * {@link ChronoField#EPOCH_DAY EPOCH_DAY}. - *

    - * The default implementation must return false. + * Note that it is valid for both {@code isDateBased()} and {@code isTimeBased()} + * to return false, such as when representing a field like minute-of-week. * * @return true if this field is a component of a date */ - default boolean isDateBased() { - return false; - } + boolean isDateBased(); /** * Checks if this field represents a component of a time. *

    * A field is time-based if it can be derived from * {@link ChronoField#NANO_OF_DAY NANO_OF_DAY}. - *

    - * The default implementation must return false. + * Note that it is valid for both {@code isDateBased()} and {@code isTimeBased()} + * to return false, such as when representing a field like minute-of-week. * * @return true if this field is a component of a time */ - default boolean isTimeBased() { - return false; - } + boolean isTimeBased(); //----------------------------------------------------------------------- /** @@ -319,45 +308,79 @@ public interface TemporalField { R adjustInto(R temporal, long newValue); /** - * Resolves this field to provide a simpler alternative. + * Resolves this field to provide a simpler alternative or a date. *

    * This method is invoked during the resolve phase of parsing. * It is designed to allow application defined fields to be simplified into - * more standard fields, such as those on {@code ChronoField}. + * more standard fields, such as those on {@code ChronoField}, or into a date. *

    - * The method will only be invoked if the specified temporal supports this field. - * The value of this field is provided. + * Applications should not normally invoke this method directly. + * + * @implSpec + * If an implementation represents a field that can be simplified, or + * combined with others, then this method must be implemented. *

    - * The temporal must be queried using the methods of {@code TemporalAccessor}, - * not using {@code getFrom}, {@code isSupportedBy} or {@code rangeRefinedBy}. - * Before querying any field, implementations must ensure it is supported, as - * exceptions of this type would negatively affect the calculation of a parsed result. + * The specified map contains the current state of the parse. + * The map is mutable and must be mutated to resolve the field and + * any related fields. This method will only be invoked during parsing + * if the map contains this field, and implementations should therefore + * assume this field is present. *

    - * If this field can resolve, it must return a map, if not it must return null. - * The returned map contains the changes to be made to the temporal, expressed - * as field-value pairs. If the value for a field is null, the field is to be - * removed from the temporal. A null key must not be added to the result map. + * Resolving a field will consist of looking at the value of this field, + * and potentially other fields, and either updating the map with a + * simpler value, such as a {@code ChronoField}, or returning a + * complete {@code ChronoLocalDate}. If a resolve is successful, + * the code must remove all the fields that were resolved from the map, + * including this field. *

    - * If the result is non-null, this field will be removed from the temporal. - * This field should not be added to the result map. + * For example, the {@code IsoFields} class contains the quarter-of-year + * and day-of-quarter fields. The implementation of this method in that class + * resolves the two fields plus the {@link ChronoField#YEAR YEAR} into a + * complete {@code LocalDate}. The resolve method will remove all three + * fields from the map before returning the {@code LocalDate}. *

    - * The {@link ResolverStyle} should be used by implementations to determine - * how to perform the resolve. + * If resolution should be possible, but the data is invalid, the resolver + * style should be used to determine an appropriate level of leniency, which + * may require throwing a {@code DateTimeException} or {@code ArithmeticException}. + * If no resolution is possible, the resolve method must return null. + *

    + * When resolving time fields, the map will be altered and null returned. + * When resolving date fields, the date is normally returned from the method, + * with the map altered to remove the resolved fields. However, it would also + * be acceptable for the date fields to be resolved into other {@code ChronoField} + * instances that can produce a date, such as {@code EPOCH_DAY}. + *

    + * The zone is not normally required for resolution, but is provided for completeness. *

    * The default implementation must return null. * - * @param temporal the temporal to resolve, not null - * @param value the value of this field + * @param fieldValues the map of fields to values, which can be updated, not null + * @param chronology the effective chronology, not null + * @param zone the effective zone, not null * @param resolverStyle the requested type of resolve, not null - * @return a map of fields to update in the temporal, with a mapping to null - * indicating a deletion. The whole map must be null if no resolving occurred + * @return the resolved date; null if resolving only changed the map, + * or no resolve occurred + * @throws ArithmeticException if numeric overflow occurs * @throws DateTimeException if resolving results in an error. This must not be thrown * by querying a field on the temporal without first checking if it is supported - * @throws ArithmeticException if numeric overflow occurs */ - default Map resolve( - TemporalAccessor temporal, long value, ResolverStyle resolverStyle) { + default ChronoLocalDate resolve( + Map fieldValues, Chronology chronology, + ZoneId zone, ResolverStyle resolverStyle) { return null; } + /** + * Gets a descriptive name for the field. + *

    + * The should be of the format 'BaseOfRange', such as 'MonthOfYear', + * unless the field has a range of {@code FOREVER}, when only + * the base unit is mentioned, such as 'Year' or 'Era'. + * + * @return the name of the field, not null + */ + @Override + String toString(); + + } diff --git a/jdk/src/share/classes/java/time/temporal/TemporalUnit.java b/jdk/src/share/classes/java/time/temporal/TemporalUnit.java index 01ab406f85a..05577d713f8 100644 --- a/jdk/src/share/classes/java/time/temporal/TemporalUnit.java +++ b/jdk/src/share/classes/java/time/temporal/TemporalUnit.java @@ -63,7 +63,11 @@ package java.time.temporal; import java.time.DateTimeException; import java.time.Duration; +import java.time.LocalTime; import java.time.Period; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.ChronoLocalDateTime; +import java.time.chrono.ChronoZonedDateTime; /** * A unit of date-time, such as Days or Hours. @@ -92,15 +96,6 @@ import java.time.Period; */ public interface TemporalUnit { - /** - * Gets a descriptive name for the unit. - *

    - * This should be in the plural and upper-first camel case, such as 'Days' or 'Minutes'. - * - * @return the name, not null - */ - String getName(); - /** * Gets the duration of this unit, which may be an estimate. *

    @@ -130,6 +125,33 @@ public interface TemporalUnit { */ boolean isDurationEstimated(); + //----------------------------------------------------------------------- + /** + * Checks if this unit represents a component of a date. + *

    + * A date is time-based if it can be used to imply meaning from a date. + * It must have a {@linkplain #getDuration() duration} that is an integral + * multiple of the length of a standard day. + * Note that it is valid for both {@code isDateBased()} and {@code isTimeBased()} + * to return false, such as when representing a unit like 36 hours. + * + * @return true if this unit is a component of a date + */ + boolean isDateBased(); + + /** + * Checks if this unit represents a component of a time. + *

    + * A unit is time-based if it can be used to imply meaning from a time. + * It must have a {@linkplain #getDuration() duration} that divides into + * the length of a standard day without remainder. + * Note that it is valid for both {@code isDateBased()} and {@code isTimeBased()} + * to return false, such as when representing a unit like 36 hours. + * + * @return true if this unit is a component of a time + */ + boolean isTimeBased(); + //----------------------------------------------------------------------- /** * Checks if this unit is supported by the specified temporal object. @@ -144,6 +166,15 @@ public interface TemporalUnit { * @return true if the unit is supported */ default boolean isSupportedBy(Temporal temporal) { + if (temporal instanceof LocalTime) { + return isTimeBased(); + } + if (temporal instanceof ChronoLocalDate) { + return isDateBased(); + } + if (temporal instanceof ChronoLocalDateTime || temporal instanceof ChronoZonedDateTime) { + return true; + } try { temporal.plus(1, this); return true; @@ -212,11 +243,11 @@ public interface TemporalUnit { *

    * There are two equivalent ways of using this method. * The first is to invoke this method directly. - * The second is to use {@link Temporal#periodUntil(Temporal, TemporalUnit)}: + * The second is to use {@link Temporal#until(Temporal, TemporalUnit)}: *

          *   // these two lines are equivalent
          *   between = thisUnit.between(start, end);
    -     *   between = start.periodUntil(end, thisUnit);
    +     *   between = start.until(end, thisUnit);
          * 
    * The choice should be made based on which makes the code more readable. *

    @@ -225,7 +256,7 @@ public interface TemporalUnit { *

          *  long daysBetween = DAYS.between(start, end);
          *  // or alternatively
    -     *  long daysBetween = start.periodUntil(end, DAYS);
    +     *  long daysBetween = start.until(end, DAYS);
          * 
    *

    * Implementations should perform any queries or calculations using the units @@ -245,7 +276,9 @@ public interface TemporalUnit { //----------------------------------------------------------------------- /** - * Outputs this unit as a {@code String} using the name. + * Gets a descriptive name for the unit. + *

    + * This should be in the plural and upper-first camel case, such as 'Days' or 'Minutes'. * * @return the name of this unit, not null */ diff --git a/jdk/src/share/classes/java/time/temporal/ValueRange.java b/jdk/src/share/classes/java/time/temporal/ValueRange.java index 4ac8e74402a..e003f114adc 100644 --- a/jdk/src/share/classes/java/time/temporal/ValueRange.java +++ b/jdk/src/share/classes/java/time/temporal/ValueRange.java @@ -331,7 +331,7 @@ public final class ValueRange implements Serializable { private String genInvalidFieldMessage(TemporalField field, long value) { if (field != null) { - return "Invalid value for " + field.getName() + " (valid values " + this + "): " + value; + return "Invalid value for " + field + " (valid values " + this + "): " + value; } else { return "Invalid value (valid values " + this + "): " + value; } diff --git a/jdk/src/share/classes/java/time/temporal/WeekFields.java b/jdk/src/share/classes/java/time/temporal/WeekFields.java index 07ffa91d2a3..b3eb1383450 100644 --- a/jdk/src/share/classes/java/time/temporal/WeekFields.java +++ b/jdk/src/share/classes/java/time/temporal/WeekFields.java @@ -75,7 +75,9 @@ import static java.time.temporal.ChronoUnit.YEARS; import java.io.InvalidObjectException; import java.io.Serializable; +import java.time.DateTimeException; import java.time.DayOfWeek; +import java.time.ZoneId; import java.time.chrono.ChronoLocalDate; import java.time.chrono.Chronology; import java.time.format.ResolverStyle; @@ -395,6 +397,11 @@ public final class WeekFields implements Serializable { *

    * 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. + *

    + * In the resolving phase of parsing, a localized day-of-week will be converted + * to a standardized {@code ChronoField} day-of-week. + * The day-of-week must be in the valid range 1 to 7. + * Other fields in this class build dates using the standardized day-of-week. * * @return a field providing access to the day-of-week with localized numbering, not null */ @@ -421,6 +428,26 @@ 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
    *

    * This field can be used with any calendar system. + *

    + * In the resolving phase of parsing, a date can be created from a year, + * week-of-month, month-of-year and day-of-week. + *

    + * In {@linkplain ResolverStyle#STRICT strict mode}, all four fields are + * validated against their range of valid values. The week-of-month field + * is validated to ensure that the resulting month is the month requested. + *

    + * In {@linkplain ResolverStyle#SMART smart mode}, all four fields are + * validated against their range of valid values. The week-of-month field + * is validated from 0 to 6, meaning that the resulting date can be in a + * different month to that specified. + *

    + * In {@linkplain ResolverStyle#LENIENT lenient mode}, the year and day-of-week + * are validated against the range of valid values. The resulting date is calculated + * equivalent to the following four stage approach. + * First, create a date on the first day of the first week of January in the requested year. + * Then take the month-of-year, subtract one, and add the amount in months to the date. + * Then take the week-of-month, subtract one, and add the amount in weeks to the date. + * Finally, adjust to the correct day-of-week within the localized week. * * @return a field providing access to the week-of-month, not null */ @@ -447,6 +474,25 @@ 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
    *

    * This field can be used with any calendar system. + *

    + * In the resolving phase of parsing, a date can be created from a year, + * week-of-year and day-of-week. + *

    + * In {@linkplain ResolverStyle#STRICT strict mode}, all three fields are + * validated against their range of valid values. The week-of-year field + * is validated to ensure that the resulting year is the year requested. + *

    + * In {@linkplain ResolverStyle#SMART smart mode}, all three fields are + * validated against their range of valid values. The week-of-year field + * is validated from 0 to 54, meaning that the resulting date can be in a + * different year to that specified. + *

    + * In {@linkplain ResolverStyle#LENIENT lenient mode}, the year and day-of-week + * are validated against the range of valid values. The resulting date is calculated + * equivalent to the following three stage approach. + * First, create a date on the first day of the first week in the requested year. + * Then take the week-of-year, subtract one, and add the amount in weeks to the date. + * Finally, adjust to the correct day-of-week within the localized week. * * @return a field providing access to the week-of-year, not null */ @@ -477,6 +523,26 @@ public final class WeekFields implements Serializable { * the 1st to 4th is in week one
    *

    * This field can be used with any calendar system. + *

    + * In the resolving phase of parsing, a date can be created from a week-based-year, + * week-of-year and day-of-week. + *

    + * In {@linkplain ResolverStyle#STRICT strict mode}, all three fields are + * validated against their range of valid values. The week-of-year field + * is validated to ensure that the resulting week-based-year is the + * week-based-year requested. + *

    + * In {@linkplain ResolverStyle#SMART smart mode}, all three fields are + * validated against their range of valid values. The week-of-week-based-year field + * is validated from 1 to 53, meaning that the resulting date can be in the + * following week-based-year to that specified. + *

    + * In {@linkplain ResolverStyle#LENIENT lenient mode}, the year and day-of-week + * are validated against the range of valid values. The resulting date is calculated + * equivalent to the following three stage approach. + * First, create a date on the first day of the first week in the requested week-based-year. + * Then take the week-of-week-based-year, subtract one, and add the amount in weeks to the date. + * Finally, adjust to the correct day-of-week within the localized week. * * @return a field providing access to the week-of-week-based-year, not null */ @@ -499,6 +565,26 @@ public final class WeekFields implements Serializable { * is in the last week of the previous year. *

    * This field can be used with any calendar system. + *

    + * In the resolving phase of parsing, a date can be created from a week-based-year, + * week-of-year and day-of-week. + *

    + * In {@linkplain ResolverStyle#STRICT strict mode}, all three fields are + * validated against their range of valid values. The week-of-year field + * is validated to ensure that the resulting week-based-year is the + * week-based-year requested. + *

    + * In {@linkplain ResolverStyle#SMART smart mode}, all three fields are + * validated against their range of valid values. The week-of-week-based-year field + * is validated from 1 to 53, meaning that the resulting date can be in the + * following week-based-year to that specified. + *

    + * In {@linkplain ResolverStyle#LENIENT lenient mode}, the year and day-of-week + * are validated against the range of valid values. The resulting date is calculated + * equivalent to the following three stage approach. + * First, create a date on the first day of the first week in the requested week-based-year. + * Then take the week-of-week-based-year, subtract one, and add the amount in weeks to the date. + * Finally, adjust to the correct day-of-week within the localized week. * * @return a field providing access to the week-based-year, not null */ @@ -615,9 +701,9 @@ public final class WeekFields implements Serializable { * @param dow the day of the week * @return a ChronoLocalDate for the requested year, week of year, and day of week */ - private ChronoLocalDate ofWeekBasedYear(Chronology chrono, + private ChronoLocalDate ofWeekBasedYear(Chronology chrono, int yowby, int wowby, int dow) { - ChronoLocalDate date = chrono.date(yowby, 1, 1); + ChronoLocalDate date = chrono.date(yowby, 1, 1); int ldow = localizedDayOfWeek(date); int offset = startOfWeekOffset(1, ldow); @@ -671,6 +757,11 @@ public final class WeekFields implements Serializable { return Math.floorMod(isoDow - sow, 7) + 1; } + private int localizedDayOfWeek(int isoDow) { + int sow = weekDef.getFirstDayOfWeek().getValue(); + return Math.floorMod(isoDow - sow, 7) + 1; + } + private long localizedWeekOfMonth(TemporalAccessor temporal) { int dow = localizedDayOfWeek(temporal); int dom = temporal.get(DAY_OF_MONTH); @@ -800,75 +891,121 @@ public final class WeekFields implements Serializable { } @Override - public Map resolve(TemporalAccessor temporal, long value, ResolverStyle resolverStyle) { - int newValue = range.checkValidIntValue(value, this); - int sow = weekDef.getFirstDayOfWeek().getValue(); + public ChronoLocalDate resolve( + Map fieldValues, Chronology chronology, ZoneId zone, ResolverStyle resolverStyle) { + final long value = fieldValues.get(this); + final int newValue = Math.toIntExact(value); // broad limit makes overflow checking lighter + // first convert localized day-of-week to ISO day-of-week + // doing this first handles case where both ISO and localized were parsed and might mismatch + // day-of-week is always strict as two different day-of-week values makes lenient complex if (rangeUnit == WEEKS) { // day-of-week - int isoDow = Math.floorMod((sow - 1) + (newValue - 1), 7) + 1; - return Collections.singletonMap(DAY_OF_WEEK, (long) isoDow); - } - if (temporal.isSupported(DAY_OF_WEEK) == false) { + final int checkedValue = range.checkValidIntValue(value, this); // no leniency as too complex + final int startDow = weekDef.getFirstDayOfWeek().getValue(); + long isoDow = Math.floorMod((startDow - 1) + (checkedValue - 1), 7) + 1; + fieldValues.remove(this); + fieldValues.put(DAY_OF_WEEK, isoDow); return null; } - Chronology chrono = Chronology.from(temporal); // defaults to ISO - int dow = localizedDayOfWeek(temporal); - if (temporal.isSupported(YEAR)) { - int year = temporal.get(YEAR); - if (rangeUnit == MONTHS) { // week-of-month - if (temporal.isSupported(MONTH_OF_YEAR) == false) { - return null; - } - int month = temporal.get(ChronoField.MONTH_OF_YEAR); - @SuppressWarnings("rawtypes") - ChronoLocalDate date = chrono.date(year, month, 1); - int dateDow = localizedDayOfWeek(date); - long weeks = newValue - localizedWeekOfMonth(date); - int days = dow - dateDow; - date = date.plus(weeks * 7 + days, DAYS); - Map result = new HashMap<>(4, 1.0f); - result.put(EPOCH_DAY, date.toEpochDay()); - result.put(YEAR, null); - result.put(MONTH_OF_YEAR, null); - result.put(DAY_OF_WEEK, null); - return result; - } else if (rangeUnit == YEARS) { // week-of-year - @SuppressWarnings("rawtypes") - ChronoLocalDate date = chrono.date(year, 1, 1); - int dateDow = localizedDayOfWeek(date); - long weeks = newValue - localizedWeekOfYear(date); - int days = dow - dateDow; - date = date.plus(weeks * 7 + days, DAYS); - Map result = new HashMap<>(4, 1.0f); - result.put(EPOCH_DAY, date.toEpochDay()); - result.put(YEAR, null); - result.put(DAY_OF_WEEK, null); - return result; - } - } else if (rangeUnit == WEEK_BASED_YEARS || rangeUnit == FOREVER) { - if (temporal.isSupported(weekDef.weekBasedYear) && - temporal.isSupported(weekDef.weekOfWeekBasedYear)) { - // week-of-week-based-year and year-of-week-based-year - int yowby = temporal.get(weekDef.weekBasedYear); - int wowby = temporal.get(weekDef.weekOfWeekBasedYear); - ChronoLocalDate date = ofWeekBasedYear(Chronology.from(temporal), yowby, wowby, dow); - Map result = new HashMap<>(4, 1.0f); - result.put(EPOCH_DAY, date.toEpochDay()); - result.put(DAY_OF_WEEK, null); - result.put(weekDef.weekOfWeekBasedYear, null); - result.put(weekDef.weekBasedYear, null); - return result; + // can only build date if ISO day-of-week is present + if (fieldValues.containsKey(DAY_OF_WEEK) == false) { + return null; + } + int isoDow = DAY_OF_WEEK.checkValidIntValue(fieldValues.get(DAY_OF_WEEK)); + int dow = localizedDayOfWeek(isoDow); + + // build date + if (fieldValues.containsKey(YEAR)) { + int year = YEAR.checkValidIntValue(fieldValues.get(YEAR)); // validate + if (rangeUnit == MONTHS && fieldValues.containsKey(MONTH_OF_YEAR)) { // week-of-month + long month = fieldValues.get(MONTH_OF_YEAR); // not validated yet + return resolveWoM(fieldValues, chronology, year, month, newValue, dow, resolverStyle); } + if (rangeUnit == YEARS) { // week-of-year + return resolveWoY(fieldValues, chronology, year, newValue, dow, resolverStyle); + } + } else if ((rangeUnit == WEEK_BASED_YEARS || rangeUnit == FOREVER) && + fieldValues.containsKey(weekDef.weekBasedYear) && + fieldValues.containsKey(weekDef.weekOfWeekBasedYear)) { // week-of-week-based-year and year-of-week-based-year + return resolveWBY(fieldValues, chronology, dow, resolverStyle); } return null; } - //----------------------------------------------------------------------- - @Override - public String getName() { - return name; + private ChronoLocalDate resolveWoM( + Map fieldValues, Chronology chrono, int year, long month, long wom, int localDow, ResolverStyle resolverStyle) { + ChronoLocalDate date; + if (resolverStyle == ResolverStyle.LENIENT) { + date = chrono.date(year, 1, 1).plus(Math.subtractExact(month, 1), MONTHS); + long weeks = Math.subtractExact(wom, localizedWeekOfMonth(date)); + int days = localDow - localizedDayOfWeek(date); // safe from overflow + date = date.plus(Math.addExact(Math.multiplyExact(weeks, 7), days), DAYS); + } else { + int monthValid = MONTH_OF_YEAR.checkValidIntValue(month); // validate + date = chrono.date(year, monthValid, 1); + int womInt = range.checkValidIntValue(wom, this); // validate + int weeks = (int) (womInt - localizedWeekOfMonth(date)); // safe from overflow + int days = localDow - localizedDayOfWeek(date); // safe from overflow + date = date.plus(weeks * 7 + days, DAYS); + if (resolverStyle == ResolverStyle.STRICT && date.getLong(MONTH_OF_YEAR) != month) { + throw new DateTimeException("Strict mode rejected resolved date as it is in a different month"); + } + } + fieldValues.remove(this); + fieldValues.remove(YEAR); + fieldValues.remove(MONTH_OF_YEAR); + fieldValues.remove(DAY_OF_WEEK); + return date; } + private ChronoLocalDate resolveWoY( + Map fieldValues, Chronology chrono, int year, long woy, int localDow, ResolverStyle resolverStyle) { + ChronoLocalDate date = chrono.date(year, 1, 1); + if (resolverStyle == ResolverStyle.LENIENT) { + long weeks = Math.subtractExact(woy, localizedWeekOfYear(date)); + int days = localDow - localizedDayOfWeek(date); // safe from overflow + date = date.plus(Math.addExact(Math.multiplyExact(weeks, 7), days), DAYS); + } else { + int womInt = range.checkValidIntValue(woy, this); // validate + int weeks = (int) (womInt - localizedWeekOfYear(date)); // safe from overflow + int days = localDow - localizedDayOfWeek(date); // safe from overflow + date = date.plus(weeks * 7 + days, DAYS); + if (resolverStyle == ResolverStyle.STRICT && date.getLong(YEAR) != year) { + throw new DateTimeException("Strict mode rejected resolved date as it is in a different year"); + } + } + fieldValues.remove(this); + fieldValues.remove(YEAR); + fieldValues.remove(DAY_OF_WEEK); + return date; + } + + private ChronoLocalDate resolveWBY( + Map fieldValues, Chronology chrono, int localDow, ResolverStyle resolverStyle) { + int yowby = weekDef.weekBasedYear.range().checkValidIntValue( + fieldValues.get(weekDef.weekBasedYear), weekDef.weekBasedYear); + ChronoLocalDate date; + if (resolverStyle == ResolverStyle.LENIENT) { + date = ofWeekBasedYear(chrono, yowby, 1, localDow); + long wowby = fieldValues.get(weekDef.weekOfWeekBasedYear); + long weeks = Math.subtractExact(wowby, 1); + date = date.plus(weeks, WEEKS); + } else { + int wowby = weekDef.weekOfWeekBasedYear.range().checkValidIntValue( + fieldValues.get(weekDef.weekOfWeekBasedYear), weekDef.weekOfWeekBasedYear); // validate + date = ofWeekBasedYear(chrono, yowby, wowby, localDow); + if (resolverStyle == ResolverStyle.STRICT && localizedWeekBasedYear(date) != yowby) { + throw new DateTimeException("Strict mode rejected resolved date as it is in a different week-based-year"); + } + } + fieldValues.remove(this); + fieldValues.remove(weekDef.weekBasedYear); + fieldValues.remove(weekDef.weekOfWeekBasedYear); + fieldValues.remove(DAY_OF_WEEK); + return date; + } + + //----------------------------------------------------------------------- @Override public String getDisplayName(Locale locale) { Objects.requireNonNull(locale, "locale"); @@ -876,9 +1013,9 @@ public final class WeekFields implements Serializable { LocaleResources lr = LocaleProviderAdapter.getResourceBundleBased() .getLocaleResources(locale); ResourceBundle rb = lr.getJavaTimeFormatData(); - return rb.containsKey("field.week") ? rb.getString("field.week") : getName(); + return rb.containsKey("field.week") ? rb.getString("field.week") : name; } - return getName(); + return name; } @Override @@ -896,6 +1033,11 @@ public final class WeekFields implements Serializable { return true; } + @Override + public boolean isTimeBased() { + return false; + } + @Override public ValueRange range() { return range; @@ -988,7 +1130,7 @@ public final class WeekFields implements Serializable { //----------------------------------------------------------------------- @Override public String toString() { - return getName() + "[" + weekDef.toString() + "]"; + return name + "[" + weekDef.toString() + "]"; } } } diff --git a/jdk/src/share/lib/hijrah-config-umalqura.properties b/jdk/src/share/lib/hijrah-config-umalqura.properties index ac16c7e222f..1786c14de97 100644 --- a/jdk/src/share/lib/hijrah-config-umalqura.properties +++ b/jdk/src/share/lib/hijrah-config-umalqura.properties @@ -1,58 +1,369 @@ -# -# hijrah-config-umalqura.properties -# -# -# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. -# -# This properties file defines a Hijrah calendar variant. -# -# Fields: -# -# ::= 'version' '=' -# ::= 'id' '=' -# ::= 'type' '=' -# ::= 'iso-start' '=' -# ::= '=' -# -# version ... (Required) -# -# id ... (Required) -# Identifies the Java Chronology -# -# type ... (Required) -# Identifies the type of calendar in the standard calendar ID scheme -# iso-start ... (Required) -# Specifies the corresponding ISO date to the first Hijrah day -# in the defined range of dates -# -# year ... (Required) -# Number of days for each month of a Hijrah year -# * Each line defines a year. The years must be in the chronological -# order and no gap is allowed. -# * Each line is in the form indicated above. is a Hijrah year and -# nn is the number of days for a month listed in the order of the months. -# * Each year must have 12 months. -# * Each month should be 29 or 30 days long. -# * There must be one or more space characters between the months. -# - -# indicates the version of this definition -version=1.8.0_1 - -# Java chronology ID -id=Hijrah-umalqura - -# Standard calendar type specification -type=islamic-umalqura - -# defines the corresponding ISO date to the earliest Hijrah date -iso-start=2010-12-07 - -# -# the data section; defines the dates with the number of days for each month -# -# Placeholder data until full Umm alQura data can be validated -1432=29 30 30 30 29 30 29 30 29 30 29 29 -1433=30 29 30 30 29 30 30 29 30 29 30 29 -1434=29 30 29 30 29 30 30 29 30 30 29 29 -1435=30 29 30 29 30 29 30 29 30 30 29 30 +# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# This properties file defines a Hijrah calendar variant. +# +# Fields: +# +# ::= 'version' '=' +# ::= 'id' '=' +# ::= 'type' '=' +# ::= 'iso-start' '=' +# ::= '=' +# +# version ... (Required) +# +# id ... (Required) +# Identifies the Java Chronology +# +# type ... (Required) +# Identifies the type of calendar in the standard calendar ID scheme +# iso-start ... (Required) +# Specifies the corresponding ISO date to the first Hijrah day +# in the defined range of dates +# +# year ... (Required) +# Number of days for each month of a Hijrah year +# * Each line defines a year. The years must be in chronological +# order and no gap is allowed. +# * Each line is in the form indicated above. is a Hijrah year and +# nn is the number of days for a month listed in the order of the months. +# * Each year must have 12 months. +# * Each month should be 29 or 30 days long. +# * There must be one or more space characters between the months. +# + +# Version of this definition +version=1.8.0_1 + +# Java chronology ID +id=Hijrah-umalqura + +# Standard calendar type specification +type=islamic-umalqura + +# defines the corresponding ISO date to the earliest Hijrah date +iso-start=1882-11-12 + +# 1 2 3 4 5 6 7 8 9 10 11 12 +1300=30 29 30 29 30 29 30 29 30 29 30 29 +1301=30 30 29 30 29 30 29 30 29 30 29 29 +1302=30 30 30 29 30 30 29 29 30 29 29 30 +1303=29 30 30 29 30 30 29 30 29 30 29 29 +1304=29 30 30 29 30 30 30 29 30 29 30 29 +1305=29 29 30 30 29 30 30 29 30 30 29 29 +1306=30 29 30 29 30 29 30 29 30 30 29 30 +1307=29 30 29 30 29 30 29 30 29 30 29 30 +1308=29 30 30 29 30 29 30 29 30 29 29 30 +1309=29 30 30 30 30 29 29 30 29 29 30 29 +1310=30 29 30 30 30 29 30 29 30 29 29 30 +1311=29 30 29 30 30 30 29 30 29 30 29 29 +1312=30 29 30 29 30 30 29 30 30 29 30 29 +1313=29 30 29 30 29 30 29 30 30 30 29 29 +1314=30 30 29 30 29 29 30 29 30 30 29 30 +1315=29 30 30 29 30 29 29 30 29 30 29 30 +1316=29 30 30 30 29 30 29 29 30 29 30 29 +1317=30 29 30 30 29 30 29 30 29 30 29 29 +1318=30 29 30 30 29 30 30 29 30 29 30 29 +1319=29 30 29 30 30 29 30 29 30 30 29 30 +1320=29 30 29 29 30 29 30 29 30 30 30 29 +1321=30 29 30 29 29 30 29 29 30 30 30 30 +1322=29 30 29 30 29 29 29 30 29 30 30 30 +1323=29 30 30 29 30 29 29 29 30 29 30 30 +1324=29 30 30 29 30 29 30 29 29 30 29 30 +1325=30 29 30 29 30 30 29 30 29 30 29 30 +1326=29 29 30 29 30 30 29 30 29 30 30 29 +1327=30 29 29 30 29 30 29 30 30 29 30 30 +1328=29 30 29 29 30 29 29 30 30 30 29 30 +1329=30 29 30 29 29 30 29 29 30 30 29 30 +1330=30 30 29 30 29 29 30 29 29 30 30 29 +1331=30 30 29 30 30 29 29 30 29 30 29 30 +1332=29 30 29 30 30 29 30 29 30 30 29 29 +1333=30 29 29 30 30 29 30 30 29 30 30 29 +1334=29 29 30 29 30 29 30 30 30 29 30 29 +1335=30 29 30 29 29 30 29 30 30 29 30 30 +1336=29 30 29 30 29 29 30 29 30 29 30 30 +1337=30 29 30 29 30 29 29 30 29 30 29 30 +1338=29 30 30 29 30 30 29 29 30 29 30 29 +1339=30 29 30 29 30 30 30 29 30 29 29 30 +1340=29 29 30 29 30 30 30 30 29 30 29 29 +1341=30 29 29 30 29 30 30 30 29 30 30 29 +1342=29 29 30 29 30 29 30 30 29 30 30 29 +1343=30 29 29 30 29 30 29 30 29 30 30 29 +1344=30 29 30 29 30 30 29 29 30 29 30 29 +1345=30 29 30 30 30 29 30 29 29 30 29 29 +1346=30 29 30 30 30 30 29 30 29 29 30 29 +1347=29 30 29 30 30 30 29 30 30 29 29 30 +1348=29 29 30 29 30 30 29 30 30 30 29 29 +1349=30 29 29 30 29 30 30 29 30 30 29 30 +1350=29 30 29 30 29 30 29 29 30 30 29 30 +1351=30 29 30 29 30 29 30 29 29 30 29 30 +1352=30 29 30 30 29 30 29 30 29 29 30 29 +1353=30 29 30 30 30 29 30 29 29 30 29 30 +1354=29 30 29 30 30 29 30 30 29 30 29 29 +1355=30 29 29 30 30 29 30 30 29 30 30 29 +1356=29 30 29 30 29 30 29 30 29 30 30 30 +1357=29 29 30 29 30 29 29 30 29 30 30 30 +1358=29 30 29 30 29 30 29 29 30 29 30 30 +1359=29 30 30 29 30 29 30 29 29 29 30 30 +1360=29 30 30 30 29 30 29 30 29 29 30 29 +1361=30 29 30 30 29 30 30 29 29 30 29 30 +1362=29 30 29 30 29 30 30 29 30 29 30 29 +1363=30 29 30 29 30 29 30 29 30 29 30 30 +1364=29 30 29 30 29 29 30 29 30 29 30 30 +1365=30 30 29 29 30 29 29 30 29 30 29 30 +1366=30 30 29 30 29 30 29 29 30 29 30 29 +1367=30 30 29 30 30 29 30 29 29 30 29 30 +1368=29 30 29 30 30 30 29 29 30 29 30 29 +1369=30 29 30 29 30 30 29 30 29 30 30 29 +1370=30 29 29 30 29 30 29 30 29 30 30 30 +1371=29 30 29 29 30 29 30 29 30 29 30 30 +1372=30 29 29 30 29 30 29 29 30 29 30 30 +1373=30 29 30 29 30 29 30 29 29 30 29 30 +1374=30 29 30 30 29 30 29 30 29 29 30 29 +1375=30 29 30 30 29 30 30 29 30 29 30 29 +1376=29 30 29 30 29 30 30 30 29 30 29 30 +1377=29 29 30 29 29 30 30 30 29 30 30 29 +1378=30 29 29 29 30 29 30 30 29 30 30 30 +1379=29 30 29 29 29 30 29 30 30 29 30 30 +1380=29 30 29 30 29 30 29 30 29 30 29 30 +1381=29 30 29 30 30 29 30 29 30 29 29 30 +1382=29 30 29 30 30 29 30 30 29 30 29 29 +1383=30 29 29 30 30 30 29 30 30 29 30 29 +1384=29 30 29 29 30 30 29 30 30 30 29 30 +1385=29 29 30 29 29 30 30 29 30 30 30 29 +1386=30 29 29 30 29 29 30 30 29 30 30 29 +1387=30 29 30 29 30 29 30 29 30 29 30 29 +1388=30 30 29 30 29 30 29 30 29 30 29 29 +1389=30 30 29 30 30 29 30 30 29 29 30 29 +1390=29 30 29 30 30 30 29 30 29 30 29 30 +1391=29 29 30 29 30 30 29 30 30 29 30 29 +1392=30 29 29 30 29 30 29 30 30 29 30 30 +1393=29 30 29 29 30 29 30 29 30 29 30 30 +1394=30 29 30 29 29 30 29 30 29 30 29 30 +1395=30 29 30 30 29 30 29 29 30 29 29 30 +1396=30 29 30 30 29 30 30 29 29 30 29 29 +1397=30 29 30 30 29 30 30 30 29 29 29 30 +1398=29 30 29 30 30 29 30 30 29 30 29 29 +1399=30 29 30 29 30 29 30 30 29 30 29 30 +1400=30 29 30 29 29 30 29 30 29 30 29 30 +1401=30 30 29 30 29 29 30 29 29 30 29 30 +1402=30 30 30 29 30 29 29 30 29 29 30 29 +1403=30 30 30 29 30 30 29 29 30 29 29 30 +1404=29 30 30 29 30 30 29 30 29 30 29 29 +1405=30 29 30 29 30 30 30 29 30 29 29 30 +1406=30 29 29 30 29 30 30 29 30 29 30 30 +1407=29 30 29 29 30 29 30 29 30 29 30 30 +1408=30 29 30 29 30 29 29 30 29 29 30 30 +1409=30 30 29 30 29 30 29 29 30 29 29 30 +1410=30 30 29 30 30 29 30 29 29 30 29 29 +1411=30 30 29 30 30 29 30 30 29 29 30 29 +1412=30 29 30 29 30 29 30 30 30 29 29 30 +1413=29 30 29 29 30 29 30 30 30 29 30 29 +1414=30 29 30 29 29 30 29 30 30 29 30 30 +1415=29 30 29 30 29 29 30 29 30 29 30 30 +1416=30 29 30 29 30 29 29 30 29 30 29 30 +1417=30 29 30 30 29 29 30 29 30 29 30 29 +1418=30 29 30 30 29 30 29 30 29 30 29 30 +1419=29 30 29 30 29 30 29 30 30 30 29 29 +1420=29 30 29 29 30 29 30 30 30 30 29 30 +1421=29 29 30 29 29 29 30 30 30 30 29 30 +1422=30 29 29 30 29 29 29 30 30 30 29 30 +1423=30 29 30 29 30 29 29 30 29 30 29 30 +1424=30 29 30 30 29 30 29 29 30 29 30 29 +1425=30 29 30 30 29 30 29 30 30 29 30 29 +1426=29 30 29 30 29 30 30 29 30 30 29 30 +1427=29 29 30 29 30 29 30 30 29 30 30 29 +1428=30 29 29 30 29 29 30 30 30 29 30 30 +1429=29 30 29 29 30 29 29 30 30 29 30 30 +1430=29 30 30 29 29 30 29 30 29 30 29 30 +1431=29 30 30 29 30 29 30 29 30 29 29 30 +1432=29 30 30 30 29 30 29 30 29 30 29 29 +1433=30 29 30 30 29 30 30 29 30 29 30 29 +1434=29 30 29 30 29 30 30 29 30 30 29 29 +1435=30 29 30 29 30 29 30 29 30 30 29 30 +1436=29 30 29 30 29 30 29 30 29 30 29 30 +1437=30 29 30 30 29 29 30 29 30 29 29 30 +1438=30 29 30 30 30 29 29 30 29 29 30 29 +1439=30 29 30 30 30 29 30 29 30 29 29 30 +1440=29 30 29 30 30 30 29 30 29 30 29 29 +1441=30 29 30 29 30 30 29 30 30 29 30 29 +1442=29 30 29 30 29 30 29 30 30 29 30 29 +1443=30 29 30 29 30 29 30 29 30 29 30 30 +1444=29 30 29 30 30 29 29 30 29 30 29 30 +1445=29 30 30 30 29 30 29 29 30 29 29 30 +1446=29 30 30 30 29 30 30 29 29 30 29 29 +1447=30 29 30 30 30 29 30 29 30 29 30 29 +1448=29 30 29 30 30 29 30 30 29 30 29 30 +1449=29 29 30 29 30 29 30 30 29 30 30 29 +1450=30 29 30 29 29 30 29 30 29 30 30 29 +1451=30 30 30 29 29 30 29 29 30 30 29 30 +1452=30 29 30 30 29 29 30 29 29 30 29 30 +1453=30 29 30 30 29 30 29 30 29 29 30 29 +1454=30 29 30 30 29 30 30 29 30 29 30 29 +1455=29 30 29 30 30 29 30 29 30 30 29 30 +1456=29 29 30 29 30 29 30 29 30 30 30 29 +1457=30 29 29 30 29 29 30 29 30 30 30 30 +1458=29 30 29 29 30 29 29 30 29 30 30 30 +1459=29 30 30 29 29 30 29 29 30 29 30 30 +1460=29 30 30 29 30 29 30 29 29 30 29 30 +1461=29 30 30 29 30 29 30 29 30 30 29 29 +1462=30 29 30 29 30 30 29 30 29 30 30 29 +1463=29 30 29 30 29 30 29 30 30 30 29 30 +1464=29 30 29 29 30 29 29 30 30 30 29 30 +1465=30 29 30 29 29 30 29 29 30 30 29 30 +1466=30 30 29 30 29 29 29 30 29 30 30 29 +1467=30 30 29 30 30 29 29 30 29 30 29 30 +1468=29 30 29 30 30 29 30 29 30 29 30 29 +1469=29 30 29 30 30 29 30 30 29 30 29 30 +1470=29 29 30 29 30 30 29 30 30 29 30 29 +1471=30 29 29 30 29 30 29 30 30 29 30 30 +1472=29 30 29 29 30 29 30 29 30 30 29 30 +1473=29 30 29 30 30 29 29 30 29 30 29 30 +1474=29 30 30 29 30 30 29 29 30 29 30 29 +1475=29 30 30 29 30 30 30 29 29 30 29 29 +1476=30 29 30 29 30 30 30 29 30 29 30 29 +1477=29 30 29 29 30 30 30 30 29 30 29 30 +1478=29 29 30 29 30 29 30 30 29 30 30 29 +1479=30 29 29 30 29 30 29 30 29 30 30 29 +1480=30 29 30 29 30 29 30 29 30 29 30 29 +1481=30 29 30 30 29 30 29 30 29 30 29 29 +1482=30 29 30 30 30 30 29 30 29 29 30 29 +1483=29 30 29 30 30 30 29 30 30 29 29 30 +1484=29 29 30 29 30 30 30 29 30 29 30 29 +1485=30 29 29 30 29 30 30 29 30 30 29 30 +1486=29 30 29 29 30 29 30 29 30 30 29 30 +1487=30 29 30 29 30 29 29 30 29 30 29 30 +1488=30 29 30 30 29 30 29 29 30 29 30 29 +1489=30 29 30 30 30 29 30 29 29 30 29 30 +1490=29 30 29 30 30 29 30 30 29 29 30 29 +1491=30 29 29 30 30 29 30 30 29 30 29 30 +1492=29 30 29 29 30 30 29 30 29 30 30 29 +1493=30 29 30 29 30 29 29 30 29 30 30 30 +1494=29 30 29 30 29 30 29 29 29 30 30 30 +1495=29 30 30 29 30 29 29 30 29 29 30 30 +1496=29 30 30 30 29 30 29 29 30 29 29 30 +1497=30 29 30 30 29 30 29 30 29 30 29 30 +1498=29 30 29 30 29 30 30 29 30 29 30 29 +1499=30 29 30 29 29 30 30 29 30 29 30 30 +1500=29 30 29 30 29 29 30 29 30 29 30 30 +1501=30 29 30 29 30 29 29 29 30 29 30 30 +1502=30 30 29 30 29 30 29 29 29 30 30 29 +1503=30 30 29 30 30 29 30 29 29 29 30 30 +1504=29 30 29 30 30 30 29 29 30 29 30 29 +1505=30 29 30 29 30 30 29 30 29 30 30 29 +1506=29 30 29 29 30 30 29 30 30 29 30 30 +1507=29 29 30 29 29 30 30 29 30 29 30 30 +1508=30 29 29 30 29 30 29 29 30 29 30 30 +1509=30 29 30 29 30 29 30 29 29 30 29 30 +1510=30 29 30 30 29 30 29 30 29 29 30 29 +1511=30 29 30 30 29 30 30 29 30 29 29 30 +1512=29 30 29 30 29 30 30 30 29 30 29 30 +1513=29 29 29 30 29 30 30 30 29 30 30 29 +1514=30 29 29 29 30 29 30 30 29 30 30 30 +1515=29 29 30 29 29 30 29 30 30 29 30 30 +1516=29 30 29 30 29 29 30 29 30 29 30 30 +1517=29 30 29 30 29 30 30 29 29 30 29 30 +1518=29 30 29 30 30 29 30 30 29 30 29 29 +1519=30 29 29 30 30 30 29 30 30 29 30 29 +1520=29 30 29 29 30 30 30 29 30 30 29 30 +1521=29 29 29 30 29 30 30 29 30 30 29 30 +1522=30 29 29 29 30 29 30 30 29 30 30 29 +1523=30 29 30 29 30 29 30 29 29 30 30 29 +1524=30 30 29 30 29 30 29 30 29 29 30 29 +1525=30 30 29 30 30 29 30 29 30 29 29 30 +1526=29 30 29 30 30 30 29 30 29 30 29 29 +1527=30 29 30 29 30 30 29 30 30 29 30 29 +1528=30 29 29 30 29 30 29 30 30 29 30 30 +1529=29 30 29 29 30 29 30 29 30 29 30 30 +1530=29 30 30 29 29 30 29 30 29 29 30 30 +1531=29 30 30 30 29 29 30 29 30 29 29 30 +1532=29 30 30 30 29 30 30 29 29 29 30 29 +1533=30 29 30 30 30 29 30 29 30 29 29 30 +1534=29 30 29 30 30 29 30 30 29 29 30 29 +1535=30 29 30 29 30 29 30 30 29 30 29 30 +1536=29 30 29 30 29 30 29 30 29 30 29 30 +1537=30 29 30 30 29 29 30 29 29 30 29 30 +1538=30 30 29 30 30 29 29 30 29 29 30 29 +1539=30 30 30 29 30 30 29 29 30 29 29 30 +1540=29 30 30 29 30 30 29 30 29 29 30 29 +1541=30 29 30 29 30 30 30 29 30 29 29 30 +1542=29 30 29 30 29 30 30 29 30 29 30 30 +1543=29 30 29 29 30 29 30 29 30 29 30 30 +1544=30 29 30 29 29 30 29 30 29 30 29 30 +1545=30 30 29 30 29 29 30 29 30 29 29 30 +1546=30 30 29 30 29 30 29 30 29 30 29 29 +1547=30 30 29 30 30 29 30 29 30 29 30 29 +1548=30 29 29 30 30 29 30 30 29 30 29 30 +1549=29 30 29 29 30 29 30 30 30 29 30 29 +1550=30 29 30 29 29 29 30 30 30 29 30 30 +1551=29 30 29 29 30 29 29 30 30 29 30 30 +1552=30 29 30 29 29 30 29 29 30 30 29 30 +1553=30 29 30 29 30 29 30 29 30 29 30 29 +1554=30 29 30 29 30 30 29 30 29 30 29 30 +1555=29 29 30 29 30 30 29 30 30 29 30 29 +1556=30 29 29 30 29 30 29 30 30 30 29 30 +1557=29 30 29 29 29 30 29 30 30 30 30 29 +1558=30 29 30 29 29 29 30 29 30 30 30 29 +1559=30 30 29 29 30 29 29 30 30 29 30 29 +1560=30 30 29 30 29 30 29 30 29 30 29 30 +1561=29 30 30 29 30 29 30 30 29 29 30 29 +1562=29 30 30 29 30 29 30 30 30 29 29 30 +1563=29 30 29 29 30 29 30 30 30 29 30 29 +1564=30 29 30 29 29 30 29 30 30 30 29 30 +1565=29 30 29 30 29 29 30 29 30 30 29 30 +1566=30 29 30 29 30 29 29 30 29 30 29 30 +1567=30 29 30 30 29 30 29 30 29 29 30 29 +1568=30 29 30 30 30 29 30 29 30 29 29 29 +1569=30 29 30 30 30 29 30 30 29 30 29 29 +1570=29 30 29 30 30 29 30 30 30 29 29 30 +1571=29 29 30 29 30 30 29 30 30 29 30 29 +1572=30 29 29 30 29 30 29 30 30 29 30 29 +1573=30 29 30 30 29 30 29 29 30 29 30 29 +1574=30 30 29 30 30 29 30 29 29 30 29 29 +1575=30 30 30 29 30 30 29 30 29 29 29 30 +1576=29 30 30 29 30 30 30 29 30 29 29 29 +1577=30 29 30 30 29 30 30 29 30 29 30 29 +1578=29 30 29 30 29 30 30 29 30 30 29 30 +1579=29 30 29 30 29 29 30 30 29 30 29 30 +1580=29 30 30 29 30 29 29 30 29 30 29 30 +1581=30 30 29 30 29 30 29 29 30 29 30 29 +1582=30 30 29 30 30 29 30 29 30 29 29 29 +1583=30 30 29 30 30 30 29 30 29 30 29 29 +1584=29 30 30 29 30 30 29 30 30 29 30 29 +1585=29 30 29 30 29 30 29 30 30 29 30 30 +1586=29 29 30 29 30 29 29 30 30 30 29 30 +1587=29 30 30 29 29 29 30 29 30 29 30 30 +1588=30 29 30 30 29 29 29 30 29 30 29 30 +1589=30 29 30 30 29 30 29 29 30 29 30 29 +1590=30 29 30 30 30 29 29 30 29 30 29 30 +1591=29 30 29 30 30 29 30 29 30 29 30 29 +1592=30 29 30 29 30 29 30 29 30 30 30 29 +1593=30 29 29 30 29 29 30 29 30 30 30 29 +1594=30 30 29 29 30 29 29 29 30 30 30 30 +1595=29 30 29 30 29 29 30 29 29 30 30 30 +1596=29 30 30 29 30 29 29 30 29 30 29 30 +1597=29 30 30 29 30 29 30 29 30 29 30 29 +1598=30 29 30 29 30 30 29 30 29 30 30 29 +1599=29 30 29 30 29 30 29 30 30 30 29 30 +1600=29 29 30 29 30 29 29 30 30 30 29 30 diff --git a/jdk/test/java/time/tck/java/time/MockSimplePeriod.java b/jdk/test/java/time/tck/java/time/MockSimplePeriod.java index 7b008341592..1548e2e98f9 100644 --- a/jdk/test/java/time/tck/java/time/MockSimplePeriod.java +++ b/jdk/test/java/time/tck/java/time/MockSimplePeriod.java @@ -176,7 +176,7 @@ public final class MockSimplePeriod @Override public String toString() { - return amount + " " + unit.getName(); + return amount + " " + unit; } } diff --git a/jdk/test/java/time/tck/java/time/TCKClock_Fixed.java b/jdk/test/java/time/tck/java/time/TCKClock_Fixed.java index 13cc7b4093d..ef9f12acc47 100644 --- a/jdk/test/java/time/tck/java/time/TCKClock_Fixed.java +++ b/jdk/test/java/time/tck/java/time/TCKClock_Fixed.java @@ -91,6 +91,7 @@ public class TCKClock_Fixed extends AbstractTCKTest { Clock test = Clock.fixed(INSTANT, PARIS); assertEquals(test.instant(), INSTANT); assertEquals(test.getZone(), PARIS); + assertEquals(test.instant().getEpochSecond()*1000, test.millis()); } @Test(expectedExceptions = NullPointerException.class) diff --git a/jdk/test/java/time/tck/java/time/TCKDayOfWeek.java b/jdk/test/java/time/tck/java/time/TCKDayOfWeek.java index 671d9ec53e9..3bf782ba954 100644 --- a/jdk/test/java/time/tck/java/time/TCKDayOfWeek.java +++ b/jdk/test/java/time/tck/java/time/TCKDayOfWeek.java @@ -158,6 +158,44 @@ public class TCKDayOfWeek extends AbstractDateTimeTest { DayOfWeek.from((TemporalAccessor) null); } + //----------------------------------------------------------------------- + // isSupported(TemporalField) + //----------------------------------------------------------------------- + @Test + public void test_isSupported_TemporalField() { + assertEquals(DayOfWeek.THURSDAY.isSupported((TemporalField) null), false); + assertEquals(DayOfWeek.THURSDAY.isSupported(ChronoField.NANO_OF_SECOND), false); + assertEquals(DayOfWeek.THURSDAY.isSupported(ChronoField.NANO_OF_DAY), false); + assertEquals(DayOfWeek.THURSDAY.isSupported(ChronoField.MICRO_OF_SECOND), false); + assertEquals(DayOfWeek.THURSDAY.isSupported(ChronoField.MICRO_OF_DAY), false); + assertEquals(DayOfWeek.THURSDAY.isSupported(ChronoField.MILLI_OF_SECOND), false); + assertEquals(DayOfWeek.THURSDAY.isSupported(ChronoField.MILLI_OF_DAY), false); + assertEquals(DayOfWeek.THURSDAY.isSupported(ChronoField.SECOND_OF_MINUTE), false); + assertEquals(DayOfWeek.THURSDAY.isSupported(ChronoField.SECOND_OF_DAY), false); + assertEquals(DayOfWeek.THURSDAY.isSupported(ChronoField.MINUTE_OF_HOUR), false); + assertEquals(DayOfWeek.THURSDAY.isSupported(ChronoField.MINUTE_OF_DAY), false); + assertEquals(DayOfWeek.THURSDAY.isSupported(ChronoField.HOUR_OF_AMPM), false); + assertEquals(DayOfWeek.THURSDAY.isSupported(ChronoField.CLOCK_HOUR_OF_AMPM), false); + assertEquals(DayOfWeek.THURSDAY.isSupported(ChronoField.HOUR_OF_DAY), false); + assertEquals(DayOfWeek.THURSDAY.isSupported(ChronoField.CLOCK_HOUR_OF_DAY), false); + assertEquals(DayOfWeek.THURSDAY.isSupported(ChronoField.AMPM_OF_DAY), false); + assertEquals(DayOfWeek.THURSDAY.isSupported(ChronoField.DAY_OF_WEEK), true); + assertEquals(DayOfWeek.THURSDAY.isSupported(ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH), false); + assertEquals(DayOfWeek.THURSDAY.isSupported(ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR), false); + assertEquals(DayOfWeek.THURSDAY.isSupported(ChronoField.DAY_OF_MONTH), false); + assertEquals(DayOfWeek.THURSDAY.isSupported(ChronoField.DAY_OF_YEAR), false); + assertEquals(DayOfWeek.THURSDAY.isSupported(ChronoField.EPOCH_DAY), false); + assertEquals(DayOfWeek.THURSDAY.isSupported(ChronoField.ALIGNED_WEEK_OF_MONTH), false); + assertEquals(DayOfWeek.THURSDAY.isSupported(ChronoField.ALIGNED_WEEK_OF_YEAR), false); + assertEquals(DayOfWeek.THURSDAY.isSupported(ChronoField.MONTH_OF_YEAR), false); + assertEquals(DayOfWeek.THURSDAY.isSupported(ChronoField.PROLEPTIC_MONTH), false); + assertEquals(DayOfWeek.THURSDAY.isSupported(ChronoField.YEAR), false); + assertEquals(DayOfWeek.THURSDAY.isSupported(ChronoField.YEAR_OF_ERA), false); + assertEquals(DayOfWeek.THURSDAY.isSupported(ChronoField.ERA), false); + assertEquals(DayOfWeek.THURSDAY.isSupported(ChronoField.INSTANT_SECONDS), false); + assertEquals(DayOfWeek.THURSDAY.isSupported(ChronoField.OFFSET_SECONDS), false); + } + //----------------------------------------------------------------------- // get(TemporalField) //----------------------------------------------------------------------- diff --git a/jdk/test/java/time/tck/java/time/TCKInstant.java b/jdk/test/java/time/tck/java/time/TCKInstant.java index bdf5fcccb70..05d7b83fcf1 100644 --- a/jdk/test/java/time/tck/java/time/TCKInstant.java +++ b/jdk/test/java/time/tck/java/time/TCKInstant.java @@ -569,10 +569,6 @@ public class TCKInstant extends AbstractDateTimeTest { // truncated(TemporalUnit) //----------------------------------------------------------------------- TemporalUnit NINETY_MINS = new TemporalUnit() { - @Override - public String getName() { - return "NinetyMins"; - } @Override public Duration getDuration() { return Duration.ofMinutes(90); @@ -582,6 +578,14 @@ public class TCKInstant extends AbstractDateTimeTest { return false; } @Override + public boolean isDateBased() { + return false; + } + @Override + public boolean isTimeBased() { + return true; + } + @Override public boolean isSupportedBy(Temporal temporal) { return false; } @@ -593,13 +597,13 @@ public class TCKInstant extends AbstractDateTimeTest { public long between(Temporal temporal1, Temporal temporal2) { throw new UnsupportedOperationException(); } + @Override + public String toString() { + return "NinetyMins"; + } }; TemporalUnit NINETY_FIVE_MINS = new TemporalUnit() { - @Override - public String getName() { - return "NinetyFiveMins"; - } @Override public Duration getDuration() { return Duration.ofMinutes(95); @@ -609,6 +613,14 @@ public class TCKInstant extends AbstractDateTimeTest { return false; } @Override + public boolean isDateBased() { + return false; + } + @Override + public boolean isTimeBased() { + return false; + } + @Override public boolean isSupportedBy(Temporal temporal) { return false; } @@ -620,6 +632,10 @@ public class TCKInstant extends AbstractDateTimeTest { public long between(Temporal temporal1, Temporal temporal2) { throw new UnsupportedOperationException(); } + @Override + public String toString() { + return "NinetyFiveMins"; + } }; @DataProvider(name="truncatedToValid") @@ -1709,7 +1725,7 @@ public class TCKInstant extends AbstractDateTimeTest { } //----------------------------------------------------------------------- - // periodUntil(Temporal, TemporalUnit) + // until(Temporal, TemporalUnit) //----------------------------------------------------------------------- @DataProvider(name="periodUntilUnit") Object[][] data_periodUntilUnit() { @@ -1805,7 +1821,7 @@ public class TCKInstant extends AbstractDateTimeTest { public void test_periodUntil_TemporalUnit(long seconds1, int nanos1, long seconds2, long nanos2, TemporalUnit unit, long expected) { Instant i1 = Instant.ofEpochSecond(seconds1, nanos1); Instant i2 = Instant.ofEpochSecond(seconds2, nanos2); - long amount = i1.periodUntil(i2, unit); + long amount = i1.until(i2, unit); assertEquals(amount, expected); } @@ -1813,23 +1829,23 @@ public class TCKInstant extends AbstractDateTimeTest { public void test_periodUntil_TemporalUnit_negated(long seconds1, int nanos1, long seconds2, long nanos2, TemporalUnit unit, long expected) { Instant i1 = Instant.ofEpochSecond(seconds1, nanos1); Instant i2 = Instant.ofEpochSecond(seconds2, nanos2); - long amount = i2.periodUntil(i1, unit); + long amount = i2.until(i1, unit); assertEquals(amount, -expected); } @Test(expectedExceptions = UnsupportedTemporalTypeException.class) public void test_periodUntil_TemporalUnit_unsupportedUnit() { - TEST_12345_123456789.periodUntil(TEST_12345_123456789, MONTHS); + TEST_12345_123456789.until(TEST_12345_123456789, MONTHS); } @Test(expectedExceptions = NullPointerException.class) public void test_periodUntil_TemporalUnit_nullEnd() { - TEST_12345_123456789.periodUntil(null, HOURS); + TEST_12345_123456789.until(null, HOURS); } @Test(expectedExceptions = NullPointerException.class) public void test_periodUntil_TemporalUnit_nullUnit() { - TEST_12345_123456789.periodUntil(TEST_12345_123456789, null); + TEST_12345_123456789.until(TEST_12345_123456789, null); } //----------------------------------------------------------------------- diff --git a/jdk/test/java/time/tck/java/time/TCKLocalDate.java b/jdk/test/java/time/tck/java/time/TCKLocalDate.java index 926aca4a761..597dd4f6574 100644 --- a/jdk/test/java/time/tck/java/time/TCKLocalDate.java +++ b/jdk/test/java/time/tck/java/time/TCKLocalDate.java @@ -619,6 +619,68 @@ public class TCKLocalDate extends AbstractDateTimeTest { LocalDate.parse("ANY", null); } + //----------------------------------------------------------------------- + // isSupported(TemporalField) + //----------------------------------------------------------------------- + @Test + public void test_isSupported_TemporalField() { + assertEquals(TEST_2007_07_15.isSupported((TemporalField) null), false); + assertEquals(TEST_2007_07_15.isSupported(ChronoField.NANO_OF_SECOND), false); + assertEquals(TEST_2007_07_15.isSupported(ChronoField.NANO_OF_DAY), false); + assertEquals(TEST_2007_07_15.isSupported(ChronoField.MICRO_OF_SECOND), false); + assertEquals(TEST_2007_07_15.isSupported(ChronoField.MICRO_OF_DAY), false); + assertEquals(TEST_2007_07_15.isSupported(ChronoField.MILLI_OF_SECOND), false); + assertEquals(TEST_2007_07_15.isSupported(ChronoField.MILLI_OF_DAY), false); + assertEquals(TEST_2007_07_15.isSupported(ChronoField.SECOND_OF_MINUTE), false); + assertEquals(TEST_2007_07_15.isSupported(ChronoField.SECOND_OF_DAY), false); + assertEquals(TEST_2007_07_15.isSupported(ChronoField.MINUTE_OF_HOUR), false); + assertEquals(TEST_2007_07_15.isSupported(ChronoField.MINUTE_OF_DAY), false); + assertEquals(TEST_2007_07_15.isSupported(ChronoField.HOUR_OF_AMPM), false); + assertEquals(TEST_2007_07_15.isSupported(ChronoField.CLOCK_HOUR_OF_AMPM), false); + assertEquals(TEST_2007_07_15.isSupported(ChronoField.HOUR_OF_DAY), false); + assertEquals(TEST_2007_07_15.isSupported(ChronoField.CLOCK_HOUR_OF_DAY), false); + assertEquals(TEST_2007_07_15.isSupported(ChronoField.AMPM_OF_DAY), false); + assertEquals(TEST_2007_07_15.isSupported(ChronoField.DAY_OF_WEEK), true); + assertEquals(TEST_2007_07_15.isSupported(ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH), true); + assertEquals(TEST_2007_07_15.isSupported(ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR), true); + assertEquals(TEST_2007_07_15.isSupported(ChronoField.DAY_OF_MONTH), true); + assertEquals(TEST_2007_07_15.isSupported(ChronoField.DAY_OF_YEAR), true); + assertEquals(TEST_2007_07_15.isSupported(ChronoField.EPOCH_DAY), true); + assertEquals(TEST_2007_07_15.isSupported(ChronoField.ALIGNED_WEEK_OF_MONTH), true); + assertEquals(TEST_2007_07_15.isSupported(ChronoField.ALIGNED_WEEK_OF_YEAR), true); + assertEquals(TEST_2007_07_15.isSupported(ChronoField.MONTH_OF_YEAR), true); + assertEquals(TEST_2007_07_15.isSupported(ChronoField.PROLEPTIC_MONTH), true); + assertEquals(TEST_2007_07_15.isSupported(ChronoField.YEAR), true); + assertEquals(TEST_2007_07_15.isSupported(ChronoField.YEAR_OF_ERA), true); + assertEquals(TEST_2007_07_15.isSupported(ChronoField.ERA), true); + assertEquals(TEST_2007_07_15.isSupported(ChronoField.INSTANT_SECONDS), false); + assertEquals(TEST_2007_07_15.isSupported(ChronoField.OFFSET_SECONDS), false); + } + + //----------------------------------------------------------------------- + // isSupported(TemporalUnit) + //----------------------------------------------------------------------- + @Test + public void test_isSupported_TemporalUnit() { + assertEquals(TEST_2007_07_15.isSupported((TemporalUnit) null), false); + assertEquals(TEST_2007_07_15.isSupported(ChronoUnit.NANOS), false); + assertEquals(TEST_2007_07_15.isSupported(ChronoUnit.MICROS), false); + assertEquals(TEST_2007_07_15.isSupported(ChronoUnit.MILLIS), false); + assertEquals(TEST_2007_07_15.isSupported(ChronoUnit.SECONDS), false); + assertEquals(TEST_2007_07_15.isSupported(ChronoUnit.MINUTES), false); + assertEquals(TEST_2007_07_15.isSupported(ChronoUnit.HOURS), false); + assertEquals(TEST_2007_07_15.isSupported(ChronoUnit.HALF_DAYS), false); + assertEquals(TEST_2007_07_15.isSupported(ChronoUnit.DAYS), true); + assertEquals(TEST_2007_07_15.isSupported(ChronoUnit.WEEKS), true); + assertEquals(TEST_2007_07_15.isSupported(ChronoUnit.MONTHS), true); + assertEquals(TEST_2007_07_15.isSupported(ChronoUnit.YEARS), true); + assertEquals(TEST_2007_07_15.isSupported(ChronoUnit.DECADES), true); + assertEquals(TEST_2007_07_15.isSupported(ChronoUnit.CENTURIES), true); + assertEquals(TEST_2007_07_15.isSupported(ChronoUnit.MILLENNIA), true); + assertEquals(TEST_2007_07_15.isSupported(ChronoUnit.ERAS), true); + assertEquals(TEST_2007_07_15.isSupported(ChronoUnit.FOREVER), false); + } + //----------------------------------------------------------------------- // get(TemporalField) //----------------------------------------------------------------------- @@ -1635,7 +1697,7 @@ public class TCKLocalDate extends AbstractDateTimeTest { } //----------------------------------------------------------------------- - // periodUntil(Temporal, TemporalUnit) + // until(Temporal, TemporalUnit) //----------------------------------------------------------------------- @DataProvider(name="periodUntilUnit") Object[][] data_periodUntilUnit() { @@ -1684,35 +1746,35 @@ public class TCKLocalDate extends AbstractDateTimeTest { @Test(dataProvider="periodUntilUnit") public void test_periodUntil_TemporalUnit(LocalDate date1, LocalDate date2, TemporalUnit unit, long expected) { - long amount = date1.periodUntil(date2, unit); + long amount = date1.until(date2, unit); assertEquals(amount, expected); } @Test(dataProvider="periodUntilUnit") public void test_periodUntil_TemporalUnit_negated(LocalDate date1, LocalDate date2, TemporalUnit unit, long expected) { - long amount = date2.periodUntil(date1, unit); + long amount = date2.until(date1, unit); assertEquals(amount, -expected); } @Test(expectedExceptions = UnsupportedTemporalTypeException.class) public void test_periodUntil_TemporalUnit_unsupportedUnit() { - TEST_2007_07_15.periodUntil(TEST_2007_07_15, HOURS); + TEST_2007_07_15.until(TEST_2007_07_15, HOURS); } @Test(expectedExceptions = NullPointerException.class) public void test_periodUntil_TemporalUnit_nullEnd() { - TEST_2007_07_15.periodUntil(null, DAYS); + TEST_2007_07_15.until(null, DAYS); } @Test(expectedExceptions = NullPointerException.class) public void test_periodUntil_TemporalUnit_nullUnit() { - TEST_2007_07_15.periodUntil(TEST_2007_07_15, null); + TEST_2007_07_15.until(TEST_2007_07_15, null); } //----------------------------------------------------------------------- - // periodUntil(ChronoLocalDate) + // until(ChronoLocalDate) //----------------------------------------------------------------------- - @DataProvider(name="periodUntil") + @DataProvider(name="until") Object[][] data_periodUntil() { return new Object[][] { {2010, 1, 1, 2010, 1, 1, 0, 0, 0}, @@ -1799,11 +1861,11 @@ public class TCKLocalDate extends AbstractDateTimeTest { }; } - @Test(dataProvider="periodUntil") + @Test(dataProvider="until") public void test_periodUntil_LocalDate(int y1, int m1, int d1, int y2, int m2, int d2, int ye, int me, int de) { LocalDate start = LocalDate.of(y1, m1, d1); LocalDate end = LocalDate.of(y2, m2, d2); - Period test = start.periodUntil(end); + Period test = start.until(end); assertEquals(test.getYears(), ye); assertEquals(test.getMonths(), me); assertEquals(test.getDays(), de); @@ -1812,12 +1874,12 @@ public class TCKLocalDate extends AbstractDateTimeTest { @Test public void test_periodUntil_LocalDate_max() { int years = Math.toIntExact((long) Year.MAX_VALUE - (long) Year.MIN_VALUE); - assertEquals(LocalDate.MIN.periodUntil(LocalDate.MAX), Period.of(years, 11, 30)); + assertEquals(LocalDate.MIN.until(LocalDate.MAX), Period.of(years, 11, 30)); } @Test(expectedExceptions=NullPointerException.class) public void test_periodUntil_LocalDate_null() { - TEST_2007_07_15.periodUntil(null); + TEST_2007_07_15.until(null); } //----------------------------------------------------------------------- diff --git a/jdk/test/java/time/tck/java/time/TCKLocalDateTime.java b/jdk/test/java/time/tck/java/time/TCKLocalDateTime.java index f7d5c9ed1f4..f55bdb4a961 100644 --- a/jdk/test/java/time/tck/java/time/TCKLocalDateTime.java +++ b/jdk/test/java/time/tck/java/time/TCKLocalDateTime.java @@ -937,6 +937,68 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { LocalDateTime.parse("ANY", null); } + //----------------------------------------------------------------------- + // isSupported(TemporalField) + //----------------------------------------------------------------------- + @Test + public void test_isSupported_TemporalField() { + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported((TemporalField) null), false); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoField.NANO_OF_SECOND), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoField.NANO_OF_DAY), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoField.MICRO_OF_SECOND), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoField.MICRO_OF_DAY), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoField.MILLI_OF_SECOND), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoField.MILLI_OF_DAY), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoField.SECOND_OF_MINUTE), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoField.SECOND_OF_DAY), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoField.MINUTE_OF_HOUR), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoField.MINUTE_OF_DAY), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoField.HOUR_OF_AMPM), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoField.CLOCK_HOUR_OF_AMPM), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoField.HOUR_OF_DAY), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoField.CLOCK_HOUR_OF_DAY), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoField.AMPM_OF_DAY), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoField.DAY_OF_WEEK), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoField.DAY_OF_MONTH), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoField.DAY_OF_YEAR), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoField.EPOCH_DAY), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoField.ALIGNED_WEEK_OF_MONTH), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoField.ALIGNED_WEEK_OF_YEAR), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoField.MONTH_OF_YEAR), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoField.PROLEPTIC_MONTH), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoField.YEAR), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoField.YEAR_OF_ERA), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoField.ERA), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoField.INSTANT_SECONDS), false); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoField.OFFSET_SECONDS), false); + } + + //----------------------------------------------------------------------- + // isSupported(TemporalUnit) + //----------------------------------------------------------------------- + @Test + public void test_isSupported_TemporalUnit() { + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported((TemporalUnit) null), false); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoUnit.NANOS), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoUnit.MICROS), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoUnit.MILLIS), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoUnit.SECONDS), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoUnit.MINUTES), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoUnit.HOURS), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoUnit.HALF_DAYS), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoUnit.DAYS), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoUnit.WEEKS), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoUnit.MONTHS), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoUnit.YEARS), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoUnit.DECADES), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoUnit.CENTURIES), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoUnit.MILLENNIA), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoUnit.ERAS), true); + assertEquals(TEST_2007_07_15_12_30_40_987654321.isSupported(ChronoUnit.FOREVER), false); + } + //----------------------------------------------------------------------- // get(TemporalField) //----------------------------------------------------------------------- @@ -2717,7 +2779,7 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { } //----------------------------------------------------------------------- - // periodUntil(Temporal, TemporalUnit) + // until(Temporal, TemporalUnit) //----------------------------------------------------------------------- @DataProvider(name="periodUntilUnit") Object[][] data_periodUntilUnit() { @@ -2859,24 +2921,24 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { @Test(dataProvider="periodUntilUnit") public void test_periodUntil_TemporalUnit(LocalDateTime dt1, LocalDateTime dt2, TemporalUnit unit, long expected) { - long amount = dt1.periodUntil(dt2, unit); + long amount = dt1.until(dt2, unit); assertEquals(amount, expected); } @Test(dataProvider="periodUntilUnit") public void test_periodUntil_TemporalUnit_negated(LocalDateTime dt1, LocalDateTime dt2, TemporalUnit unit, long expected) { - long amount = dt2.periodUntil(dt1, unit); + long amount = dt2.until(dt1, unit); assertEquals(amount, -expected); } @Test(expectedExceptions = NullPointerException.class) public void test_periodUntil_TemporalUnit_nullEnd() { - TEST_2007_07_15_12_30_40_987654321.periodUntil(null, HOURS); + TEST_2007_07_15_12_30_40_987654321.until(null, HOURS); } @Test(expectedExceptions = NullPointerException.class) public void test_periodUntil_TemporalUnit_nullUnit() { - TEST_2007_07_15_12_30_40_987654321.periodUntil(TEST_2007_07_15_12_30_40_987654321, null); + TEST_2007_07_15_12_30_40_987654321.until(TEST_2007_07_15_12_30_40_987654321, null); } //----------------------------------------------------------------------- diff --git a/jdk/test/java/time/tck/java/time/TCKLocalTime.java b/jdk/test/java/time/tck/java/time/TCKLocalTime.java index 28c59491501..e0ef94cdadc 100644 --- a/jdk/test/java/time/tck/java/time/TCKLocalTime.java +++ b/jdk/test/java/time/tck/java/time/TCKLocalTime.java @@ -619,6 +619,68 @@ public class TCKLocalTime extends AbstractDateTimeTest { LocalTime.parse("ANY", null); } + //----------------------------------------------------------------------- + // isSupported(TemporalField) + //----------------------------------------------------------------------- + @Test + public void test_isSupported_TemporalField() { + assertEquals(TEST_12_30_40_987654321.isSupported((TemporalField) null), false); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoField.NANO_OF_SECOND), true); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoField.NANO_OF_DAY), true); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoField.MICRO_OF_SECOND), true); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoField.MICRO_OF_DAY), true); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoField.MILLI_OF_SECOND), true); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoField.MILLI_OF_DAY), true); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoField.SECOND_OF_MINUTE), true); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoField.SECOND_OF_DAY), true); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoField.MINUTE_OF_HOUR), true); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoField.MINUTE_OF_DAY), true); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoField.HOUR_OF_AMPM), true); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoField.CLOCK_HOUR_OF_AMPM), true); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoField.HOUR_OF_DAY), true); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoField.CLOCK_HOUR_OF_DAY), true); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoField.AMPM_OF_DAY), true); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoField.DAY_OF_WEEK), false); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH), false); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR), false); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoField.DAY_OF_MONTH), false); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoField.DAY_OF_YEAR), false); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoField.EPOCH_DAY), false); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoField.ALIGNED_WEEK_OF_MONTH), false); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoField.ALIGNED_WEEK_OF_YEAR), false); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoField.MONTH_OF_YEAR), false); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoField.PROLEPTIC_MONTH), false); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoField.YEAR), false); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoField.YEAR_OF_ERA), false); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoField.ERA), false); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoField.INSTANT_SECONDS), false); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoField.OFFSET_SECONDS), false); + } + + //----------------------------------------------------------------------- + // isSupported(TemporalUnit) + //----------------------------------------------------------------------- + @Test + public void test_isSupported_TemporalUnit() { + assertEquals(TEST_12_30_40_987654321.isSupported((TemporalUnit) null), false); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoUnit.NANOS), true); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoUnit.MICROS), true); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoUnit.MILLIS), true); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoUnit.SECONDS), true); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoUnit.MINUTES), true); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoUnit.HOURS), true); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoUnit.HALF_DAYS), true); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoUnit.DAYS), false); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoUnit.WEEKS), false); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoUnit.MONTHS), false); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoUnit.YEARS), false); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoUnit.DECADES), false); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoUnit.CENTURIES), false); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoUnit.MILLENNIA), false); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoUnit.ERAS), false); + assertEquals(TEST_12_30_40_987654321.isSupported(ChronoUnit.FOREVER), false); + } + //----------------------------------------------------------------------- // get(TemporalField) //----------------------------------------------------------------------- @@ -952,10 +1014,6 @@ public class TCKLocalTime extends AbstractDateTimeTest { // truncated(TemporalUnit) //----------------------------------------------------------------------- TemporalUnit NINETY_MINS = new TemporalUnit() { - @Override - public String getName() { - return "NinetyMins"; - } @Override public Duration getDuration() { return Duration.ofMinutes(90); @@ -965,6 +1023,14 @@ public class TCKLocalTime extends AbstractDateTimeTest { return false; } @Override + public boolean isDateBased() { + return false; + } + @Override + public boolean isTimeBased() { + return true; + } + @Override public boolean isSupportedBy(Temporal temporal) { return false; } @@ -976,13 +1042,13 @@ public class TCKLocalTime extends AbstractDateTimeTest { public long between(Temporal temporal1, Temporal temporal2) { throw new UnsupportedOperationException(); } + @Override + public String toString() { + return "NinetyMins"; + } }; TemporalUnit NINETY_FIVE_MINS = new TemporalUnit() { - @Override - public String getName() { - return "NinetyFiveMins"; - } @Override public Duration getDuration() { return Duration.ofMinutes(95); @@ -992,6 +1058,14 @@ public class TCKLocalTime extends AbstractDateTimeTest { return false; } @Override + public boolean isDateBased() { + return false; + } + @Override + public boolean isTimeBased() { + return false; + } + @Override public boolean isSupportedBy(Temporal temporal) { return false; } @@ -1003,6 +1077,10 @@ public class TCKLocalTime extends AbstractDateTimeTest { public long between(Temporal temporal1, Temporal temporal2) { throw new UnsupportedOperationException(); } + @Override + public String toString() { + return "NinetyFiveMins"; + } }; @DataProvider(name="truncatedToValid") @@ -1922,7 +2000,7 @@ public class TCKLocalTime extends AbstractDateTimeTest { } //----------------------------------------------------------------------- - // periodUntil(Temporal, TemporalUnit) + // until(Temporal, TemporalUnit) //----------------------------------------------------------------------- @DataProvider(name="periodUntilUnit") Object[][] data_periodUntilUnit() { @@ -1962,29 +2040,29 @@ public class TCKLocalTime extends AbstractDateTimeTest { @Test(dataProvider="periodUntilUnit") public void test_periodUntil_TemporalUnit(LocalTime time1, LocalTime time2, TemporalUnit unit, long expected) { - long amount = time1.periodUntil(time2, unit); + long amount = time1.until(time2, unit); assertEquals(amount, expected); } @Test(dataProvider="periodUntilUnit") public void test_periodUntil_TemporalUnit_negated(LocalTime time1, LocalTime time2, TemporalUnit unit, long expected) { - long amount = time2.periodUntil(time1, unit); + long amount = time2.until(time1, unit); assertEquals(amount, -expected); } @Test(expectedExceptions = UnsupportedTemporalTypeException.class) public void test_periodUntil_TemporalUnit_unsupportedUnit() { - TEST_12_30_40_987654321.periodUntil(TEST_12_30_40_987654321, DAYS); + TEST_12_30_40_987654321.until(TEST_12_30_40_987654321, DAYS); } @Test(expectedExceptions = NullPointerException.class) public void test_periodUntil_TemporalUnit_nullEnd() { - TEST_12_30_40_987654321.periodUntil(null, HOURS); + TEST_12_30_40_987654321.until(null, HOURS); } @Test(expectedExceptions = NullPointerException.class) public void test_periodUntil_TemporalUnit_nullUnit() { - TEST_12_30_40_987654321.periodUntil(TEST_12_30_40_987654321, null); + TEST_12_30_40_987654321.until(TEST_12_30_40_987654321, null); } //----------------------------------------------------------------------- diff --git a/jdk/test/java/time/tck/java/time/TCKMonth.java b/jdk/test/java/time/tck/java/time/TCKMonth.java index 77e9eef7a96..3bff8c9beb6 100644 --- a/jdk/test/java/time/tck/java/time/TCKMonth.java +++ b/jdk/test/java/time/tck/java/time/TCKMonth.java @@ -150,6 +150,44 @@ public class TCKMonth extends AbstractDateTimeTest { Month.from((TemporalAccessor) null); } + //----------------------------------------------------------------------- + // isSupported(TemporalField) + //----------------------------------------------------------------------- + @Test + public void test_isSupported_TemporalField() { + assertEquals(Month.AUGUST.isSupported((TemporalField) null), false); + assertEquals(Month.AUGUST.isSupported(ChronoField.NANO_OF_SECOND), false); + assertEquals(Month.AUGUST.isSupported(ChronoField.NANO_OF_DAY), false); + assertEquals(Month.AUGUST.isSupported(ChronoField.MICRO_OF_SECOND), false); + assertEquals(Month.AUGUST.isSupported(ChronoField.MICRO_OF_DAY), false); + assertEquals(Month.AUGUST.isSupported(ChronoField.MILLI_OF_SECOND), false); + assertEquals(Month.AUGUST.isSupported(ChronoField.MILLI_OF_DAY), false); + assertEquals(Month.AUGUST.isSupported(ChronoField.SECOND_OF_MINUTE), false); + assertEquals(Month.AUGUST.isSupported(ChronoField.SECOND_OF_DAY), false); + assertEquals(Month.AUGUST.isSupported(ChronoField.MINUTE_OF_HOUR), false); + assertEquals(Month.AUGUST.isSupported(ChronoField.MINUTE_OF_DAY), false); + assertEquals(Month.AUGUST.isSupported(ChronoField.HOUR_OF_AMPM), false); + assertEquals(Month.AUGUST.isSupported(ChronoField.CLOCK_HOUR_OF_AMPM), false); + assertEquals(Month.AUGUST.isSupported(ChronoField.HOUR_OF_DAY), false); + assertEquals(Month.AUGUST.isSupported(ChronoField.CLOCK_HOUR_OF_DAY), false); + assertEquals(Month.AUGUST.isSupported(ChronoField.AMPM_OF_DAY), false); + assertEquals(Month.AUGUST.isSupported(ChronoField.DAY_OF_WEEK), false); + assertEquals(Month.AUGUST.isSupported(ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH), false); + assertEquals(Month.AUGUST.isSupported(ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR), false); + assertEquals(Month.AUGUST.isSupported(ChronoField.DAY_OF_MONTH), false); + assertEquals(Month.AUGUST.isSupported(ChronoField.DAY_OF_YEAR), false); + assertEquals(Month.AUGUST.isSupported(ChronoField.EPOCH_DAY), false); + assertEquals(Month.AUGUST.isSupported(ChronoField.ALIGNED_WEEK_OF_MONTH), false); + assertEquals(Month.AUGUST.isSupported(ChronoField.ALIGNED_WEEK_OF_YEAR), false); + assertEquals(Month.AUGUST.isSupported(ChronoField.MONTH_OF_YEAR), true); + assertEquals(Month.AUGUST.isSupported(ChronoField.PROLEPTIC_MONTH), false); + assertEquals(Month.AUGUST.isSupported(ChronoField.YEAR), false); + assertEquals(Month.AUGUST.isSupported(ChronoField.YEAR_OF_ERA), false); + assertEquals(Month.AUGUST.isSupported(ChronoField.ERA), false); + assertEquals(Month.AUGUST.isSupported(ChronoField.INSTANT_SECONDS), false); + assertEquals(Month.AUGUST.isSupported(ChronoField.OFFSET_SECONDS), false); + } + //----------------------------------------------------------------------- // get(TemporalField) //----------------------------------------------------------------------- diff --git a/jdk/test/java/time/tck/java/time/TCKMonthDay.java b/jdk/test/java/time/tck/java/time/TCKMonthDay.java index 0bcbdef8195..f2a2b93f473 100644 --- a/jdk/test/java/time/tck/java/time/TCKMonthDay.java +++ b/jdk/test/java/time/tck/java/time/TCKMonthDay.java @@ -387,6 +387,44 @@ public class TCKMonthDay extends AbstractDateTimeTest { MonthDay.parse("ANY", null); } + //----------------------------------------------------------------------- + // isSupported(TemporalField) + //----------------------------------------------------------------------- + @Test + public void test_isSupported_TemporalField() { + assertEquals(TEST_07_15.isSupported((TemporalField) null), false); + assertEquals(TEST_07_15.isSupported(ChronoField.NANO_OF_SECOND), false); + assertEquals(TEST_07_15.isSupported(ChronoField.NANO_OF_DAY), false); + assertEquals(TEST_07_15.isSupported(ChronoField.MICRO_OF_SECOND), false); + assertEquals(TEST_07_15.isSupported(ChronoField.MICRO_OF_DAY), false); + assertEquals(TEST_07_15.isSupported(ChronoField.MILLI_OF_SECOND), false); + assertEquals(TEST_07_15.isSupported(ChronoField.MILLI_OF_DAY), false); + assertEquals(TEST_07_15.isSupported(ChronoField.SECOND_OF_MINUTE), false); + assertEquals(TEST_07_15.isSupported(ChronoField.SECOND_OF_DAY), false); + assertEquals(TEST_07_15.isSupported(ChronoField.MINUTE_OF_HOUR), false); + assertEquals(TEST_07_15.isSupported(ChronoField.MINUTE_OF_DAY), false); + assertEquals(TEST_07_15.isSupported(ChronoField.HOUR_OF_AMPM), false); + assertEquals(TEST_07_15.isSupported(ChronoField.CLOCK_HOUR_OF_AMPM), false); + assertEquals(TEST_07_15.isSupported(ChronoField.HOUR_OF_DAY), false); + assertEquals(TEST_07_15.isSupported(ChronoField.CLOCK_HOUR_OF_DAY), false); + assertEquals(TEST_07_15.isSupported(ChronoField.AMPM_OF_DAY), false); + assertEquals(TEST_07_15.isSupported(ChronoField.DAY_OF_WEEK), false); + assertEquals(TEST_07_15.isSupported(ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH), false); + assertEquals(TEST_07_15.isSupported(ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR), false); + assertEquals(TEST_07_15.isSupported(ChronoField.DAY_OF_MONTH), true); + assertEquals(TEST_07_15.isSupported(ChronoField.DAY_OF_YEAR), false); + assertEquals(TEST_07_15.isSupported(ChronoField.EPOCH_DAY), false); + assertEquals(TEST_07_15.isSupported(ChronoField.ALIGNED_WEEK_OF_MONTH), false); + assertEquals(TEST_07_15.isSupported(ChronoField.ALIGNED_WEEK_OF_YEAR), false); + assertEquals(TEST_07_15.isSupported(ChronoField.MONTH_OF_YEAR), true); + assertEquals(TEST_07_15.isSupported(ChronoField.PROLEPTIC_MONTH), false); + assertEquals(TEST_07_15.isSupported(ChronoField.YEAR), false); + assertEquals(TEST_07_15.isSupported(ChronoField.YEAR_OF_ERA), false); + assertEquals(TEST_07_15.isSupported(ChronoField.ERA), false); + assertEquals(TEST_07_15.isSupported(ChronoField.INSTANT_SECONDS), false); + assertEquals(TEST_07_15.isSupported(ChronoField.OFFSET_SECONDS), false); + } + //----------------------------------------------------------------------- // get(TemporalField) //----------------------------------------------------------------------- diff --git a/jdk/test/java/time/tck/java/time/TCKOffsetDateTime.java b/jdk/test/java/time/tck/java/time/TCKOffsetDateTime.java index a6bb7c30418..7cfc2a61dec 100644 --- a/jdk/test/java/time/tck/java/time/TCKOffsetDateTime.java +++ b/jdk/test/java/time/tck/java/time/TCKOffsetDateTime.java @@ -126,6 +126,7 @@ import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalAdjuster; import java.time.temporal.TemporalField; import java.time.temporal.TemporalQuery; +import java.time.temporal.TemporalUnit; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -554,6 +555,68 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { assertEquals(a.toString(), localDateTime.toString() + offset.toString()); } + //----------------------------------------------------------------------- + // isSupported(TemporalField) + //----------------------------------------------------------------------- + @Test + public void test_isSupported_TemporalField() { + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported((TemporalField) null), false); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoField.NANO_OF_SECOND), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoField.NANO_OF_DAY), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoField.MICRO_OF_SECOND), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoField.MICRO_OF_DAY), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoField.MILLI_OF_SECOND), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoField.MILLI_OF_DAY), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoField.SECOND_OF_MINUTE), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoField.SECOND_OF_DAY), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoField.MINUTE_OF_HOUR), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoField.MINUTE_OF_DAY), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoField.HOUR_OF_AMPM), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoField.CLOCK_HOUR_OF_AMPM), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoField.HOUR_OF_DAY), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoField.CLOCK_HOUR_OF_DAY), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoField.AMPM_OF_DAY), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoField.DAY_OF_WEEK), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoField.DAY_OF_MONTH), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoField.DAY_OF_YEAR), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoField.EPOCH_DAY), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoField.ALIGNED_WEEK_OF_MONTH), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoField.ALIGNED_WEEK_OF_YEAR), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoField.MONTH_OF_YEAR), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoField.PROLEPTIC_MONTH), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoField.YEAR), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoField.YEAR_OF_ERA), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoField.ERA), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoField.INSTANT_SECONDS), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoField.OFFSET_SECONDS), true); + } + + //----------------------------------------------------------------------- + // isSupported(TemporalUnit) + //----------------------------------------------------------------------- + @Test + public void test_isSupported_TemporalUnit() { + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported((TemporalUnit) null), false); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoUnit.NANOS), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoUnit.MICROS), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoUnit.MILLIS), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoUnit.SECONDS), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoUnit.MINUTES), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoUnit.HOURS), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoUnit.HALF_DAYS), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoUnit.DAYS), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoUnit.WEEKS), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoUnit.MONTHS), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoUnit.YEARS), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoUnit.DECADES), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoUnit.CENTURIES), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoUnit.MILLENNIA), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoUnit.ERAS), true); + assertEquals(TEST_2008_6_30_11_30_59_000000500.isSupported(ChronoUnit.FOREVER), false); + } + //----------------------------------------------------------------------- // get(TemporalField) //----------------------------------------------------------------------- @@ -1203,6 +1266,7 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { assertEquals(a.compareTo(a) == 0, true); assertEquals(b.compareTo(b) == 0, true); assertEquals(a.toInstant().compareTo(b.toInstant()) < 0, true); + assertEquals(OffsetDateTime.timeLineOrder().compare(a, b) < 0, true); } @Test @@ -1214,6 +1278,7 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { assertEquals(a.compareTo(a) == 0, true); assertEquals(b.compareTo(b) == 0, true); assertEquals(a.toInstant().compareTo(b.toInstant()) < 0, true); + assertEquals(OffsetDateTime.timeLineOrder().compare(a, b) < 0, true); } @Test @@ -1225,6 +1290,7 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { assertEquals(a.compareTo(a) == 0, true); assertEquals(b.compareTo(b) == 0, true); assertEquals(a.toInstant().compareTo(b.toInstant()) < 0, true); + assertEquals(OffsetDateTime.timeLineOrder().compare(a, b) < 0, true); } @Test @@ -1236,6 +1302,7 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { assertEquals(a.compareTo(a) == 0, true); assertEquals(b.compareTo(b) == 0, true); assertEquals(a.toInstant().compareTo(b.toInstant()) < 0, true); + assertEquals(OffsetDateTime.timeLineOrder().compare(a, b) < 0, true); } @Test @@ -1247,6 +1314,7 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { assertEquals(a.compareTo(a) == 0, true); assertEquals(b.compareTo(b) == 0, true); assertEquals(a.toInstant().compareTo(b.toInstant()) < 0, true); + assertEquals(OffsetDateTime.timeLineOrder().compare(a, b) < 0, true); } @Test @@ -1258,6 +1326,7 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { assertEquals(a.compareTo(a) == 0, true); assertEquals(b.compareTo(b) == 0, true); assertEquals(a.toInstant().compareTo(b.toInstant()) < 0, true); + assertEquals(OffsetDateTime.timeLineOrder().compare(a, b) < 0, true); } @Test @@ -1269,6 +1338,14 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { assertEquals(a.compareTo(a) == 0, true); assertEquals(b.compareTo(b) == 0, true); assertEquals(a.toInstant().compareTo(b.toInstant()) < 0, true); + assertEquals(OffsetDateTime.timeLineOrder().compare(a, b) < 0, true); + } + + @Test + public void test_compareTo_bothInstantComparator() { + OffsetDateTime a = OffsetDateTime.of(2008, 6, 30, 11, 20, 40, 4, OFFSET_PTWO); + OffsetDateTime b = OffsetDateTime.of(2008, 6, 30, 10, 20, 40, 5, OFFSET_PONE); + assertEquals(a.compareTo(b), OffsetDateTime.timeLineOrder().compare(a,b), "for nano != nano, compareTo and timeLineOrder() should be the same"); } @Test diff --git a/jdk/test/java/time/tck/java/time/TCKOffsetTime.java b/jdk/test/java/time/tck/java/time/TCKOffsetTime.java index 7b97380e4de..b3d7e5b26a9 100644 --- a/jdk/test/java/time/tck/java/time/TCKOffsetTime.java +++ b/jdk/test/java/time/tck/java/time/TCKOffsetTime.java @@ -542,6 +542,68 @@ public class TCKOffsetTime extends AbstractDateTimeTest { assertEquals(a.getNano(), localTime.getNano()); } + //----------------------------------------------------------------------- + // isSupported(TemporalField) + //----------------------------------------------------------------------- + @Test + public void test_isSupported_TemporalField() { + assertEquals(TEST_11_30_59_500_PONE.isSupported((TemporalField) null), false); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoField.NANO_OF_SECOND), true); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoField.NANO_OF_DAY), true); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoField.MICRO_OF_SECOND), true); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoField.MICRO_OF_DAY), true); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoField.MILLI_OF_SECOND), true); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoField.MILLI_OF_DAY), true); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoField.SECOND_OF_MINUTE), true); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoField.SECOND_OF_DAY), true); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoField.MINUTE_OF_HOUR), true); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoField.MINUTE_OF_DAY), true); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoField.HOUR_OF_AMPM), true); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoField.CLOCK_HOUR_OF_AMPM), true); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoField.HOUR_OF_DAY), true); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoField.CLOCK_HOUR_OF_DAY), true); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoField.AMPM_OF_DAY), true); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoField.DAY_OF_WEEK), false); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH), false); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR), false); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoField.DAY_OF_MONTH), false); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoField.DAY_OF_YEAR), false); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoField.EPOCH_DAY), false); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoField.ALIGNED_WEEK_OF_MONTH), false); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoField.ALIGNED_WEEK_OF_YEAR), false); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoField.MONTH_OF_YEAR), false); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoField.PROLEPTIC_MONTH), false); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoField.YEAR), false); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoField.YEAR_OF_ERA), false); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoField.ERA), false); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoField.INSTANT_SECONDS), false); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoField.OFFSET_SECONDS), true); + } + + //----------------------------------------------------------------------- + // isSupported(TemporalUnit) + //----------------------------------------------------------------------- + @Test + public void test_isSupported_TemporalUnit() { + assertEquals(TEST_11_30_59_500_PONE.isSupported((TemporalUnit) null), false); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoUnit.NANOS), true); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoUnit.MICROS), true); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoUnit.MILLIS), true); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoUnit.SECONDS), true); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoUnit.MINUTES), true); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoUnit.HOURS), true); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoUnit.HALF_DAYS), true); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoUnit.DAYS), false); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoUnit.WEEKS), false); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoUnit.MONTHS), false); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoUnit.YEARS), false); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoUnit.DECADES), false); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoUnit.CENTURIES), false); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoUnit.MILLENNIA), false); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoUnit.ERAS), false); + assertEquals(TEST_11_30_59_500_PONE.isSupported(ChronoUnit.FOREVER), false); + } + //----------------------------------------------------------------------- // get(TemporalField) //----------------------------------------------------------------------- @@ -1038,7 +1100,7 @@ public class TCKOffsetTime extends AbstractDateTimeTest { } //----------------------------------------------------------------------- - // periodUntil(Temporal, TemporalUnit) + // until(Temporal, TemporalUnit) //----------------------------------------------------------------------- @DataProvider(name="periodUntilUnit") Object[][] data_periodUntilUnit() { @@ -1063,13 +1125,13 @@ public class TCKOffsetTime extends AbstractDateTimeTest { @Test(dataProvider="periodUntilUnit") public void test_periodUntil_TemporalUnit(OffsetTime offsetTime1, OffsetTime offsetTime2, TemporalUnit unit, long expected) { - long amount = offsetTime1.periodUntil(offsetTime2, unit); + long amount = offsetTime1.until(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); + long amount = offsetTime2.until(offsetTime1, unit); assertEquals(amount, -expected); } @@ -1077,14 +1139,14 @@ public class TCKOffsetTime extends AbstractDateTimeTest { 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); + offsetTime.until(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); + offsetTime1.until(offsetTime2, MONTHS); } //----------------------------------------------------------------------- diff --git a/jdk/test/java/time/tck/java/time/TCKPeriod.java b/jdk/test/java/time/tck/java/time/TCKPeriod.java index 95907b237a7..7a06b95e6ef 100644 --- a/jdk/test/java/time/tck/java/time/TCKPeriod.java +++ b/jdk/test/java/time/tck/java/time/TCKPeriod.java @@ -120,11 +120,24 @@ public class TCKPeriod extends AbstractTCKTest { assertPeriod(Period.ofMonths(Integer.MIN_VALUE), 0, Integer.MIN_VALUE, 0); } + //----------------------------------------------------------------------- + // ofWeeks(int) + //----------------------------------------------------------------------- + @Test + public void factory_ofWeeks_int() { + assertPeriod(Period.ofWeeks(0), 0, 0, 0); + assertPeriod(Period.ofWeeks(1), 0, 0, 7); + assertPeriod(Period.ofWeeks(234), 0, 0, 234 * 7); + assertPeriod(Period.ofWeeks(-100), 0, 0, -100 * 7); + assertPeriod(Period.ofWeeks(Integer.MAX_VALUE / 7), 0, 0, (Integer.MAX_VALUE / 7) * 7); + assertPeriod(Period.ofWeeks(Integer.MIN_VALUE / 7), 0, 0, (Integer.MIN_VALUE / 7) * 7); + } + //----------------------------------------------------------------------- // ofDays(int) //----------------------------------------------------------------------- @Test - public void factory_ofDay_int() { + public void factory_ofDays_int() { assertPeriod(Period.ofDays(0), 0, 0, 0); assertPeriod(Period.ofDays(1), 0, 0, 1); assertPeriod(Period.ofDays(234), 0, 0, 234); @@ -251,6 +264,18 @@ public class TCKPeriod extends AbstractTCKTest { {"P" + Integer.MAX_VALUE + "M", Period.ofMonths(Integer.MAX_VALUE)}, {"P" + Integer.MIN_VALUE + "M", Period.ofMonths(Integer.MIN_VALUE)}, + {"P1W", Period.ofDays(1 * 7)}, + {"P12W", Period.ofDays(12 * 7)}, + {"P7654321W", Period.ofDays(7654321 * 7)}, + {"P+1W", Period.ofDays(1 * 7)}, + {"P+12W", Period.ofDays(12 * 7)}, + {"P+7654321W", Period.ofDays(7654321 * 7)}, + {"P+0W", Period.ofDays(0)}, + {"P0W", Period.ofDays(0)}, + {"P-0W", Period.ofDays(0)}, + {"P-25W", Period.ofDays(-25 * 7)}, + {"P-7654321W", Period.ofDays(-7654321 * 7)}, + {"P1D", Period.ofDays(1)}, {"P12D", Period.ofDays(12)}, {"P987654321D", Period.ofDays(987654321)}, @@ -274,6 +299,10 @@ public class TCKPeriod extends AbstractTCKTest { {"P2Y-3M25D", Period.of(2, -3, 25)}, {"P2Y3M-25D", Period.of(2, 3, -25)}, {"P-2Y-3M-25D", Period.of(-2, -3, -25)}, + + {"P0Y0M0W0D", Period.of(0, 0, 0)}, + {"P2Y3M4W25D", Period.of(2, 3, 4 * 7 + 25)}, + {"P-2Y-3M-4W-25D", Period.of(-2, -3, -4 * 7 - 25)}, }; } @@ -334,6 +363,13 @@ public class TCKPeriod extends AbstractTCKTest { {"P1Y2Y"}, {"PT1M+3S"}, + {"P1M2Y"}, + {"P1W2Y"}, + {"P1D2Y"}, + {"P1W2M"}, + {"P1D2M"}, + {"P1D2W"}, + {"PT1S1"}, {"PT1S."}, {"PT1SA"}, diff --git a/jdk/test/java/time/tck/java/time/TCKYear.java b/jdk/test/java/time/tck/java/time/TCKYear.java index ac25f0b4fb3..53f0db0b56e 100644 --- a/jdk/test/java/time/tck/java/time/TCKYear.java +++ b/jdk/test/java/time/tck/java/time/TCKYear.java @@ -347,6 +347,68 @@ public class TCKYear extends AbstractDateTimeTest { Year.parse("ANY", null); } + //----------------------------------------------------------------------- + // isSupported(TemporalField) + //----------------------------------------------------------------------- + @Test + public void test_isSupported_TemporalField() { + assertEquals(TEST_2008.isSupported((TemporalField) null), false); + assertEquals(TEST_2008.isSupported(ChronoField.NANO_OF_SECOND), false); + assertEquals(TEST_2008.isSupported(ChronoField.NANO_OF_DAY), false); + assertEquals(TEST_2008.isSupported(ChronoField.MICRO_OF_SECOND), false); + assertEquals(TEST_2008.isSupported(ChronoField.MICRO_OF_DAY), false); + assertEquals(TEST_2008.isSupported(ChronoField.MILLI_OF_SECOND), false); + assertEquals(TEST_2008.isSupported(ChronoField.MILLI_OF_DAY), false); + assertEquals(TEST_2008.isSupported(ChronoField.SECOND_OF_MINUTE), false); + assertEquals(TEST_2008.isSupported(ChronoField.SECOND_OF_DAY), false); + assertEquals(TEST_2008.isSupported(ChronoField.MINUTE_OF_HOUR), false); + assertEquals(TEST_2008.isSupported(ChronoField.MINUTE_OF_DAY), false); + assertEquals(TEST_2008.isSupported(ChronoField.HOUR_OF_AMPM), false); + assertEquals(TEST_2008.isSupported(ChronoField.CLOCK_HOUR_OF_AMPM), false); + assertEquals(TEST_2008.isSupported(ChronoField.HOUR_OF_DAY), false); + assertEquals(TEST_2008.isSupported(ChronoField.CLOCK_HOUR_OF_DAY), false); + assertEquals(TEST_2008.isSupported(ChronoField.AMPM_OF_DAY), false); + assertEquals(TEST_2008.isSupported(ChronoField.DAY_OF_WEEK), false); + assertEquals(TEST_2008.isSupported(ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH), false); + assertEquals(TEST_2008.isSupported(ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR), false); + assertEquals(TEST_2008.isSupported(ChronoField.DAY_OF_MONTH), false); + assertEquals(TEST_2008.isSupported(ChronoField.DAY_OF_YEAR), false); + assertEquals(TEST_2008.isSupported(ChronoField.EPOCH_DAY), false); + assertEquals(TEST_2008.isSupported(ChronoField.ALIGNED_WEEK_OF_MONTH), false); + assertEquals(TEST_2008.isSupported(ChronoField.ALIGNED_WEEK_OF_YEAR), false); + assertEquals(TEST_2008.isSupported(ChronoField.MONTH_OF_YEAR), false); + assertEquals(TEST_2008.isSupported(ChronoField.PROLEPTIC_MONTH), false); + assertEquals(TEST_2008.isSupported(ChronoField.YEAR), true); + assertEquals(TEST_2008.isSupported(ChronoField.YEAR_OF_ERA), true); + assertEquals(TEST_2008.isSupported(ChronoField.ERA), true); + assertEquals(TEST_2008.isSupported(ChronoField.INSTANT_SECONDS), false); + assertEquals(TEST_2008.isSupported(ChronoField.OFFSET_SECONDS), false); + } + + //----------------------------------------------------------------------- + // isSupported(TemporalUnit) + //----------------------------------------------------------------------- + @Test + public void test_isSupported_TemporalUnit() { + assertEquals(TEST_2008.isSupported((TemporalUnit) null), false); + assertEquals(TEST_2008.isSupported(ChronoUnit.NANOS), false); + assertEquals(TEST_2008.isSupported(ChronoUnit.MICROS), false); + assertEquals(TEST_2008.isSupported(ChronoUnit.MILLIS), false); + assertEquals(TEST_2008.isSupported(ChronoUnit.SECONDS), false); + assertEquals(TEST_2008.isSupported(ChronoUnit.MINUTES), false); + assertEquals(TEST_2008.isSupported(ChronoUnit.HOURS), false); + assertEquals(TEST_2008.isSupported(ChronoUnit.HALF_DAYS), false); + assertEquals(TEST_2008.isSupported(ChronoUnit.DAYS), false); + assertEquals(TEST_2008.isSupported(ChronoUnit.WEEKS), false); + assertEquals(TEST_2008.isSupported(ChronoUnit.MONTHS), false); + assertEquals(TEST_2008.isSupported(ChronoUnit.YEARS), true); + assertEquals(TEST_2008.isSupported(ChronoUnit.DECADES), true); + assertEquals(TEST_2008.isSupported(ChronoUnit.CENTURIES), true); + assertEquals(TEST_2008.isSupported(ChronoUnit.MILLENNIA), true); + assertEquals(TEST_2008.isSupported(ChronoUnit.ERAS), true); + assertEquals(TEST_2008.isSupported(ChronoUnit.FOREVER), false); + } + //----------------------------------------------------------------------- // get(TemporalField) //----------------------------------------------------------------------- @@ -829,7 +891,7 @@ public class TCKYear extends AbstractDateTimeTest { } //----------------------------------------------------------------------- - // periodUntil(Temporal, TemporalUnit) + // until(Temporal, TemporalUnit) //----------------------------------------------------------------------- @DataProvider(name="periodUntilUnit") Object[][] data_periodUntilUnit() { @@ -881,29 +943,29 @@ public class TCKYear extends AbstractDateTimeTest { @Test(dataProvider="periodUntilUnit") public void test_periodUntil_TemporalUnit(Year year1, Year year2, TemporalUnit unit, long expected) { - long amount = year1.periodUntil(year2, unit); + long amount = year1.until(year2, unit); assertEquals(amount, expected); } @Test(dataProvider="periodUntilUnit") public void test_periodUntil_TemporalUnit_negated(Year year1, Year year2, TemporalUnit unit, long expected) { - long amount = year2.periodUntil(year1, unit); + long amount = year2.until(year1, unit); assertEquals(amount, -expected); } @Test(expectedExceptions = UnsupportedTemporalTypeException.class) public void test_periodUntil_TemporalUnit_unsupportedUnit() { - TEST_2008.periodUntil(TEST_2008, MONTHS); + TEST_2008.until(TEST_2008, MONTHS); } @Test(expectedExceptions = NullPointerException.class) public void test_periodUntil_TemporalUnit_nullEnd() { - TEST_2008.periodUntil(null, DAYS); + TEST_2008.until(null, DAYS); } @Test(expectedExceptions = NullPointerException.class) public void test_periodUntil_TemporalUnit_nullUnit() { - TEST_2008.periodUntil(TEST_2008, null); + TEST_2008.until(TEST_2008, null); } //----------------------------------------------------------------------- diff --git a/jdk/test/java/time/tck/java/time/TCKYearMonth.java b/jdk/test/java/time/tck/java/time/TCKYearMonth.java index 14ccc774b27..66f691b0746 100644 --- a/jdk/test/java/time/tck/java/time/TCKYearMonth.java +++ b/jdk/test/java/time/tck/java/time/TCKYearMonth.java @@ -407,6 +407,68 @@ public class TCKYearMonth extends AbstractDateTimeTest { YearMonth.parse("ANY", null); } + //----------------------------------------------------------------------- + // isSupported(TemporalField) + //----------------------------------------------------------------------- + @Test + public void test_isSupported_TemporalField() { + assertEquals(TEST_2008_06.isSupported((TemporalField) null), false); + assertEquals(TEST_2008_06.isSupported(ChronoField.NANO_OF_SECOND), false); + assertEquals(TEST_2008_06.isSupported(ChronoField.NANO_OF_DAY), false); + assertEquals(TEST_2008_06.isSupported(ChronoField.MICRO_OF_SECOND), false); + assertEquals(TEST_2008_06.isSupported(ChronoField.MICRO_OF_DAY), false); + assertEquals(TEST_2008_06.isSupported(ChronoField.MILLI_OF_SECOND), false); + assertEquals(TEST_2008_06.isSupported(ChronoField.MILLI_OF_DAY), false); + assertEquals(TEST_2008_06.isSupported(ChronoField.SECOND_OF_MINUTE), false); + assertEquals(TEST_2008_06.isSupported(ChronoField.SECOND_OF_DAY), false); + assertEquals(TEST_2008_06.isSupported(ChronoField.MINUTE_OF_HOUR), false); + assertEquals(TEST_2008_06.isSupported(ChronoField.MINUTE_OF_DAY), false); + assertEquals(TEST_2008_06.isSupported(ChronoField.HOUR_OF_AMPM), false); + assertEquals(TEST_2008_06.isSupported(ChronoField.CLOCK_HOUR_OF_AMPM), false); + assertEquals(TEST_2008_06.isSupported(ChronoField.HOUR_OF_DAY), false); + assertEquals(TEST_2008_06.isSupported(ChronoField.CLOCK_HOUR_OF_DAY), false); + assertEquals(TEST_2008_06.isSupported(ChronoField.AMPM_OF_DAY), false); + assertEquals(TEST_2008_06.isSupported(ChronoField.DAY_OF_WEEK), false); + assertEquals(TEST_2008_06.isSupported(ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH), false); + assertEquals(TEST_2008_06.isSupported(ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR), false); + assertEquals(TEST_2008_06.isSupported(ChronoField.DAY_OF_MONTH), false); + assertEquals(TEST_2008_06.isSupported(ChronoField.DAY_OF_YEAR), false); + assertEquals(TEST_2008_06.isSupported(ChronoField.EPOCH_DAY), false); + assertEquals(TEST_2008_06.isSupported(ChronoField.ALIGNED_WEEK_OF_MONTH), false); + assertEquals(TEST_2008_06.isSupported(ChronoField.ALIGNED_WEEK_OF_YEAR), false); + assertEquals(TEST_2008_06.isSupported(ChronoField.MONTH_OF_YEAR), true); + assertEquals(TEST_2008_06.isSupported(ChronoField.PROLEPTIC_MONTH), true); + assertEquals(TEST_2008_06.isSupported(ChronoField.YEAR), true); + assertEquals(TEST_2008_06.isSupported(ChronoField.YEAR_OF_ERA), true); + assertEquals(TEST_2008_06.isSupported(ChronoField.ERA), true); + assertEquals(TEST_2008_06.isSupported(ChronoField.INSTANT_SECONDS), false); + assertEquals(TEST_2008_06.isSupported(ChronoField.OFFSET_SECONDS), false); + } + + //----------------------------------------------------------------------- + // isSupported(TemporalUnit) + //----------------------------------------------------------------------- + @Test + public void test_isSupported_TemporalUnit() { + assertEquals(TEST_2008_06.isSupported((TemporalUnit) null), false); + assertEquals(TEST_2008_06.isSupported(ChronoUnit.NANOS), false); + assertEquals(TEST_2008_06.isSupported(ChronoUnit.MICROS), false); + assertEquals(TEST_2008_06.isSupported(ChronoUnit.MILLIS), false); + assertEquals(TEST_2008_06.isSupported(ChronoUnit.SECONDS), false); + assertEquals(TEST_2008_06.isSupported(ChronoUnit.MINUTES), false); + assertEquals(TEST_2008_06.isSupported(ChronoUnit.HOURS), false); + assertEquals(TEST_2008_06.isSupported(ChronoUnit.HALF_DAYS), false); + assertEquals(TEST_2008_06.isSupported(ChronoUnit.DAYS), false); + assertEquals(TEST_2008_06.isSupported(ChronoUnit.WEEKS), false); + assertEquals(TEST_2008_06.isSupported(ChronoUnit.MONTHS), true); + assertEquals(TEST_2008_06.isSupported(ChronoUnit.YEARS), true); + assertEquals(TEST_2008_06.isSupported(ChronoUnit.DECADES), true); + assertEquals(TEST_2008_06.isSupported(ChronoUnit.CENTURIES), true); + assertEquals(TEST_2008_06.isSupported(ChronoUnit.MILLENNIA), true); + assertEquals(TEST_2008_06.isSupported(ChronoUnit.ERAS), true); + assertEquals(TEST_2008_06.isSupported(ChronoUnit.FOREVER), false); + } + //----------------------------------------------------------------------- // get(TemporalField) //----------------------------------------------------------------------- @@ -1120,7 +1182,7 @@ public class TCKYearMonth extends AbstractDateTimeTest { } //----------------------------------------------------------------------- - // periodUntil(Temporal, TemporalUnit) + // until(Temporal, TemporalUnit) //----------------------------------------------------------------------- @DataProvider(name="periodUntilUnit") Object[][] data_periodUntilUnit() { @@ -1200,29 +1262,29 @@ public class TCKYearMonth extends AbstractDateTimeTest { @Test(dataProvider="periodUntilUnit") public void test_periodUntil_TemporalUnit(YearMonth ym1, YearMonth ym2, TemporalUnit unit, long expected) { - long amount = ym1.periodUntil(ym2, unit); + long amount = ym1.until(ym2, unit); assertEquals(amount, expected); } @Test(dataProvider="periodUntilUnit") public void test_periodUntil_TemporalUnit_negated(YearMonth ym1, YearMonth ym2, TemporalUnit unit, long expected) { - long amount = ym2.periodUntil(ym1, unit); + long amount = ym2.until(ym1, unit); assertEquals(amount, -expected); } @Test(expectedExceptions = UnsupportedTemporalTypeException.class) public void test_periodUntil_TemporalUnit_unsupportedUnit() { - TEST_2008_06.periodUntil(TEST_2008_06, HOURS); + TEST_2008_06.until(TEST_2008_06, HOURS); } @Test(expectedExceptions = NullPointerException.class) public void test_periodUntil_TemporalUnit_nullEnd() { - TEST_2008_06.periodUntil(null, DAYS); + TEST_2008_06.until(null, DAYS); } @Test(expectedExceptions = NullPointerException.class) public void test_periodUntil_TemporalUnit_nullUnit() { - TEST_2008_06.periodUntil(TEST_2008_06, null); + TEST_2008_06.until(TEST_2008_06, null); } //----------------------------------------------------------------------- diff --git a/jdk/test/java/time/tck/java/time/TCKZoneId.java b/jdk/test/java/time/tck/java/time/TCKZoneId.java index dd37d804dff..c63b393d29d 100644 --- a/jdk/test/java/time/tck/java/time/TCKZoneId.java +++ b/jdk/test/java/time/tck/java/time/TCKZoneId.java @@ -464,6 +464,53 @@ public class TCKZoneId extends AbstractTCKTest { return id; } + //----------------------------------------------------------------------- + @DataProvider(name="prefixValid") + Object[][] data_prefixValid() { + return new Object[][] { + {"GMT", "+01:00"}, + {"UTC", "+01:00"}, + {"UT", "+01:00"}, + {"", "+01:00"}, + }; + } + + @Test(dataProvider="prefixValid") + public void test_prefixOfOffset(String prefix, String offset) { + ZoneOffset zoff = ZoneOffset.of(offset); + ZoneId zoneId = ZoneId.ofOffset(prefix, zoff); + assertEquals(zoneId.getId(), prefix + zoff.getId(), "in correct id for : " + prefix + ", zoff: " + zoff); + + } + + //----------------------------------------------------------------------- + @DataProvider(name="prefixInvalid") + Object[][] data_prefixInvalid() { + return new Object[][] { + {"GM", "+01:00"}, + {"U", "+01:00"}, + {"UTC0", "+01:00"}, + {"A", "+01:00"}, + }; + } + + @Test(dataProvider="prefixInvalid", expectedExceptions=java.lang.IllegalArgumentException.class) + public void test_invalidPrefixOfOffset(String prefix, String offset) { + ZoneOffset zoff = ZoneOffset.of(offset); + ZoneId zoneId = ZoneId.ofOffset(prefix, zoff); + fail("should have thrown an exception for prefix: " + prefix); + } + + @Test(expectedExceptions=java.lang.NullPointerException.class) + public void test_nullPrefixOfOffset() { + ZoneId.ofOffset(null, ZoneOffset.ofTotalSeconds(1)); + } + + @Test(expectedExceptions=java.lang.NullPointerException.class) + public void test_nullOffsetOfOffset() { + ZoneId.ofOffset("GMT", null); + } + //----------------------------------------------------------------------- @DataProvider(name="offsetBasedValidOther") Object[][] data_offsetBasedValidOther() { diff --git a/jdk/test/java/time/tck/java/time/TCKZonedDateTime.java b/jdk/test/java/time/tck/java/time/TCKZonedDateTime.java index 3bf1dbfa6e6..d1db67fca90 100644 --- a/jdk/test/java/time/tck/java/time/TCKZonedDateTime.java +++ b/jdk/test/java/time/tck/java/time/TCKZonedDateTime.java @@ -127,6 +127,7 @@ import java.time.temporal.TemporalAdjuster; import java.time.temporal.TemporalAmount; import java.time.temporal.TemporalField; import java.time.temporal.TemporalQuery; +import java.time.temporal.TemporalUnit; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -723,10 +724,12 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { public boolean isSupported(TemporalField field) { return TEST_DATE_TIME_PARIS.toLocalDateTime().isSupported(field); } + @Override public long getLong(TemporalField field) { return TEST_DATE_TIME_PARIS.toLocalDateTime().getLong(field); } + @SuppressWarnings("unchecked") @Override public R query(TemporalQuery query) { @@ -791,17 +794,18 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { @DataProvider(name="parseAdditional") Object[][] data_parseAdditional() { return new Object[][] { - {"2012-06-30T12:30:40Z[GMT]", 2012, 6, 30, 12, 30, 40, 0, "Z"}, - {"2012-06-30T12:30:40Z[UT]", 2012, 6, 30, 12, 30, 40, 0, "Z"}, - {"2012-06-30T12:30:40Z[UTC]", 2012, 6, 30, 12, 30, 40, 0, "Z"}, + {"2012-06-30T12:30:40Z[GMT]", 2012, 6, 30, 12, 30, 40, 0, "GMT"}, + {"2012-06-30T12:30:40Z[UT]", 2012, 6, 30, 12, 30, 40, 0, "UT"}, + {"2012-06-30T12:30:40Z[UTC]", 2012, 6, 30, 12, 30, 40, 0, "UTC"}, + {"2012-06-30T12:30:40+01:00[Z]", 2012, 6, 30, 12, 30, 40, 0, "Z"}, {"2012-06-30T12:30:40+01:00[+01:00]", 2012, 6, 30, 12, 30, 40, 0, "+01:00"}, - {"2012-06-30T12:30:40+01:00[GMT+01:00]", 2012, 6, 30, 12, 30, 40, 0, "+01:00"}, - {"2012-06-30T12:30:40+01:00[UT+01:00]", 2012, 6, 30, 12, 30, 40, 0, "+01:00"}, - {"2012-06-30T12:30:40+01:00[UTC+01:00]", 2012, 6, 30, 12, 30, 40, 0, "+01:00"}, + {"2012-06-30T12:30:40+01:00[GMT+01:00]", 2012, 6, 30, 12, 30, 40, 0, "GMT+01:00"}, + {"2012-06-30T12:30:40+01:00[UT+01:00]", 2012, 6, 30, 12, 30, 40, 0, "UT+01:00"}, + {"2012-06-30T12:30:40+01:00[UTC+01:00]", 2012, 6, 30, 12, 30, 40, 0, "UTC+01:00"}, {"2012-06-30T12:30:40-01:00[-01:00]", 2012, 6, 30, 12, 30, 40, 0, "-01:00"}, - {"2012-06-30T12:30:40-01:00[GMT-01:00]", 2012, 6, 30, 12, 30, 40, 0, "-01:00"}, - {"2012-06-30T12:30:40-01:00[UT-01:00]", 2012, 6, 30, 12, 30, 40, 0, "-01:00"}, - {"2012-06-30T12:30:40-01:00[UTC-01:00]", 2012, 6, 30, 12, 30, 40, 0, "-01:00"}, + {"2012-06-30T12:30:40-01:00[GMT-01:00]", 2012, 6, 30, 12, 30, 40, 0, "GMT-01:00"}, + {"2012-06-30T12:30:40-01:00[UT-01:00]", 2012, 6, 30, 12, 30, 40, 0, "UT-01:00"}, + {"2012-06-30T12:30:40-01:00[UTC-01:00]", 2012, 6, 30, 12, 30, 40, 0, "UTC-01:00"}, {"2012-06-30T12:30:40+01:00[Europe/London]", 2012, 6, 30, 12, 30, 40, 0, "Europe/London"}, }; } @@ -899,6 +903,68 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { } } + //----------------------------------------------------------------------- + // isSupported(TemporalField) + //----------------------------------------------------------------------- + @Test + public void test_isSupported_TemporalField() { + assertEquals(TEST_DATE_TIME.isSupported((TemporalField) null), false); + assertEquals(TEST_DATE_TIME.isSupported(ChronoField.NANO_OF_SECOND), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoField.NANO_OF_DAY), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoField.MICRO_OF_SECOND), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoField.MICRO_OF_DAY), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoField.MILLI_OF_SECOND), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoField.MILLI_OF_DAY), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoField.SECOND_OF_MINUTE), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoField.SECOND_OF_DAY), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoField.MINUTE_OF_HOUR), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoField.MINUTE_OF_DAY), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoField.HOUR_OF_AMPM), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoField.CLOCK_HOUR_OF_AMPM), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoField.HOUR_OF_DAY), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoField.CLOCK_HOUR_OF_DAY), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoField.AMPM_OF_DAY), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoField.DAY_OF_WEEK), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoField.DAY_OF_MONTH), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoField.DAY_OF_YEAR), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoField.EPOCH_DAY), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoField.ALIGNED_WEEK_OF_MONTH), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoField.ALIGNED_WEEK_OF_YEAR), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoField.MONTH_OF_YEAR), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoField.PROLEPTIC_MONTH), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoField.YEAR), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoField.YEAR_OF_ERA), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoField.ERA), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoField.INSTANT_SECONDS), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoField.OFFSET_SECONDS), true); + } + + //----------------------------------------------------------------------- + // isSupported(TemporalUnit) + //----------------------------------------------------------------------- + @Test + public void test_isSupported_TemporalUnit() { + assertEquals(TEST_DATE_TIME.isSupported((TemporalUnit) null), false); + assertEquals(TEST_DATE_TIME.isSupported(ChronoUnit.NANOS), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoUnit.MICROS), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoUnit.MILLIS), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoUnit.SECONDS), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoUnit.MINUTES), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoUnit.HOURS), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoUnit.HALF_DAYS), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoUnit.DAYS), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoUnit.WEEKS), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoUnit.MONTHS), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoUnit.YEARS), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoUnit.DECADES), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoUnit.CENTURIES), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoUnit.MILLENNIA), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoUnit.ERAS), true); + assertEquals(TEST_DATE_TIME.isSupported(ChronoUnit.FOREVER), false); + } + //----------------------------------------------------------------------- // get(TemporalField) //----------------------------------------------------------------------- @@ -1977,37 +2043,37 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { } //----------------------------------------------------------------------- - // periodUntil(Temporal,TemporalUnit) + // until(Temporal,TemporalUnit) //----------------------------------------------------------------------- // TODO: more tests for period between two different zones - // compare results to OffsetDateTime.periodUntil, especially wrt dates + // compare results to OffsetDateTime.until, especially wrt dates @Test(dataProvider="plusDays") public void test_periodUntil_days(ZonedDateTime base, long expected, ZonedDateTime end) { if (base.toLocalTime().equals(end.toLocalTime()) == false) { return; // avoid DST gap input values } - assertEquals(base.periodUntil(end, DAYS), expected); + assertEquals(base.until(end, DAYS), expected); } @Test(dataProvider="plusTime") public void test_periodUntil_hours(ZonedDateTime base, long expected, ZonedDateTime end) { - assertEquals(base.periodUntil(end, HOURS), expected); + assertEquals(base.until(end, HOURS), expected); } @Test(dataProvider="plusTime") public void test_periodUntil_minutes(ZonedDateTime base, long expected, ZonedDateTime end) { - assertEquals(base.periodUntil(end, MINUTES), expected * 60); + assertEquals(base.until(end, MINUTES), expected * 60); } @Test(dataProvider="plusTime") public void test_periodUntil_seconds(ZonedDateTime base, long expected, ZonedDateTime end) { - assertEquals(base.periodUntil(end, SECONDS), expected * 3600); + assertEquals(base.until(end, SECONDS), expected * 3600); } @Test(dataProvider="plusTime") public void test_periodUntil_nanos(ZonedDateTime base, long expected, ZonedDateTime end) { - assertEquals(base.periodUntil(end, NANOS), expected * 3600_000_000_000L); + assertEquals(base.until(end, NANOS), expected * 3600_000_000_000L); } @Test @@ -2017,13 +2083,13 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { ZonedDateTime oneAm1 = LocalDateTime.of(2012, 6, 29, 1, 0).atZone(ZONE_PARIS); ZonedDateTime midnightParis2 = LocalDate.of(2012, 6, 30).atStartOfDay(ZONE_PARIS); - assertEquals(midnightLondon.periodUntil(midnightParis1, HOURS), 23); - assertEquals(midnightLondon.periodUntil(oneAm1, HOURS), 24); - assertEquals(midnightLondon.periodUntil(midnightParis2, HOURS), 23 + 24); + assertEquals(midnightLondon.until(midnightParis1, HOURS), 23); + assertEquals(midnightLondon.until(oneAm1, HOURS), 24); + assertEquals(midnightLondon.until(midnightParis2, HOURS), 23 + 24); - assertEquals(midnightLondon.periodUntil(midnightParis1, DAYS), 0); - assertEquals(midnightLondon.periodUntil(oneAm1, DAYS), 1); - assertEquals(midnightLondon.periodUntil(midnightParis2, DAYS), 1); + assertEquals(midnightLondon.until(midnightParis1, DAYS), 0); + assertEquals(midnightLondon.until(oneAm1, DAYS), 1); + assertEquals(midnightLondon.until(midnightParis2, DAYS), 1); } @Test @@ -2031,8 +2097,8 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { ZonedDateTime before = TEST_PARIS_GAP_2008_03_30_02_30.withHour(0).withMinute(0).atZone(ZONE_PARIS); ZonedDateTime after = TEST_PARIS_GAP_2008_03_30_02_30.withHour(0).withMinute(0).plusDays(1).atZone(ZONE_PARIS); - assertEquals(before.periodUntil(after, HOURS), 23); - assertEquals(before.periodUntil(after, DAYS), 1); + assertEquals(before.until(after, HOURS), 23); + assertEquals(before.until(after, DAYS), 1); } @Test @@ -2040,23 +2106,23 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { ZonedDateTime before = TEST_PARIS_OVERLAP_2008_10_26_02_30.withHour(0).withMinute(0).atZone(ZONE_PARIS); ZonedDateTime after = TEST_PARIS_OVERLAP_2008_10_26_02_30.withHour(0).withMinute(0).plusDays(1).atZone(ZONE_PARIS); - assertEquals(before.periodUntil(after, HOURS), 25); - assertEquals(before.periodUntil(after, DAYS), 1); + assertEquals(before.until(after, HOURS), 25); + assertEquals(before.until(after, DAYS), 1); } @Test(expectedExceptions=DateTimeException.class) public void test_periodUntil_differentType() { - TEST_DATE_TIME_PARIS.periodUntil(TEST_LOCAL_2008_06_30_11_30_59_500, DAYS); + TEST_DATE_TIME_PARIS.until(TEST_LOCAL_2008_06_30_11_30_59_500, DAYS); } @Test(expectedExceptions=NullPointerException.class) public void test_periodUntil_nullTemporal() { - TEST_DATE_TIME_PARIS.periodUntil(null, DAYS); + TEST_DATE_TIME_PARIS.until(null, DAYS); } @Test(expectedExceptions=NullPointerException.class) public void test_periodUntil_nullUnit() { - TEST_DATE_TIME_PARIS.periodUntil(TEST_DATE_TIME_PARIS, null); + TEST_DATE_TIME_PARIS.until(TEST_DATE_TIME_PARIS, null); } //----------------------------------------------------------------------- diff --git a/jdk/test/java/time/tck/java/time/chrono/CopticDate.java b/jdk/test/java/time/tck/java/time/chrono/CopticDate.java index aa2d627058c..eca228adecb 100644 --- a/jdk/test/java/time/tck/java/time/chrono/CopticDate.java +++ b/jdk/test/java/time/tck/java/time/chrono/CopticDate.java @@ -87,7 +87,7 @@ import java.time.temporal.UnsupportedTemporalTypeException; * This class is immutable and thread-safe. */ public final class CopticDate - implements ChronoLocalDate, Serializable { + implements ChronoLocalDate, Serializable { /** * Serialization version. @@ -202,7 +202,7 @@ public final class CopticDate } return getChronology().range(f); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.rangeRefinedBy(this); } @@ -224,7 +224,7 @@ public final class CopticDate case YEAR: return prolepticYear; case ERA: return (prolepticYear >= 1 ? 1 : 0); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.getFrom(this); } @@ -249,7 +249,7 @@ public final class CopticDate case YEAR: return resolvePreviousValid(nvalue, month, day); case ERA: return resolvePreviousValid(1 - prolepticYear, month, day); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.adjustInto(this, newValue); } @@ -268,7 +268,7 @@ public final class CopticDate case CENTURIES: return plusYears(Math.multiplyExact(amountToAdd, 100)); case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000)); } - throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName()); + throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit); } return unit.addTo(this, amountToAdd); } @@ -297,22 +297,22 @@ public final class CopticDate } @Override - public long periodUntil(Temporal endDateTime, TemporalUnit unit) { + public long until(Temporal endDateTime, TemporalUnit unit) { if (endDateTime instanceof ChronoLocalDate == false) { throw new DateTimeException("Unable to calculate period between objects of two different types"); } - ChronoLocalDate end = (ChronoLocalDate) endDateTime; + ChronoLocalDate end = (ChronoLocalDate) endDateTime; if (getChronology().equals(end.getChronology()) == false) { throw new DateTimeException("Unable to calculate period between two different chronologies"); } if (unit instanceof ChronoUnit) { - return LocalDate.from(this).periodUntil(end, unit); // TODO: this is wrong + return LocalDate.from(this).until(end, unit); // TODO: this is wrong } return unit.between(this, endDateTime); } @Override - public Period periodUntil(ChronoLocalDate endDate) { + public Period until(ChronoLocalDate endDate) { // TODO: untested CopticDate end = (CopticDate) getChronology().date(endDate); long totalMonths = (end.prolepticYear - this.prolepticYear) * 13 + (end.month - this.month); // safe diff --git a/jdk/test/java/time/tck/java/time/chrono/TCKChronoLocalDate.java b/jdk/test/java/time/tck/java/time/chrono/TCKChronoLocalDate.java index b30a255995c..92f083ef6f4 100644 --- a/jdk/test/java/time/tck/java/time/chrono/TCKChronoLocalDate.java +++ b/jdk/test/java/time/tck/java/time/chrono/TCKChronoLocalDate.java @@ -113,10 +113,10 @@ public class TCKChronoLocalDate { @Test(dataProvider="calendars") public void test_badWithAdjusterChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(2013, 1, 1); - ChronoLocalDate date = chrono.date(refDate); + ChronoLocalDate date = chrono.date(refDate); for (Chronology[] clist : data_of_calendars()) { Chronology chrono2 = clist[0]; - ChronoLocalDate date2 = chrono2.date(refDate); + ChronoLocalDate date2 = chrono2.date(refDate); TemporalAdjuster adjuster = new FixedAdjuster(date2); if (chrono != chrono2) { try { @@ -127,7 +127,7 @@ public class TCKChronoLocalDate { } } else { // Same chronology, - ChronoLocalDate result = date.with(adjuster); + ChronoLocalDate result = date.with(adjuster); assertEquals(result, date2, "WithAdjuster failed to replace date"); } } @@ -136,10 +136,10 @@ public class TCKChronoLocalDate { @Test(dataProvider="calendars") public void test_badPlusAdjusterChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(2013, 1, 1); - ChronoLocalDate date = chrono.date(refDate); + ChronoLocalDate date = chrono.date(refDate); for (Chronology[] clist : data_of_calendars()) { Chronology chrono2 = clist[0]; - ChronoLocalDate date2 = chrono2.date(refDate); + ChronoLocalDate date2 = chrono2.date(refDate); TemporalAmount adjuster = new FixedAdjuster(date2); if (chrono != chrono2) { try { @@ -150,7 +150,7 @@ public class TCKChronoLocalDate { } } else { // Same chronology, - ChronoLocalDate result = date.plus(adjuster); + ChronoLocalDate result = date.plus(adjuster); assertEquals(result, date2, "WithAdjuster failed to replace date"); } } @@ -159,10 +159,10 @@ public class TCKChronoLocalDate { @Test(dataProvider="calendars") public void test_badMinusAdjusterChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(2013, 1, 1); - ChronoLocalDate date = chrono.date(refDate); + ChronoLocalDate date = chrono.date(refDate); for (Chronology[] clist : data_of_calendars()) { Chronology chrono2 = clist[0]; - ChronoLocalDate date2 = chrono2.date(refDate); + ChronoLocalDate date2 = chrono2.date(refDate); TemporalAmount adjuster = new FixedAdjuster(date2); if (chrono != chrono2) { try { @@ -173,7 +173,7 @@ public class TCKChronoLocalDate { } } else { // Same chronology, - ChronoLocalDate result = date.minus(adjuster); + ChronoLocalDate result = date.minus(adjuster); assertEquals(result, date2, "WithAdjuster failed to replace date"); } } @@ -182,10 +182,10 @@ public class TCKChronoLocalDate { @Test(dataProvider="calendars") public void test_badPlusTemporalUnitChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(2013, 1, 1); - ChronoLocalDate date = chrono.date(refDate); + ChronoLocalDate date = chrono.date(refDate); for (Chronology[] clist : data_of_calendars()) { Chronology chrono2 = clist[0]; - ChronoLocalDate date2 = chrono2.date(refDate); + ChronoLocalDate date2 = chrono2.date(refDate); TemporalUnit adjuster = new FixedTemporalUnit(date2); if (chrono != chrono2) { try { @@ -197,7 +197,7 @@ public class TCKChronoLocalDate { } } else { // Same chronology, - ChronoLocalDate result = date.plus(1, adjuster); + ChronoLocalDate result = date.plus(1, adjuster); assertEquals(result, date2, "WithAdjuster failed to replace date"); } } @@ -206,10 +206,10 @@ public class TCKChronoLocalDate { @Test(dataProvider="calendars") public void test_badMinusTemporalUnitChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(2013, 1, 1); - ChronoLocalDate date = chrono.date(refDate); + ChronoLocalDate date = chrono.date(refDate); for (Chronology[] clist : data_of_calendars()) { Chronology chrono2 = clist[0]; - ChronoLocalDate date2 = chrono2.date(refDate); + ChronoLocalDate date2 = chrono2.date(refDate); TemporalUnit adjuster = new FixedTemporalUnit(date2); if (chrono != chrono2) { try { @@ -221,7 +221,7 @@ public class TCKChronoLocalDate { } } else { // Same chronology, - ChronoLocalDate result = date.minus(1, adjuster); + ChronoLocalDate result = date.minus(1, adjuster); assertEquals(result, date2, "WithAdjuster failed to replace date"); } } @@ -230,10 +230,10 @@ public class TCKChronoLocalDate { @Test(dataProvider="calendars") public void test_badTemporalFieldChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(2013, 1, 1); - ChronoLocalDate date = chrono.date(refDate); + ChronoLocalDate date = chrono.date(refDate); for (Chronology[] clist : data_of_calendars()) { Chronology chrono2 = clist[0]; - ChronoLocalDate date2 = chrono2.date(refDate); + ChronoLocalDate date2 = chrono2.date(refDate); TemporalField adjuster = new FixedTemporalField(date2); if (chrono != chrono2) { try { @@ -245,7 +245,7 @@ public class TCKChronoLocalDate { } } else { // Same chronology, - ChronoLocalDate result = date.with(adjuster, 1); + ChronoLocalDate result = date.with(adjuster, 1); assertEquals(result, date2, "TemporalField doSet failed to replace date"); } } @@ -258,7 +258,7 @@ public class TCKChronoLocalDate { public void test_date_comparisons(Chronology chrono) { List dates = new ArrayList<>(); - ChronoLocalDate date = chrono.date(LocalDate.of(2013, 1, 1)); + ChronoLocalDate date = chrono.date(LocalDate.of(2013, 1, 1)); // Insert dates in order, no duplicates dates.add(date.minus(1, ChronoUnit.YEARS)); @@ -273,17 +273,17 @@ public class TCKChronoLocalDate { // Check these dates against the corresponding dates for every calendar for (Chronology[] clist : data_of_calendars()) { - List> otherDates = new ArrayList<>(); + List otherDates = new ArrayList<>(); Chronology chrono2 = clist[0]; - for (ChronoLocalDate d : dates) { + for (ChronoLocalDate d : dates) { otherDates.add(chrono2.date(d)); } // Now compare the sequence of original dates with the sequence of converted dates for (int i = 0; i < dates.size(); i++) { - ChronoLocalDate a = dates.get(i); + ChronoLocalDate a = dates.get(i); for (int j = 0; j < otherDates.size(); j++) { - ChronoLocalDate b = otherDates.get(j); + ChronoLocalDate b = otherDates.get(j); int cmp = ChronoLocalDate.timeLineOrder().compare(a, b); if (i < j) { assertTrue(cmp < 0, a + " compare " + b); @@ -312,7 +312,7 @@ public class TCKChronoLocalDate { @Test( dataProvider="calendars") public void test_ChronoSerialization(Chronology chrono) throws Exception { LocalDate ref = LocalDate.of(2013, 1, 5); - ChronoLocalDate orginal = chrono.date(ref); + ChronoLocalDate orginal = chrono.date(ref); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(baos); out.writeObject(orginal); @@ -320,7 +320,7 @@ public class TCKChronoLocalDate { ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream in = new ObjectInputStream(bais); @SuppressWarnings("unchecked") - ChronoLocalDate ser = (ChronoLocalDate) in.readObject(); + ChronoLocalDate ser = (ChronoLocalDate) in.readObject(); assertEquals(ser, orginal, "deserialized date is wrong"); } @@ -328,12 +328,12 @@ public class TCKChronoLocalDate { @Test(dataProvider="calendars") public void test_from_TemporalAccessor(Chronology chrono) { LocalDate refDate = LocalDate.of(2013, 1, 1); - ChronoLocalDate date = chrono.date(refDate); - ChronoLocalDate test1 = ChronoLocalDate.from(date); + ChronoLocalDate date = chrono.date(refDate); + ChronoLocalDate test1 = ChronoLocalDate.from(date); assertEquals(test1, date); - ChronoLocalDate test2 = ChronoLocalDate.from(date.atTime(LocalTime.of(12, 30))); + ChronoLocalDate test2 = ChronoLocalDate.from(date.atTime(LocalTime.of(12, 30))); assertEquals(test2, date); - ChronoLocalDate test3 = ChronoLocalDate.from(date.atTime(LocalTime.of(12, 30)).atZone(ZoneOffset.UTC)); + ChronoLocalDate test3 = ChronoLocalDate.from(date.atTime(LocalTime.of(12, 30)).atZone(ZoneOffset.UTC)); assertEquals(test3, date); } @@ -396,11 +396,6 @@ public class TCKChronoLocalDate { this.temporal = temporal; } - @Override - public String getName() { - return "FixedTemporalUnit"; - } - @Override public Duration getDuration() { throw new UnsupportedOperationException("Not supported yet."); @@ -411,6 +406,16 @@ public class TCKChronoLocalDate { throw new UnsupportedOperationException("Not supported yet."); } + @Override + public boolean isDateBased() { + return false; + } + + @Override + public boolean isTimeBased() { + return false; + } + @Override public boolean isSupportedBy(Temporal temporal) { throw new UnsupportedOperationException("Not supported yet."); @@ -426,6 +431,11 @@ public class TCKChronoLocalDate { public long between(Temporal temporal1, Temporal temporal2) { throw new UnsupportedOperationException("Not supported yet."); } + + @Override + public String toString() { + return "FixedTemporalUnit"; + } } /** @@ -438,11 +448,6 @@ public class TCKChronoLocalDate { this.temporal = temporal; } - @Override - public String getName() { - return "FixedTemporalField"; - } - @Override public TemporalUnit getBaseUnit() { throw new UnsupportedOperationException("Not supported yet."); @@ -458,6 +463,16 @@ public class TCKChronoLocalDate { throw new UnsupportedOperationException("Not supported yet."); } + @Override + public boolean isDateBased() { + return false; + } + + @Override + public boolean isTimeBased() { + return false; + } + @Override public boolean isSupportedBy(TemporalAccessor temporal) { throw new UnsupportedOperationException("Not supported yet."); @@ -478,5 +493,10 @@ public class TCKChronoLocalDate { public R adjustInto(R temporal, long newValue) { return (R) this.temporal; } + + @Override + public String toString() { + return "FixedTemporalField"; + } } } diff --git a/jdk/test/java/time/tck/java/time/chrono/TCKChronoLocalDateTime.java b/jdk/test/java/time/tck/java/time/chrono/TCKChronoLocalDateTime.java index 251c071d318..129a1903998 100644 --- a/jdk/test/java/time/tck/java/time/chrono/TCKChronoLocalDateTime.java +++ b/jdk/test/java/time/tck/java/time/chrono/TCKChronoLocalDateTime.java @@ -410,11 +410,6 @@ public class TCKChronoLocalDateTime { this.temporal = temporal; } - @Override - public String getName() { - return "FixedTemporalUnit"; - } - @Override public Duration getDuration() { throw new UnsupportedOperationException("Not supported yet."); @@ -425,6 +420,16 @@ public class TCKChronoLocalDateTime { throw new UnsupportedOperationException("Not supported yet."); } + @Override + public boolean isDateBased() { + return false; + } + + @Override + public boolean isTimeBased() { + return false; + } + @Override public boolean isSupportedBy(Temporal temporal) { throw new UnsupportedOperationException("Not supported yet."); @@ -440,6 +445,11 @@ public class TCKChronoLocalDateTime { public long between(Temporal temporal1, Temporal temporal2) { throw new UnsupportedOperationException("Not supported yet."); } + + @Override + public String toString() { + return "FixedTemporalUnit"; + } } /** @@ -452,11 +462,6 @@ public class TCKChronoLocalDateTime { this.temporal = temporal; } - @Override - public String getName() { - return "FixedTemporalField"; - } - @Override public TemporalUnit getBaseUnit() { throw new UnsupportedOperationException("Not supported yet."); @@ -472,6 +477,16 @@ public class TCKChronoLocalDateTime { throw new UnsupportedOperationException("Not supported yet."); } + @Override + public boolean isDateBased() { + return false; + } + + @Override + public boolean isTimeBased() { + return false; + } + @Override public boolean isSupportedBy(TemporalAccessor temporal) { throw new UnsupportedOperationException("Not supported yet."); @@ -492,5 +507,10 @@ public class TCKChronoLocalDateTime { public R adjustInto(R temporal, long newValue) { return (R) this.temporal; } + + @Override + public String toString() { + return "FixedTemporalField"; + } } } diff --git a/jdk/test/java/time/tck/java/time/chrono/TCKChronoZonedDateTime.java b/jdk/test/java/time/tck/java/time/chrono/TCKChronoZonedDateTime.java index 611c9258df9..3b89857fa45 100644 --- a/jdk/test/java/time/tck/java/time/chrono/TCKChronoZonedDateTime.java +++ b/jdk/test/java/time/tck/java/time/chrono/TCKChronoZonedDateTime.java @@ -256,7 +256,7 @@ public class TCKChronoZonedDateTime { } //----------------------------------------------------------------------- - // isBefore, isAfter, isEqual, INSTANT_COMPARATOR test a Chronology against the other Chronos + // isBefore, isAfter, isEqual, timeLineOrder() test a Chronology against the other Chronos //----------------------------------------------------------------------- @Test(dataProvider="calendars") public void test_zonedDateTime_comparisons(Chronology chrono) { @@ -412,11 +412,6 @@ public class TCKChronoZonedDateTime { this.temporal = temporal; } - @Override - public String getName() { - return "FixedTemporalUnit"; - } - @Override public Duration getDuration() { throw new UnsupportedOperationException("Not supported yet."); @@ -427,6 +422,16 @@ public class TCKChronoZonedDateTime { throw new UnsupportedOperationException("Not supported yet."); } + @Override + public boolean isDateBased() { + return false; + } + + @Override + public boolean isTimeBased() { + return false; + } + @Override public boolean isSupportedBy(Temporal temporal) { throw new UnsupportedOperationException("Not supported yet."); @@ -442,6 +447,12 @@ public class TCKChronoZonedDateTime { public long between(Temporal temporal1, Temporal temporal2) { throw new UnsupportedOperationException("Not supported yet."); } + + @Override + public String toString() { + return "FixedTemporalUnit"; + } + } /** @@ -454,11 +465,6 @@ public class TCKChronoZonedDateTime { this.temporal = temporal; } - @Override - public String getName() { - return "FixedTemporalField"; - } - @Override public TemporalUnit getBaseUnit() { throw new UnsupportedOperationException("Not supported yet."); @@ -474,6 +480,16 @@ public class TCKChronoZonedDateTime { throw new UnsupportedOperationException("Not supported yet."); } + @Override + public boolean isDateBased() { + return false; + } + + @Override + public boolean isTimeBased() { + return false; + } + @Override public boolean isSupportedBy(TemporalAccessor temporal) { throw new UnsupportedOperationException("Not supported yet."); @@ -494,5 +510,10 @@ public class TCKChronoZonedDateTime { public R adjustInto(R temporal, long newValue) { return (R) this.temporal; } + + @Override + public String toString() { + return "FixedTemporalField"; + } } } diff --git a/jdk/test/java/time/tck/java/time/chrono/TCKChronology.java b/jdk/test/java/time/tck/java/time/chrono/TCKChronology.java index 0077be55315..c705f9794ce 100644 --- a/jdk/test/java/time/tck/java/time/chrono/TCKChronology.java +++ b/jdk/test/java/time/tck/java/time/chrono/TCKChronology.java @@ -64,18 +64,27 @@ import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertSame; import static org.testng.Assert.assertTrue; +import java.util.Locale; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.time.ZoneId; +import java.time.Clock; import java.time.DateTimeException; import java.time.chrono.ChronoLocalDate; import java.time.chrono.Chronology; import java.time.chrono.HijrahChronology; +import java.time.chrono.HijrahEra; import java.time.chrono.IsoChronology; +import java.time.chrono.IsoEra; import java.time.chrono.JapaneseChronology; +import java.time.chrono.JapaneseEra; import java.time.chrono.MinguoChronology; +import java.time.chrono.MinguoEra; import java.time.chrono.ThaiBuddhistChronology; +import java.time.chrono.ThaiBuddhistEra; +import java.time.format.TextStyle; import java.time.temporal.ChronoField; import java.util.Locale; import java.util.Set; @@ -133,15 +142,35 @@ public class TCKChronology { + ", expected >= " + data_of_calendars().length); } + //----------------------------------------------------------------------- + // getDisplayName() + //----------------------------------------------------------------------- + @DataProvider(name = "calendarDisplayName") + Object[][] data_of_calendarDisplayNames() { + return new Object[][] { + {"Hijrah", "Hijrah-umalqura"}, + {"ISO", "ISO"}, + {"Japanese", "Japanese Calendar"}, + {"Minguo", "Minguo Calendar"}, + {"ThaiBuddhist", "Buddhist Calendar"}, + }; + } + + @Test(dataProvider = "calendarDisplayName") + public void test_getDisplayName(String chronoId, String calendarDisplayName) { + Chronology chrono = Chronology.of(chronoId); + assertEquals(chrono.getDisplayName(TextStyle.FULL, Locale.ENGLISH), calendarDisplayName); + } + /** * Compute the number of days from the Epoch and compute the date from the number of days. */ @Test(dataProvider = "calendarNameAndType") public void test_epoch(String name, String alias) { Chronology chrono = Chronology.of(name); // a chronology. In practice this is rarely hardcoded - ChronoLocalDate date1 = chrono.dateNow(); + ChronoLocalDate date1 = chrono.dateNow(); long epoch1 = date1.getLong(ChronoField.EPOCH_DAY); - ChronoLocalDate date2 = date1.with(ChronoField.EPOCH_DAY, epoch1); + ChronoLocalDate date2 = date1.with(ChronoField.EPOCH_DAY, epoch1); assertEquals(date1, date2, "Date from epoch day is not same date: " + date1 + " != " + date2); long epoch2 = date1.getLong(ChronoField.EPOCH_DAY); assertEquals(epoch1, epoch2, "Epoch day not the same: " + epoch1 + " != " + epoch2); @@ -150,9 +179,9 @@ public class TCKChronology { @Test(dataProvider = "calendarNameAndType") public void test_dateEpochDay(String name, String alias) { Chronology chrono = Chronology.of(name); - ChronoLocalDate date = chrono.dateNow(); + ChronoLocalDate date = chrono.dateNow(); long epochDay = date.getLong(ChronoField.EPOCH_DAY); - ChronoLocalDate test = chrono.dateEpochDay(epochDay); + ChronoLocalDate test = chrono.dateEpochDay(epochDay); assertEquals(test, date); } @@ -184,6 +213,101 @@ public class TCKChronology { assertEquals(Chronology.ofLocale(locale), chrono); } + //----------------------------------------------------------------------- + // dateNow() + //----------------------------------------------------------------------- + @Test + public void test_MinguoChronology_dateNow() { + ZoneId zoneId_paris = ZoneId.of("Europe/Paris"); + Clock clock = Clock.system(zoneId_paris); + + Chronology chrono = Chronology.of("Minguo"); + assertEquals(chrono.dateNow(), MinguoChronology.INSTANCE.dateNow()); + assertEquals(chrono.dateNow(zoneId_paris), MinguoChronology.INSTANCE.dateNow(zoneId_paris)); + assertEquals(chrono.dateNow(clock), MinguoChronology.INSTANCE.dateNow(clock)); + } + + @Test + public void test_IsoChronology_dateNow() { + ZoneId zoneId_paris = ZoneId.of("Europe/Paris"); + Clock clock = Clock.system(zoneId_paris); + + Chronology chrono = Chronology.of("ISO"); + assertEquals(chrono.dateNow(), IsoChronology.INSTANCE.dateNow()); + assertEquals(chrono.dateNow(zoneId_paris), IsoChronology.INSTANCE.dateNow(zoneId_paris)); + assertEquals(chrono.dateNow(clock), IsoChronology.INSTANCE.dateNow(clock)); + } + + @Test + public void test_JapaneseChronology_dateNow() { + ZoneId zoneId_paris = ZoneId.of("Europe/Paris"); + Clock clock = Clock.system(zoneId_paris); + + Chronology chrono = Chronology.of("Japanese"); + assertEquals(chrono.dateNow(), JapaneseChronology.INSTANCE.dateNow()); + assertEquals(chrono.dateNow(zoneId_paris), JapaneseChronology.INSTANCE.dateNow(zoneId_paris)); + assertEquals(chrono.dateNow(clock), JapaneseChronology.INSTANCE.dateNow(clock)); + } + + @Test + public void test_ThaiBuddhistChronology_dateNow() { + ZoneId zoneId_paris = ZoneId.of("Europe/Paris"); + Clock clock = Clock.system(zoneId_paris); + + Chronology chrono = Chronology.of("ThaiBuddhist"); + assertEquals(chrono.dateNow(), ThaiBuddhistChronology.INSTANCE.dateNow()); + assertEquals(chrono.dateNow(zoneId_paris), ThaiBuddhistChronology.INSTANCE.dateNow(zoneId_paris)); + assertEquals(chrono.dateNow(clock), ThaiBuddhistChronology.INSTANCE.dateNow(clock)); + } + + //----------------------------------------------------------------------- + // dateYearDay() and date() + //----------------------------------------------------------------------- + @Test + public void test_HijrahChronology_dateYearDay() { + Chronology chrono = Chronology.of("Hijrah"); + ChronoLocalDate date1 = chrono.dateYearDay(HijrahEra.AH, 1434, 178); + ChronoLocalDate date2 = chrono.date(HijrahEra.AH, 1434, 7, 1); + assertEquals(date1, HijrahChronology.INSTANCE.dateYearDay(HijrahEra.AH, 1434, 178)); + assertEquals(date2, HijrahChronology.INSTANCE.dateYearDay(HijrahEra.AH, 1434, 178)); + } + + @Test + public void test_MinguoChronology_dateYearDay() { + Chronology chrono = Chronology.of("Minguo"); + ChronoLocalDate date1 = chrono.dateYearDay(MinguoEra.ROC, 5, 60); + ChronoLocalDate date2 = chrono.date(MinguoEra.ROC, 5, 2, 29); + assertEquals(date1, MinguoChronology.INSTANCE.dateYearDay(MinguoEra.ROC, 5, 60)); + assertEquals(date2, MinguoChronology.INSTANCE.dateYearDay(MinguoEra.ROC, 5, 60)); + } + + @Test + public void test_IsoChronology_dateYearDay() { + Chronology chrono = Chronology.of("ISO"); + ChronoLocalDate date1 = chrono.dateYearDay(IsoEra.CE, 5, 60); + ChronoLocalDate date2 = chrono.date(IsoEra.CE, 5, 3, 1); + assertEquals(date1, IsoChronology.INSTANCE.dateYearDay(IsoEra.CE, 5, 60)); + assertEquals(date2, IsoChronology.INSTANCE.dateYearDay(IsoEra.CE, 5, 60)); + } + + @Test + public void test_JapaneseChronology_dateYearDay() { + Chronology chrono = Chronology.of("Japanese"); + ChronoLocalDate date1 = chrono.dateYearDay(JapaneseEra.HEISEI, 8, 60); + ChronoLocalDate date2 = chrono.date(JapaneseEra.HEISEI, 8, 2, 29); + assertEquals(date1, JapaneseChronology.INSTANCE.dateYearDay(JapaneseEra.HEISEI, 8, 60)); + assertEquals(date2, JapaneseChronology.INSTANCE.dateYearDay(JapaneseEra.HEISEI, 8, 60)); + } + + @Test + public void test_ThaiBuddhistChronology_dateYearDay() { + Chronology chrono = Chronology.of("ThaiBuddhist"); + ChronoLocalDate date1 = chrono.dateYearDay(ThaiBuddhistEra.BE, 2459, 60); + ChronoLocalDate date2 = chrono.date(ThaiBuddhistEra.BE, 2459, 2, 29); + assertEquals(date1, ThaiBuddhistChronology.INSTANCE.dateYearDay(ThaiBuddhistEra.BE, 2459, 60)); + assertEquals(date2, ThaiBuddhistChronology.INSTANCE.dateYearDay(ThaiBuddhistEra.BE, 2459, 60)); + } + /** * Test lookup by calendarType of each chronology. * Verify that the calendar can be found by {@link java.time.chrono.Chronology#ofLocale}. diff --git a/jdk/test/java/time/tck/java/time/chrono/TCKHijrahChronology.java b/jdk/test/java/time/tck/java/time/chrono/TCKHijrahChronology.java index 81b3ab740ae..61c19ab16cf 100644 --- a/jdk/test/java/time/tck/java/time/chrono/TCKHijrahChronology.java +++ b/jdk/test/java/time/tck/java/time/chrono/TCKHijrahChronology.java @@ -56,18 +56,13 @@ */ package tck.java.time.chrono; -import static java.time.temporal.ChronoField.DAY_OF_WEEK; +import java.time.Clock; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; -import java.time.Clock; import java.time.DateTimeException; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.Month; -import java.time.Period; import java.time.ZoneId; import java.time.ZoneOffset; import java.time.chrono.ChronoLocalDate; @@ -77,11 +72,12 @@ import java.time.chrono.HijrahChronology; import java.time.chrono.HijrahDate; import java.time.chrono.HijrahEra; import java.time.chrono.IsoChronology; -import java.time.chrono.MinguoChronology; -import java.time.chrono.MinguoDate; -import java.time.temporal.ChronoUnit; -import java.time.temporal.TemporalAdjuster; +import java.time.format.ResolverStyle; +import java.time.temporal.ChronoField; +import java.time.temporal.TemporalField; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.testng.Assert; import org.testng.annotations.DataProvider; @@ -106,49 +102,7 @@ public class TCKHijrahChronology { Assert.assertEquals(test, c); } - //----------------------------------------------------------------------- - // creation, toLocalDate() - //----------------------------------------------------------------------- - @DataProvider(name="samples") - Object[][] data_samples() { - return new Object[][] { - //{HijrahChronology.INSTANCE.date(1320, 1, 1), LocalDate.of(1902, 4, 9)}, - //{HijrahChronology.INSTANCE.date(1320, 1, 2), LocalDate.of(1902, 4, 10)}, - //{HijrahChronology.INSTANCE.date(1320, 1, 3), LocalDate.of(1902, 4, 11)}, - - //{HijrahChronology.INSTANCE.date(1322, 1, 1), LocalDate.of(1904, 3, 18)}, - //{HijrahChronology.INSTANCE.date(1323, 1, 1), LocalDate.of(1905, 3, 7)}, - //{HijrahChronology.INSTANCE.date(1323, 12, 6), LocalDate.of(1906, 1, 30)}, - //{HijrahChronology.INSTANCE.date(1324, 1, 1), LocalDate.of(1906, 2, 24)}, - //{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(1325, 1, 1), LocalDate.of(1907, 2, 13)}, - - {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, 10, 28), LocalDate.of(2079, 8, 25)}, - //{HijrahChronology.INSTANCE.date(1500, 10, 29), LocalDate.of(2079, 8, 26)}, - }; - } - - @Test(dataProvider="samples") - public void test_toLocalDate(ChronoLocalDate hijrahDate, LocalDate iso) { - assertEquals(LocalDate.from(hijrahDate), iso); - } - - @Test(dataProvider="samples") - public void test_fromCalendrical(ChronoLocalDate hijrahDate, LocalDate iso) { - assertEquals(HijrahChronology.INSTANCE.date(iso), hijrahDate); - } - - @Test(dataProvider="samples") - public void test_dayOfWeekEqualIsoDayOfWeek(ChronoLocalDate hijrahDate, LocalDate iso) { - assertEquals(hijrahDate.get(DAY_OF_WEEK), iso.get(DAY_OF_WEEK), "Hijrah day of week should be same as ISO day of week"); - } - + // Tests for dateNow() method @Test public void test_dateNow(){ assertEquals(HijrahChronology.INSTANCE.dateNow(), HijrahDate.now()) ; @@ -169,31 +123,41 @@ public class TCKHijrahChronology { assertEquals(HijrahChronology.INSTANCE.dateNow(ZoneId.of(ZoneOffset.UTC.getId())), HijrahChronology.INSTANCE.dateNow(Clock.systemUTC())) ; } + // Sample invalid dates @DataProvider(name="badDates") Object[][] data_badDates() { return new Object[][] { - {1434, 0, 0}, - + {1299, 12, 29}, + {1320, 1, 29 + 1}, + {1320, 12, 29 + 1}, {1434, -1, 1}, + {1605, 1, 29}, {1434, 0, 1}, {1434, 14, 1}, {1434, 15, 1}, - {1434, 1, -1}, {1434, 1, 0}, {1434, 1, 32}, - {1434, 12, -1}, {1434, 12, 0}, {1434, 12, 32}, }; } + // This is a negative test to verify if the API throws exception if an invalid date is provided @Test(dataProvider="badDates", expectedExceptions=DateTimeException.class) public void test_badDates(int year, int month, int dom) { HijrahChronology.INSTANCE.date(year, month, dom); } + // Negative test or dateYearDay with day too large + @Test(expectedExceptions=java.time.DateTimeException.class) + public void test_ofYearDayTooLarge() { + int year = 1435; + int lengthOfYear = HijrahChronology.INSTANCE.dateYearDay(year, 1).lengthOfYear(); + HijrahDate hd = HijrahChronology.INSTANCE.dateYearDay(year, lengthOfYear + 1); + } + //----------------------------------------------------------------------- // Bad Era for Chronology.date(era,...) and Chronology.prolepticYear(Era,...) //----------------------------------------------------------------------- @@ -213,7 +177,7 @@ public class TCKHijrahChronology { ; // ignore expected exception } - /* TODO: Test for missing HijrahDate.of(Era, y, m, d) method. + /* TODO: Test for checking HijrahDate.of(Era, y, m, d) method if it is added. try { @SuppressWarnings("unused") HijrahDate jdate = HijrahDate.of(era, 1, 1, 1); @@ -233,102 +197,344 @@ public class TCKHijrahChronology { } } } - //----------------------------------------------------------------------- - // with(WithAdjuster) + // Tests for HijrahChronology resolve //----------------------------------------------------------------------- - @Test - public void test_adjust1() { - ChronoLocalDate base = HijrahChronology.INSTANCE.date(1434, 5, 15); - ChronoLocalDate test = base.with(TemporalAdjuster.lastDayOfMonth()); - assertEquals(test, HijrahChronology.INSTANCE.date(1434, 5, 29)); + @DataProvider(name = "resolve_styleByEra") + Object[][] data_resolve_styleByEra() { + Object[][] result = new Object[ResolverStyle.values().length * HijrahEra.values().length][]; + int i = 0; + for (ResolverStyle style : ResolverStyle.values()) { + for (HijrahEra era : HijrahEra.values()) { + result[i++] = new Object[] {style, era}; + } + } + return result; } - @Test - public void test_adjust2() { - ChronoLocalDate base = HijrahChronology.INSTANCE.date(1434, 6, 2); - ChronoLocalDate test = base.with(TemporalAdjuster.lastDayOfMonth()); - assertEquals(test, HijrahChronology.INSTANCE.date(1434, 6, 30)); + @Test(dataProvider = "resolve_styleByEra") + public void test_resolve_yearOfEra_eraOnly_valid(ResolverStyle style, HijrahEra era) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.ERA, (long) era.getValue()); + HijrahDate date = HijrahChronology.INSTANCE.resolveDate(fieldValues, style); + assertEquals(date, null); + assertEquals(fieldValues.get(ChronoField.ERA), (Long) (long) era.getValue()); + assertEquals(fieldValues.size(), 1); + } + + @Test(dataProvider = "resolve_styleByEra") + public void test_resolve_yearOfEra_eraAndYearOfEraOnly_valid(ResolverStyle style, HijrahEra era) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.ERA, (long) era.getValue()); + fieldValues.put(ChronoField.YEAR_OF_ERA, 1343L); + HijrahDate date = HijrahChronology.INSTANCE.resolveDate(fieldValues, style); + assertEquals(date, null); + assertEquals(fieldValues.get(ChronoField.ERA), null); + assertEquals(fieldValues.get(ChronoField.YEAR_OF_ERA), null); + assertEquals(fieldValues.get(ChronoField.YEAR), (Long) 1343L); + assertEquals(fieldValues.size(), 1); + } + + @Test(dataProvider = "resolve_styleByEra") + public void test_resolve_yearOfEra_eraAndYearOnly_valid(ResolverStyle style, HijrahEra era) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.ERA, (long) era.getValue()); + fieldValues.put(ChronoField.YEAR, 1343L); + HijrahDate date = HijrahChronology.INSTANCE.resolveDate(fieldValues, style); + assertEquals(date, null); + assertEquals(fieldValues.get(ChronoField.ERA), (Long) (long) era.getValue()); + assertEquals(fieldValues.get(ChronoField.YEAR), (Long) 1343L); + assertEquals(fieldValues.size(), 2); + } + + @DataProvider(name = "resolve_styles") + Object[][] data_resolve_styles() { + Object[][] result = new Object[ResolverStyle.values().length][]; + int i = 0; + for (ResolverStyle style : ResolverStyle.values()) { + result[i++] = new Object[] {style}; + } + return result; + } + + @Test(dataProvider = "resolve_styles") + public void test_resolve_yearOfEra_yearOfEraOnly_valid(ResolverStyle style) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.YEAR_OF_ERA, 1343L); + HijrahDate date = HijrahChronology.INSTANCE.resolveDate(fieldValues, style); + assertEquals(date, null); + assertEquals(fieldValues.get(ChronoField.YEAR_OF_ERA), (style != ResolverStyle.STRICT) ? null : (Long) 1343L); + assertEquals(fieldValues.get(ChronoField.YEAR), (style == ResolverStyle.STRICT) ? null : (Long) 1343L); + assertEquals(fieldValues.size(), 1); + } + + @Test(dataProvider = "resolve_styles") + public void test_resolve_yearOfEra_yearOfEraAndYearOnly_valid(ResolverStyle style) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.YEAR_OF_ERA, 1343L); + fieldValues.put(ChronoField.YEAR, 1343L); + HijrahDate date = HijrahChronology.INSTANCE.resolveDate(fieldValues, style); + assertEquals(date, null); + assertEquals(fieldValues.get(ChronoField.YEAR_OF_ERA), null); + assertEquals(fieldValues.get(ChronoField.YEAR), (Long) 1343L); + assertEquals(fieldValues.size(), 1); } //----------------------------------------------------------------------- - // HijrahDate.with(Local*) + // Sample Hijrah Calendar data; official data is in lib/hijrah-ummalqura.properties + // 1432=29 30 30 30 29 30 29 30 29 30 29 29 total = 354 + // 1433=30 29 30 30 29 30 30 29 30 29 30 29 total = 355 + // 1434=29 30 29 30 29 30 30 29 30 30 29 29 total = 354 + // 1435=30 29 30 29 30 29 30 29 30 30 29 30 total = 355 //----------------------------------------------------------------------- - @Test - public void test_adjust_toLocalDate() { - ChronoLocalDate hijrahDate = HijrahChronology.INSTANCE.date(1435, 1, 4); - ChronoLocalDate test = hijrahDate.with(LocalDate.of(2012, 7, 6)); - assertEquals(test, HijrahChronology.INSTANCE.date(1433, 8, 16)); - } + @DataProvider(name = "resolve_ymd") + Object[][] data_resolve_ymd() { + // Compute the number of days in various month and years so that test cases + // are not dependent on specific calendar data + // Month numbers are always 1..12 so they can be used literally + final int year = 1434; + final int yearP1 = year + 1; + final int yearP2 = year + 2; + final int yearM1 = year - 1; + final int yearM2 = year - 2; + final int lastDayInYear = dateYearDay(year, 1).lengthOfYear(); + final int lastDayInYearP1 = dateYearDay(yearP1, 1).lengthOfYear(); + final int lastDayInYearM1 = dateYearDay(yearM1, 1).lengthOfYear(); + final int lastDayInYearM2 = dateYearDay(yearM2, 1).lengthOfYear(); + final int lastDayInMonthM1 = date(yearM1, 12, 1).lengthOfMonth(); + final int lastDayInMonthM2 = date(yearM1, 11, 1).lengthOfMonth(); + final int lastDayInMonthM11 = date(yearM1, 2, 1).lengthOfMonth(); - @Test(expectedExceptions=DateTimeException.class) - public void test_adjust_toMonth() { - ChronoLocalDate hijrahDate = HijrahChronology.INSTANCE.date(1435, 1, 4); - hijrahDate.with(Month.APRIL); - } + final int lastDayInMonth1 = date(year, 1, 1).lengthOfMonth(); + final int lastDayInMonth2 = date(year, 2, 1).lengthOfMonth(); + final int lastDayInMonth4 = date(year, 4, 1).lengthOfMonth(); + final int lastDayInMonth5 = date(year, 5, 1).lengthOfMonth(); + final int lastDayInMonth6 = date(year, 6, 1).lengthOfMonth(); + final int lastDayInMonth7 = date(year, 7, 1).lengthOfMonth(); - //----------------------------------------------------------------------- - // LocalDate.with(HijrahDate) - //----------------------------------------------------------------------- - @Test - public void test_LocalDate_adjustToHijrahDate() { - ChronoLocalDate hijrahDate = HijrahChronology.INSTANCE.date(1434, 5, 15); - LocalDate test = LocalDate.MIN.with(hijrahDate); - assertEquals(test, LocalDate.of(2013, 3, 27)); - } - - @Test - public void test_LocalDateTime_adjustToHijrahDate() { - ChronoLocalDate hijrahDate = HijrahChronology.INSTANCE.date(1435, 5, 15); - LocalDateTime test = LocalDateTime.MIN.with(hijrahDate); - assertEquals(test, LocalDateTime.of(2014, 3, 16, 0, 0)); - } - - //----------------------------------------------------------------------- - // PeriodUntil() - //----------------------------------------------------------------------- - @Test - public void test_periodUntilDate() { - HijrahDate mdate1 = HijrahDate.of(1434, 1, 1); - HijrahDate mdate2 = HijrahDate.of(1435, 2, 2); - Period period = mdate1.periodUntil(mdate2); - assertEquals(period, Period.of(1, 1, 1)); - } - - @Test - public void test_periodUntilUnit() { - HijrahDate mdate1 = HijrahDate.of(1434, 1, 1); - HijrahDate mdate2 = HijrahDate.of(1435, 2, 2); - long months = mdate1.periodUntil(mdate2, ChronoUnit.MONTHS); - assertEquals(months, 13); - } - - @Test - public void test_periodUntilDiffChrono() { - HijrahDate mdate1 = HijrahDate.of(1434, 1, 1); - HijrahDate mdate2 = HijrahDate.of(1435, 2, 2); - MinguoDate ldate2 = MinguoChronology.INSTANCE.date(mdate2); - Period period = mdate1.periodUntil(ldate2); - assertEquals(period, Period.of(1, 1, 1)); - } - - //----------------------------------------------------------------------- - // toString() - //----------------------------------------------------------------------- - @DataProvider(name="toString") - Object[][] data_toString() { return new Object[][] { - //{HijrahChronology.INSTANCE.date(1320, 1, 1), "Hijrah AH 1320-01-01"}, - //{HijrahChronology.INSTANCE.date(1500, 10, 28), "Hijrah AH 1500-10-28"}, - //{HijrahChronology.INSTANCE.date(1500, 10, 29), "Hijrah AH 1500-10-29"}, - {HijrahChronology.INSTANCE.date(1434, 12, 5), "Hijrah-umalqura AH 1434-12-05"}, - {HijrahChronology.INSTANCE.date(1434, 12, 6), "Hijrah-umalqura AH 1434-12-06"}, + {year, 1, -lastDayInYearM1, dateYearDay(yearM2, lastDayInYearM2), false, false}, + {year, 1, -lastDayInYearM1 + 1, date(yearM1, 1, 1), false, false}, + {year, 1, -lastDayInMonthM1, date(yearM1, 11, lastDayInMonthM2), false, false}, + {year, 1, -lastDayInMonthM1 + 1, date(yearM1, 12, 1), false, false}, + {year, 1, -12, date(yearM1, 12, lastDayInMonthM1 - 12), false, false}, + {year, 1, 1, date(year, 1, 1), true, true}, + {year, 1, lastDayInMonth1 + lastDayInMonth2 - 1, date(year, 2, lastDayInMonth2 - 1), false, false}, + {year, 1, lastDayInMonth1 + lastDayInMonth2, date(year, 2, lastDayInMonth2), false, false}, + {year, 1, lastDayInMonth1 + lastDayInMonth2 + 1 , date(year, 3, 1), false, false}, + {year, 1, lastDayInYear, dateYearDay(year, lastDayInYear), false, false}, + {year, 1, lastDayInYear + 1, date(1435, 1, 1), false, false}, + {year, 1, lastDayInYear + lastDayInYearP1, dateYearDay(yearP1, lastDayInYearP1), false, false}, + {year, 1, lastDayInYear + lastDayInYearP1 + 1, date(yearP2, 1, 1), false, false}, + + {year, 2, 1, date(year, 2, 1), true, true}, + {year, 2, lastDayInMonth2 - 2, date(year, 2, lastDayInMonth2 - 2), true, true}, + {year, 2, lastDayInMonth2 - 1, date(year, 2, lastDayInMonth2 - 1), true, true}, + {year, 2, lastDayInMonth2, date(year, 2, lastDayInMonth2), date(year, 2, lastDayInMonth2), true}, + {year, 2, lastDayInMonth2 + 1, date(year, 3, 1), false, false}, + + {year, -12, 1, date(yearM2, 12, 1), false, false}, + {year, -11, 1, date(yearM1, 1, 1), false, false}, + {year, -1, 1, date(yearM1, 11, 1), false, false}, + {year, 0, 1, date(yearM1, 12, 1), false, false}, + {year, 1, 1, date(year, 1, 1), true, true}, + {year, 12, 1, date(year, 12, 1), true, true}, + {year, 13, 1, date(yearP1, 1, 1), false, false}, + {year, 24, 1, date(yearP1, 12, 1), false, false}, + {year, 25, 1, date(yearP2, 1, 1), false, false}, + + {year, 6, -lastDayInMonth5, date(year, 4, lastDayInMonth4), false, false}, + {year, 6, -lastDayInMonth5 + 1, date(year, 5, 1), false, false}, + {year, 6, -1, date(year, 5, lastDayInMonth5 - 1), false, false}, + {year, 6, 0, date(year, 5, lastDayInMonth5), false, false}, + {year, 6, 1, date(year, 6, 1), true, true}, + {year, 6, lastDayInMonth6 - 1 , date(year, 6, lastDayInMonth6 - 1), true, true}, + {year, 6, lastDayInMonth6, date(year, 6, lastDayInMonth6), date(year, 6, lastDayInMonth6), true}, + {year, 6, lastDayInMonth6 + 1, date(year, 7, 1), false, false}, + {year, 6, lastDayInMonth6 + lastDayInMonth7 , date(year, 7, lastDayInMonth7), false, false}, + {year, 6, lastDayInMonth6 + lastDayInMonth7 + 1, date(year, 8, 1), false, false}, + + {yearM1, 2, 1, date(yearM1, 2, 1), true, true}, + {yearM1, 2, lastDayInMonthM11 - 1, date(yearM1, 2, lastDayInMonthM11 - 1), true, true}, + {yearM1, 2, lastDayInMonthM11, date(yearM1, 2, lastDayInMonthM11), true, true}, + {yearM1, 2, lastDayInMonthM11 + 1, date(yearM1, 3, 1), date(yearM1, 2, lastDayInMonthM11), false}, + {yearM1, 2, lastDayInMonthM11 + 2, date(yearM1, 3, 2), false, false}, + // Bad dates + {1299, 12, 1, null, false, false}, + {1601, 1, 1, null, false, false}, + }; } - @Test(dataProvider="toString") - public void test_toString(ChronoLocalDate hijrahDate, String expected) { - assertEquals(hijrahDate.toString(), expected); + @Test(dataProvider = "resolve_ymd") + public void test_resolve_ymd_lenient(int y, int m, int d, HijrahDate expected, Object smart, boolean strict) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.YEAR, (long) y); + fieldValues.put(ChronoField.MONTH_OF_YEAR, (long) m); + fieldValues.put(ChronoField.DAY_OF_MONTH, (long) d); + + if (expected != null) { + HijrahDate date = HijrahChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.LENIENT); + assertEquals(date, expected); + assertEquals(fieldValues.size(), 0); + } else { + try { + HijrahDate date = HijrahChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.LENIENT); + fail("Should have failed, returned: " + date); + } catch (DateTimeException ex) { + // expected + } + } + } + + @Test(dataProvider = "resolve_ymd") + public void test_resolve_ymd_smart(int y, int m, int d, HijrahDate expected, Object smart, boolean strict) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.YEAR, (long) y); + fieldValues.put(ChronoField.MONTH_OF_YEAR, (long) m); + fieldValues.put(ChronoField.DAY_OF_MONTH, (long) d); + if (Boolean.TRUE.equals(smart)) { + HijrahDate date = HijrahChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.SMART); + assertEquals(date, expected); + assertEquals(fieldValues.size(), 0); + } else if (smart instanceof HijrahDate) { + HijrahDate date = HijrahChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.SMART); + assertEquals(date, smart); + } else { + try { + HijrahDate date = HijrahChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.SMART); + fail("Should have failed, returned: " + date); + } catch (DateTimeException ex) { + // expected + } + } + } + + @Test(dataProvider = "resolve_ymd") + public void test_resolve_ymd_strict(int y, int m, int d, HijrahDate expected, Object smart, boolean strict) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.YEAR, (long) y); + fieldValues.put(ChronoField.MONTH_OF_YEAR, (long) m); + fieldValues.put(ChronoField.DAY_OF_MONTH, (long) d); + if (strict) { + HijrahDate date = HijrahChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.STRICT); + assertEquals(date, expected, "Resolved to incorrect date"); + assertEquals(fieldValues.size(), 0); + } else { + try { + HijrahDate date = HijrahChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.STRICT); + fail("Should have failed, returned: " + date); + } catch (DateTimeException ex) { + // expected + } + } + } + + //----------------------------------------------------------------------- + @DataProvider(name = "resolve_yd") + Object[][] data_resolve_yd() { + // Compute the number of days in various month and years so that test cases + // are not dependent on specific calendar data + // Month numbers are always 1..12 so they can be used literally + final int year = 1343; + final int yearP1 = year + 1; + final int yearP2 = year + 2; + final int yearM1 = year - 1; + final int yearM2 = year - 2; + final int lastDayInYear = dateYearDay(year, 1).lengthOfYear(); + final int lastDayInYearP1 = dateYearDay(yearP1, 1).lengthOfYear(); + final int lastDayInYearM1 = dateYearDay(yearM1, 1).lengthOfYear(); + final int lastDayInYearM2 = dateYearDay(yearM2, 1).lengthOfYear(); + + final int lastDayInMonthM1 = date(yearM1, 12, 1).lengthOfMonth(); + final int lastDayInMonthM2 = date(yearM1, 11, 1).lengthOfMonth(); + final int lastDayInMonthM11 = date(yearM1, 2, 1).lengthOfMonth(); + + final int lastDayInMonth1 = date(year, 1, 1).lengthOfMonth(); + final int lastDayInMonth2 = date(year, 2, 1).lengthOfMonth(); + final int lastDayInMonth4 = date(year, 4, 1).lengthOfMonth(); + final int lastDayInMonth5 = date(year, 5, 1).lengthOfMonth(); + final int lastDayInMonth6 = date(year, 6, 1).lengthOfMonth(); + final int lastDayInMonth7 = date(year, 7, 1).lengthOfMonth(); + + return new Object[][] { + {year, -lastDayInYearM1, dateYearDay(yearM2, lastDayInYearM2), false, false}, + {year, -lastDayInYearM1 + 1, date(yearM1, 1, 1), false, false}, + {year, -lastDayInMonthM1, date(yearM1, 11, lastDayInMonthM2), false, false}, + {year, -lastDayInMonthM1 + 1, date(yearM1, 12, 1), false, false}, + {year, -12, date(yearM1, 12, lastDayInMonthM1 - 12), false, false}, + {year, -1, date(yearM1, 12, lastDayInMonthM1 - 1), false, false}, + {year, 0, date(yearM1, 12, lastDayInMonthM1), false, false}, + {year, 1, date(year, 1, 1), true, true}, + {year, 2, date(year, 1, 2), true, true}, + {year, lastDayInMonth1, date(year, 1, lastDayInMonth1), true, true}, + {year, lastDayInMonth1 + 1, date(year, 2, 1), true, true}, + {year, lastDayInMonth1 + lastDayInMonth2 - 1, date(year, 2, lastDayInMonth2 - 1), true, true}, + {year, lastDayInMonth1 + lastDayInMonth2, date(year, 2, lastDayInMonth2), true, true}, + {year, lastDayInMonth1 + lastDayInMonth2 + 1, date(year, 3, 1), true, true}, + {year, lastDayInYear - 1, dateYearDay(year, lastDayInYear - 1), true, true}, + {year, lastDayInYear, dateYearDay(year, lastDayInYear), true, true}, + {year, lastDayInYear + 1, date(yearP1, 1, 1), false, false}, + {year, lastDayInYear + lastDayInYearP1, dateYearDay(yearP1, lastDayInYearP1), false, false}, + {year, lastDayInYear + lastDayInYearP1 + 1, date(yearP2, 1, 1), false, false}, + }; + } + + @Test(dataProvider = "resolve_yd") + public void test_resolve_yd_lenient(int y, int d, HijrahDate expected, boolean smart, boolean strict) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.YEAR, (long) y); + fieldValues.put(ChronoField.DAY_OF_YEAR, (long) d); + HijrahDate date = HijrahChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.LENIENT); + assertEquals(date, expected); + assertEquals(fieldValues.size(), 0); + } + + @Test(dataProvider = "resolve_yd") + public void test_resolve_yd_smart(int y, int d, HijrahDate expected, boolean smart, boolean strict) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.YEAR, (long) y); + fieldValues.put(ChronoField.DAY_OF_YEAR, (long) d); + if (smart) { + HijrahDate date = HijrahChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.SMART); + assertEquals(date, expected); + assertEquals(fieldValues.size(), 0); + } else { + try { + HijrahDate date = HijrahChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.SMART); + fail("Should have failed, returned date: " + date); + } catch (DateTimeException ex) { + // expected + } + } + } + + @Test(dataProvider = "resolve_yd") + public void test_resolve_yd_strict(int y, int d, HijrahDate expected, boolean smart, boolean strict) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.YEAR, (long) y); + fieldValues.put(ChronoField.DAY_OF_YEAR, (long) d); + if (strict) { + HijrahDate date = HijrahChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.STRICT); + assertEquals(date, expected); + assertEquals(fieldValues.size(), 0); + } else { + try { + HijrahDate date = HijrahChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.STRICT); + fail("Should have failed, returned date: " + date); + } catch (DateTimeException ex) { + // expected + } + } + } + + //----------------------------------------------------------------------- + private static HijrahDate date(int y, int m, int d) { + return HijrahDate.of(y, m, d); + } + + private static HijrahDate dateYearDay(int y, int doy) { + return HijrahChronology.INSTANCE.dateYearDay(y, doy); } //----------------------------------------------------------------------- @@ -343,5 +549,4 @@ public class TCKHijrahChronology { public void test_equals_false() { assertFalse(HijrahChronology.INSTANCE.equals(IsoChronology.INSTANCE)); } - } diff --git a/jdk/test/java/time/tck/java/time/chrono/TCKHijrahEra.java b/jdk/test/java/time/tck/java/time/chrono/TCKHijrahEra.java index 569eff0f3f4..23eaf3aaed8 100644 --- a/jdk/test/java/time/tck/java/time/chrono/TCKHijrahEra.java +++ b/jdk/test/java/time/tck/java/time/chrono/TCKHijrahEra.java @@ -85,6 +85,8 @@ public class TCKHijrahEra { @Test(dataProvider="HijrahEras") public void test_valueOf(HijrahEra era , String eraName, int eraValue) { assertEquals(era.getValue(), eraValue); + + assertEquals(HijrahChronology.INSTANCE.eraOf(eraValue), era); assertEquals(HijrahEra.of(eraValue), era); assertEquals(HijrahEra.valueOf(eraName), era); } diff --git a/jdk/test/java/time/tck/java/time/chrono/TCKIsoChronology.java b/jdk/test/java/time/tck/java/time/chrono/TCKIsoChronology.java index b30c1ffbfcc..a69f556b5cd 100644 --- a/jdk/test/java/time/tck/java/time/chrono/TCKIsoChronology.java +++ b/jdk/test/java/time/tck/java/time/chrono/TCKIsoChronology.java @@ -278,91 +278,88 @@ public class TCKIsoChronology { @DataProvider(name = "resolve_yearOfEra") Object[][] data_resolve_yearOfEra() { return new Object[][] { - {-1, 2012, null, null, false, false}, - {0, 2012, null, -2011, true, true}, - {1, 2012, null, 2012, true, true}, - {2, 2012, null, null, false, false}, + // era only + {ResolverStyle.STRICT, -1, null, null, null, null}, + {ResolverStyle.SMART, -1, null, null, null, null}, + {ResolverStyle.LENIENT, -1, null, null, null, null}, - {null, 2012, null, 2012, true, null}, - {null, 2012, 2012, 2012, true, true}, - {null, 2012, -2011, -2011, true, true}, - {null, 2012, 2013, null, false, false}, - {null, 2012, -2013, null, false, false}, + {ResolverStyle.STRICT, 0, null, null, ChronoField.ERA, 0}, + {ResolverStyle.SMART, 0, null, null, ChronoField.ERA, 0}, + {ResolverStyle.LENIENT, 0, null, null, ChronoField.ERA, 0}, + + {ResolverStyle.STRICT, 1, null, null, ChronoField.ERA, 1}, + {ResolverStyle.SMART, 1, null, null, ChronoField.ERA, 1}, + {ResolverStyle.LENIENT, 1, null, null, ChronoField.ERA, 1}, + + {ResolverStyle.STRICT, 2, null, null, null, null}, + {ResolverStyle.SMART, 2, null, null, null, null}, + {ResolverStyle.LENIENT, 2, null, null, null, null}, + + // era and year-of-era + {ResolverStyle.STRICT, -1, 2012, null, null, null}, + {ResolverStyle.SMART, -1, 2012, null, null, null}, + {ResolverStyle.LENIENT, -1, 2012, null, null, null}, + + {ResolverStyle.STRICT, 0, 2012, null, ChronoField.YEAR, -2011}, + {ResolverStyle.SMART, 0, 2012, null, ChronoField.YEAR, -2011}, + {ResolverStyle.LENIENT, 0, 2012, null, ChronoField.YEAR, -2011}, + + {ResolverStyle.STRICT, 1, 2012, null, ChronoField.YEAR, 2012}, + {ResolverStyle.SMART, 1, 2012, null, ChronoField.YEAR, 2012}, + {ResolverStyle.LENIENT, 1, 2012, null, ChronoField.YEAR, 2012}, + + {ResolverStyle.STRICT, 2, 2012, null, null, null}, + {ResolverStyle.SMART, 2, 2012, null, null, null}, + {ResolverStyle.LENIENT, 2, 2012, null, null, null}, + + // year-of-era only + {ResolverStyle.STRICT, null, 2012, null, ChronoField.YEAR_OF_ERA, 2012}, + {ResolverStyle.SMART, null, 2012, null, ChronoField.YEAR, 2012}, + {ResolverStyle.LENIENT, null, 2012, null, ChronoField.YEAR, 2012}, + + {ResolverStyle.STRICT, null, Integer.MAX_VALUE, null, null, null}, + {ResolverStyle.SMART, null, Integer.MAX_VALUE, null, null, null}, + {ResolverStyle.LENIENT, null, Integer.MAX_VALUE, null, ChronoField.YEAR, Integer.MAX_VALUE}, + + // year-of-era and year + {ResolverStyle.STRICT, null, 2012, 2012, ChronoField.YEAR, 2012}, + {ResolverStyle.SMART, null, 2012, 2012, ChronoField.YEAR, 2012}, + {ResolverStyle.LENIENT, null, 2012, 2012, ChronoField.YEAR, 2012}, + + {ResolverStyle.STRICT, null, 2012, -2011, ChronoField.YEAR, -2011}, + {ResolverStyle.SMART, null, 2012, -2011, ChronoField.YEAR, -2011}, + {ResolverStyle.LENIENT, null, 2012, -2011, ChronoField.YEAR, -2011}, + + {ResolverStyle.STRICT, null, 2012, 2013, null, null}, + {ResolverStyle.SMART, null, 2012, 2013, null, null}, + {ResolverStyle.LENIENT, null, 2012, 2013, null, null}, + + {ResolverStyle.STRICT, null, 2012, -2013, null, null}, + {ResolverStyle.SMART, null, 2012, -2013, null, null}, + {ResolverStyle.LENIENT, null, 2012, -2013, null, null}, }; } @Test(dataProvider = "resolve_yearOfEra") - public void test_resolve_yearOfEra_lenient(Integer e, int yoe, Integer y, Integer expected, boolean smart, Boolean strict) { + public void test_resolve_yearOfEra(ResolverStyle style, Integer e, Integer yoe, Integer y, ChronoField field, Integer expected) { Map fieldValues = new HashMap<>(); if (e != null) { fieldValues.put(ChronoField.ERA, (long) e); } - fieldValues.put(ChronoField.YEAR_OF_ERA, (long) yoe); + if (yoe != null) { + fieldValues.put(ChronoField.YEAR_OF_ERA, (long) yoe); + } if (y != null) { fieldValues.put(ChronoField.YEAR, (long) y); } - if (smart) { - LocalDate date = IsoChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.LENIENT); + if (field != null) { + LocalDate date = IsoChronology.INSTANCE.resolveDate(fieldValues, style); assertEquals(date, null); - assertEquals(fieldValues.get(ChronoField.YEAR), (Long) (long) expected); + assertEquals(fieldValues.get(field), (Long) expected.longValue()); assertEquals(fieldValues.size(), 1); } else { try { - IsoChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.LENIENT); - fail("Should have failed"); - } catch (DateTimeException ex) { - // expected - } - } - } - - @Test(dataProvider = "resolve_yearOfEra") - public void test_resolve_yearOfEra_smart(Integer e, int yoe, Integer y, Integer expected, boolean smart, Boolean strict) { - Map fieldValues = new HashMap<>(); - if (e != null) { - fieldValues.put(ChronoField.ERA, (long) e); - } - fieldValues.put(ChronoField.YEAR_OF_ERA, (long) yoe); - if (y != null) { - fieldValues.put(ChronoField.YEAR, (long) y); - } - if (smart) { - LocalDate date = IsoChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.SMART); - assertEquals(date, null); - assertEquals(fieldValues.get(ChronoField.YEAR), (Long) (long) expected); - assertEquals(fieldValues.size(), 1); - } else { - try { - IsoChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.SMART); - fail("Should have failed"); - } catch (DateTimeException ex) { - // expected - } - } - } - - @Test(dataProvider = "resolve_yearOfEra") - public void test_resolve_yearOfEra_strict(Integer e, int yoe, Integer y, Integer expected, boolean smart, Boolean strict) { - Map fieldValues = new HashMap<>(); - if (e != null) { - fieldValues.put(ChronoField.ERA, (long) e); - } - fieldValues.put(ChronoField.YEAR_OF_ERA, (long) yoe); - if (y != null) { - fieldValues.put(ChronoField.YEAR, (long) y); - } - if (strict == null) { - LocalDate date = IsoChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.STRICT); - assertEquals(date, null); - assertEquals(fieldValues.get(ChronoField.YEAR_OF_ERA), (Long) (long) yoe); - } else if (strict) { - LocalDate date = IsoChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.STRICT); - assertEquals(date, null); - assertEquals(fieldValues.get(ChronoField.YEAR), (Long) (long) expected); - assertEquals(fieldValues.size(), 1); - } else { - try { - IsoChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.STRICT); + IsoChronology.INSTANCE.resolveDate(fieldValues, style); fail("Should have failed"); } catch (DateTimeException ex) { // expected @@ -381,6 +378,11 @@ public class TCKIsoChronology { {2012, 1, -30, date(2011, 12, 1), false, false}, {2012, 1, -12, date(2011, 12, 19), false, false}, {2012, 1, 1, date(2012, 1, 1), true, true}, + {2012, 1, 27, date(2012, 1, 27), true, true}, + {2012, 1, 28, date(2012, 1, 28), true, true}, + {2012, 1, 29, date(2012, 1, 29), true, true}, + {2012, 1, 30, date(2012, 1, 30), true, true}, + {2012, 1, 31, date(2012, 1, 31), true, true}, {2012, 1, 59, date(2012, 2, 28), false, false}, {2012, 1, 60, date(2012, 2, 29), false, false}, {2012, 1, 61, date(2012, 3, 1), false, false}, diff --git a/jdk/test/java/time/tck/java/time/chrono/TCKJapaneseChronology.java b/jdk/test/java/time/tck/java/time/chrono/TCKJapaneseChronology.java index 7802e5bab52..e9d963c73af 100644 --- a/jdk/test/java/time/tck/java/time/chrono/TCKJapaneseChronology.java +++ b/jdk/test/java/time/tck/java/time/chrono/TCKJapaneseChronology.java @@ -57,12 +57,15 @@ package tck.java.time.chrono; import static java.time.temporal.ChronoField.DAY_OF_MONTH; +import static java.time.temporal.ChronoField.DAY_OF_YEAR; +import static java.time.temporal.ChronoField.EPOCH_DAY; import static java.time.temporal.ChronoField.ERA; import static java.time.temporal.ChronoField.MONTH_OF_YEAR; import static java.time.temporal.ChronoField.YEAR; import static java.time.temporal.ChronoField.YEAR_OF_ERA; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotEquals; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; @@ -84,10 +87,19 @@ import java.time.chrono.JapaneseDate; import java.time.chrono.JapaneseEra; import java.time.chrono.MinguoChronology; import java.time.chrono.MinguoDate; +import java.time.format.ResolverStyle; +import java.time.temporal.ChronoField; import java.time.temporal.ChronoUnit; +import java.time.temporal.Temporal; import java.time.temporal.TemporalAdjuster; +import java.time.temporal.TemporalField; +import java.time.temporal.TemporalQuery; +import java.time.temporal.ValueRange; + +import java.util.HashMap; import java.util.List; import java.util.Locale; +import java.util.Map; import org.testng.Assert; import org.testng.annotations.DataProvider; @@ -155,59 +167,145 @@ public class TCKJapaneseChronology { } //----------------------------------------------------------------------- - // creation, toLocalDate() + // creation and cross-checks //----------------------------------------------------------------------- - @DataProvider(name="samples") - Object[][] data_samples() { + @DataProvider(name="createByEra") + Object[][] data_createByEra() { return new Object[][] { - {JapaneseChronology.INSTANCE.date(1, 1, 1), LocalDate.of(1, 1, 1)}, - {JapaneseChronology.INSTANCE.date(1, 1, 2), LocalDate.of(1, 1, 2)}, - {JapaneseChronology.INSTANCE.date(1, 1, 3), LocalDate.of(1, 1, 3)}, - - {JapaneseChronology.INSTANCE.date(2, 1, 1), LocalDate.of(2, 1, 1)}, - {JapaneseChronology.INSTANCE.date(3, 1, 1), LocalDate.of(3, 1, 1)}, - {JapaneseChronology.INSTANCE.date(3, 12, 6), LocalDate.of(3, 12, 6)}, - {JapaneseChronology.INSTANCE.date(4, 1, 1), LocalDate.of(4, 1, 1)}, - {JapaneseChronology.INSTANCE.date(4, 7, 3), LocalDate.of(4, 7, 3)}, - {JapaneseChronology.INSTANCE.date(4, 7, 4), LocalDate.of(4, 7, 4)}, - {JapaneseChronology.INSTANCE.date(5, 1, 1), LocalDate.of(5, 1, 1)}, - {JapaneseChronology.INSTANCE.date(1662, 3, 3), LocalDate.of(1662, 3, 3)}, - {JapaneseChronology.INSTANCE.date(1728, 10, 28), LocalDate.of(1728, 10, 28)}, - {JapaneseChronology.INSTANCE.date(1728, 10, 29), LocalDate.of(1728, 10, 29)}, - - {JapaneseChronology.INSTANCE.date(JapaneseEra.HEISEI, 1996 - YDIFF_HEISEI, 2, 29), LocalDate.of(1996, 2, 29)}, - {JapaneseChronology.INSTANCE.date(JapaneseEra.HEISEI, 2000 - YDIFF_HEISEI, 2, 29), LocalDate.of(2000, 2, 29)}, - {JapaneseChronology.INSTANCE.date(JapaneseEra.MEIJI, 1868 - YDIFF_MEIJI, 2, 29), LocalDate.of(1868, 2, 29)}, - {JapaneseChronology.INSTANCE.date(JapaneseEra.SHOWA, 1928 - YDIFF_SHOWA, 12, 25), LocalDate.of(1928, 12, 25)}, - {JapaneseChronology.INSTANCE.date(JapaneseEra.TAISHO, 1912 - YDIFF_TAISHO, 7, 30), LocalDate.of(1912, 7, 30)}, - - {JapaneseChronology.INSTANCE.dateYearDay(1996, 60), LocalDate.of(1996, 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(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)}, + {JapaneseEra.HEISEI, 1996 - YDIFF_HEISEI, 2, 29, 60, LocalDate.of(1996, 2, 29)}, + {JapaneseEra.HEISEI, 2000 - YDIFF_HEISEI, 2, 29, 60, LocalDate.of(2000, 2, 29)}, + {JapaneseEra.MEIJI, 1874 - YDIFF_MEIJI, 2, 28, 59, LocalDate.of(1874, 2, 28)}, + {JapaneseEra.SHOWA, 1928 - YDIFF_SHOWA, 12, 25, 360, LocalDate.of(1928, 12, 25)}, + {JapaneseEra.TAISHO, 1916 - YDIFF_TAISHO, 7, 30, 212, LocalDate.of(1916, 7, 30)}, + {JapaneseEra.MEIJI, 6, 1, 1, 1, LocalDate.of(1873, 1, 1)}, + {JapaneseEra.MEIJI, 45, 7, 29, 211, LocalDate.of(1912, 7, 29)}, + {JapaneseEra.TAISHO, 1, 7, 30, 1, LocalDate.of(1912, 7, 30)}, + {JapaneseEra.TAISHO, 15, 12, 24, 358, LocalDate.of(1926, 12, 24)}, + {JapaneseEra.SHOWA, 1, 12, 25, 1, LocalDate.of(1926, 12, 25)}, + {JapaneseEra.SHOWA, 64, 1, 7, 7, LocalDate.of(1989, 1, 7)}, + {JapaneseEra.HEISEI, 1, 1, 8, 1, LocalDate.of(1989, 1, 8)}, }; } - @Test(dataProvider="samples") - public void test_toLocalDate(JapaneseDate jdate, LocalDate iso) { - assertEquals(LocalDate.from(jdate), iso); + @Test(dataProvider="createByEra") + public void test_createEymd(JapaneseEra era, int yoe, int moy, int dom, int doy, LocalDate iso) { + JapaneseDate dateByChronoFactory = JapaneseChronology.INSTANCE.date(era, yoe, moy, dom); + JapaneseDate dateByDateFactory = JapaneseDate.of(era, yoe, moy, dom); + assertEquals(dateByChronoFactory, dateByDateFactory); + assertEquals(dateByChronoFactory.hashCode(), dateByDateFactory.hashCode()); } - @Test(dataProvider="samples") - public void test_fromCalendrical(JapaneseDate jdate, LocalDate iso) { - assertEquals(JapaneseChronology.INSTANCE.date(iso), jdate); + @Test(dataProvider="createByEra") + public void test_createEyd(JapaneseEra era, int yoe, int moy, int dom, int doy, LocalDate iso) { + JapaneseDate dateByChronoFactory = JapaneseChronology.INSTANCE.dateYearDay(era, yoe, doy); + JapaneseDate dateByDateFactory = JapaneseDate.of(era, yoe, moy, dom); + assertEquals(dateByChronoFactory, dateByDateFactory); + assertEquals(dateByChronoFactory.hashCode(), dateByDateFactory.hashCode()); } + @Test(dataProvider="createByEra") + public void test_createByEra_isEqual(JapaneseEra era, int yoe, int moy, int dom, int doy, LocalDate iso) { + JapaneseDate test = JapaneseDate.of(era, yoe, moy, dom); + assertEquals(test.isEqual(iso), true); + assertEquals(iso.isEqual(test), true); + } + + @Test(dataProvider="createByEra") + public void test_createByEra_chronologyTemporalFactory(JapaneseEra era, int yoe, int moy, int dom, int doy, LocalDate iso) { + JapaneseDate test = JapaneseDate.of(era, yoe, moy, dom); + assertEquals(IsoChronology.INSTANCE.date(test), iso); + assertEquals(JapaneseChronology.INSTANCE.date(iso), test); + } + + @Test(dataProvider="createByEra") + public void test_createByEra_dateFrom(JapaneseEra era, int yoe, int moy, int dom, int doy, LocalDate iso) { + JapaneseDate test = JapaneseDate.of(era, yoe, moy, dom); + assertEquals(LocalDate.from(test), iso); + assertEquals(JapaneseDate.from(iso), test); + } + + @Test(dataProvider="createByEra") + public void test_createByEra_query(JapaneseEra era, int yoe, int moy, int dom, int doy, LocalDate iso) { + JapaneseDate test = JapaneseDate.of(era, yoe, moy, dom); + assertEquals(test.query(TemporalQuery.localDate()), iso); + } + + @Test(dataProvider="createByEra") + public void test_createByEra_epochDay(JapaneseEra era, int yoe, int moy, int dom, int doy, LocalDate iso) { + JapaneseDate test = JapaneseDate.of(era, yoe, moy, dom); + assertEquals(test.getLong(EPOCH_DAY), iso.getLong(EPOCH_DAY)); + assertEquals(test.toEpochDay(), iso.toEpochDay()); + } + + //----------------------------------------------------------------------- + @DataProvider(name="createByProleptic") + Object[][] data_createByProleptic() { + return new Object[][] { + {1928, 2, 28, 59, LocalDate.of(1928, 2, 28)}, + {1928, 2, 29, 60, LocalDate.of(1928, 2, 29)}, + + {1873, 9, 7, 250, LocalDate.of(1873, 9, 7)}, + {1873, 9, 8, 251, LocalDate.of(1873, 9, 8)}, + {1912, 7, 29, 211, LocalDate.of(1912, 7, 29)}, + {1912, 7, 30, 212, LocalDate.of(1912, 7, 30)}, + {1926, 12, 24, 358, LocalDate.of(1926, 12, 24)}, + {1926, 12, 25, 359, LocalDate.of(1926, 12, 25)}, + {1989, 1, 7, 7, LocalDate.of(1989, 1, 7)}, + {1989, 1, 8, 8, LocalDate.of(1989, 1, 8)}, + }; + } + + @Test(dataProvider="createByProleptic") + public void test_createYmd(int y, int moy, int dom, int doy, LocalDate iso) { + JapaneseDate dateByChronoFactory = JapaneseChronology.INSTANCE.date(y, moy, dom); + JapaneseDate dateByDateFactory = JapaneseDate.of(y, moy, dom); + assertEquals(dateByChronoFactory, dateByDateFactory); + assertEquals(dateByChronoFactory.hashCode(), dateByDateFactory.hashCode()); + } + + @Test(dataProvider="createByProleptic") + public void test_createYd(int y, int moy, int dom, int doy, LocalDate iso) { + JapaneseDate dateByChronoFactory = JapaneseChronology.INSTANCE.dateYearDay(y, doy); + JapaneseDate dateByDateFactory = JapaneseDate.of(y, moy, dom); + assertEquals(dateByChronoFactory, dateByDateFactory); + assertEquals(dateByChronoFactory.hashCode(), dateByDateFactory.hashCode()); + } + + @Test(dataProvider="createByProleptic") + public void test_createByProleptic_isEqual(int y, int moy, int dom, int doy, LocalDate iso) { + JapaneseDate test = JapaneseDate.of(y, moy, dom); + assertEquals(test.isEqual(iso), true); + assertEquals(iso.isEqual(test), true); + } + + @Test(dataProvider="createByProleptic") + public void test_createByProleptic_chronologyTemporalFactory(int y, int moy, int dom, int doy, LocalDate iso) { + JapaneseDate test = JapaneseDate.of(y, moy, dom); + assertEquals(IsoChronology.INSTANCE.date(test), iso); + assertEquals(JapaneseChronology.INSTANCE.date(iso), test); + } + + @Test(dataProvider="createByProleptic") + public void test_createByProleptic_dateFrom(int y, int moy, int dom, int doy, LocalDate iso) { + JapaneseDate test = JapaneseDate.of(y, moy, dom); + assertEquals(LocalDate.from(test), iso); + assertEquals(JapaneseDate.from(iso), test); + } + + @Test(dataProvider="createByProleptic") + public void test_createByProleptic_query(int y, int moy, int dom, int doy, LocalDate iso) { + JapaneseDate test = JapaneseDate.of(y, moy, dom); + assertEquals(test.query(TemporalQuery.localDate()), iso); + } + + @Test(dataProvider="createByProleptic") + public void test_createByProleptic_epochDay(int y, int moy, int dom, int doy, LocalDate iso) { + JapaneseDate test = JapaneseDate.of(y, moy, dom); + assertEquals(test.getLong(EPOCH_DAY), iso.getLong(EPOCH_DAY)); + assertEquals(test.toEpochDay(), iso.toEpochDay()); + } + + //----------------------------------------------------------------------- @Test public void test_dateNow(){ assertEquals(JapaneseChronology.INSTANCE.dateNow(), JapaneseDate.now()) ; @@ -228,27 +326,30 @@ public class TCKJapaneseChronology { assertEquals(JapaneseChronology.INSTANCE.dateNow(ZoneId.of(ZoneOffset.UTC.getId())), JapaneseChronology.INSTANCE.dateNow(Clock.systemUTC())) ; } + //----------------------------------------------------------------------- @DataProvider(name="badDates") Object[][] data_badDates() { return new Object[][] { - {1728, 0, 0}, + {1928, 0, 0}, - {1728, -1, 1}, - {1728, 0, 1}, - {1728, 14, 1}, - {1728, 15, 1}, + {1928, -1, 1}, + {1928, 0, 1}, + {1928, 14, 1}, + {1928, 15, 1}, - {1728, 1, -1}, - {1728, 1, 0}, - {1728, 1, 32}, + {1928, 1, -1}, + {1928, 1, 0}, + {1928, 1, 32}, - {1728, 12, -1}, - {1728, 12, 0}, - {1728, 12, 32}, + {1928, 12, -1}, + {1928, 12, 0}, + {1928, 12, 32}, {1725, 2, 29}, {500, 2, 29}, {2100, 2, 29}, + + {1872, 12, 31}, // Last day of MEIJI 5 }; } @@ -266,8 +367,8 @@ public class TCKJapaneseChronology { {2, JapaneseEra.HEISEI, 1, 1 + YDIFF_HEISEI, false}, {2, JapaneseEra.HEISEI, 100, 100 + YDIFF_HEISEI, true}, - {-1, JapaneseEra.MEIJI, 1, 1 + YDIFF_MEIJI, true}, - {-1, JapaneseEra.MEIJI, 4, 4 + YDIFF_MEIJI, false}, + {-1, JapaneseEra.MEIJI, 9, 9 + YDIFF_MEIJI, true}, + {-1, JapaneseEra.MEIJI, 10, 10 + YDIFF_MEIJI, false}, {1, JapaneseEra.SHOWA, 1, 1 + YDIFF_SHOWA, false}, {1, JapaneseEra.SHOWA, 7, 7 + YDIFF_SHOWA, true}, @@ -279,12 +380,24 @@ public class TCKJapaneseChronology { @Test(dataProvider="prolepticYear") public void test_prolepticYear(int eraValue, Era era, int yearOfEra, int expectedProlepticYear, boolean isLeapYear) { - Era eraObj = JapaneseChronology.INSTANCE.eraOf(eraValue) ; + Era eraObj = JapaneseChronology.INSTANCE.eraOf(eraValue); assertTrue(JapaneseChronology.INSTANCE.eras().contains(eraObj)); assertEquals(eraObj, era); assertEquals(JapaneseChronology.INSTANCE.prolepticYear(era, yearOfEra), expectedProlepticYear); - assertEquals(JapaneseChronology.INSTANCE.isLeapYear(expectedProlepticYear), isLeapYear) ; - assertEquals(JapaneseChronology.INSTANCE.isLeapYear(expectedProlepticYear), Year.of(expectedProlepticYear).isLeap()) ; + } + + @Test(dataProvider="prolepticYear") + public void test_isLeapYear(int eraValue, Era era, int yearOfEra, int expectedProlepticYear, boolean isLeapYear) { + assertEquals(JapaneseChronology.INSTANCE.isLeapYear(expectedProlepticYear), isLeapYear); + assertEquals(JapaneseChronology.INSTANCE.isLeapYear(expectedProlepticYear), Year.of(expectedProlepticYear).isLeap()); + + JapaneseDate jdate = JapaneseDate.now(); + jdate = jdate.with(ChronoField.YEAR, expectedProlepticYear).with(ChronoField.MONTH_OF_YEAR, 2); + if (isLeapYear) { + assertEquals(jdate.lengthOfMonth(), 29); + } else { + assertEquals(jdate.lengthOfMonth(), 28); + } } @DataProvider(name="prolepticYearError") @@ -327,15 +440,6 @@ public class TCKJapaneseChronology { } catch (ClassCastException cex) { ; // ignore expected exception } - - try { - @SuppressWarnings("unused") - JapaneseDate jdate = JapaneseDate.of(era, 1, 1, 1); - fail("JapaneseDate.of did not throw ClassCastException for Era: " + era); - } catch (ClassCastException cex) { - ; // ignore expected exception - } - try { @SuppressWarnings("unused") int year = JapaneseChronology.INSTANCE.prolepticYear(era, 1); @@ -388,16 +492,16 @@ public class TCKJapaneseChronology { //----------------------------------------------------------------------- @Test public void test_adjust1() { - JapaneseDate base = JapaneseChronology.INSTANCE.date(1728, 10, 29); + JapaneseDate base = JapaneseChronology.INSTANCE.date(1928, 10, 29); JapaneseDate test = base.with(TemporalAdjuster.lastDayOfMonth()); - assertEquals(test, JapaneseChronology.INSTANCE.date(1728, 10, 31)); + assertEquals(test, JapaneseChronology.INSTANCE.date(1928, 10, 31)); } @Test public void test_adjust2() { - JapaneseDate base = JapaneseChronology.INSTANCE.date(1728, 12, 2); + JapaneseDate base = JapaneseChronology.INSTANCE.date(1928, 12, 2); JapaneseDate test = base.with(TemporalAdjuster.lastDayOfMonth()); - assertEquals(test, JapaneseChronology.INSTANCE.date(1728, 12, 31)); + assertEquals(test, JapaneseChronology.INSTANCE.date(1928, 12, 31)); } //----------------------------------------------------------------------- @@ -405,14 +509,14 @@ public class TCKJapaneseChronology { //----------------------------------------------------------------------- @Test public void test_adjust_toLocalDate() { - JapaneseDate jdate = JapaneseChronology.INSTANCE.date(1726, 1, 4); + JapaneseDate jdate = JapaneseChronology.INSTANCE.date(1926, 1, 4); JapaneseDate test = jdate.with(LocalDate.of(2012, 7, 6)); assertEquals(test, JapaneseChronology.INSTANCE.date(2012, 7, 6)); } @Test(expectedExceptions=DateTimeException.class) public void test_adjust_toMonth() { - JapaneseDate jdate = JapaneseChronology.INSTANCE.date(1726, 1, 4); + JapaneseDate jdate = JapaneseChronology.INSTANCE.date(1926, 1, 4); jdate.with(Month.APRIL); } @@ -421,16 +525,16 @@ public class TCKJapaneseChronology { //----------------------------------------------------------------------- @Test public void test_LocalDate_adjustToJapaneseDate() { - JapaneseDate jdate = JapaneseChronology.INSTANCE.date(1728, 10, 29); + JapaneseDate jdate = JapaneseChronology.INSTANCE.date(1928, 10, 29); LocalDate test = LocalDate.MIN.with(jdate); - assertEquals(test, LocalDate.of(1728, 10, 29)); + assertEquals(test, LocalDate.of(1928, 10, 29)); } @Test public void test_LocalDateTime_adjustToJapaneseDate() { - JapaneseDate jdate = JapaneseChronology.INSTANCE.date(1728, 10, 29); + JapaneseDate jdate = JapaneseChronology.INSTANCE.date(1928, 10, 29); LocalDateTime test = LocalDateTime.MIN.with(jdate); - assertEquals(test, LocalDateTime.of(1728, 10, 29, 0, 0)); + assertEquals(test, LocalDateTime.of(1928, 10, 29, 0, 0)); } //----------------------------------------------------------------------- @@ -439,7 +543,6 @@ public class TCKJapaneseChronology { @DataProvider(name="japaneseEras") Object[][] data_japanseseEras() { return new Object[][] { - { JapaneseEra.SEIREKI, -999, "Seireki"}, { JapaneseEra.MEIJI, -1, "Meiji"}, { JapaneseEra.TAISHO, 0, "Taisho"}, { JapaneseEra.SHOWA, 1, "Showa"}, @@ -512,7 +615,7 @@ public class TCKJapaneseChronology { public void test_periodUntilDate() { JapaneseDate mdate1 = JapaneseDate.of(1970, 1, 1); JapaneseDate mdate2 = JapaneseDate.of(1971, 2, 2); - Period period = mdate1.periodUntil(mdate2); + Period period = mdate1.until(mdate2); assertEquals(period, Period.of(1, 1, 1)); } @@ -520,7 +623,7 @@ public class TCKJapaneseChronology { public void test_periodUntilUnit() { JapaneseDate mdate1 = JapaneseDate.of(1970, 1, 1); JapaneseDate mdate2 = JapaneseDate.of(1971, 2, 2); - long months = mdate1.periodUntil(mdate2, ChronoUnit.MONTHS); + long months = mdate1.until(mdate2, ChronoUnit.MONTHS); assertEquals(months, 13); } @@ -529,22 +632,49 @@ public class TCKJapaneseChronology { JapaneseDate mdate1 = JapaneseDate.of(1970, 1, 1); JapaneseDate mdate2 = JapaneseDate.of(1971, 2, 2); MinguoDate ldate2 = MinguoChronology.INSTANCE.date(mdate2); - Period period = mdate1.periodUntil(ldate2); + Period period = mdate1.until(ldate2); assertEquals(period, Period.of(1, 1, 1)); } + //----------------------------------------------------------------------- + // JapaneseChronology.dateYearDay, getDayOfYear + //----------------------------------------------------------------------- + @Test + public void test_getDayOfYear() { + // Test all the Eras + for (JapaneseEra era : JapaneseEra.values()) { + int firstYear = (era == JapaneseEra.MEIJI) ? 6 : 1; // Until Era supports range(YEAR_OF_ERA) + JapaneseDate hd1 = JapaneseChronology.INSTANCE.dateYearDay(era, firstYear, 1); + ValueRange range = hd1.range(DAY_OF_YEAR); + assertEquals(range.getMaximum(), hd1.lengthOfYear(), "lengthOfYear should match range.getMaximum()"); + + for (int i = 1; i <= hd1.lengthOfYear(); i++) { + JapaneseDate hd = JapaneseChronology.INSTANCE.dateYearDay(era, firstYear, i); + int doy = hd.get(DAY_OF_YEAR); + assertEquals(doy, i, "get(DAY_OF_YEAR) incorrect for " + i + ", of date: " + hd); + } + } + } + + @Test + public void test_withDayOfYear() { + JapaneseDate hd = JapaneseChronology.INSTANCE.dateYearDay(1990, 1); + for (int i = 1; i <= hd.lengthOfYear(); i++) { + JapaneseDate hd2 = hd.with(DAY_OF_YEAR, i); + int doy = hd2.get(DAY_OF_YEAR); + assertEquals(doy, i, "with(DAY_OF_YEAR) incorrect for " + i + " " + hd2); + } + } + //----------------------------------------------------------------------- // toString() //----------------------------------------------------------------------- @DataProvider(name="toString") Object[][] data_toString() { return new Object[][] { - {JapaneseChronology.INSTANCE.date(0001, 1, 1), "Japanese 0001-01-01"}, - {JapaneseChronology.INSTANCE.date(1728, 10, 28), "Japanese 1728-10-28"}, - {JapaneseChronology.INSTANCE.date(1728, 10, 29), "Japanese 1728-10-29"}, - {JapaneseChronology.INSTANCE.date(1727, 12, 5), "Japanese 1727-12-05"}, - {JapaneseChronology.INSTANCE.date(1727, 12, 6), "Japanese 1727-12-06"}, - {JapaneseChronology.INSTANCE.date(1868, 9, 8), "Japanese Meiji 1-09-08"}, + {JapaneseChronology.INSTANCE.date(1873, 12, 5), "Japanese Meiji 6-12-05"}, + {JapaneseChronology.INSTANCE.date(1873, 12, 6), "Japanese Meiji 6-12-06"}, + {JapaneseChronology.INSTANCE.date(1873, 9, 8), "Japanese Meiji 6-09-08"}, {JapaneseChronology.INSTANCE.date(1912, 7, 29), "Japanese Meiji 45-07-29"}, {JapaneseChronology.INSTANCE.date(1912, 7, 30), "Japanese Taisho 1-07-30"}, {JapaneseChronology.INSTANCE.date(1926, 12, 24), "Japanese Taisho 15-12-24"}, @@ -573,4 +703,476 @@ public class TCKJapaneseChronology { assertFalse(JapaneseChronology.INSTANCE.equals(IsoChronology.INSTANCE)); } + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @DataProvider(name = "resolve_styleByEra") + Object[][] data_resolve_styleByEra() { + Object[][] result = new Object[ResolverStyle.values().length * JapaneseEra.values().length][]; + int i = 0; + for (ResolverStyle style : ResolverStyle.values()) { + for (JapaneseEra era : JapaneseEra.values()) { + result[i++] = new Object[] {style, era}; + } + } + return result; + } + + @Test(dataProvider = "resolve_styleByEra") + public void test_resolve_yearOfEra_eraOnly_valid(ResolverStyle style, JapaneseEra era) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.ERA, (long) era.getValue()); + JapaneseDate date = JapaneseChronology.INSTANCE.resolveDate(fieldValues, style); + assertEquals(date, null); + assertEquals(fieldValues.get(ChronoField.ERA), (Long) (long) era.getValue()); + assertEquals(fieldValues.size(), 1); + } + + @Test(dataProvider = "resolve_styleByEra") + public void test_resolve_yearOfEra_eraAndYearOfEraOnly_valid(ResolverStyle style, JapaneseEra era) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.ERA, (long) era.getValue()); + fieldValues.put(ChronoField.YEAR_OF_ERA, 1L); + JapaneseDate date = JapaneseChronology.INSTANCE.resolveDate(fieldValues, style); + assertEquals(date, null); + assertEquals(fieldValues.get(ChronoField.ERA), (Long) (long) era.getValue()); + assertEquals(fieldValues.get(ChronoField.YEAR_OF_ERA), (Long) 1L); + assertEquals(fieldValues.size(), 2); + } + + @Test(dataProvider = "resolve_styleByEra") + public void test_resolve_yearOfEra_eraAndYearOnly_valid(ResolverStyle style, JapaneseEra era) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.ERA, (long) era.getValue()); + fieldValues.put(ChronoField.YEAR, 1L); + JapaneseDate date = JapaneseChronology.INSTANCE.resolveDate(fieldValues, style); + assertEquals(date, null); + assertEquals(fieldValues.get(ChronoField.ERA), (Long) (long) era.getValue()); + assertEquals(fieldValues.get(ChronoField.YEAR), (Long) 1L); + assertEquals(fieldValues.size(), 2); + } + + @DataProvider(name = "resolve_styles") + Object[][] data_resolve_styles() { + Object[][] result = new Object[ResolverStyle.values().length][]; + int i = 0; + for (ResolverStyle style : ResolverStyle.values()) { + result[i++] = new Object[] {style}; + } + return result; + } + + @Test(dataProvider = "resolve_styles") + public void test_resolve_yearOfEra_yearOfEraOnly_valid(ResolverStyle style) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.YEAR_OF_ERA, 1L); + JapaneseDate date = JapaneseChronology.INSTANCE.resolveDate(fieldValues, style); + assertEquals(date, null); + assertEquals(fieldValues.get(ChronoField.YEAR_OF_ERA), (Long) 1L); + assertEquals(fieldValues.size(), 1); + } + + @Test(dataProvider = "resolve_styles") + public void test_resolve_yearOfEra_yearOfEraAndYearOnly_valid(ResolverStyle style) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.YEAR_OF_ERA, 1L); + fieldValues.put(ChronoField.YEAR, 2012L); + JapaneseDate date = JapaneseChronology.INSTANCE.resolveDate(fieldValues, style); + assertEquals(date, null); + assertEquals(fieldValues.get(ChronoField.YEAR_OF_ERA), (Long) 1L); + assertEquals(fieldValues.get(ChronoField.YEAR), (Long) 2012L); + assertEquals(fieldValues.size(), 2); + } + + public void test_resolve_yearOfEra_eraOnly_invalidTooSmall() { + for (ResolverStyle style : ResolverStyle.values()) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.ERA, JapaneseEra.MEIJI.getValue() - 1L); + try { + JapaneseChronology.INSTANCE.resolveDate(fieldValues, style); + fail("Should have failed: " + style); + } catch (DateTimeException ex) { + // expected + } + } + } + + public void test_resolve_yearOfEra_eraOnly_invalidTooLarge() { + for (ResolverStyle style : ResolverStyle.values()) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.ERA, JapaneseEra.values()[JapaneseEra.values().length - 1].getValue() + 1L); + try { + JapaneseChronology.INSTANCE.resolveDate(fieldValues, style); + fail("Should have failed: " + style); + } catch (DateTimeException ex) { + // expected + } + } + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @DataProvider(name = "resolve_ymd") + Object[][] data_resolve_ymd() { + return new Object[][] { + {2012, 1, -365, date(2010, 12, 31), false, false}, + {2012, 1, -364, date(2011, 1, 1), false, false}, + {2012, 1, -31, date(2011, 11, 30), false, false}, + {2012, 1, -30, date(2011, 12, 1), false, false}, + {2012, 1, -12, date(2011, 12, 19), false, false}, + {2012, 1, 1, date(2012, 1, 1), true, true}, + {2012, 1, 59, date(2012, 2, 28), false, false}, + {2012, 1, 60, date(2012, 2, 29), false, false}, + {2012, 1, 61, date(2012, 3, 1), false, false}, + {2012, 1, 365, date(2012, 12, 30), false, false}, + {2012, 1, 366, date(2012, 12, 31), false, false}, + {2012, 1, 367, date(2013, 1, 1), false, false}, + {2012, 1, 367 + 364, date(2013, 12, 31), false, false}, + {2012, 1, 367 + 365, date(2014, 1, 1), false, false}, + + {2012, 2, 1, date(2012, 2, 1), true, true}, + {2012, 2, 28, date(2012, 2, 28), true, true}, + {2012, 2, 29, date(2012, 2, 29), true, true}, + {2012, 2, 30, date(2012, 3, 1), date(2012, 2, 29), false}, + {2012, 2, 31, date(2012, 3, 2), date(2012, 2, 29), false}, + {2012, 2, 32, date(2012, 3, 3), false, false}, + + {2012, -12, 1, date(2010, 12, 1), false, false}, + {2012, -11, 1, date(2011, 1, 1), false, false}, + {2012, -1, 1, date(2011, 11, 1), false, false}, + {2012, 0, 1, date(2011, 12, 1), false, false}, + {2012, 1, 1, date(2012, 1, 1), true, true}, + {2012, 12, 1, date(2012, 12, 1), true, true}, + {2012, 13, 1, date(2013, 1, 1), false, false}, + {2012, 24, 1, date(2013, 12, 1), false, false}, + {2012, 25, 1, date(2014, 1, 1), false, false}, + + {2012, 6, -31, date(2012, 4, 30), false, false}, + {2012, 6, -30, date(2012, 5, 1), false, false}, + {2012, 6, -1, date(2012, 5, 30), false, false}, + {2012, 6, 0, date(2012, 5, 31), false, false}, + {2012, 6, 1, date(2012, 6, 1), true, true}, + {2012, 6, 30, date(2012, 6, 30), true, true}, + {2012, 6, 31, date(2012, 7, 1), date(2012, 6, 30), false}, + {2012, 6, 61, date(2012, 7, 31), false, false}, + {2012, 6, 62, date(2012, 8, 1), false, false}, + + {2011, 2, 1, date(2011, 2, 1), true, true}, + {2011, 2, 28, date(2011, 2, 28), true, true}, + {2011, 2, 29, date(2011, 3, 1), date(2011, 2, 28), false}, + {2011, 2, 30, date(2011, 3, 2), date(2011, 2, 28), false}, + {2011, 2, 31, date(2011, 3, 3), date(2011, 2, 28), false}, + {2011, 2, 32, date(2011, 3, 4), false, false}, + }; + } + + @Test(dataProvider = "resolve_ymd") + public void test_resolve_ymd_lenient(int y, int m, int d, JapaneseDate expected, Object smart, boolean strict) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.YEAR, (long) y); + fieldValues.put(ChronoField.MONTH_OF_YEAR, (long) m); + fieldValues.put(ChronoField.DAY_OF_MONTH, (long) d); + JapaneseDate date = JapaneseChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.LENIENT); + assertEquals(date, expected); + assertEquals(fieldValues.size(), 0); + } + + @Test(dataProvider = "resolve_ymd") + public void test_resolve_ymd_smart(int y, int m, int d, JapaneseDate expected, Object smart, boolean strict) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.YEAR, (long) y); + fieldValues.put(ChronoField.MONTH_OF_YEAR, (long) m); + fieldValues.put(ChronoField.DAY_OF_MONTH, (long) d); + if (Boolean.TRUE.equals(smart)) { + JapaneseDate date = JapaneseChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.SMART); + assertEquals(date, expected); + assertEquals(fieldValues.size(), 0); + } else if (smart instanceof JapaneseDate) { + JapaneseDate date = JapaneseChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.SMART); + assertEquals(date, smart); + } else { + try { + JapaneseChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.SMART); + fail("Should have failed"); + } catch (DateTimeException ex) { + // expected + } + } + } + + @Test(dataProvider = "resolve_ymd") + public void test_resolve_ymd_strict(int y, int m, int d, JapaneseDate expected, Object smart, boolean strict) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.YEAR, (long) y); + fieldValues.put(ChronoField.MONTH_OF_YEAR, (long) m); + fieldValues.put(ChronoField.DAY_OF_MONTH, (long) d); + if (strict) { + JapaneseDate date = JapaneseChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.STRICT); + assertEquals(date, expected); + assertEquals(fieldValues.size(), 0); + } else { + try { + JapaneseChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.STRICT); + fail("Should have failed"); + } catch (DateTimeException ex) { + // expected + } + } + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @DataProvider(name = "resolve_yd") + Object[][] data_resolve_yd() { + return new Object[][] { + {2012, -365, date(2010, 12, 31), false, false}, + {2012, -364, date(2011, 1, 1), false, false}, + {2012, -31, date(2011, 11, 30), false, false}, + {2012, -30, date(2011, 12, 1), false, false}, + {2012, -12, date(2011, 12, 19), false, false}, + {2012, -1, date(2011, 12, 30), false, false}, + {2012, 0, date(2011, 12, 31), false, false}, + {2012, 1, date(2012, 1, 1), true, true}, + {2012, 2, date(2012, 1, 2), true, true}, + {2012, 31, date(2012, 1, 31), true, true}, + {2012, 32, date(2012, 2, 1), true, true}, + {2012, 59, date(2012, 2, 28), true, true}, + {2012, 60, date(2012, 2, 29), true, true}, + {2012, 61, date(2012, 3, 1), true, true}, + {2012, 365, date(2012, 12, 30), true, true}, + {2012, 366, date(2012, 12, 31), true, true}, + {2012, 367, date(2013, 1, 1), false, false}, + {2012, 367 + 364, date(2013, 12, 31), false, false}, + {2012, 367 + 365, date(2014, 1, 1), false, false}, + + {2011, 59, date(2011, 2, 28), true, true}, + {2011, 60, date(2011, 3, 1), true, true}, + }; + } + + @Test(dataProvider = "resolve_yd") + public void test_resolve_yd_lenient(int y, int d, JapaneseDate expected, boolean smart, boolean strict) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.YEAR, (long) y); + fieldValues.put(ChronoField.DAY_OF_YEAR, (long) d); + JapaneseDate date = JapaneseChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.LENIENT); + assertEquals(date, expected); + assertEquals(fieldValues.size(), 0); + } + + @Test(dataProvider = "resolve_yd") + public void test_resolve_yd_smart(int y, int d, JapaneseDate expected, boolean smart, boolean strict) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.YEAR, (long) y); + fieldValues.put(ChronoField.DAY_OF_YEAR, (long) d); + if (smart) { + JapaneseDate date = JapaneseChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.SMART); + assertEquals(date, expected); + assertEquals(fieldValues.size(), 0); + } else { + try { + JapaneseChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.SMART); + fail("Should have failed"); + } catch (DateTimeException ex) { + // expected + } + } + } + + @Test(dataProvider = "resolve_yd") + public void test_resolve_yd_strict(int y, int d, JapaneseDate expected, boolean smart, boolean strict) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.YEAR, (long) y); + fieldValues.put(ChronoField.DAY_OF_YEAR, (long) d); + if (strict) { + JapaneseDate date = JapaneseChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.STRICT); + assertEquals(date, expected); + assertEquals(fieldValues.size(), 0); + } else { + try { + JapaneseChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.STRICT); + fail("Should have failed"); + } catch (DateTimeException ex) { + // expected + } + } + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @DataProvider(name = "resolve_eymd") + Object[][] data_resolve_eymd() { + return new Object[][] { + // lenient + {ResolverStyle.LENIENT, JapaneseEra.HEISEI, 1, 1, 1, date(1989, 1, 1)}, // SHOWA, not HEISEI + {ResolverStyle.LENIENT, JapaneseEra.HEISEI, 1, 1, 7, date(1989, 1, 7)}, // SHOWA, not HEISEI + {ResolverStyle.LENIENT, JapaneseEra.HEISEI, 1, 1, 8, date(1989, 1, 8)}, + {ResolverStyle.LENIENT, JapaneseEra.HEISEI, 1, 12, 31, date(1989, 12, 31)}, + {ResolverStyle.LENIENT, JapaneseEra.HEISEI, 2, 1, 1, date(1990, 1, 1)}, + + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 64, 1, 1, date(1989, 1, 1)}, + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 64, 1, 7, date(1989, 1, 7)}, + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 64, 1, 8, date(1989, 1, 8)}, // HEISEI, not SHOWA + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 64, 12, 31, date(1989, 12, 31)}, // HEISEI, not SHOWA + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 65, 1, 1, date(1990, 1, 1)}, // HEISEI, not SHOWA + + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 64, 1, -366, date(1987, 12, 31)}, + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 64, 1, -365, date(1988, 1, 1)}, + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 64, 1, -31, date(1988, 11, 30)}, + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 64, 1, -30, date(1988, 12, 1)}, + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 64, 1, 0, date(1988, 12, 31)}, + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 64, 1, 1, date(1989, 1, 1)}, + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 64, 1, 27, date(1989, 1, 27)}, + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 64, 1, 28, date(1989, 1, 28)}, + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 64, 1, 29, date(1989, 1, 29)}, + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 64, 1, 30, date(1989, 1, 30)}, + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 64, 1, 31, date(1989, 1, 31)}, + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 64, 1, 32, date(1989, 2, 1)}, + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 64, 1, 58, date(1989, 2, 27)}, + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 64, 1, 59, date(1989, 2, 28)}, + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 64, 1, 60, date(1989, 3, 1)}, + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 64, 1, 365, date(1989, 12, 31)}, + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 64, 1, 366, date(1990, 1, 1)}, + + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 63, 1, 1, date(1988, 1, 1)}, + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 63, 1, 31, date(1988, 1, 31)}, + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 63, 1, 32, date(1988, 2, 1)}, + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 63, 1, 58, date(1988, 2, 27)}, + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 63, 1, 59, date(1988, 2, 28)}, + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 63, 1, 60, date(1988, 2, 29)}, + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 63, 1, 61, date(1988, 3, 1)}, + + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 64, 2, 1, date(1989, 2, 1)}, + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 64, 2, 28, date(1989, 2, 28)}, + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 64, 2, 29, date(1989, 3, 1)}, + + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 63, 2, 1, date(1988, 2, 1)}, + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 63, 2, 28, date(1988, 2, 28)}, + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 63, 2, 29, date(1988, 2, 29)}, + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 63, 2, 30, date(1988, 3, 1)}, + + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 62, -11, 1, date(1986, 1, 1)}, + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 62, -1, 1, date(1986, 11, 1)}, + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 62, 0, 1, date(1986, 12, 1)}, + {ResolverStyle.LENIENT, JapaneseEra.SHOWA, 62, 13, 1, date(1988, 1, 1)}, + + // smart + {ResolverStyle.SMART, JapaneseEra.HEISEI, 0, 1, 1, null}, + {ResolverStyle.SMART, JapaneseEra.HEISEI, 1, 1, 1, date(1989, 1, 1)}, // SHOWA, not HEISEI + {ResolverStyle.SMART, JapaneseEra.HEISEI, 1, 1, 7, date(1989, 1, 7)}, // SHOWA, not HEISEI + {ResolverStyle.SMART, JapaneseEra.HEISEI, 1, 1, 8, date(1989, 1, 8)}, + {ResolverStyle.SMART, JapaneseEra.HEISEI, 1, 12, 31, date(1989, 12, 31)}, + {ResolverStyle.SMART, JapaneseEra.HEISEI, 2, 1, 1, date(1990, 1, 1)}, + + {ResolverStyle.SMART, JapaneseEra.SHOWA, 64, 1, 1, date(1989, 1, 1)}, + {ResolverStyle.SMART, JapaneseEra.SHOWA, 64, 1, 7, date(1989, 1, 7)}, + {ResolverStyle.SMART, JapaneseEra.SHOWA, 64, 1, 8, date(1989, 1, 8)}, // HEISEI, not SHOWA + {ResolverStyle.SMART, JapaneseEra.SHOWA, 64, 12, 31, date(1989, 12, 31)}, // HEISEI, not SHOWA + {ResolverStyle.SMART, JapaneseEra.SHOWA, 65, 1, 1, null}, // HEISEI, not SHOWA + + {ResolverStyle.SMART, JapaneseEra.SHOWA, 62, 1, 0, null}, + {ResolverStyle.SMART, JapaneseEra.SHOWA, 62, 1, 1, date(1987, 1, 1)}, + {ResolverStyle.SMART, JapaneseEra.SHOWA, 62, 1, 27, date(1987, 1, 27)}, + {ResolverStyle.SMART, JapaneseEra.SHOWA, 62, 1, 28, date(1987, 1, 28)}, + {ResolverStyle.SMART, JapaneseEra.SHOWA, 62, 1, 29, date(1987, 1, 29)}, + {ResolverStyle.SMART, JapaneseEra.SHOWA, 62, 1, 30, date(1987, 1, 30)}, + {ResolverStyle.SMART, JapaneseEra.SHOWA, 62, 1, 31, date(1987, 1, 31)}, + {ResolverStyle.SMART, JapaneseEra.SHOWA, 62, 1, 32, null}, + + {ResolverStyle.SMART, JapaneseEra.SHOWA, 62, 2, 0, null}, + {ResolverStyle.SMART, JapaneseEra.SHOWA, 62, 2, 1, date(1987, 2, 1)}, + {ResolverStyle.SMART, JapaneseEra.SHOWA, 62, 2, 27, date(1987, 2, 27)}, + {ResolverStyle.SMART, JapaneseEra.SHOWA, 62, 2, 28, date(1987, 2, 28)}, + {ResolverStyle.SMART, JapaneseEra.SHOWA, 62, 2, 29, date(1987, 2, 28)}, + {ResolverStyle.SMART, JapaneseEra.SHOWA, 62, 2, 30, date(1987, 2, 28)}, + {ResolverStyle.SMART, JapaneseEra.SHOWA, 62, 2, 31, date(1987, 2, 28)}, + {ResolverStyle.SMART, JapaneseEra.SHOWA, 62, 2, 32, null}, + + {ResolverStyle.SMART, JapaneseEra.SHOWA, 63, 2, 0, null}, + {ResolverStyle.SMART, JapaneseEra.SHOWA, 63, 2, 1, date(1988, 2, 1)}, + {ResolverStyle.SMART, JapaneseEra.SHOWA, 63, 2, 27, date(1988, 2, 27)}, + {ResolverStyle.SMART, JapaneseEra.SHOWA, 63, 2, 28, date(1988, 2, 28)}, + {ResolverStyle.SMART, JapaneseEra.SHOWA, 63, 2, 29, date(1988, 2, 29)}, + {ResolverStyle.SMART, JapaneseEra.SHOWA, 63, 2, 30, date(1988, 2, 29)}, + {ResolverStyle.SMART, JapaneseEra.SHOWA, 63, 2, 31, date(1988, 2, 29)}, + {ResolverStyle.SMART, JapaneseEra.SHOWA, 63, 2, 32, null}, + + {ResolverStyle.SMART, JapaneseEra.SHOWA, 62, -12, 1, null}, + {ResolverStyle.SMART, JapaneseEra.SHOWA, 62, -1, 1, null}, + {ResolverStyle.SMART, JapaneseEra.SHOWA, 62, 0, 1, null}, + {ResolverStyle.SMART, JapaneseEra.SHOWA, 62, 13, 1, null}, + + // strict + {ResolverStyle.STRICT, JapaneseEra.HEISEI, 0, 1, 1, null}, + {ResolverStyle.STRICT, JapaneseEra.HEISEI, 1, 1, 1, null}, // SHOWA, not HEISEI + {ResolverStyle.STRICT, JapaneseEra.HEISEI, 1, 1, 7, null}, // SHOWA, not HEISEI + {ResolverStyle.STRICT, JapaneseEra.HEISEI, 1, 1, 8, date(1989, 1, 8)}, + {ResolverStyle.STRICT, JapaneseEra.HEISEI, 1, 12, 31, date(1989, 12, 31)}, + {ResolverStyle.STRICT, JapaneseEra.HEISEI, 2, 1, 1, date(1990, 1, 1)}, + + {ResolverStyle.STRICT, JapaneseEra.SHOWA, 64, 1, 1, date(1989, 1, 1)}, + {ResolverStyle.STRICT, JapaneseEra.SHOWA, 64, 1, 7, date(1989, 1, 7)}, + {ResolverStyle.STRICT, JapaneseEra.SHOWA, 64, 1, 8, null}, // HEISEI, not SHOWA + {ResolverStyle.STRICT, JapaneseEra.SHOWA, 64, 12, 31, null}, // HEISEI, not SHOWA + {ResolverStyle.STRICT, JapaneseEra.SHOWA, 65, 1, 1, null}, // HEISEI, not SHOWA + + {ResolverStyle.STRICT, JapaneseEra.SHOWA, 62, 1, 0, null}, + {ResolverStyle.STRICT, JapaneseEra.SHOWA, 62, 1, 1, date(1987, 1, 1)}, + {ResolverStyle.STRICT, JapaneseEra.SHOWA, 62, 1, 27, date(1987, 1, 27)}, + {ResolverStyle.STRICT, JapaneseEra.SHOWA, 62, 1, 28, date(1987, 1, 28)}, + {ResolverStyle.STRICT, JapaneseEra.SHOWA, 62, 1, 29, date(1987, 1, 29)}, + {ResolverStyle.STRICT, JapaneseEra.SHOWA, 62, 1, 30, date(1987, 1, 30)}, + {ResolverStyle.STRICT, JapaneseEra.SHOWA, 62, 1, 31, date(1987, 1, 31)}, + {ResolverStyle.STRICT, JapaneseEra.SHOWA, 62, 1, 32, null}, + + {ResolverStyle.STRICT, JapaneseEra.SHOWA, 62, 2, 0, null}, + {ResolverStyle.STRICT, JapaneseEra.SHOWA, 62, 2, 1, date(1987, 2, 1)}, + {ResolverStyle.STRICT, JapaneseEra.SHOWA, 62, 2, 27, date(1987, 2, 27)}, + {ResolverStyle.STRICT, JapaneseEra.SHOWA, 62, 2, 28, date(1987, 2, 28)}, + {ResolverStyle.STRICT, JapaneseEra.SHOWA, 62, 2, 29, null}, + {ResolverStyle.STRICT, JapaneseEra.SHOWA, 62, 2, 30, null}, + {ResolverStyle.STRICT, JapaneseEra.SHOWA, 62, 2, 31, null}, + {ResolverStyle.STRICT, JapaneseEra.SHOWA, 62, 2, 32, null}, + + {ResolverStyle.STRICT, JapaneseEra.SHOWA, 63, 2, 0, null}, + {ResolverStyle.STRICT, JapaneseEra.SHOWA, 63, 2, 1, date(1988, 2, 1)}, + {ResolverStyle.STRICT, JapaneseEra.SHOWA, 63, 2, 27, date(1988, 2, 27)}, + {ResolverStyle.STRICT, JapaneseEra.SHOWA, 63, 2, 28, date(1988, 2, 28)}, + {ResolverStyle.STRICT, JapaneseEra.SHOWA, 63, 2, 29, date(1988, 2, 29)}, + {ResolverStyle.STRICT, JapaneseEra.SHOWA, 63, 2, 30, null}, + {ResolverStyle.STRICT, JapaneseEra.SHOWA, 63, 2, 31, null}, + {ResolverStyle.STRICT, JapaneseEra.SHOWA, 63, 2, 32, null}, + + {ResolverStyle.STRICT, JapaneseEra.SHOWA, 62, -12, 1, null}, + {ResolverStyle.STRICT, JapaneseEra.SHOWA, 62, -1, 1, null}, + {ResolverStyle.STRICT, JapaneseEra.SHOWA, 62, 0, 1, null}, + {ResolverStyle.STRICT, JapaneseEra.SHOWA, 62, 13, 1, null}, + }; + } + + @Test(dataProvider = "resolve_eymd") + public void test_resolve_eymd(ResolverStyle style, JapaneseEra era, int yoe, int m, int d, JapaneseDate expected) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.ERA, (long) era.getValue()); + fieldValues.put(ChronoField.YEAR_OF_ERA, (long) yoe); + fieldValues.put(ChronoField.MONTH_OF_YEAR, (long) m); + fieldValues.put(ChronoField.DAY_OF_MONTH, (long) d); + if (expected != null) { + JapaneseDate date = JapaneseChronology.INSTANCE.resolveDate(fieldValues, style); + assertEquals(date, expected); + assertEquals(fieldValues.size(), 0); + } else { + try { + JapaneseChronology.INSTANCE.resolveDate(fieldValues, style); + fail("Should have failed"); + } catch (DateTimeException ex) { + // expected + } + } + } + + //----------------------------------------------------------------------- + private static JapaneseDate date(int y, int m, int d) { + return JapaneseDate.of(y, m, d); + } + } diff --git a/jdk/test/java/time/tck/java/time/chrono/TCKJapaneseEra.java b/jdk/test/java/time/tck/java/time/chrono/TCKJapaneseEra.java index 1aa1df360f6..de83e1d3bc3 100644 --- a/jdk/test/java/time/tck/java/time/chrono/TCKJapaneseEra.java +++ b/jdk/test/java/time/tck/java/time/chrono/TCKJapaneseEra.java @@ -81,7 +81,6 @@ public class TCKJapaneseEra { {JapaneseEra.SHOWA, "Showa", 1}, {JapaneseEra.TAISHO, "Taisho", 0}, {JapaneseEra.MEIJI, "Meiji", -1}, - {JapaneseEra.SEIREKI, "Seireki", -999}, }; } @@ -112,8 +111,8 @@ public class TCKJapaneseEra { public void test_range() { // eras may be added after release for (JapaneseEra era : JapaneseEra.values()) { - assertEquals(era.range(ERA).getMinimum(), -999); - assertEquals(era.range(ERA).getLargestMinimum(), -999); + assertEquals(era.range(ERA).getMinimum(), -1); + assertEquals(era.range(ERA).getLargestMinimum(), -1); assertEquals(era.range(ERA).getSmallestMaximum(), era.range(ERA).getMaximum()); assertEquals(era.range(ERA).getMaximum() >= 2, true); } diff --git a/jdk/test/java/time/tck/java/time/chrono/TCKMinguoChronology.java b/jdk/test/java/time/tck/java/time/chrono/TCKMinguoChronology.java index cad29d76f29..50ddf70cb3e 100644 --- a/jdk/test/java/time/tck/java/time/chrono/TCKMinguoChronology.java +++ b/jdk/test/java/time/tck/java/time/chrono/TCKMinguoChronology.java @@ -58,6 +58,7 @@ package tck.java.time.chrono; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotEquals; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; @@ -83,12 +84,19 @@ import java.time.chrono.JapaneseDate; import java.time.chrono.MinguoChronology; import java.time.chrono.MinguoDate; import java.time.chrono.MinguoEra; +import java.time.chrono.MinguoChronology; +import java.time.chrono.MinguoDate; import java.time.chrono.ThaiBuddhistChronology; import java.time.chrono.ThaiBuddhistDate; +import java.time.format.ResolverStyle; +import java.time.temporal.ChronoField; import java.time.temporal.ChronoUnit; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalAdjuster; +import java.time.temporal.TemporalField; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.testng.Assert; import org.testng.annotations.DataProvider; @@ -162,6 +170,18 @@ public class TCKMinguoChronology { @Test(dataProvider="samples") public void test_fromCalendrical(MinguoDate minguo, LocalDate iso) { assertEquals(MinguoChronology.INSTANCE.date(iso), minguo); + assertEquals(MinguoDate.from(iso), minguo); + } + + @Test(dataProvider="samples") + public void test_isEqual(MinguoDate minguo, LocalDate iso) { + assertTrue(minguo.isEqual(iso)); + } + + @Test(dataProvider="samples") + public void test_date_equals(MinguoDate minguo, LocalDate iso) { + assertFalse(minguo.equals(iso)); + assertNotEquals(minguo.hashCode(), iso.hashCode()); } @Test @@ -276,12 +296,24 @@ public class TCKMinguoChronology { @Test(dataProvider="prolepticYear") public void test_prolepticYear(int eraValue, Era era, int yearOfEra, int expectedProlepticYear, boolean isLeapYear) { - Era eraObj = MinguoChronology.INSTANCE.eraOf(eraValue) ; + Era eraObj = MinguoChronology.INSTANCE.eraOf(eraValue); assertTrue(MinguoChronology.INSTANCE.eras().contains(eraObj)); assertEquals(eraObj, era); assertEquals(MinguoChronology.INSTANCE.prolepticYear(era, yearOfEra), expectedProlepticYear); - assertEquals(MinguoChronology.INSTANCE.isLeapYear(expectedProlepticYear), isLeapYear) ; - assertEquals(MinguoChronology.INSTANCE.isLeapYear(expectedProlepticYear), Year.of(expectedProlepticYear + YDIFF).isLeap()) ; + } + + @Test(dataProvider="prolepticYear") + public void test_isLeapYear(int eraValue, Era era, int yearOfEra, int expectedProlepticYear, boolean isLeapYear) { + assertEquals(MinguoChronology.INSTANCE.isLeapYear(expectedProlepticYear), isLeapYear); + assertEquals(MinguoChronology.INSTANCE.isLeapYear(expectedProlepticYear), Year.of(expectedProlepticYear + YDIFF).isLeap()); + + MinguoDate minguo = MinguoDate.now(); + minguo = minguo.with(ChronoField.YEAR, expectedProlepticYear).with(ChronoField.MONTH_OF_YEAR, 2); + if (isLeapYear) { + assertEquals(minguo.lengthOfMonth(), 29); + } else { + assertEquals(minguo.lengthOfMonth(), 28); + } } //----------------------------------------------------------------------- @@ -467,7 +499,7 @@ public class TCKMinguoChronology { public void test_periodUntilDate() { MinguoDate mdate1 = MinguoDate.of(1970, 1, 1); MinguoDate mdate2 = MinguoDate.of(1971, 2, 2); - Period period = mdate1.periodUntil(mdate2); + Period period = mdate1.until(mdate2); assertEquals(period, Period.of(1, 1, 1)); } @@ -475,7 +507,7 @@ public class TCKMinguoChronology { public void test_periodUntilUnit() { MinguoDate mdate1 = MinguoDate.of(1970, 1, 1); MinguoDate mdate2 = MinguoDate.of(1971, 2, 2); - long months = mdate1.periodUntil(mdate2, ChronoUnit.MONTHS); + long months = mdate1.until(mdate2, ChronoUnit.MONTHS); assertEquals(months, 13); } @@ -484,7 +516,7 @@ public class TCKMinguoChronology { MinguoDate mdate1 = MinguoDate.of(1970, 1, 1); MinguoDate mdate2 = MinguoDate.of(1971, 2, 2); ThaiBuddhistDate ldate2 = ThaiBuddhistChronology.INSTANCE.date(mdate2); - Period period = mdate1.periodUntil(ldate2); + Period period = mdate1.until(ldate2); assertEquals(period, Period.of(1, 1, 1)); } @@ -520,4 +552,409 @@ public class TCKMinguoChronology { assertFalse(MinguoChronology.INSTANCE.equals(IsoChronology.INSTANCE)); } + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @DataProvider(name = "resolve_yearOfEra") + Object[][] data_resolve_yearOfEra() { + return new Object[][] { + // era only + {ResolverStyle.STRICT, -1, null, null, null, null}, + {ResolverStyle.SMART, -1, null, null, null, null}, + {ResolverStyle.LENIENT, -1, null, null, null, null}, + + {ResolverStyle.STRICT, 0, null, null, ChronoField.ERA, 0}, + {ResolverStyle.SMART, 0, null, null, ChronoField.ERA, 0}, + {ResolverStyle.LENIENT, 0, null, null, ChronoField.ERA, 0}, + + {ResolverStyle.STRICT, 1, null, null, ChronoField.ERA, 1}, + {ResolverStyle.SMART, 1, null, null, ChronoField.ERA, 1}, + {ResolverStyle.LENIENT, 1, null, null, ChronoField.ERA, 1}, + + {ResolverStyle.STRICT, 2, null, null, null, null}, + {ResolverStyle.SMART, 2, null, null, null, null}, + {ResolverStyle.LENIENT, 2, null, null, null, null}, + + // era and year-of-era + {ResolverStyle.STRICT, -1, 2012, null, null, null}, + {ResolverStyle.SMART, -1, 2012, null, null, null}, + {ResolverStyle.LENIENT, -1, 2012, null, null, null}, + + {ResolverStyle.STRICT, 0, 2012, null, ChronoField.YEAR, -2011}, + {ResolverStyle.SMART, 0, 2012, null, ChronoField.YEAR, -2011}, + {ResolverStyle.LENIENT, 0, 2012, null, ChronoField.YEAR, -2011}, + + {ResolverStyle.STRICT, 1, 2012, null, ChronoField.YEAR, 2012}, + {ResolverStyle.SMART, 1, 2012, null, ChronoField.YEAR, 2012}, + {ResolverStyle.LENIENT, 1, 2012, null, ChronoField.YEAR, 2012}, + + {ResolverStyle.STRICT, 2, 2012, null, null, null}, + {ResolverStyle.SMART, 2, 2012, null, null, null}, + {ResolverStyle.LENIENT, 2, 2012, null, null, null}, + + // year-of-era only + {ResolverStyle.STRICT, null, 2012, null, ChronoField.YEAR_OF_ERA, 2012}, + {ResolverStyle.SMART, null, 2012, null, ChronoField.YEAR, 2012}, + {ResolverStyle.LENIENT, null, 2012, null, ChronoField.YEAR, 2012}, + + {ResolverStyle.STRICT, null, Integer.MAX_VALUE, null, null, null}, + {ResolverStyle.SMART, null, Integer.MAX_VALUE, null, null, null}, + {ResolverStyle.LENIENT, null, Integer.MAX_VALUE, null, ChronoField.YEAR, Integer.MAX_VALUE}, + + // year-of-era and year + {ResolverStyle.STRICT, null, 2012, 2012, ChronoField.YEAR, 2012}, + {ResolverStyle.SMART, null, 2012, 2012, ChronoField.YEAR, 2012}, + {ResolverStyle.LENIENT, null, 2012, 2012, ChronoField.YEAR, 2012}, + + {ResolverStyle.STRICT, null, 2012, -2011, ChronoField.YEAR, -2011}, + {ResolverStyle.SMART, null, 2012, -2011, ChronoField.YEAR, -2011}, + {ResolverStyle.LENIENT, null, 2012, -2011, ChronoField.YEAR, -2011}, + + {ResolverStyle.STRICT, null, 2012, 2013, null, null}, + {ResolverStyle.SMART, null, 2012, 2013, null, null}, + {ResolverStyle.LENIENT, null, 2012, 2013, null, null}, + + {ResolverStyle.STRICT, null, 2012, -2013, null, null}, + {ResolverStyle.SMART, null, 2012, -2013, null, null}, + {ResolverStyle.LENIENT, null, 2012, -2013, null, null}, + }; + } + + @Test(dataProvider = "resolve_yearOfEra") + public void test_resolve_yearOfEra(ResolverStyle style, Integer e, Integer yoe, Integer y, ChronoField field, Integer expected) { + Map fieldValues = new HashMap<>(); + if (e != null) { + fieldValues.put(ChronoField.ERA, (long) e); + } + if (yoe != null) { + fieldValues.put(ChronoField.YEAR_OF_ERA, (long) yoe); + } + if (y != null) { + fieldValues.put(ChronoField.YEAR, (long) y); + } + if (field != null) { + MinguoDate date = MinguoChronology.INSTANCE.resolveDate(fieldValues, style); + assertEquals(date, null); + assertEquals(fieldValues.get(field), (Long) expected.longValue()); + assertEquals(fieldValues.size(), 1); + } else { + try { + MinguoChronology.INSTANCE.resolveDate(fieldValues, style); + fail("Should have failed"); + } catch (DateTimeException ex) { + // expected + } + } + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @DataProvider(name = "resolve_ymd") + Object[][] data_resolve_ymd() { + return new Object[][] { + {2012 - YDIFF, 1, -365, date(2010 - YDIFF, 12, 31), false, false}, + {2012 - YDIFF, 1, -364, date(2011 - YDIFF, 1, 1), false, false}, + {2012 - YDIFF, 1, -31, date(2011 - YDIFF, 11, 30), false, false}, + {2012 - YDIFF, 1, -30, date(2011 - YDIFF, 12, 1), false, false}, + {2012 - YDIFF, 1, -12, date(2011 - YDIFF, 12, 19), false, false}, + {2012 - YDIFF, 1, 1, date(2012 - YDIFF, 1, 1), true, true}, + {2012 - YDIFF, 1, 27, date(2012 - YDIFF, 1, 27), true, true}, + {2012 - YDIFF, 1, 28, date(2012 - YDIFF, 1, 28), true, true}, + {2012 - YDIFF, 1, 29, date(2012 - YDIFF, 1, 29), true, true}, + {2012 - YDIFF, 1, 30, date(2012 - YDIFF, 1, 30), true, true}, + {2012 - YDIFF, 1, 31, date(2012 - YDIFF, 1, 31), true, true}, + {2012 - YDIFF, 1, 59, date(2012 - YDIFF, 2, 28), false, false}, + {2012 - YDIFF, 1, 60, date(2012 - YDIFF, 2, 29), false, false}, + {2012 - YDIFF, 1, 61, date(2012 - YDIFF, 3, 1), false, false}, + {2012 - YDIFF, 1, 365, date(2012 - YDIFF, 12, 30), false, false}, + {2012 - YDIFF, 1, 366, date(2012 - YDIFF, 12, 31), false, false}, + {2012 - YDIFF, 1, 367, date(2013 - YDIFF, 1, 1), false, false}, + {2012 - YDIFF, 1, 367 + 364, date(2013 - YDIFF, 12, 31), false, false}, + {2012 - YDIFF, 1, 367 + 365, date(2014 - YDIFF, 1, 1), false, false}, + + {2012 - YDIFF, 2, 1, date(2012 - YDIFF, 2, 1), true, true}, + {2012 - YDIFF, 2, 28, date(2012 - YDIFF, 2, 28), true, true}, + {2012 - YDIFF, 2, 29, date(2012 - YDIFF, 2, 29), true, true}, + {2012 - YDIFF, 2, 30, date(2012 - YDIFF, 3, 1), date(2012 - YDIFF, 2, 29), false}, + {2012 - YDIFF, 2, 31, date(2012 - YDIFF, 3, 2), date(2012 - YDIFF, 2, 29), false}, + {2012 - YDIFF, 2, 32, date(2012 - YDIFF, 3, 3), false, false}, + + {2012 - YDIFF, -12, 1, date(2010 - YDIFF, 12, 1), false, false}, + {2012 - YDIFF, -11, 1, date(2011 - YDIFF, 1, 1), false, false}, + {2012 - YDIFF, -1, 1, date(2011 - YDIFF, 11, 1), false, false}, + {2012 - YDIFF, 0, 1, date(2011 - YDIFF, 12, 1), false, false}, + {2012 - YDIFF, 1, 1, date(2012 - YDIFF, 1, 1), true, true}, + {2012 - YDIFF, 12, 1, date(2012 - YDIFF, 12, 1), true, true}, + {2012 - YDIFF, 13, 1, date(2013 - YDIFF, 1, 1), false, false}, + {2012 - YDIFF, 24, 1, date(2013 - YDIFF, 12, 1), false, false}, + {2012 - YDIFF, 25, 1, date(2014 - YDIFF, 1, 1), false, false}, + + {2012 - YDIFF, 6, -31, date(2012 - YDIFF, 4, 30), false, false}, + {2012 - YDIFF, 6, -30, date(2012 - YDIFF, 5, 1), false, false}, + {2012 - YDIFF, 6, -1, date(2012 - YDIFF, 5, 30), false, false}, + {2012 - YDIFF, 6, 0, date(2012 - YDIFF, 5, 31), false, false}, + {2012 - YDIFF, 6, 1, date(2012 - YDIFF, 6, 1), true, true}, + {2012 - YDIFF, 6, 30, date(2012 - YDIFF, 6, 30), true, true}, + {2012 - YDIFF, 6, 31, date(2012 - YDIFF, 7, 1), date(2012 - YDIFF, 6, 30), false}, + {2012 - YDIFF, 6, 61, date(2012 - YDIFF, 7, 31), false, false}, + {2012 - YDIFF, 6, 62, date(2012 - YDIFF, 8, 1), false, false}, + + {2011 - YDIFF, 2, 1, date(2011 - YDIFF, 2, 1), true, true}, + {2011 - YDIFF, 2, 28, date(2011 - YDIFF, 2, 28), true, true}, + {2011 - YDIFF, 2, 29, date(2011 - YDIFF, 3, 1), date(2011 - YDIFF, 2, 28), false}, + {2011 - YDIFF, 2, 30, date(2011 - YDIFF, 3, 2), date(2011 - YDIFF, 2, 28), false}, + {2011 - YDIFF, 2, 31, date(2011 - YDIFF, 3, 3), date(2011 - YDIFF, 2, 28), false}, + {2011 - YDIFF, 2, 32, date(2011 - YDIFF, 3, 4), false, false}, + }; + } + + @Test(dataProvider = "resolve_ymd") + public void test_resolve_ymd_lenient(int y, int m, int d, MinguoDate expected, Object smart, boolean strict) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.YEAR, (long) y); + fieldValues.put(ChronoField.MONTH_OF_YEAR, (long) m); + fieldValues.put(ChronoField.DAY_OF_MONTH, (long) d); + MinguoDate date = MinguoChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.LENIENT); + assertEquals(date, expected); + assertEquals(fieldValues.size(), 0); + } + + @Test(dataProvider = "resolve_ymd") + public void test_resolve_ymd_smart(int y, int m, int d, MinguoDate expected, Object smart, boolean strict) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.YEAR, (long) y); + fieldValues.put(ChronoField.MONTH_OF_YEAR, (long) m); + fieldValues.put(ChronoField.DAY_OF_MONTH, (long) d); + if (Boolean.TRUE.equals(smart)) { + MinguoDate date = MinguoChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.SMART); + assertEquals(date, expected); + assertEquals(fieldValues.size(), 0); + } else if (smart instanceof MinguoDate) { + MinguoDate date = MinguoChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.SMART); + assertEquals(date, smart); + } else { + try { + MinguoChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.SMART); + fail("Should have failed"); + } catch (DateTimeException ex) { + // expected + } + } + } + + @Test(dataProvider = "resolve_ymd") + public void test_resolve_ymd_strict(int y, int m, int d, MinguoDate expected, Object smart, boolean strict) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.YEAR, (long) y); + fieldValues.put(ChronoField.MONTH_OF_YEAR, (long) m); + fieldValues.put(ChronoField.DAY_OF_MONTH, (long) d); + if (strict) { + MinguoDate date = MinguoChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.STRICT); + assertEquals(date, expected); + assertEquals(fieldValues.size(), 0); + } else { + try { + MinguoChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.STRICT); + fail("Should have failed"); + } catch (DateTimeException ex) { + // expected + } + } + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @DataProvider(name = "resolve_yd") + Object[][] data_resolve_yd() { + return new Object[][] { + {2012 - YDIFF, -365, date(2010 - YDIFF, 12, 31), false, false}, + {2012 - YDIFF, -364, date(2011 - YDIFF, 1, 1), false, false}, + {2012 - YDIFF, -31, date(2011 - YDIFF, 11, 30), false, false}, + {2012 - YDIFF, -30, date(2011 - YDIFF, 12, 1), false, false}, + {2012 - YDIFF, -12, date(2011 - YDIFF, 12, 19), false, false}, + {2012 - YDIFF, -1, date(2011 - YDIFF, 12, 30), false, false}, + {2012 - YDIFF, 0, date(2011 - YDIFF, 12, 31), false, false}, + {2012 - YDIFF, 1, date(2012 - YDIFF, 1, 1), true, true}, + {2012 - YDIFF, 2, date(2012 - YDIFF, 1, 2), true, true}, + {2012 - YDIFF, 31, date(2012 - YDIFF, 1, 31), true, true}, + {2012 - YDIFF, 32, date(2012 - YDIFF, 2, 1), true, true}, + {2012 - YDIFF, 59, date(2012 - YDIFF, 2, 28), true, true}, + {2012 - YDIFF, 60, date(2012 - YDIFF, 2, 29), true, true}, + {2012 - YDIFF, 61, date(2012 - YDIFF, 3, 1), true, true}, + {2012 - YDIFF, 365, date(2012 - YDIFF, 12, 30), true, true}, + {2012 - YDIFF, 366, date(2012 - YDIFF, 12, 31), true, true}, + {2012 - YDIFF, 367, date(2013 - YDIFF, 1, 1), false, false}, + {2012 - YDIFF, 367 + 364, date(2013 - YDIFF, 12, 31), false, false}, + {2012 - YDIFF, 367 + 365, date(2014 - YDIFF, 1, 1), false, false}, + + {2011 - YDIFF, 59, date(2011 - YDIFF, 2, 28), true, true}, + {2011 - YDIFF, 60, date(2011 - YDIFF, 3, 1), true, true}, + }; + } + + @Test(dataProvider = "resolve_yd") + public void test_resolve_yd_lenient(int y, int d, MinguoDate expected, boolean smart, boolean strict) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.YEAR, (long) y); + fieldValues.put(ChronoField.DAY_OF_YEAR, (long) d); + MinguoDate date = MinguoChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.LENIENT); + assertEquals(date, expected); + assertEquals(fieldValues.size(), 0); + } + + @Test(dataProvider = "resolve_yd") + public void test_resolve_yd_smart(int y, int d, MinguoDate expected, boolean smart, boolean strict) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.YEAR, (long) y); + fieldValues.put(ChronoField.DAY_OF_YEAR, (long) d); + if (smart) { + MinguoDate date = MinguoChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.SMART); + assertEquals(date, expected); + assertEquals(fieldValues.size(), 0); + } else { + try { + MinguoChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.SMART); + fail("Should have failed"); + } catch (DateTimeException ex) { + // expected + } + } + } + + @Test(dataProvider = "resolve_yd") + public void test_resolve_yd_strict(int y, int d, MinguoDate expected, boolean smart, boolean strict) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.YEAR, (long) y); + fieldValues.put(ChronoField.DAY_OF_YEAR, (long) d); + if (strict) { + MinguoDate date = MinguoChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.STRICT); + assertEquals(date, expected); + assertEquals(fieldValues.size(), 0); + } else { + try { + MinguoChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.STRICT); + fail("Should have failed"); + } catch (DateTimeException ex) { + // expected + } + } + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @DataProvider(name = "resolve_ymaa") + Object[][] data_resolve_ymaa() { + return new Object[][] { + {2012 - YDIFF, 1, 1, -365, date(2010 - YDIFF, 12, 31), false, false}, + {2012 - YDIFF, 1, 1, -364, date(2011 - YDIFF, 1, 1), false, false}, + {2012 - YDIFF, 1, 1, -31, date(2011 - YDIFF, 11, 30), false, false}, + {2012 - YDIFF, 1, 1, -30, date(2011 - YDIFF, 12, 1), false, false}, + {2012 - YDIFF, 1, 1, -12, date(2011 - YDIFF, 12, 19), false, false}, + {2012 - YDIFF, 1, 1, 1, date(2012 - YDIFF, 1, 1), true, true}, + {2012 - YDIFF, 1, 1, 59, date(2012 - YDIFF, 2, 28), false, false}, + {2012 - YDIFF, 1, 1, 60, date(2012 - YDIFF, 2, 29), false, false}, + {2012 - YDIFF, 1, 1, 61, date(2012 - YDIFF, 3, 1), false, false}, + {2012 - YDIFF, 1, 1, 365, date(2012 - YDIFF, 12, 30), false, false}, + {2012 - YDIFF, 1, 1, 366, date(2012 - YDIFF, 12, 31), false, false}, + {2012 - YDIFF, 1, 1, 367, date(2013 - YDIFF, 1, 1), false, false}, + {2012 - YDIFF, 1, 1, 367 + 364, date(2013 - YDIFF, 12, 31), false, false}, + {2012 - YDIFF, 1, 1, 367 + 365, date(2014 - YDIFF, 1, 1), false, false}, + + {2012 - YDIFF, 2, 0, 1, date(2012 - YDIFF, 1, 25), false, false}, + {2012 - YDIFF, 2, 0, 7, date(2012 - YDIFF, 1, 31), false, false}, + {2012 - YDIFF, 2, 1, 1, date(2012 - YDIFF, 2, 1), true, true}, + {2012 - YDIFF, 2, 1, 7, date(2012 - YDIFF, 2, 7), true, true}, + {2012 - YDIFF, 2, 2, 1, date(2012 - YDIFF, 2, 8), true, true}, + {2012 - YDIFF, 2, 2, 7, date(2012 - YDIFF, 2, 14), true, true}, + {2012 - YDIFF, 2, 3, 1, date(2012 - YDIFF, 2, 15), true, true}, + {2012 - YDIFF, 2, 3, 7, date(2012 - YDIFF, 2, 21), true, true}, + {2012 - YDIFF, 2, 4, 1, date(2012 - YDIFF, 2, 22), true, true}, + {2012 - YDIFF, 2, 4, 7, date(2012 - YDIFF, 2, 28), true, true}, + {2012 - YDIFF, 2, 5, 1, date(2012 - YDIFF, 2, 29), true, true}, + {2012 - YDIFF, 2, 5, 2, date(2012 - YDIFF, 3, 1), true, false}, + {2012 - YDIFF, 2, 5, 7, date(2012 - YDIFF, 3, 6), true, false}, + {2012 - YDIFF, 2, 6, 1, date(2012 - YDIFF, 3, 7), false, false}, + {2012 - YDIFF, 2, 6, 7, date(2012 - YDIFF, 3, 13), false, false}, + + {2012 - YDIFF, 12, 1, 1, date(2012 - YDIFF, 12, 1), true, true}, + {2012 - YDIFF, 12, 5, 1, date(2012 - YDIFF, 12, 29), true, true}, + {2012 - YDIFF, 12, 5, 2, date(2012 - YDIFF, 12, 30), true, true}, + {2012 - YDIFF, 12, 5, 3, date(2012 - YDIFF, 12, 31), true, true}, + {2012 - YDIFF, 12, 5, 4, date(2013 - YDIFF, 1, 1), true, false}, + {2012 - YDIFF, 12, 5, 7, date(2013 - YDIFF, 1, 4), true, false}, + + {2012 - YDIFF, -12, 1, 1, date(2010 - YDIFF, 12, 1), false, false}, + {2012 - YDIFF, -11, 1, 1, date(2011 - YDIFF, 1, 1), false, false}, + {2012 - YDIFF, -1, 1, 1, date(2011 - YDIFF, 11, 1), false, false}, + {2012 - YDIFF, 0, 1, 1, date(2011 - YDIFF, 12, 1), false, false}, + {2012 - YDIFF, 1, 1, 1, date(2012 - YDIFF, 1, 1), true, true}, + {2012 - YDIFF, 12, 1, 1, date(2012 - YDIFF, 12, 1), true, true}, + {2012 - YDIFF, 13, 1, 1, date(2013 - YDIFF, 1, 1), false, false}, + {2012 - YDIFF, 24, 1, 1, date(2013 - YDIFF, 12, 1), false, false}, + {2012 - YDIFF, 25, 1, 1, date(2014 - YDIFF, 1, 1), false, false}, + + {2011 - YDIFF, 2, 1, 1, date(2011 - YDIFF, 2, 1), true, true}, + {2011 - YDIFF, 2, 4, 7, date(2011 - YDIFF, 2, 28), true, true}, + {2011 - YDIFF, 2, 5, 1, date(2011 - YDIFF, 3, 1), true, false}, + }; + } + + @Test(dataProvider = "resolve_ymaa") + public void test_resolve_ymaa_lenient(int y, int m, int w, int d, MinguoDate expected, boolean smart, boolean strict) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.YEAR, (long) y); + fieldValues.put(ChronoField.MONTH_OF_YEAR, (long) m); + fieldValues.put(ChronoField.ALIGNED_WEEK_OF_MONTH, (long) w); + fieldValues.put(ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH, (long) d); + MinguoDate date = MinguoChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.LENIENT); + assertEquals(date, expected); + assertEquals(fieldValues.size(), 0); + } + + @Test(dataProvider = "resolve_ymaa") + public void test_resolve_ymaa_smart(int y, int m, int w, int d, MinguoDate expected, boolean smart, boolean strict) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.YEAR, (long) y); + fieldValues.put(ChronoField.MONTH_OF_YEAR, (long) m); + fieldValues.put(ChronoField.ALIGNED_WEEK_OF_MONTH, (long) w); + fieldValues.put(ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH, (long) d); + if (smart) { + MinguoDate date = MinguoChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.SMART); + assertEquals(date, expected); + assertEquals(fieldValues.size(), 0); + } else { + try { + MinguoChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.SMART); + fail("Should have failed"); + } catch (DateTimeException ex) { + // expected + } + } + } + + @Test(dataProvider = "resolve_ymaa") + public void test_resolve_ymaa_strict(int y, int m, int w, int d, MinguoDate expected, boolean smart, boolean strict) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.YEAR, (long) y); + fieldValues.put(ChronoField.MONTH_OF_YEAR, (long) m); + fieldValues.put(ChronoField.ALIGNED_WEEK_OF_MONTH, (long) w); + fieldValues.put(ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH, (long) d); + if (strict) { + MinguoDate date = MinguoChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.STRICT); + assertEquals(date, expected); + assertEquals(fieldValues.size(), 0); + } else { + try { + MinguoChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.STRICT); + fail("Should have failed"); + } catch (DateTimeException ex) { + // expected + } + } + } + + //----------------------------------------------------------------------- + private static MinguoDate date(int y, int m, int d) { + return MinguoDate.of(y, m, d); + } + } diff --git a/jdk/test/java/time/tck/java/time/chrono/TCKThaiBuddhistChronology.java b/jdk/test/java/time/tck/java/time/chrono/TCKThaiBuddhistChronology.java index f6c79449638..e57847c0619 100644 --- a/jdk/test/java/time/tck/java/time/chrono/TCKThaiBuddhistChronology.java +++ b/jdk/test/java/time/tck/java/time/chrono/TCKThaiBuddhistChronology.java @@ -63,6 +63,7 @@ import static java.time.temporal.ChronoField.YEAR; import static java.time.temporal.ChronoField.YEAR_OF_ERA; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotEquals; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; @@ -84,12 +85,16 @@ import java.time.chrono.MinguoDate; import java.time.chrono.ThaiBuddhistChronology; import java.time.chrono.ThaiBuddhistDate; import java.time.chrono.ThaiBuddhistEra; +import java.time.format.ResolverStyle; import java.time.temporal.ChronoField; import java.time.temporal.ChronoUnit; import java.time.temporal.TemporalAdjuster; +import java.time.temporal.TemporalField; import java.time.temporal.ValueRange; +import java.util.HashMap; import java.util.List; import java.util.Locale; +import java.util.Map; import org.testng.Assert; import org.testng.annotations.DataProvider; @@ -200,6 +205,18 @@ public class TCKThaiBuddhistChronology { @Test(dataProvider="samples") public void test_fromCalendrical(ThaiBuddhistDate jdate, LocalDate iso) { assertEquals(ThaiBuddhistChronology.INSTANCE.date(iso), jdate); + assertEquals(ThaiBuddhistDate.from(iso), jdate); + } + + @Test(dataProvider="samples") + public void test_isEqual(ThaiBuddhistDate jdate, LocalDate iso) { + assertTrue(jdate.isEqual(iso)); + } + + @Test(dataProvider="samples") + public void test_date_equals(ThaiBuddhistDate jdate, LocalDate iso) { + assertFalse(jdate.equals(iso)); + assertNotEquals(jdate.hashCode(), iso.hashCode()); } @Test @@ -251,46 +268,58 @@ public class TCKThaiBuddhistChronology { ThaiBuddhistChronology.INSTANCE.date(year, month, dom); } - //----------------------------------------------------------------------- - // prolepticYear() and is LeapYear() - //----------------------------------------------------------------------- - @DataProvider(name="prolepticYear") - Object[][] data_prolepticYear() { - return new Object[][] { - {1, ThaiBuddhistEra.BE, 4 + YDIFF, 4 + YDIFF, true}, - {1, ThaiBuddhistEra.BE, 7 + YDIFF, 7 + YDIFF, false}, - {1, ThaiBuddhistEra.BE, 8 + YDIFF, 8 + YDIFF, true}, - {1, ThaiBuddhistEra.BE, 1000 + YDIFF, 1000 + YDIFF, false}, - {1, ThaiBuddhistEra.BE, 2000 + YDIFF, 2000 + YDIFF, true}, - {1, ThaiBuddhistEra.BE, 0, 0, false}, - {1, ThaiBuddhistEra.BE, -4 + YDIFF, -4 + YDIFF, true}, - {1, ThaiBuddhistEra.BE, -7 + YDIFF, -7 + YDIFF, false}, - {1, ThaiBuddhistEra.BE, -100 + YDIFF, -100 + YDIFF, false}, - {1, ThaiBuddhistEra.BE, -800 + YDIFF, -800 + YDIFF, true}, + //----------------------------------------------------------------------- + // prolepticYear() and is LeapYear() + //----------------------------------------------------------------------- + @DataProvider(name="prolepticYear") + Object[][] data_prolepticYear() { + return new Object[][] { + {1, ThaiBuddhistEra.BE, 4 + YDIFF, 4 + YDIFF, true}, + {1, ThaiBuddhistEra.BE, 7 + YDIFF, 7 + YDIFF, false}, + {1, ThaiBuddhistEra.BE, 8 + YDIFF, 8 + YDIFF, true}, + {1, ThaiBuddhistEra.BE, 1000 + YDIFF, 1000 + YDIFF, false}, + {1, ThaiBuddhistEra.BE, 2000 + YDIFF, 2000 + YDIFF, true}, + {1, ThaiBuddhistEra.BE, 0, 0, false}, + {1, ThaiBuddhistEra.BE, -4 + YDIFF, -4 + YDIFF, true}, + {1, ThaiBuddhistEra.BE, -7 + YDIFF, -7 + YDIFF, false}, + {1, ThaiBuddhistEra.BE, -100 + YDIFF, -100 + YDIFF, false}, + {1, ThaiBuddhistEra.BE, -800 + YDIFF, -800 + YDIFF, true}, - {0, ThaiBuddhistEra.BEFORE_BE, -3 - YDIFF, 4 + YDIFF, true}, - {0, ThaiBuddhistEra.BEFORE_BE, -6 - YDIFF, 7 + YDIFF, false}, - {0, ThaiBuddhistEra.BEFORE_BE, -7 - YDIFF, 8 + YDIFF, true}, - {0, ThaiBuddhistEra.BEFORE_BE, -999 - YDIFF, 1000 + YDIFF, false}, - {0, ThaiBuddhistEra.BEFORE_BE, -1999 - YDIFF, 2000 + YDIFF, true}, - {0, ThaiBuddhistEra.BEFORE_BE, 1, 0, false}, - {0, ThaiBuddhistEra.BEFORE_BE, 5 - YDIFF, -4 + YDIFF, true}, - {0, ThaiBuddhistEra.BEFORE_BE, 8 - YDIFF, -7 + YDIFF, false}, - {0, ThaiBuddhistEra.BEFORE_BE, 101 - YDIFF, -100 + YDIFF, false}, - {0, ThaiBuddhistEra.BEFORE_BE, 801 - YDIFF, -800 + YDIFF, true}, + {0, ThaiBuddhistEra.BEFORE_BE, -3 - YDIFF, 4 + YDIFF, true}, + {0, ThaiBuddhistEra.BEFORE_BE, -6 - YDIFF, 7 + YDIFF, false}, + {0, ThaiBuddhistEra.BEFORE_BE, -7 - YDIFF, 8 + YDIFF, true}, + {0, ThaiBuddhistEra.BEFORE_BE, -999 - YDIFF, 1000 + YDIFF, false}, + {0, ThaiBuddhistEra.BEFORE_BE, -1999 - YDIFF, 2000 + YDIFF, true}, + {0, ThaiBuddhistEra.BEFORE_BE, 1, 0, false}, + {0, ThaiBuddhistEra.BEFORE_BE, 5 - YDIFF, -4 + YDIFF, true}, + {0, ThaiBuddhistEra.BEFORE_BE, 8 - YDIFF, -7 + YDIFF, false}, + {0, ThaiBuddhistEra.BEFORE_BE, 101 - YDIFF, -100 + YDIFF, false}, + {0, ThaiBuddhistEra.BEFORE_BE, 801 - YDIFF, -800 + YDIFF, true}, - }; - } + }; + } - @Test(dataProvider="prolepticYear") - public void test_prolepticYear(int eraValue, Era era, int yearOfEra, int expectedProlepticYear, boolean isLeapYear) { - Era eraObj = ThaiBuddhistChronology.INSTANCE.eraOf(eraValue) ; - assertTrue(ThaiBuddhistChronology.INSTANCE.eras().contains(eraObj)); - assertEquals(eraObj, era); - assertEquals(ThaiBuddhistChronology.INSTANCE.prolepticYear(era, yearOfEra), expectedProlepticYear); - assertEquals(ThaiBuddhistChronology.INSTANCE.isLeapYear(expectedProlepticYear), isLeapYear) ; - assertEquals(ThaiBuddhistChronology.INSTANCE.isLeapYear(expectedProlepticYear), Year.of(expectedProlepticYear - YDIFF).isLeap()) ; - } + @Test(dataProvider="prolepticYear") + public void test_prolepticYear(int eraValue, Era era, int yearOfEra, int expectedProlepticYear, boolean isLeapYear) { + Era eraObj = ThaiBuddhistChronology.INSTANCE.eraOf(eraValue); + assertTrue(ThaiBuddhistChronology.INSTANCE.eras().contains(eraObj)); + assertEquals(eraObj, era); + assertEquals(ThaiBuddhistChronology.INSTANCE.prolepticYear(era, yearOfEra), expectedProlepticYear); + } + + @Test(dataProvider="prolepticYear") + public void test_isLeapYear(int eraValue, Era era, int yearOfEra, int expectedProlepticYear, boolean isLeapYear) { + assertEquals(ThaiBuddhistChronology.INSTANCE.isLeapYear(expectedProlepticYear), isLeapYear) ; + assertEquals(ThaiBuddhistChronology.INSTANCE.isLeapYear(expectedProlepticYear), Year.of(expectedProlepticYear - YDIFF).isLeap()); + + ThaiBuddhistDate jdate = ThaiBuddhistDate.now(); + jdate = jdate.with(ChronoField.YEAR, expectedProlepticYear).with(ChronoField.MONTH_OF_YEAR, 2); + if (isLeapYear) { + assertEquals(jdate.lengthOfMonth(), 29); + } else { + assertEquals(jdate.lengthOfMonth(), 28); + } + } //----------------------------------------------------------------------- // Bad Era for Chronology.date(era,...) and Chronology.prolepticYear(Era,...) @@ -429,7 +458,7 @@ public class TCKThaiBuddhistChronology { public void test_periodUntilDate() { ThaiBuddhistDate mdate1 = ThaiBuddhistDate.of(1, 1, 1); ThaiBuddhistDate mdate2 = ThaiBuddhistDate.of(2, 2, 2); - Period period = mdate1.periodUntil(mdate2); + Period period = mdate1.until(mdate2); assertEquals(period, Period.of(1, 1, 1)); } @@ -437,7 +466,7 @@ public class TCKThaiBuddhistChronology { public void test_periodUntilUnit() { ThaiBuddhistDate mdate1 = ThaiBuddhistDate.of(1, 1, 1); ThaiBuddhistDate mdate2 = ThaiBuddhistDate.of(2, 2, 2); - long months = mdate1.periodUntil(mdate2, ChronoUnit.MONTHS); + long months = mdate1.until(mdate2, ChronoUnit.MONTHS); assertEquals(months, 13); } @@ -446,7 +475,7 @@ public class TCKThaiBuddhistChronology { ThaiBuddhistDate mdate1 = ThaiBuddhistDate.of(1, 1, 1); ThaiBuddhistDate mdate2 = ThaiBuddhistDate.of(2, 2, 2); MinguoDate ldate2 = MinguoChronology.INSTANCE.date(mdate2); - Period period = mdate1.periodUntil(ldate2); + Period period = mdate1.until(ldate2); assertEquals(period, Period.of(1, 1, 1)); } @@ -497,4 +526,409 @@ public class TCKThaiBuddhistChronology { assertFalse(ThaiBuddhistChronology.INSTANCE.equals(IsoChronology.INSTANCE)); } + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @DataProvider(name = "resolve_yearOfEra") + Object[][] data_resolve_yearOfEra() { + return new Object[][] { + // era only + {ResolverStyle.STRICT, -1, null, null, null, null}, + {ResolverStyle.SMART, -1, null, null, null, null}, + {ResolverStyle.LENIENT, -1, null, null, null, null}, + + {ResolverStyle.STRICT, 0, null, null, ChronoField.ERA, 0}, + {ResolverStyle.SMART, 0, null, null, ChronoField.ERA, 0}, + {ResolverStyle.LENIENT, 0, null, null, ChronoField.ERA, 0}, + + {ResolverStyle.STRICT, 1, null, null, ChronoField.ERA, 1}, + {ResolverStyle.SMART, 1, null, null, ChronoField.ERA, 1}, + {ResolverStyle.LENIENT, 1, null, null, ChronoField.ERA, 1}, + + {ResolverStyle.STRICT, 2, null, null, null, null}, + {ResolverStyle.SMART, 2, null, null, null, null}, + {ResolverStyle.LENIENT, 2, null, null, null, null}, + + // era and year-of-era + {ResolverStyle.STRICT, -1, 2012, null, null, null}, + {ResolverStyle.SMART, -1, 2012, null, null, null}, + {ResolverStyle.LENIENT, -1, 2012, null, null, null}, + + {ResolverStyle.STRICT, 0, 2012, null, ChronoField.YEAR, -2011}, + {ResolverStyle.SMART, 0, 2012, null, ChronoField.YEAR, -2011}, + {ResolverStyle.LENIENT, 0, 2012, null, ChronoField.YEAR, -2011}, + + {ResolverStyle.STRICT, 1, 2012, null, ChronoField.YEAR, 2012}, + {ResolverStyle.SMART, 1, 2012, null, ChronoField.YEAR, 2012}, + {ResolverStyle.LENIENT, 1, 2012, null, ChronoField.YEAR, 2012}, + + {ResolverStyle.STRICT, 2, 2012, null, null, null}, + {ResolverStyle.SMART, 2, 2012, null, null, null}, + {ResolverStyle.LENIENT, 2, 2012, null, null, null}, + + // year-of-era only + {ResolverStyle.STRICT, null, 2012, null, ChronoField.YEAR_OF_ERA, 2012}, + {ResolverStyle.SMART, null, 2012, null, ChronoField.YEAR, 2012}, + {ResolverStyle.LENIENT, null, 2012, null, ChronoField.YEAR, 2012}, + + {ResolverStyle.STRICT, null, Integer.MAX_VALUE, null, null, null}, + {ResolverStyle.SMART, null, Integer.MAX_VALUE, null, null, null}, + {ResolverStyle.LENIENT, null, Integer.MAX_VALUE, null, ChronoField.YEAR, Integer.MAX_VALUE}, + + // year-of-era and year + {ResolverStyle.STRICT, null, 2012, 2012, ChronoField.YEAR, 2012}, + {ResolverStyle.SMART, null, 2012, 2012, ChronoField.YEAR, 2012}, + {ResolverStyle.LENIENT, null, 2012, 2012, ChronoField.YEAR, 2012}, + + {ResolverStyle.STRICT, null, 2012, -2011, ChronoField.YEAR, -2011}, + {ResolverStyle.SMART, null, 2012, -2011, ChronoField.YEAR, -2011}, + {ResolverStyle.LENIENT, null, 2012, -2011, ChronoField.YEAR, -2011}, + + {ResolverStyle.STRICT, null, 2012, 2013, null, null}, + {ResolverStyle.SMART, null, 2012, 2013, null, null}, + {ResolverStyle.LENIENT, null, 2012, 2013, null, null}, + + {ResolverStyle.STRICT, null, 2012, -2013, null, null}, + {ResolverStyle.SMART, null, 2012, -2013, null, null}, + {ResolverStyle.LENIENT, null, 2012, -2013, null, null}, + }; + } + + @Test(dataProvider = "resolve_yearOfEra") + public void test_resolve_yearOfEra(ResolverStyle style, Integer e, Integer yoe, Integer y, ChronoField field, Integer expected) { + Map fieldValues = new HashMap<>(); + if (e != null) { + fieldValues.put(ChronoField.ERA, (long) e); + } + if (yoe != null) { + fieldValues.put(ChronoField.YEAR_OF_ERA, (long) yoe); + } + if (y != null) { + fieldValues.put(ChronoField.YEAR, (long) y); + } + if (field != null) { + ThaiBuddhistDate date = ThaiBuddhistChronology.INSTANCE.resolveDate(fieldValues, style); + assertEquals(date, null); + assertEquals(fieldValues.get(field), (Long) expected.longValue()); + assertEquals(fieldValues.size(), 1); + } else { + try { + ThaiBuddhistChronology.INSTANCE.resolveDate(fieldValues, style); + fail("Should have failed"); + } catch (DateTimeException ex) { + // expected + } + } + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @DataProvider(name = "resolve_ymd") + Object[][] data_resolve_ymd() { + return new Object[][] { + {YDIFF + 2012, 1, -365, date(YDIFF + 2010, 12, 31), false, false}, + {YDIFF + 2012, 1, -364, date(YDIFF + 2011, 1, 1), false, false}, + {YDIFF + 2012, 1, -31, date(YDIFF + 2011, 11, 30), false, false}, + {YDIFF + 2012, 1, -30, date(YDIFF + 2011, 12, 1), false, false}, + {YDIFF + 2012, 1, -12, date(YDIFF + 2011, 12, 19), false, false}, + {YDIFF + 2012, 1, 1, date(YDIFF + 2012, 1, 1), true, true}, + {YDIFF + 2012, 1, 27, date(YDIFF + 2012, 1, 27), true, true}, + {YDIFF + 2012, 1, 28, date(YDIFF + 2012, 1, 28), true, true}, + {YDIFF + 2012, 1, 29, date(YDIFF + 2012, 1, 29), true, true}, + {YDIFF + 2012, 1, 30, date(YDIFF + 2012, 1, 30), true, true}, + {YDIFF + 2012, 1, 31, date(YDIFF + 2012, 1, 31), true, true}, + {YDIFF + 2012, 1, 59, date(YDIFF + 2012, 2, 28), false, false}, + {YDIFF + 2012, 1, 60, date(YDIFF + 2012, 2, 29), false, false}, + {YDIFF + 2012, 1, 61, date(YDIFF + 2012, 3, 1), false, false}, + {YDIFF + 2012, 1, 365, date(YDIFF + 2012, 12, 30), false, false}, + {YDIFF + 2012, 1, 366, date(YDIFF + 2012, 12, 31), false, false}, + {YDIFF + 2012, 1, 367, date(YDIFF + 2013, 1, 1), false, false}, + {YDIFF + 2012, 1, 367 + 364, date(YDIFF + 2013, 12, 31), false, false}, + {YDIFF + 2012, 1, 367 + 365, date(YDIFF + 2014, 1, 1), false, false}, + + {YDIFF + 2012, 2, 1, date(YDIFF + 2012, 2, 1), true, true}, + {YDIFF + 2012, 2, 28, date(YDIFF + 2012, 2, 28), true, true}, + {YDIFF + 2012, 2, 29, date(YDIFF + 2012, 2, 29), true, true}, + {YDIFF + 2012, 2, 30, date(YDIFF + 2012, 3, 1), date(YDIFF + 2012, 2, 29), false}, + {YDIFF + 2012, 2, 31, date(YDIFF + 2012, 3, 2), date(YDIFF + 2012, 2, 29), false}, + {YDIFF + 2012, 2, 32, date(YDIFF + 2012, 3, 3), false, false}, + + {YDIFF + 2012, -12, 1, date(YDIFF + 2010, 12, 1), false, false}, + {YDIFF + 2012, -11, 1, date(YDIFF + 2011, 1, 1), false, false}, + {YDIFF + 2012, -1, 1, date(YDIFF + 2011, 11, 1), false, false}, + {YDIFF + 2012, 0, 1, date(YDIFF + 2011, 12, 1), false, false}, + {YDIFF + 2012, 1, 1, date(YDIFF + 2012, 1, 1), true, true}, + {YDIFF + 2012, 12, 1, date(YDIFF + 2012, 12, 1), true, true}, + {YDIFF + 2012, 13, 1, date(YDIFF + 2013, 1, 1), false, false}, + {YDIFF + 2012, 24, 1, date(YDIFF + 2013, 12, 1), false, false}, + {YDIFF + 2012, 25, 1, date(YDIFF + 2014, 1, 1), false, false}, + + {YDIFF + 2012, 6, -31, date(YDIFF + 2012, 4, 30), false, false}, + {YDIFF + 2012, 6, -30, date(YDIFF + 2012, 5, 1), false, false}, + {YDIFF + 2012, 6, -1, date(YDIFF + 2012, 5, 30), false, false}, + {YDIFF + 2012, 6, 0, date(YDIFF + 2012, 5, 31), false, false}, + {YDIFF + 2012, 6, 1, date(YDIFF + 2012, 6, 1), true, true}, + {YDIFF + 2012, 6, 30, date(YDIFF + 2012, 6, 30), true, true}, + {YDIFF + 2012, 6, 31, date(YDIFF + 2012, 7, 1), date(YDIFF + 2012, 6, 30), false}, + {YDIFF + 2012, 6, 61, date(YDIFF + 2012, 7, 31), false, false}, + {YDIFF + 2012, 6, 62, date(YDIFF + 2012, 8, 1), false, false}, + + {YDIFF + 2011, 2, 1, date(YDIFF + 2011, 2, 1), true, true}, + {YDIFF + 2011, 2, 28, date(YDIFF + 2011, 2, 28), true, true}, + {YDIFF + 2011, 2, 29, date(YDIFF + 2011, 3, 1), date(YDIFF + 2011, 2, 28), false}, + {YDIFF + 2011, 2, 30, date(YDIFF + 2011, 3, 2), date(YDIFF + 2011, 2, 28), false}, + {YDIFF + 2011, 2, 31, date(YDIFF + 2011, 3, 3), date(YDIFF + 2011, 2, 28), false}, + {YDIFF + 2011, 2, 32, date(YDIFF + 2011, 3, 4), false, false}, + }; + } + + @Test(dataProvider = "resolve_ymd") + public void test_resolve_ymd_lenient(int y, int m, int d, ThaiBuddhistDate expected, Object smart, boolean strict) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.YEAR, (long) y); + fieldValues.put(ChronoField.MONTH_OF_YEAR, (long) m); + fieldValues.put(ChronoField.DAY_OF_MONTH, (long) d); + ThaiBuddhistDate date = ThaiBuddhistChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.LENIENT); + assertEquals(date, expected); + assertEquals(fieldValues.size(), 0); + } + + @Test(dataProvider = "resolve_ymd") + public void test_resolve_ymd_smart(int y, int m, int d, ThaiBuddhistDate expected, Object smart, boolean strict) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.YEAR, (long) y); + fieldValues.put(ChronoField.MONTH_OF_YEAR, (long) m); + fieldValues.put(ChronoField.DAY_OF_MONTH, (long) d); + if (Boolean.TRUE.equals(smart)) { + ThaiBuddhistDate date = ThaiBuddhistChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.SMART); + assertEquals(date, expected); + assertEquals(fieldValues.size(), 0); + } else if (smart instanceof ThaiBuddhistDate) { + ThaiBuddhistDate date = ThaiBuddhistChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.SMART); + assertEquals(date, smart); + } else { + try { + ThaiBuddhistChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.SMART); + fail("Should have failed"); + } catch (DateTimeException ex) { + // expected + } + } + } + + @Test(dataProvider = "resolve_ymd") + public void test_resolve_ymd_strict(int y, int m, int d, ThaiBuddhistDate expected, Object smart, boolean strict) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.YEAR, (long) y); + fieldValues.put(ChronoField.MONTH_OF_YEAR, (long) m); + fieldValues.put(ChronoField.DAY_OF_MONTH, (long) d); + if (strict) { + ThaiBuddhistDate date = ThaiBuddhistChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.STRICT); + assertEquals(date, expected); + assertEquals(fieldValues.size(), 0); + } else { + try { + ThaiBuddhistChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.STRICT); + fail("Should have failed"); + } catch (DateTimeException ex) { + // expected + } + } + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @DataProvider(name = "resolve_yd") + Object[][] data_resolve_yd() { + return new Object[][] { + {YDIFF + 2012, -365, date(YDIFF + 2010, 12, 31), false, false}, + {YDIFF + 2012, -364, date(YDIFF + 2011, 1, 1), false, false}, + {YDIFF + 2012, -31, date(YDIFF + 2011, 11, 30), false, false}, + {YDIFF + 2012, -30, date(YDIFF + 2011, 12, 1), false, false}, + {YDIFF + 2012, -12, date(YDIFF + 2011, 12, 19), false, false}, + {YDIFF + 2012, -1, date(YDIFF + 2011, 12, 30), false, false}, + {YDIFF + 2012, 0, date(YDIFF + 2011, 12, 31), false, false}, + {YDIFF + 2012, 1, date(YDIFF + 2012, 1, 1), true, true}, + {YDIFF + 2012, 2, date(YDIFF + 2012, 1, 2), true, true}, + {YDIFF + 2012, 31, date(YDIFF + 2012, 1, 31), true, true}, + {YDIFF + 2012, 32, date(YDIFF + 2012, 2, 1), true, true}, + {YDIFF + 2012, 59, date(YDIFF + 2012, 2, 28), true, true}, + {YDIFF + 2012, 60, date(YDIFF + 2012, 2, 29), true, true}, + {YDIFF + 2012, 61, date(YDIFF + 2012, 3, 1), true, true}, + {YDIFF + 2012, 365, date(YDIFF + 2012, 12, 30), true, true}, + {YDIFF + 2012, 366, date(YDIFF + 2012, 12, 31), true, true}, + {YDIFF + 2012, 367, date(YDIFF + 2013, 1, 1), false, false}, + {YDIFF + 2012, 367 + 364, date(YDIFF + 2013, 12, 31), false, false}, + {YDIFF + 2012, 367 + 365, date(YDIFF + 2014, 1, 1), false, false}, + + {YDIFF + 2011, 59, date(YDIFF + 2011, 2, 28), true, true}, + {YDIFF + 2011, 60, date(YDIFF + 2011, 3, 1), true, true}, + }; + } + + @Test(dataProvider = "resolve_yd") + public void test_resolve_yd_lenient(int y, int d, ThaiBuddhistDate expected, boolean smart, boolean strict) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.YEAR, (long) y); + fieldValues.put(ChronoField.DAY_OF_YEAR, (long) d); + ThaiBuddhistDate date = ThaiBuddhistChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.LENIENT); + assertEquals(date, expected); + assertEquals(fieldValues.size(), 0); + } + + @Test(dataProvider = "resolve_yd") + public void test_resolve_yd_smart(int y, int d, ThaiBuddhistDate expected, boolean smart, boolean strict) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.YEAR, (long) y); + fieldValues.put(ChronoField.DAY_OF_YEAR, (long) d); + if (smart) { + ThaiBuddhistDate date = ThaiBuddhistChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.SMART); + assertEquals(date, expected); + assertEquals(fieldValues.size(), 0); + } else { + try { + ThaiBuddhistChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.SMART); + fail("Should have failed"); + } catch (DateTimeException ex) { + // expected + } + } + } + + @Test(dataProvider = "resolve_yd") + public void test_resolve_yd_strict(int y, int d, ThaiBuddhistDate expected, boolean smart, boolean strict) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.YEAR, (long) y); + fieldValues.put(ChronoField.DAY_OF_YEAR, (long) d); + if (strict) { + ThaiBuddhistDate date = ThaiBuddhistChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.STRICT); + assertEquals(date, expected); + assertEquals(fieldValues.size(), 0); + } else { + try { + ThaiBuddhistChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.STRICT); + fail("Should have failed"); + } catch (DateTimeException ex) { + // expected + } + } + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @DataProvider(name = "resolve_ymaa") + Object[][] data_resolve_ymaa() { + return new Object[][] { + {YDIFF + 2012, 1, 1, -365, date(YDIFF + 2010, 12, 31), false, false}, + {YDIFF + 2012, 1, 1, -364, date(YDIFF + 2011, 1, 1), false, false}, + {YDIFF + 2012, 1, 1, -31, date(YDIFF + 2011, 11, 30), false, false}, + {YDIFF + 2012, 1, 1, -30, date(YDIFF + 2011, 12, 1), false, false}, + {YDIFF + 2012, 1, 1, -12, date(YDIFF + 2011, 12, 19), false, false}, + {YDIFF + 2012, 1, 1, 1, date(YDIFF + 2012, 1, 1), true, true}, + {YDIFF + 2012, 1, 1, 59, date(YDIFF + 2012, 2, 28), false, false}, + {YDIFF + 2012, 1, 1, 60, date(YDIFF + 2012, 2, 29), false, false}, + {YDIFF + 2012, 1, 1, 61, date(YDIFF + 2012, 3, 1), false, false}, + {YDIFF + 2012, 1, 1, 365, date(YDIFF + 2012, 12, 30), false, false}, + {YDIFF + 2012, 1, 1, 366, date(YDIFF + 2012, 12, 31), false, false}, + {YDIFF + 2012, 1, 1, 367, date(YDIFF + 2013, 1, 1), false, false}, + {YDIFF + 2012, 1, 1, 367 + 364, date(YDIFF + 2013, 12, 31), false, false}, + {YDIFF + 2012, 1, 1, 367 + 365, date(YDIFF + 2014, 1, 1), false, false}, + + {YDIFF + 2012, 2, 0, 1, date(YDIFF + 2012, 1, 25), false, false}, + {YDIFF + 2012, 2, 0, 7, date(YDIFF + 2012, 1, 31), false, false}, + {YDIFF + 2012, 2, 1, 1, date(YDIFF + 2012, 2, 1), true, true}, + {YDIFF + 2012, 2, 1, 7, date(YDIFF + 2012, 2, 7), true, true}, + {YDIFF + 2012, 2, 2, 1, date(YDIFF + 2012, 2, 8), true, true}, + {YDIFF + 2012, 2, 2, 7, date(YDIFF + 2012, 2, 14), true, true}, + {YDIFF + 2012, 2, 3, 1, date(YDIFF + 2012, 2, 15), true, true}, + {YDIFF + 2012, 2, 3, 7, date(YDIFF + 2012, 2, 21), true, true}, + {YDIFF + 2012, 2, 4, 1, date(YDIFF + 2012, 2, 22), true, true}, + {YDIFF + 2012, 2, 4, 7, date(YDIFF + 2012, 2, 28), true, true}, + {YDIFF + 2012, 2, 5, 1, date(YDIFF + 2012, 2, 29), true, true}, + {YDIFF + 2012, 2, 5, 2, date(YDIFF + 2012, 3, 1), true, false}, + {YDIFF + 2012, 2, 5, 7, date(YDIFF + 2012, 3, 6), true, false}, + {YDIFF + 2012, 2, 6, 1, date(YDIFF + 2012, 3, 7), false, false}, + {YDIFF + 2012, 2, 6, 7, date(YDIFF + 2012, 3, 13), false, false}, + + {YDIFF + 2012, 12, 1, 1, date(YDIFF + 2012, 12, 1), true, true}, + {YDIFF + 2012, 12, 5, 1, date(YDIFF + 2012, 12, 29), true, true}, + {YDIFF + 2012, 12, 5, 2, date(YDIFF + 2012, 12, 30), true, true}, + {YDIFF + 2012, 12, 5, 3, date(YDIFF + 2012, 12, 31), true, true}, + {YDIFF + 2012, 12, 5, 4, date(YDIFF + 2013, 1, 1), true, false}, + {YDIFF + 2012, 12, 5, 7, date(YDIFF + 2013, 1, 4), true, false}, + + {YDIFF + 2012, -12, 1, 1, date(YDIFF + 2010, 12, 1), false, false}, + {YDIFF + 2012, -11, 1, 1, date(YDIFF + 2011, 1, 1), false, false}, + {YDIFF + 2012, -1, 1, 1, date(YDIFF + 2011, 11, 1), false, false}, + {YDIFF + 2012, 0, 1, 1, date(YDIFF + 2011, 12, 1), false, false}, + {YDIFF + 2012, 1, 1, 1, date(YDIFF + 2012, 1, 1), true, true}, + {YDIFF + 2012, 12, 1, 1, date(YDIFF + 2012, 12, 1), true, true}, + {YDIFF + 2012, 13, 1, 1, date(YDIFF + 2013, 1, 1), false, false}, + {YDIFF + 2012, 24, 1, 1, date(YDIFF + 2013, 12, 1), false, false}, + {YDIFF + 2012, 25, 1, 1, date(YDIFF + 2014, 1, 1), false, false}, + + {YDIFF + 2011, 2, 1, 1, date(YDIFF + 2011, 2, 1), true, true}, + {YDIFF + 2011, 2, 4, 7, date(YDIFF + 2011, 2, 28), true, true}, + {YDIFF + 2011, 2, 5, 1, date(YDIFF + 2011, 3, 1), true, false}, + }; + } + + @Test(dataProvider = "resolve_ymaa") + public void test_resolve_ymaa_lenient(int y, int m, int w, int d, ThaiBuddhistDate expected, boolean smart, boolean strict) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.YEAR, (long) y); + fieldValues.put(ChronoField.MONTH_OF_YEAR, (long) m); + fieldValues.put(ChronoField.ALIGNED_WEEK_OF_MONTH, (long) w); + fieldValues.put(ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH, (long) d); + ThaiBuddhistDate date = ThaiBuddhistChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.LENIENT); + assertEquals(date, expected); + assertEquals(fieldValues.size(), 0); + } + + @Test(dataProvider = "resolve_ymaa") + public void test_resolve_ymaa_smart(int y, int m, int w, int d, ThaiBuddhistDate expected, boolean smart, boolean strict) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.YEAR, (long) y); + fieldValues.put(ChronoField.MONTH_OF_YEAR, (long) m); + fieldValues.put(ChronoField.ALIGNED_WEEK_OF_MONTH, (long) w); + fieldValues.put(ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH, (long) d); + if (smart) { + ThaiBuddhistDate date = ThaiBuddhistChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.SMART); + assertEquals(date, expected); + assertEquals(fieldValues.size(), 0); + } else { + try { + ThaiBuddhistChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.SMART); + fail("Should have failed"); + } catch (DateTimeException ex) { + // expected + } + } + } + + @Test(dataProvider = "resolve_ymaa") + public void test_resolve_ymaa_strict(int y, int m, int w, int d, ThaiBuddhistDate expected, boolean smart, boolean strict) { + Map fieldValues = new HashMap<>(); + fieldValues.put(ChronoField.YEAR, (long) y); + fieldValues.put(ChronoField.MONTH_OF_YEAR, (long) m); + fieldValues.put(ChronoField.ALIGNED_WEEK_OF_MONTH, (long) w); + fieldValues.put(ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH, (long) d); + if (strict) { + ThaiBuddhistDate date = ThaiBuddhistChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.STRICT); + assertEquals(date, expected); + assertEquals(fieldValues.size(), 0); + } else { + try { + ThaiBuddhistChronology.INSTANCE.resolveDate(fieldValues, ResolverStyle.STRICT); + fail("Should have failed"); + } catch (DateTimeException ex) { + // expected + } + } + } + + //----------------------------------------------------------------------- + private static ThaiBuddhistDate date(int y, int m, int d) { + return ThaiBuddhistDate.of(y, m, d); + } + } diff --git a/jdk/test/java/time/tck/java/time/format/TCKFormatStyle.java b/jdk/test/java/time/tck/java/time/format/TCKFormatStyle.java new file mode 100644 index 00000000000..280dd0999de --- /dev/null +++ b/jdk/test/java/time/tck/java/time/format/TCKFormatStyle.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.format; + +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.FormatStyle; +import java.time.temporal.Temporal; + +import static org.testng.Assert.assertEquals; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test. + */ +@Test +public class TCKFormatStyle { + + private static final ZoneId ZONEID_PARIS = ZoneId.of("Europe/Paris"); + private static final ZoneId OFFSET_PTWO = ZoneOffset.of("+02:00"); + + //----------------------------------------------------------------------- + // valueOf() + //----------------------------------------------------------------------- + @Test + public void test_valueOf() { + for (FormatStyle style : FormatStyle.values()) { + assertEquals(FormatStyle.valueOf(style.name()), style); + } + } + + @DataProvider(name="formatStyle") + Object[][] data_formatStyle() { + return new Object[][] { + {ZonedDateTime.of(LocalDateTime.of(2001, 10, 2, 1, 2, 3), ZONEID_PARIS), FormatStyle.FULL, "Tuesday, October 2, 2001 1:02:03 AM CEST Europe/Paris"}, + {ZonedDateTime.of(LocalDateTime.of(2001, 10, 2, 1, 2, 3), ZONEID_PARIS), FormatStyle.LONG, "October 2, 2001 1:02:03 AM CEST Europe/Paris"}, + {ZonedDateTime.of(LocalDateTime.of(2001, 10, 2, 1, 2, 3), ZONEID_PARIS), FormatStyle.MEDIUM, "Oct 2, 2001 1:02:03 AM Europe/Paris"}, + {ZonedDateTime.of(LocalDateTime.of(2001, 10, 2, 1, 2, 3), ZONEID_PARIS), FormatStyle.SHORT, "10/2/01 1:02 AM Europe/Paris"}, + + {ZonedDateTime.of(LocalDateTime.of(2001, 10, 2, 1, 2, 3), OFFSET_PTWO), FormatStyle.FULL, "Tuesday, October 2, 2001 1:02:03 AM +02:00 +02:00"}, + {ZonedDateTime.of(LocalDateTime.of(2001, 10, 2, 1, 2, 3), OFFSET_PTWO), FormatStyle.LONG, "October 2, 2001 1:02:03 AM +02:00 +02:00"}, + {ZonedDateTime.of(LocalDateTime.of(2001, 10, 2, 1, 2, 3), OFFSET_PTWO), FormatStyle.MEDIUM, "Oct 2, 2001 1:02:03 AM +02:00"}, + {ZonedDateTime.of(LocalDateTime.of(2001, 10, 2, 1, 2, 3), OFFSET_PTWO), FormatStyle.SHORT, "10/2/01 1:02 AM +02:00"}, + }; + } + + @Test(dataProvider = "formatStyle") + public void test_formatStyle(Temporal temporal, FormatStyle style, String formattedStr) { + DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder(); + DateTimeFormatter formatter = builder.appendLocalized(style, style).appendLiteral(" ").appendZoneOrOffsetId().toFormatter(); + assertEquals(formatter.format(temporal), formattedStr); + } +} diff --git a/jdk/test/java/time/tck/java/time/format/TCKResolverStyle.java b/jdk/test/java/time/tck/java/time/format/TCKResolverStyle.java new file mode 100644 index 00000000000..ef4bbb24b2d --- /dev/null +++ b/jdk/test/java/time/tck/java/time/format/TCKResolverStyle.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.format; + +import java.util.HashMap; +import java.util.Map; + +import java.time.DateTimeException; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.ResolverStyle; +import java.time.temporal.ChronoField; +import java.time.temporal.TemporalAccessor; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test. + */ +@Test +public class TCKResolverStyle { + + //----------------------------------------------------------------------- + // valueOf() + //----------------------------------------------------------------------- + @Test + public void test_valueOf() { + for (ResolverStyle style : ResolverStyle.values()) { + assertEquals(ResolverStyle.valueOf(style.name()), style); + } + } + + @DataProvider(name="resolverStyle") + Object[][] data_resolverStyle() { + return new Object[][] { + {"2000/15/30", ResolverStyle.LENIENT, null, 2001, 3, 30}, + {"2000/02/30", ResolverStyle.SMART, null, 2000, 2, 29}, + {"2000/02/29", ResolverStyle.STRICT, null, 2000, 2, 29}, + + {"2000/15/30 CE", ResolverStyle.LENIENT, null, 2001, 3, 30}, + {"2000/02/30 CE", ResolverStyle.SMART, null, 2000, 2, 29}, + {"5/02/29 BCE", ResolverStyle.STRICT, null, 5, 2, 29}, + + {"4/02/29 BCE", ResolverStyle.STRICT, DateTimeException.class, -1, -1, -1}, + {"2000/02/30 CE", ResolverStyle.STRICT, DateTimeException.class, -1, -1, -1}, + + }; + } + + @Test(dataProvider = "resolverStyle") + public void test_resolverStyle(String str, ResolverStyle style, Class expectedEx, int year, int month, int day) { + DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder(); + builder.appendValue(ChronoField.YEAR_OF_ERA); + builder.appendLiteral("/"); + builder.appendValue(ChronoField.MONTH_OF_YEAR); + builder.appendLiteral("/"); + builder.appendValue(ChronoField.DAY_OF_MONTH); + + Map eraMap = new HashMap(); + eraMap.put(1L, "CE"); + eraMap.put(0L, "BCE"); + DateTimeFormatter optionalFormatter = new DateTimeFormatterBuilder().appendLiteral(" ").appendText(ChronoField.ERA, eraMap).toFormatter(); + + DateTimeFormatter formatter = builder.appendOptional(optionalFormatter).toFormatter(); + formatter = formatter.withResolverStyle(style); + if (expectedEx == null) { + TemporalAccessor accessor = formatter.parse(str); + assertEquals(accessor.get(ChronoField.YEAR_OF_ERA), year); + assertEquals(accessor.get(ChronoField.MONTH_OF_YEAR), month); + assertEquals(accessor.get(ChronoField.DAY_OF_MONTH), day); + } else { + try { + formatter.parse(str); + fail(); + } catch (Exception ex) { + assertTrue(expectedEx.isInstance(ex)); + } + } + } +} diff --git a/jdk/test/java/time/tck/java/time/format/TCKSignStyle.java b/jdk/test/java/time/tck/java/time/format/TCKSignStyle.java new file mode 100644 index 00000000000..a6faec3fd83 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/format/TCKSignStyle.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.format; + +import java.time.DateTimeException; +import java.time.LocalDate; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.SignStyle; +import java.time.temporal.ChronoField; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test. + */ +@Test +public class TCKSignStyle { + + //----------------------------------------------------------------------- + // valueOf() + //----------------------------------------------------------------------- + @Test + public void test_valueOf() { + for (SignStyle style : SignStyle.values()) { + assertEquals(SignStyle.valueOf(style.name()), style); + } + } + + @DataProvider(name="signStyle") + Object[][] data_signStyle() { + return new Object[][] { + {LocalDate.of(0, 10, 2), SignStyle.ALWAYS, null, "+00"}, + {LocalDate.of(2001, 10, 2), SignStyle.ALWAYS, null, "+2001"}, + {LocalDate.of(-2001, 10, 2), SignStyle.ALWAYS, null, "-2001"}, + + {LocalDate.of(2001, 10, 2), SignStyle.NORMAL, null, "2001"}, + {LocalDate.of(-2001, 10, 2), SignStyle.NORMAL, null, "-2001"}, + + {LocalDate.of(2001, 10, 2), SignStyle.NEVER, null, "2001"}, + {LocalDate.of(-2001, 10, 2), SignStyle.NEVER, null, "2001"}, + + {LocalDate.of(2001, 10, 2), SignStyle.NOT_NEGATIVE, null, "2001"}, + {LocalDate.of(-2001, 10, 2), SignStyle.NOT_NEGATIVE, DateTimeException.class, ""}, + + {LocalDate.of(0, 10, 2), SignStyle.EXCEEDS_PAD, null, "00"}, + {LocalDate.of(1, 10, 2), SignStyle.EXCEEDS_PAD, null, "01"}, + {LocalDate.of(-1, 10, 2), SignStyle.EXCEEDS_PAD, null, "-01"}, + + {LocalDate.of(20001, 10, 2), SignStyle.ALWAYS, DateTimeException.class, ""}, + {LocalDate.of(20001, 10, 2), SignStyle.NORMAL, DateTimeException.class, ""}, + {LocalDate.of(20001, 10, 2), SignStyle.NEVER, DateTimeException.class, ""}, + {LocalDate.of(20001, 10, 2), SignStyle.EXCEEDS_PAD, DateTimeException.class, ""}, + {LocalDate.of(20001, 10, 2), SignStyle.NOT_NEGATIVE, DateTimeException.class, ""}, + }; + } + + @Test(dataProvider = "signStyle") + public void test_signStyle(LocalDate localDate, SignStyle style, Class expectedEx, String expectedStr) { + DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder(); + DateTimeFormatter formatter = builder.appendValue(ChronoField.YEAR, 2, 4, style) + .toFormatter(); + formatter = formatter.withZone(ZoneOffset.UTC); + if (expectedEx == null) { + String output = formatter.format(localDate); + assertEquals(output, expectedStr); + } else { + try { + formatter.format(localDate); + fail(); + } catch (Exception ex) { + assertTrue(expectedEx.isInstance(ex)); + } + } + } + +} diff --git a/jdk/test/java/time/tck/java/time/format/TCKTextStyle.java b/jdk/test/java/time/tck/java/time/format/TCKTextStyle.java index 344a8709ca2..68da619751a 100644 --- a/jdk/test/java/time/tck/java/time/format/TCKTextStyle.java +++ b/jdk/test/java/time/tck/java/time/format/TCKTextStyle.java @@ -91,4 +91,14 @@ public class TCKTextStyle { assertTrue(!TextStyle.NARROW.isStandalone()); } + //----------------------------------------------------------------------- + // valueOf() + //----------------------------------------------------------------------- + @Test + public void test_valueOf() { + for (TextStyle style : TextStyle.values()) { + assertEquals(TextStyle.valueOf(style.name()), style); + } + } + } diff --git a/jdk/test/java/time/tck/java/time/format/TCKZoneIdPrinterParser.java b/jdk/test/java/time/tck/java/time/format/TCKZoneIdPrinterParser.java index f6c4c46f2a1..414d390c610 100644 --- a/jdk/test/java/time/tck/java/time/format/TCKZoneIdPrinterParser.java +++ b/jdk/test/java/time/tck/java/time/format/TCKZoneIdPrinterParser.java @@ -60,16 +60,20 @@ package tck.java.time.format; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; import java.text.ParsePosition; +import java.time.DateTimeException; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalQuery; import java.util.Locale; +import java.util.Objects; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; @@ -148,43 +152,44 @@ public class TCKZoneIdPrinterParser { @DataProvider(name="parseSuccess") Object[][] data_parseSuccess() { return new Object[][] { - {"Z", 1, -1, ZoneOffset.UTC}, - {"UTC", 3, -1, ZoneOffset.UTC}, - {"UT", 2, -1, ZoneOffset.UTC}, - {"GMT", 3, -1, ZoneOffset.UTC}, - {"UTC0", 4, -1, ZoneOffset.UTC}, - {"UT0", 3, -1, ZoneOffset.UTC}, - {"GMT0", 4, -1, ZoneOffset.UTC}, + {"Z", 1, -1, ZoneId.of("Z")}, + {"UTC", 3, -1, ZoneId.of("UTC")}, + {"UT", 2, -1, ZoneId.of("UT")}, + {"GMT", 3, -1, ZoneId.of("GMT")}, {"+00:00", 6, -1, ZoneOffset.UTC}, - {"UTC+00:00", 9, -1, ZoneOffset.UTC}, - {"UT+00:00", 8, -1, ZoneOffset.UTC}, - {"GMT+00:00", 9, -1, ZoneOffset.UTC}, + {"UTC+00:00", 9, -1, ZoneId.of("UTC")}, + {"UT+00:00", 8, -1, ZoneId.of("UT")}, + {"GMT+00:00", 9, -1, ZoneId.of("GMT")}, {"-00:00", 6, -1, ZoneOffset.UTC}, - {"UTC-00:00", 9, -1, ZoneOffset.UTC}, - {"UT-00:00", 8, -1, ZoneOffset.UTC}, - {"GMT-00:00", 9, -1, ZoneOffset.UTC}, + {"UTC-00:00", 9, -1, ZoneId.of("UTC")}, + {"UT-00:00", 8, -1, ZoneId.of("UT")}, + {"GMT-00:00", 9, -1, ZoneId.of("GMT")}, {"+01:30", 6, -1, ZoneOffset.ofHoursMinutes(1, 30)}, - {"UTC+01:30", 9, -1, ZoneOffset.ofHoursMinutes(1, 30)}, - {"UT+02:30", 8, -1, ZoneOffset.ofHoursMinutes(2, 30)}, - {"GMT+03:30", 9, -1, ZoneOffset.ofHoursMinutes(3, 30)}, + {"UTC+01:30", 9, -1, ZoneId.of("UTC+01:30")}, + {"UT+02:30", 8, -1, ZoneId.of("UT+02:30")}, + {"GMT+03:30", 9, -1, ZoneId.of("GMT+03:30")}, {"-01:30", 6, -1, ZoneOffset.ofHoursMinutes(-1, -30)}, - {"UTC-01:30", 9, -1, ZoneOffset.ofHoursMinutes(-1, -30)}, - {"UT-02:30", 8, -1, ZoneOffset.ofHoursMinutes(-2, -30)}, - {"GMT-03:30", 9, -1, ZoneOffset.ofHoursMinutes(-3, -30)}, + {"UTC-01:30", 9, -1, ZoneId.of("UTC-01:30")}, + {"UT-02:30", 8, -1, ZoneId.of("UT-02:30")}, + {"GMT-03:30", 9, -1, ZoneId.of("GMT-03:30")}, // fallback to UTC - {"UTC-01:WW", 3, -1, ZoneOffset.UTC}, - {"UT-02:WW", 2, -1, ZoneOffset.UTC}, - {"GMT-03:WW", 3, -1, ZoneOffset.UTC}, + {"UTC-01:WW", 3, -1, ZoneId.of("UTC")}, + {"UT-02:WW", 2, -1, ZoneId.of("UT")}, + {"GMT-03:WW", 3, -1, ZoneId.of("GMT")}, {"Z0", 1, -1, ZoneOffset.UTC}, - {"UTC1", 3, -1, ZoneOffset.UTC}, + {"UTC1", 3, -1, ZoneId.of("UTC")}, // Z not parsed as zero - {"UTCZ", 3, -1, ZoneOffset.UTC}, - {"UTZ", 2, -1, ZoneOffset.UTC}, - {"GMTZ", 3, -1, ZoneOffset.UTC}, + {"UTCZ", 3, -1, ZoneId.of("UTC")}, + {"UTZ", 2, -1, ZoneId.of("UT")}, + {"GMTZ", 3, -1, ZoneId.of("GMT")}, + + // 0 not parsed + {"UTC0", 3, -1, ZoneId.of("UTC")}, + {"UT0", 2, -1, ZoneId.of("UT")}, // fail to parse {"", 0, 0, null}, @@ -206,12 +211,12 @@ public class TCKZoneIdPrinterParser { public void test_parseSuccess_plain(String text, int expectedIndex, int expectedErrorIndex, ZoneId expected) { builder.appendZoneId(); TemporalAccessor parsed = builder.toFormatter().parseUnresolved(text, pos); - assertEquals(pos.getErrorIndex(), expectedErrorIndex); - assertEquals(pos.getIndex(), expectedIndex); + assertEquals(pos.getErrorIndex(), expectedErrorIndex, "Incorrect error index parsing: " + text); + assertEquals(pos.getIndex(), expectedIndex, "Incorrect index parsing: " + text); if (expected != null) { - assertEquals(parsed.query(TemporalQuery.zoneId()), expected); - assertEquals(parsed.query(TemporalQuery.offset()), null); - assertEquals(parsed.query(TemporalQuery.zone()), expected); + assertEquals(parsed.query(TemporalQuery.zoneId()), expected, "Incorrect zoneId parsing: " + text); + assertEquals(parsed.query(TemporalQuery.offset()), null, "Incorrect offset parsing: " + text); + assertEquals(parsed.query(TemporalQuery.zone()), expected, "Incorrect zone parsing: " + text); } else { assertEquals(parsed, null); } @@ -221,13 +226,14 @@ public class TCKZoneIdPrinterParser { public void test_parseSuccess_prefix(String text, int expectedIndex, int expectedErrorIndex, ZoneId expected) { builder.appendZoneId(); pos.setIndex(3); - TemporalAccessor parsed = builder.toFormatter().parseUnresolved("XXX" + text, pos); - assertEquals(pos.getErrorIndex(), expectedErrorIndex >= 0 ? expectedErrorIndex + 3 : expectedErrorIndex); - assertEquals(pos.getIndex(), expectedIndex + 3); + String prefixText = "XXX" + text; + TemporalAccessor parsed = builder.toFormatter().parseUnresolved(prefixText, pos); + assertEquals(pos.getErrorIndex(), expectedErrorIndex >= 0 ? expectedErrorIndex + 3 : expectedErrorIndex, "Incorrect error index parsing: " + prefixText); + assertEquals(pos.getIndex(), expectedIndex + 3, "Incorrect index parsing: " + prefixText); if (expected != null) { - assertEquals(parsed.query(TemporalQuery.zoneId()), expected); - assertEquals(parsed.query(TemporalQuery.offset()), null); - assertEquals(parsed.query(TemporalQuery.zone()), expected); + assertEquals(parsed.query(TemporalQuery.zoneId()), expected, "Incorrect zoneId parsing: " + prefixText); + assertEquals(parsed.query(TemporalQuery.offset()), null, "Incorrect offset parsing: " + prefixText); + assertEquals(parsed.query(TemporalQuery.zone()), expected, "Incorrect zone parsing: " + prefixText); } else { assertEquals(parsed, null); } @@ -236,13 +242,14 @@ public class TCKZoneIdPrinterParser { @Test(dataProvider="parseSuccess") public void test_parseSuccess_suffix(String text, int expectedIndex, int expectedErrorIndex, ZoneId expected) { builder.appendZoneId(); - TemporalAccessor parsed = builder.toFormatter().parseUnresolved(text + "XXX", pos); - assertEquals(pos.getErrorIndex(), expectedErrorIndex); - assertEquals(pos.getIndex(), expectedIndex); + String suffixText = text + "XXX"; + TemporalAccessor parsed = builder.toFormatter().parseUnresolved(suffixText, pos); + assertEquals(pos.getErrorIndex(), expectedErrorIndex, "Incorrect error index parsing: " + suffixText); + assertEquals(pos.getIndex(), expectedIndex, "Incorrect index parsing: " + suffixText); if (expected != null) { - assertEquals(parsed.query(TemporalQuery.zoneId()), expected); - assertEquals(parsed.query(TemporalQuery.offset()), null); - assertEquals(parsed.query(TemporalQuery.zone()), expected); + assertEquals(parsed.query(TemporalQuery.zoneId()), expected, "Incorrect zoneId parsing: " + suffixText); + assertEquals(parsed.query(TemporalQuery.offset()), null, "Incorrect offset parsing: " + suffixText); + assertEquals(parsed.query(TemporalQuery.zone()), expected, "Incorrect zone parsing: " + suffixText); } else { assertEquals(parsed, null); } @@ -251,15 +258,16 @@ public class TCKZoneIdPrinterParser { @Test(dataProvider="parseSuccess") public void test_parseSuccess_caseSensitive(String text, int expectedIndex, int expectedErrorIndex, ZoneId expected) { builder.parseCaseSensitive().appendZoneId(); - TemporalAccessor parsed = builder.toFormatter().parseUnresolved(text.toLowerCase(Locale.ENGLISH), pos); + String lcText = text.toLowerCase(Locale.ENGLISH); + TemporalAccessor parsed = builder.toFormatter().parseUnresolved(lcText, pos); if (text.matches("[^A-Z]*[A-Z].*")) { // if input has letters assertEquals(pos.getErrorIndex() >= 0, true); assertEquals(pos.getIndex(), 0); assertEquals(parsed, null); } else { // case sensitive made no difference - assertEquals(pos.getIndex(), expectedIndex); - assertEquals(pos.getErrorIndex(), expectedErrorIndex); + assertEquals(pos.getIndex(), expectedIndex, "Incorrect index parsing: " + lcText); + assertEquals(pos.getErrorIndex(), expectedErrorIndex, "Incorrect error index parsing: " + lcText); if (expected != null) { assertEquals(parsed.query(TemporalQuery.zoneId()), expected); assertEquals(parsed.query(TemporalQuery.offset()), null); @@ -273,13 +281,15 @@ public class TCKZoneIdPrinterParser { @Test(dataProvider="parseSuccess") public void test_parseSuccess_caseInsensitive(String text, int expectedIndex, int expectedErrorIndex, ZoneId expected) { builder.parseCaseInsensitive().appendZoneId(); - TemporalAccessor parsed = builder.toFormatter().parseUnresolved(text.toLowerCase(Locale.ENGLISH), pos); - assertEquals(pos.getErrorIndex(), expectedErrorIndex); - assertEquals(pos.getIndex(), expectedIndex); + String lcText = text.toLowerCase(Locale.ENGLISH); + TemporalAccessor parsed = builder.toFormatter().parseUnresolved(lcText, pos); + assertEquals(pos.getErrorIndex(), expectedErrorIndex, "Incorrect error index parsing: " + lcText); + assertEquals(pos.getIndex(), expectedIndex, "Incorrect index parsing: " + lcText); if (expected != null) { - assertEquals(parsed.query(TemporalQuery.zoneId()), expected); - assertEquals(parsed.query(TemporalQuery.offset()), null); - assertEquals(parsed.query(TemporalQuery.zone()), expected); + ZoneId zid = parsed.query(TemporalQuery.zoneId()); + assertEquals(parsed.query(TemporalQuery.zoneId()), expected, "Incorrect zoneId parsing: " + lcText); + assertEquals(parsed.query(TemporalQuery.offset()), null, "Incorrect offset parsing: " + lcText); + assertEquals(parsed.query(TemporalQuery.zone()), expected, "Incorrect zone parsing: " + lcText); } else { assertEquals(parsed, null); } diff --git a/jdk/test/java/time/tck/java/time/temporal/TCKChronoField.java b/jdk/test/java/time/tck/java/time/temporal/TCKChronoField.java new file mode 100644 index 00000000000..1e6c9ea874b --- /dev/null +++ b/jdk/test/java/time/tck/java/time/temporal/TCKChronoField.java @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.temporal; + +import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH; +import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR; +import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH; +import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR; +import static java.time.temporal.ChronoField.AMPM_OF_DAY; +import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_DAY; +import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_AMPM; +import static java.time.temporal.ChronoField.DAY_OF_MONTH; +import static java.time.temporal.ChronoField.DAY_OF_WEEK; +import static java.time.temporal.ChronoField.DAY_OF_YEAR; +import static java.time.temporal.ChronoField.EPOCH_DAY; +import static java.time.temporal.ChronoField.HOUR_OF_DAY; +import static java.time.temporal.ChronoField.HOUR_OF_AMPM; +import static java.time.temporal.ChronoField.MICRO_OF_DAY; +import static java.time.temporal.ChronoField.MICRO_OF_SECOND; +import static java.time.temporal.ChronoField.MILLI_OF_DAY; +import static java.time.temporal.ChronoField.MILLI_OF_SECOND; +import static java.time.temporal.ChronoField.MINUTE_OF_DAY; +import static java.time.temporal.ChronoField.MINUTE_OF_HOUR; +import static java.time.temporal.ChronoField.MONTH_OF_YEAR; +import static java.time.temporal.ChronoField.NANO_OF_DAY; +import static java.time.temporal.ChronoField.NANO_OF_SECOND; +import static java.time.temporal.ChronoField.PROLEPTIC_MONTH; +import static java.time.temporal.ChronoField.SECOND_OF_DAY; +import static java.time.temporal.ChronoField.SECOND_OF_MINUTE; +import static java.time.temporal.ChronoField.YEAR; +import static java.time.temporal.ChronoField.YEAR_OF_ERA; +import static java.time.temporal.ChronoField.ERA; +import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.FOREVER; +import static java.time.temporal.ChronoUnit.HOURS; +import static java.time.temporal.ChronoUnit.MICROS; +import static java.time.temporal.ChronoUnit.MILLIS; +import static java.time.temporal.ChronoUnit.MINUTES; +import static java.time.temporal.ChronoUnit.MONTHS; +import static java.time.temporal.ChronoUnit.NANOS; +import static java.time.temporal.ChronoUnit.SECONDS; +import static java.time.temporal.ChronoUnit.WEEKS; +import static java.time.temporal.ChronoUnit.YEARS; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.temporal.ChronoField; +import java.time.temporal.ChronoUnit; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.ValueRange; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test. + */ +@Test +public class TCKChronoField { + + //----------------------------------------------------------------------- + // getBaseUnit() and getRangeUnit() + //----------------------------------------------------------------------- + @DataProvider(name="fieldUnit") + Object[][] data_fieldUnit() { + return new Object[][] { + {YEAR, YEARS, FOREVER}, + {MONTH_OF_YEAR, MONTHS, YEARS}, + {DAY_OF_MONTH, DAYS, MONTHS}, + {DAY_OF_WEEK, DAYS, WEEKS}, + {DAY_OF_YEAR, DAYS, YEARS}, + {HOUR_OF_DAY, HOURS, DAYS}, + {MINUTE_OF_DAY, MINUTES, DAYS}, + {MINUTE_OF_HOUR, MINUTES, HOURS}, + {SECOND_OF_DAY, SECONDS, DAYS}, + {SECOND_OF_MINUTE, SECONDS, MINUTES}, + {MILLI_OF_DAY, MILLIS, DAYS}, + {MILLI_OF_SECOND, MILLIS, SECONDS}, + {MICRO_OF_SECOND, MICROS, SECONDS}, + {MICRO_OF_DAY, MICROS, DAYS}, + {NANO_OF_SECOND, NANOS, SECONDS}, + {NANO_OF_DAY, NANOS, DAYS}, + + }; + } + + @Test(dataProvider = "fieldUnit") + public void test_getBaseUnit(ChronoField field, ChronoUnit baseUnit, ChronoUnit rangeUnit) { + assertEquals(field.getBaseUnit(), baseUnit); + assertEquals(field.getRangeUnit(), rangeUnit); + } + + //----------------------------------------------------------------------- + // isDateBased() and isTimeBased() + //----------------------------------------------------------------------- + @DataProvider(name="fieldBased") + Object[][] data_fieldBased() { + return new Object[][] { + {DAY_OF_WEEK, true, false}, + {ALIGNED_DAY_OF_WEEK_IN_MONTH, true, false}, + {ALIGNED_DAY_OF_WEEK_IN_YEAR, true, false}, + {DAY_OF_MONTH, true, false}, + {DAY_OF_YEAR, true, false}, + {EPOCH_DAY, true, false}, + {ALIGNED_WEEK_OF_MONTH, true, false}, + {ALIGNED_WEEK_OF_YEAR, true, false}, + {MONTH_OF_YEAR, true, false}, + {PROLEPTIC_MONTH, true, false}, + {YEAR_OF_ERA, true, false}, + {YEAR, true, false}, + {ERA, true, false}, + + {AMPM_OF_DAY, false, true}, + {CLOCK_HOUR_OF_DAY, false, true}, + {HOUR_OF_DAY, false, true}, + {CLOCK_HOUR_OF_AMPM, false, true}, + {HOUR_OF_AMPM, false, true}, + {MINUTE_OF_DAY, false, true}, + {MINUTE_OF_HOUR, false, true}, + {SECOND_OF_DAY, false, true}, + {SECOND_OF_MINUTE, false, true}, + {MILLI_OF_DAY, false, true}, + {MILLI_OF_SECOND, false, true}, + {MICRO_OF_DAY, false, true}, + {MICRO_OF_SECOND, false, true}, + {NANO_OF_DAY, false, true}, + {NANO_OF_SECOND, false, true}, + }; + } + + @Test(dataProvider = "fieldBased") + public void test_isDateBased(ChronoField field, boolean isDateBased, boolean isTimeBased) { + assertEquals(field.isDateBased(), isDateBased); + assertEquals(field.isTimeBased(), isTimeBased); + } + + //----------------------------------------------------------------------- + // isSupportedBy(TemporalAccessor temporal) and getFrom(TemporalAccessor temporal) + //----------------------------------------------------------------------- + @DataProvider(name="fieldAndAccessor") + Object[][] data_fieldAndAccessor() { + return new Object[][] { + {YEAR, LocalDate.of(2000, 2, 29), true, 2000}, + {YEAR, LocalDateTime.of(2000, 2, 29, 5, 4, 3, 200), true, 2000}, + {MONTH_OF_YEAR, LocalDate.of(2000, 2, 29), true, 2}, + {MONTH_OF_YEAR, LocalDateTime.of(2000, 2, 29, 5, 4, 3, 200), true, 2}, + {DAY_OF_MONTH, LocalDate.of(2000, 2, 29), true, 29}, + {DAY_OF_MONTH, LocalDateTime.of(2000, 2, 29, 5, 4, 3, 200), true, 29}, + {DAY_OF_YEAR, LocalDate.of(2000, 2, 29), true, 60}, + {DAY_OF_YEAR, LocalDateTime.of(2000, 2, 29, 5, 4, 3, 200), true, 60}, + + {HOUR_OF_DAY, LocalTime.of(5, 4, 3, 200), true, 5}, + {HOUR_OF_DAY, LocalDateTime.of(2000, 2, 29, 5, 4, 3, 200), true, 5}, + + {MINUTE_OF_DAY, LocalTime.of(5, 4, 3, 200), true, 5*60 + 4}, + {MINUTE_OF_DAY, LocalDateTime.of(2000, 2, 29, 5, 4, 3, 200), true, 5*60 + 4}, + {MINUTE_OF_HOUR, LocalTime.of(5, 4, 3, 200), true, 4}, + {MINUTE_OF_HOUR, LocalDateTime.of(2000, 2, 29, 5, 4, 3, 200), true, 4}, + + {SECOND_OF_DAY, LocalTime.of(5, 4, 3, 200), true, 5*3600 + 4*60 + 3}, + {SECOND_OF_DAY, LocalDateTime.of(2000, 2, 29, 5, 4, 3, 200), true, 5*3600 + 4*60 + 3}, + {SECOND_OF_MINUTE, LocalTime.of(5, 4, 3, 200), true, 3}, + {SECOND_OF_MINUTE, LocalDateTime.of(2000, 2, 29, 5, 4, 3, 200), true, 3}, + + {NANO_OF_SECOND, LocalTime.of(5, 4, 3, 200), true, 200}, + {NANO_OF_SECOND, LocalDateTime.of(2000, 2, 29, 5, 4, 3, 200), true, 200}, + + {YEAR, LocalTime.of(5, 4, 3, 200), false, -1}, + {MONTH_OF_YEAR, LocalTime.of(5, 4, 3, 200), false, -1}, + {DAY_OF_MONTH, LocalTime.of(5, 4, 3, 200), false, -1}, + {DAY_OF_YEAR, LocalTime.of(5, 4, 3, 200), false, -1}, + {HOUR_OF_DAY, LocalDate.of(2000, 2, 29), false, -1}, + {MINUTE_OF_DAY, LocalDate.of(2000, 2, 29), false, -1}, + {MINUTE_OF_HOUR, LocalDate.of(2000, 2, 29), false, -1}, + {SECOND_OF_DAY, LocalDate.of(2000, 2, 29), false, -1}, + {SECOND_OF_MINUTE, LocalDate.of(2000, 2, 29), false, -1}, + {NANO_OF_SECOND, LocalDate.of(2000, 2, 29), false, -1}, + }; + } + + @Test(dataProvider = "fieldAndAccessor") + public void test_supportedAccessor(ChronoField field, TemporalAccessor accessor, boolean isSupported, long value) { + assertEquals(field.isSupportedBy(accessor), isSupported); + if (isSupported) { + assertEquals(field.getFrom(accessor), value); + } + } + + //----------------------------------------------------------------------- + // range() and rangeRefinedBy(TemporalAccessor temporal) + //----------------------------------------------------------------------- + @Test + public void test_range() { + assertEquals(MONTH_OF_YEAR.range(), ValueRange.of(1, 12)); + assertEquals(MONTH_OF_YEAR.rangeRefinedBy(LocalDate.of(2000, 2, 29)), ValueRange.of(1, 12)); + + assertEquals(DAY_OF_MONTH.range(), ValueRange.of(1, 28, 31)); + assertEquals(DAY_OF_MONTH.rangeRefinedBy(LocalDate.of(2000, 2, 29)), ValueRange.of(1, 29)); + } + + //----------------------------------------------------------------------- + // valueOf() + //----------------------------------------------------------------------- + @Test + public void test_valueOf() { + for (ChronoField field : ChronoField.values()) { + assertEquals(ChronoField.valueOf(field.name()), field); + } + } +} diff --git a/jdk/test/java/time/tck/java/time/temporal/TCKChronoUnit.java b/jdk/test/java/time/tck/java/time/temporal/TCKChronoUnit.java new file mode 100644 index 00000000000..a117030dda1 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/temporal/TCKChronoUnit.java @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.temporal; + +import static java.time.temporal.ChronoUnit.CENTURIES; +import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.DECADES; +import static java.time.temporal.ChronoUnit.ERAS; +import static java.time.temporal.ChronoUnit.FOREVER; +import static java.time.temporal.ChronoUnit.HALF_DAYS; +import static java.time.temporal.ChronoUnit.HOURS; +import static java.time.temporal.ChronoUnit.MICROS; +import static java.time.temporal.ChronoUnit.MILLENNIA; +import static java.time.temporal.ChronoUnit.MILLIS; +import static java.time.temporal.ChronoUnit.MINUTES; +import static java.time.temporal.ChronoUnit.MONTHS; +import static java.time.temporal.ChronoUnit.NANOS; +import static java.time.temporal.ChronoUnit.SECONDS; +import static java.time.temporal.ChronoUnit.WEEKS; +import static java.time.temporal.ChronoUnit.YEARS; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; + +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.temporal.ChronoField; +import java.time.temporal.ChronoUnit; +import java.time.temporal.Temporal; +import java.time.temporal.TemporalAccessor; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test. + */ +@Test +public class TCKChronoUnit { + + //----------------------------------------------------------------------- + // isDateBased(), isTimeBased() and isDurationEstimated() + //----------------------------------------------------------------------- + @DataProvider(name="chronoUnit") + Object[][] data_chronoUnit() { + return new Object[][] { + {FOREVER, false, false, true}, + {ERAS, true, false, true}, + {MILLENNIA, true, false, true}, + {CENTURIES, true, false, true}, + {DECADES, true, false, true}, + {YEARS, true, false, true}, + {MONTHS, true, false, true}, + {WEEKS, true, false, true}, + {DAYS, true, false, true}, + + {HALF_DAYS, false, true, false}, + {HOURS, false, true, false}, + {MINUTES, false, true, false}, + {SECONDS, false, true, false}, + {MICROS, false, true, false}, + {MILLIS, false, true, false}, + {NANOS, false, true, false}, + + }; + } + + @Test(dataProvider = "chronoUnit") + public void test_unitType(ChronoUnit unit, boolean isDateBased, boolean isTimeBased, boolean isDurationEstimated) { + assertEquals(unit.isDateBased(), isDateBased); + assertEquals(unit.isTimeBased(), isTimeBased); + assertEquals(unit.isDurationEstimated(), isDurationEstimated); + } + + //----------------------------------------------------------------------- + // isSupportedBy(), addTo() and between() + //----------------------------------------------------------------------- + @DataProvider(name="unitAndTemporal") + Object[][] data_unitAndTemporal() { + return new Object[][] { + {CENTURIES, LocalDate.of(2000, 1, 10), true, 1, LocalDate.of(2100, 1, 10)}, + {DECADES, LocalDate.of(2000, 1, 10), true, 1, LocalDate.of(2010, 1, 10)}, + {YEARS, LocalDate.of(2000, 1, 10), true, 1, LocalDate.of(2001, 1, 10)}, + {MONTHS, LocalDate.of(2000, 1, 10), true, 1, LocalDate.of(2000, 2, 10)}, + {WEEKS, LocalDate.of(2000, 1, 10), true, 1, LocalDate.of(2000, 1, 17)}, + {DAYS, LocalDate.of(2000, 1, 10), true, 1, LocalDate.of(2000, 1, 11)}, + + {HALF_DAYS, LocalTime.of(1, 2, 3, 400), true, 1, LocalTime.of(13, 2, 3, 400)}, + {HOURS, LocalTime.of(1, 2, 3, 400), true, 1, LocalTime.of(2, 2, 3, 400)}, + {MINUTES, LocalTime.of(1, 2, 3, 400), true, 1, LocalTime.of(1, 3, 3, 400)}, + {SECONDS, LocalTime.of(1, 2, 3, 400), true, 1, LocalTime.of(1, 2, 4, 400)}, + {MICROS, LocalTime.of(1, 2, 3, 400), true, 1, LocalTime.of(1, 2, 3, 1000 + 400)}, + {MILLIS, LocalTime.of(1, 2, 3, 400), true, 1, LocalTime.of(1, 2, 3, 1000*1000 + 400)}, + {NANOS, LocalTime.of(1, 2, 3, 400), true, 1, LocalTime.of(1, 2, 3, 1 + 400)}, + + {CENTURIES, LocalTime.of(1, 2, 3, 400), false, 1, null}, + {DECADES, LocalTime.of(1, 2, 3, 400), false, 1, null}, + {YEARS, LocalTime.of(1, 2, 3, 400), false, 1, null}, + {MONTHS, LocalTime.of(1, 2, 3, 400), false, 1, null}, + {WEEKS, LocalTime.of(1, 2, 3, 400), false, 1, null}, + {DAYS, LocalTime.of(1, 2, 3, 400), false, 1, null}, + + {HALF_DAYS, LocalDate.of(2000, 2, 29), false, 1, null}, + {HOURS, LocalDate.of(2000, 2, 29), false, 1, null}, + {MINUTES, LocalDate.of(2000, 2, 29), false, 1, null}, + {SECONDS, LocalDate.of(2000, 2, 29), false, 1, null}, + {MICROS, LocalDate.of(2000, 2, 29), false, 1, null}, + {MILLIS, LocalDate.of(2000, 2, 29), false, 1, null}, + {NANOS, LocalDate.of(2000, 2, 29), false, 1, null}, + + }; + } + + @Test(dataProvider = "unitAndTemporal") + public void test_unitAndTemporal(ChronoUnit unit, Temporal base, boolean isSupportedBy, long amount, Temporal target) { + assertEquals(unit.isSupportedBy(base), isSupportedBy); + if (isSupportedBy) { + Temporal result = unit.addTo(base, amount); + assertEquals(result, target); + assertEquals(unit.between(base, result), amount); + } + } + + //----------------------------------------------------------------------- + // valueOf() + //----------------------------------------------------------------------- + @Test + public void test_valueOf() { + for (ChronoUnit unit : ChronoUnit.values()) { + assertEquals(ChronoUnit.valueOf(unit.name()), unit); + } + } +} diff --git a/jdk/test/java/time/tck/java/time/temporal/TCKWeekFields.java b/jdk/test/java/time/tck/java/time/temporal/TCKWeekFields.java index ccb1a4ca7b9..4367ee92511 100644 --- a/jdk/test/java/time/tck/java/time/temporal/TCKWeekFields.java +++ b/jdk/test/java/time/tck/java/time/temporal/TCKWeekFields.java @@ -56,16 +56,22 @@ */ package tck.java.time.temporal; +import static java.time.format.ResolverStyle.LENIENT; +import static java.time.format.ResolverStyle.SMART; +import static java.time.format.ResolverStyle.STRICT; import static java.time.temporal.ChronoField.DAY_OF_MONTH; import static java.time.temporal.ChronoField.DAY_OF_WEEK; import static java.time.temporal.ChronoField.DAY_OF_YEAR; import static java.time.temporal.ChronoField.MONTH_OF_YEAR; import static java.time.temporal.ChronoField.YEAR; - import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotEquals; import static org.testng.Assert.assertSame; +import static org.testng.Assert.assertTrue; import java.io.IOException; +import java.time.DateTimeException; import java.time.DayOfWeek; import java.time.LocalDate; import java.time.format.DateTimeFormatter; @@ -376,14 +382,13 @@ public class TCKWeekFields extends AbstractTCKTest { TemporalField womField = week.weekOfMonth(); for (int i = 1; i <= 60; i++) { - // Test that with dayOfWeek and Week of month it computes the date DateTimeFormatter f = new DateTimeFormatterBuilder() - .appendValue(YEAR).appendLiteral('-') - .appendValue(MONTH_OF_YEAR).appendLiteral('-') - .appendValue(womField).appendLiteral('-') - .appendValue(DAY_OF_WEEK).toFormatter(); - String str = date.getYear() + "-" + date.getMonthValue() + "-" + - date.get(womField) + "-" + date.get(DAY_OF_WEEK); + .appendValue(YEAR).appendLiteral(':') + .appendValue(MONTH_OF_YEAR).appendLiteral(':') + .appendValue(womField).appendLiteral(':') + .appendValue(DAY_OF_WEEK).toFormatter().withResolverStyle(SMART); + String str = date.getYear() + ":" + date.getMonthValue() + ":" + + date.get(womField) + ":" + date.get(DAY_OF_WEEK); LocalDate parsed = LocalDate.parse(str, f); assertEquals(parsed, date, " ::" + str + "::" + i); @@ -391,6 +396,52 @@ public class TCKWeekFields extends AbstractTCKTest { } } + @Test(dataProvider="weekFields") + public void test_parse_resolve_localizedWom_lenient(DayOfWeek firstDayOfWeek, int minDays) { + LocalDate date = LocalDate.of(2012, 12, 15); + WeekFields week = WeekFields.of(firstDayOfWeek, minDays); + TemporalField womField = week.weekOfMonth(); + + for (int i = 1; i <= 60; i++) { + DateTimeFormatter f = new DateTimeFormatterBuilder() + .appendValue(YEAR).appendLiteral(':') + .appendValue(MONTH_OF_YEAR).appendLiteral(':') + .appendValue(womField).appendLiteral(':') + .appendValue(DAY_OF_WEEK).toFormatter().withResolverStyle(LENIENT); + int wom = date.get(womField); + int dow = date.get(DAY_OF_WEEK); + for (int j = wom - 10; j < wom + 10; j++) { + String str = date.getYear() + ":" + date.getMonthValue() + ":" + j + ":" + dow; + LocalDate parsed = LocalDate.parse(str, f); + assertEquals(parsed, date.plusWeeks(j - wom), " ::" + str + ": :" + i + "::" + j); + } + + date = date.plusDays(1); + } + } + + @Test(dataProvider="weekFields") + public void test_parse_resolve_localizedWom_strict(DayOfWeek firstDayOfWeek, int minDays) { + WeekFields week = WeekFields.of(firstDayOfWeek, minDays); + TemporalField womField = week.weekOfMonth(); + DateTimeFormatter f = new DateTimeFormatterBuilder() + .appendValue(YEAR).appendLiteral(':') + .appendValue(MONTH_OF_YEAR).appendLiteral(':') + .appendValue(womField).appendLiteral(':') + .appendValue(DAY_OF_WEEK).toFormatter().withResolverStyle(STRICT); + String str = "2012:1:0:1"; + try { + LocalDate date = LocalDate.parse(str, f); + assertEquals(date.getYear(), 2012); + assertEquals(date.getMonthValue(), 1); + assertEquals(date.get(womField), 0); + assertEquals(date.get(DAY_OF_WEEK), 1); + } catch (DateTimeException ex) { + // expected + } + } + + //----------------------------------------------------------------------- @Test(dataProvider="weekFields") public void test_parse_resolve_localizedWomDow(DayOfWeek firstDayOfWeek, int minDays) { LocalDate date = LocalDate.of(2012, 12, 15); @@ -399,14 +450,13 @@ public class TCKWeekFields extends AbstractTCKTest { TemporalField womField = week.weekOfMonth(); for (int i = 1; i <= 15; i++) { - // Test that with dayOfWeek and Week of month it computes the date DateTimeFormatter f = new DateTimeFormatterBuilder() - .appendValue(YEAR).appendLiteral('-') - .appendValue(MONTH_OF_YEAR).appendLiteral('-') - .appendValue(womField).appendLiteral('-') + .appendValue(YEAR).appendLiteral(':') + .appendValue(MONTH_OF_YEAR).appendLiteral(':') + .appendValue(womField).appendLiteral(':') .appendValue(dowField).toFormatter(); - String str = date.getYear() + "-" + date.getMonthValue() + "-" + - date.get(womField) + "-" + date.get(dowField); + String str = date.getYear() + ":" + date.getMonthValue() + ":" + + date.get(womField) + ":" + date.get(dowField); LocalDate parsed = LocalDate.parse(str, f); assertEquals(parsed, date, " :: " + str + " " + i); @@ -414,6 +464,32 @@ public class TCKWeekFields extends AbstractTCKTest { } } + @Test(dataProvider="weekFields") + public void test_parse_resolve_localizedWomDow_lenient(DayOfWeek firstDayOfWeek, int minDays) { + LocalDate date = LocalDate.of(2012, 12, 15); + WeekFields week = WeekFields.of(firstDayOfWeek, minDays); + TemporalField dowField = week.dayOfWeek(); + TemporalField womField = week.weekOfMonth(); + + for (int i = 1; i <= 60; i++) { + DateTimeFormatter f = new DateTimeFormatterBuilder() + .appendValue(YEAR).appendLiteral(':') + .appendValue(MONTH_OF_YEAR).appendLiteral(':') + .appendValue(womField).appendLiteral(':') + .appendValue(dowField).toFormatter().withResolverStyle(LENIENT); + int wom = date.get(womField); + int dow = date.get(dowField); + for (int j = wom - 10; j < wom + 10; j++) { + String str = date.getYear() + ":" + date.getMonthValue() + ":" + j + ":" + dow; + LocalDate parsed = LocalDate.parse(str, f); + assertEquals(parsed, date.plusWeeks(j - wom), " ::" + str + ": :" + i + "::" + j); + } + + date = date.plusDays(1); + } + } + + //----------------------------------------------------------------------- @Test(dataProvider="weekFields") public void test_parse_resolve_localizedWoy(DayOfWeek firstDayOfWeek, int minDays) { LocalDate date = LocalDate.of(2012, 12, 15); @@ -421,14 +497,12 @@ public class TCKWeekFields extends AbstractTCKTest { TemporalField woyField = week.weekOfYear(); for (int i = 1; i <= 60; i++) { - // Test that with dayOfWeek and Week of month it computes the date DateTimeFormatter f = new DateTimeFormatterBuilder() - .appendValue(YEAR).appendLiteral('-') - .appendValue(MONTH_OF_YEAR).appendLiteral('-') - .appendValue(woyField).appendLiteral('-') + .appendValue(YEAR).appendLiteral(':') + .appendValue(woyField).appendLiteral(':') .appendValue(DAY_OF_WEEK).toFormatter(); - String str = date.getYear() + "-" + date.getMonthValue() + "-" + - date.get(woyField) + "-" + date.get(DAY_OF_WEEK); + String str = date.getYear() + ":" + + date.get(woyField) + ":" + date.get(DAY_OF_WEEK); LocalDate parsed = LocalDate.parse(str, f); assertEquals(parsed, date, " :: " + str + " " + i); @@ -436,6 +510,49 @@ public class TCKWeekFields extends AbstractTCKTest { } } + @Test(dataProvider="weekFields") + public void test_parse_resolve_localizedWoy_lenient(DayOfWeek firstDayOfWeek, int minDays) { + LocalDate date = LocalDate.of(2012, 12, 15); + WeekFields week = WeekFields.of(firstDayOfWeek, minDays); + TemporalField woyField = week.weekOfYear(); + + for (int i = 1; i <= 60; i++) { + DateTimeFormatter f = new DateTimeFormatterBuilder() + .appendValue(YEAR).appendLiteral(':') + .appendValue(woyField).appendLiteral(':') + .appendValue(DAY_OF_WEEK).toFormatter().withResolverStyle(LENIENT); + int woy = date.get(woyField); + int dow = date.get(DAY_OF_WEEK); + for (int j = woy - 60; j < woy + 60; j++) { + String str = date.getYear() + ":" + j + ":" + dow; + LocalDate parsed = LocalDate.parse(str, f); + assertEquals(parsed, date.plusWeeks(j - woy), " ::" + str + ": :" + i + "::" + j); + } + + date = date.plusDays(1); + } + } + + @Test(dataProvider="weekFields") + public void test_parse_resolve_localizedWoy_strict(DayOfWeek firstDayOfWeek, int minDays) { + WeekFields week = WeekFields.of(firstDayOfWeek, minDays); + TemporalField woyField = week.weekOfYear(); + DateTimeFormatter f = new DateTimeFormatterBuilder() + .appendValue(YEAR).appendLiteral(':') + .appendValue(woyField).appendLiteral(':') + .appendValue(DAY_OF_WEEK).toFormatter().withResolverStyle(STRICT); + String str = "2012:0:1"; + try { + LocalDate date = LocalDate.parse(str, f); + assertEquals(date.getYear(), 2012); + assertEquals(date.get(woyField), 0); + assertEquals(date.get(DAY_OF_WEEK), 1); + } catch (DateTimeException ex) { + // expected + } + } + + //----------------------------------------------------------------------- @Test(dataProvider="weekFields") public void test_parse_resolve_localizedWoyDow(DayOfWeek firstDayOfWeek, int minDays) { LocalDate date = LocalDate.of(2012, 12, 15); @@ -444,14 +561,13 @@ public class TCKWeekFields extends AbstractTCKTest { TemporalField woyField = week.weekOfYear(); for (int i = 1; i <= 60; i++) { - // Test that with dayOfWeek and Week of month it computes the date DateTimeFormatter f = new DateTimeFormatterBuilder() - .appendValue(YEAR).appendLiteral('-') - .appendValue(MONTH_OF_YEAR).appendLiteral('-') - .appendValue(woyField).appendLiteral('-') + .appendValue(YEAR).appendLiteral(':') + .appendValue(MONTH_OF_YEAR).appendLiteral(':') + .appendValue(woyField).appendLiteral(':') .appendValue(dowField).toFormatter(); - String str = date.getYear() + "-" + date.getMonthValue() + "-" + - date.get(woyField) + "-" + date.get(dowField); + String str = date.getYear() + ":" + date.getMonthValue() + ":" + + date.get(woyField) + ":" + date.get(dowField); LocalDate parsed = LocalDate.parse(str, f); assertEquals(parsed, date, " :: " + str + " " + i); @@ -459,6 +575,31 @@ public class TCKWeekFields extends AbstractTCKTest { } } + @Test(dataProvider="weekFields") + public void test_parse_resolve_localizedWoyDow_lenient(DayOfWeek firstDayOfWeek, int minDays) { + LocalDate date = LocalDate.of(2012, 12, 15); + WeekFields week = WeekFields.of(firstDayOfWeek, minDays); + TemporalField dowField = week.dayOfWeek(); + TemporalField woyField = week.weekOfYear(); + + for (int i = 1; i <= 60; i++) { + DateTimeFormatter f = new DateTimeFormatterBuilder() + .appendValue(YEAR).appendLiteral(':') + .appendValue(woyField).appendLiteral(':') + .appendValue(dowField).toFormatter().withResolverStyle(LENIENT); + int woy = date.get(woyField); + int dow = date.get(dowField); + for (int j = woy - 60; j < woy + 60; j++) { + String str = date.getYear() + ":" + j + ":" + dow; + LocalDate parsed = LocalDate.parse(str, f); + assertEquals(parsed, date.plusWeeks(j - woy), " ::" + str + ": :" + i + "::" + j); + } + + date = date.plusDays(1); + } + } + + //----------------------------------------------------------------------- @Test(dataProvider="weekFields") public void test_parse_resolve_localizedWoWBY(DayOfWeek firstDayOfWeek, int minDays) { LocalDate date = LocalDate.of(2012, 12, 31); @@ -467,12 +608,11 @@ public class TCKWeekFields extends AbstractTCKTest { TemporalField yowbyField = week.weekBasedYear(); for (int i = 1; i <= 60; i++) { - // Test that with dayOfWeek, week of year and year of week-based-year it computes the date DateTimeFormatter f = new DateTimeFormatterBuilder() - .appendValue(yowbyField).appendLiteral('-') - .appendValue(wowbyField).appendLiteral('-') + .appendValue(yowbyField).appendLiteral(':') + .appendValue(wowbyField).appendLiteral(':') .appendValue(DAY_OF_WEEK).toFormatter(); - String str = date.get(yowbyField) + "-" + date.get(wowbyField) + "-" + + String str = date.get(yowbyField) + ":" + date.get(wowbyField) + ":" + date.get(DAY_OF_WEEK); LocalDate parsed = LocalDate.parse(str, f); assertEquals(parsed, date, " :: " + str + " " + i); @@ -481,6 +621,51 @@ public class TCKWeekFields extends AbstractTCKTest { } } + @Test(dataProvider="weekFields") + public void test_parse_resolve_localizedWoWBY_lenient(DayOfWeek firstDayOfWeek, int minDays) { + LocalDate date = LocalDate.of(2012, 12, 31); + WeekFields week = WeekFields.of(firstDayOfWeek, minDays); + TemporalField wowbyField = week.weekOfWeekBasedYear(); + TemporalField yowbyField = week.weekBasedYear(); + + for (int i = 1; i <= 60; i++) { + DateTimeFormatter f = new DateTimeFormatterBuilder() + .appendValue(yowbyField).appendLiteral(':') + .appendValue(wowbyField).appendLiteral(':') + .appendValue(DAY_OF_WEEK).toFormatter().withResolverStyle(LENIENT); + int wowby = date.get(wowbyField); + int dow = date.get(DAY_OF_WEEK); + for (int j = wowby - 60; j < wowby + 60; j++) { + String str = date.get(yowbyField) + ":" + j + ":" + dow; + LocalDate parsed = LocalDate.parse(str, f); + assertEquals(parsed, date.plusWeeks(j - wowby), " ::" + str + ": :" + i + "::" + j); + } + + date = date.plusDays(1); + } + } + + @Test(dataProvider="weekFields") + public void test_parse_resolve_localizedWoWBY_strict(DayOfWeek firstDayOfWeek, int minDays) { + WeekFields week = WeekFields.of(firstDayOfWeek, minDays); + TemporalField wowbyField = week.weekOfWeekBasedYear(); + TemporalField yowbyField = week.weekBasedYear(); + DateTimeFormatter f = new DateTimeFormatterBuilder() + .appendValue(yowbyField).appendLiteral(':') + .appendValue(wowbyField).appendLiteral(':') + .appendValue(DAY_OF_WEEK).toFormatter().withResolverStyle(STRICT); + String str = "2012:0:1"; + try { + LocalDate date = LocalDate.parse(str, f); + assertEquals(date.get(yowbyField), 2012); + assertEquals(date.get(wowbyField), 0); + assertEquals(date.get(DAY_OF_WEEK), 1); + } catch (DateTimeException ex) { + // expected + } + } + + //----------------------------------------------------------------------- @Test(dataProvider="weekFields") public void test_parse_resolve_localizedWoWBYDow(DayOfWeek firstDayOfWeek, int minDays) { LocalDate date = LocalDate.of(2012, 12, 31); @@ -490,12 +675,11 @@ public class TCKWeekFields extends AbstractTCKTest { TemporalField yowbyField = week.weekBasedYear(); for (int i = 1; i <= 60; i++) { - // Test that with dayOfWeek, week of year and year of week-based-year it computes the date DateTimeFormatter f = new DateTimeFormatterBuilder() - .appendValue(yowbyField).appendLiteral('-') - .appendValue(wowbyField).appendLiteral('-') + .appendValue(yowbyField).appendLiteral(':') + .appendValue(wowbyField).appendLiteral(':') .appendValue(dowField).toFormatter(); - String str = date.get(yowbyField) + "-" + date.get(wowbyField) + "-" + + String str = date.get(yowbyField) + ":" + date.get(wowbyField) + ":" + date.get(dowField); LocalDate parsed = LocalDate.parse(str, f); assertEquals(parsed, date, " :: " + str + " " + i); @@ -504,6 +688,31 @@ public class TCKWeekFields extends AbstractTCKTest { } } + @Test(dataProvider="weekFields") + public void test_parse_resolve_localizedWoWBYDow_lenient(DayOfWeek firstDayOfWeek, int minDays) { + LocalDate date = LocalDate.of(2012, 12, 31); + WeekFields week = WeekFields.of(firstDayOfWeek, minDays); + TemporalField dowField = week.dayOfWeek(); + TemporalField wowbyField = week.weekOfWeekBasedYear(); + TemporalField yowbyField = week.weekBasedYear(); + + for (int i = 1; i <= 60; i++) { + DateTimeFormatter f = new DateTimeFormatterBuilder() + .appendValue(yowbyField).appendLiteral(':') + .appendValue(wowbyField).appendLiteral(':') + .appendValue(dowField).toFormatter().withResolverStyle(LENIENT); + int wowby = date.get(wowbyField); + int dow = date.get(dowField); + for (int j = wowby - 60; j < wowby + 60; j++) { + String str = date.get(yowbyField) + ":" + j + ":" + dow; + LocalDate parsed = LocalDate.parse(str, f); + assertEquals(parsed, date.plusWeeks(j - wowby), " ::" + str + ": :" + i + "::" + j); + } + + date = date.plusDays(1); + } + } + //----------------------------------------------------------------------- @Test(dataProvider="weekFields") public void test_serializable_singleton(DayOfWeek firstDayOfWeek, int minDays) throws IOException, ClassNotFoundException { @@ -587,4 +796,21 @@ public class TCKWeekFields extends AbstractTCKTest { assertEquals(date.get(yowbyField), wby); } + //----------------------------------------------------------------------- + // equals() and hashCode(). + //----------------------------------------------------------------------- + @Test + public void test_equals() { + WeekFields weekDef_iso = WeekFields.ISO; + WeekFields weekDef_sundayStart = WeekFields.SUNDAY_START; + + assertTrue(weekDef_iso.equals(WeekFields.of(DayOfWeek.MONDAY, 4))); + assertTrue(weekDef_sundayStart.equals(WeekFields.of(DayOfWeek.SUNDAY, 1))); + assertEquals(weekDef_iso.hashCode(), WeekFields.of(DayOfWeek.MONDAY, 4).hashCode()); + assertEquals(weekDef_sundayStart.hashCode(), WeekFields.of(DayOfWeek.SUNDAY, 1).hashCode()); + + assertFalse(weekDef_iso.equals(weekDef_sundayStart)); + assertNotEquals(weekDef_iso.hashCode(), weekDef_sundayStart.hashCode()); + } + } diff --git a/jdk/test/java/time/tck/java/time/zone/TCKZoneRules.java b/jdk/test/java/time/tck/java/time/zone/TCKZoneRules.java index 4cc630d50be..af07063ebe7 100644 --- a/jdk/test/java/time/tck/java/time/zone/TCKZoneRules.java +++ b/jdk/test/java/time/tck/java/time/zone/TCKZoneRules.java @@ -75,6 +75,7 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.Month; +import java.time.OffsetDateTime; import java.time.Year; import java.time.ZoneId; import java.time.ZoneOffset; @@ -83,6 +84,7 @@ import java.time.zone.ZoneOffsetTransition; import java.time.zone.ZoneOffsetTransitionRule; import java.time.zone.ZoneOffsetTransitionRule.TimeDefinition; import java.time.zone.ZoneRules; +import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -918,6 +920,65 @@ public class TCKZoneRules { assertEquals(test.nextTransition(last.getInstant()), null); } + //----------------------------------------------------------------------- + // Apia + //----------------------------------------------------------------------- + private ZoneRules pacificApia() { + return ZoneId.of("Pacific/Apia").getRules(); + } + + public void test_Apia_nextTransition_historic() { + ZoneRules test = pacificApia(); + List trans = test.getTransitions(); + + ZoneOffsetTransition first = trans.get(0); + assertEquals(test.nextTransition(first.getInstant().minusNanos(1)), first); + + for (int i = 0; i < trans.size() - 1; i++) { + ZoneOffsetTransition cur = trans.get(i); + ZoneOffsetTransition next = trans.get(i + 1); + + assertEquals(test.nextTransition(cur.getInstant()), next); + assertEquals(test.nextTransition(next.getInstant().minusNanos(1)), next); + } + } + + public void test_Apia_jumpOverInternationalDateLine_M10_to_P14() { + // transition occurred at 2011-12-30T00:00-10:00 + ZoneRules test = pacificApia(); + Instant instantBefore = LocalDate.of(2011, 12, 27).atStartOfDay(ZoneOffset.UTC).toInstant(); + ZoneOffsetTransition trans = test.nextTransition(instantBefore); + assertEquals(trans.getDateTimeBefore(), LocalDateTime.of(2011, 12, 30, 0, 0)); + assertEquals(trans.getDateTimeAfter(), LocalDateTime.of(2011, 12, 31, 0, 0)); + assertEquals(trans.isGap(), true); + assertEquals(trans.isOverlap(), false); + assertEquals(trans.isValidOffset(ZoneOffset.ofHours(-10)), false); + assertEquals(trans.isValidOffset(ZoneOffset.ofHours(+14)), false); + assertEquals(trans.getDuration(), Duration.ofHours(24)); + assertEquals(trans.getInstant(), LocalDateTime.of(2011, 12, 31, 0, 0).toInstant(ZoneOffset.ofHours(+14))); + + ZonedDateTime zdt = ZonedDateTime.of(2011, 12, 29, 23, 0, 0, 0, ZoneId.of("Pacific/Apia")); + assertEquals(zdt.plusHours(2).toLocalDateTime(), LocalDateTime.of(2011, 12, 31, 1, 0)); + } + + public void test_Apia_jumpForwardOverInternationalDateLine_P12_to_M12() { + // transition occurred at 1879-07-04T00:00+12:33:04 + ZoneRules test = pacificApia(); + Instant instantBefore = LocalDate.of(1879, 7, 2).atStartOfDay(ZoneOffset.UTC).toInstant(); + ZoneOffsetTransition trans = test.nextTransition(instantBefore); + assertEquals(trans.getDateTimeBefore(), LocalDateTime.of(1879, 7, 5, 0, 0)); + assertEquals(trans.getDateTimeAfter(), LocalDateTime.of(1879, 7, 4, 0, 0)); + assertEquals(trans.isGap(), false); + assertEquals(trans.isOverlap(), true); + assertEquals(trans.isValidOffset(ZoneOffset.ofHoursMinutesSeconds(+12, 33, 4)), true); + assertEquals(trans.isValidOffset(ZoneOffset.ofHoursMinutesSeconds(-11, -26, -56)), true); + assertEquals(trans.getDuration(), Duration.ofHours(-24)); + assertEquals(trans.getInstant(), LocalDateTime.of(1879, 7, 4, 0, 0).toInstant(ZoneOffset.ofHoursMinutesSeconds(-11, -26, -56))); + + ZonedDateTime zdt = ZonedDateTime.of(1879, 7, 4, 23, 0, 0, 0, ZoneId.of("Pacific/Apia")); + assertEquals(zdt.plusHours(2).toLocalDateTime(), LocalDateTime.of(1879, 7, 4, 1, 0, 0)); + } + //------------------------------------------------------------------------- @Test(expectedExceptions=UnsupportedOperationException.class) public void test_getTransitions_immutable() { @@ -931,6 +992,81 @@ public class TCKZoneRules { test.getTransitionRules().clear(); } + //----------------------------------------------------------------------- + // of() + //----------------------------------------------------------------------- + public void test_of(){ + //used for standard offset + ZoneOffset stdOffset1 = ZoneOffset.UTC; + ZoneOffset stdOffset2 = ZoneOffset.ofHours(1); + LocalDateTime time_of_stdOffsetTransition1 = LocalDateTime.of(2013, 1, 5, 1, 0); + ZoneOffsetTransition stdOffsetTransition1 = ZoneOffsetTransition.of(time_of_stdOffsetTransition1, stdOffset1, stdOffset2); + List stdOffsetTransition_list = new ArrayList(); + stdOffsetTransition_list.add(stdOffsetTransition1); + + //used for wall offset + ZoneOffset wallOffset1 = ZoneOffset.ofHours(2); + ZoneOffset wallOffset2 = ZoneOffset.ofHours(4); + ZoneOffset wallOffset3 = ZoneOffset.ofHours(7); + + LocalDateTime time_of_wallOffsetTransition1 = LocalDateTime.of(2013, 2, 5, 1, 0); + LocalDateTime time_of_wallOffsetTransition2 = LocalDateTime.of(2013, 3, 5, 1, 0); + LocalDateTime time_of_wallOffsetTransition3 = LocalDateTime.of(2013, 10, 5, 1, 0); + + ZoneOffsetTransition wallOffsetTransition1 = ZoneOffsetTransition.of(time_of_wallOffsetTransition1, wallOffset1, wallOffset2); + ZoneOffsetTransition wallOffsetTransition2 = ZoneOffsetTransition.of(time_of_wallOffsetTransition2, wallOffset2, wallOffset3); + ZoneOffsetTransition wallOffsetTransition3 = ZoneOffsetTransition.of(time_of_wallOffsetTransition3, wallOffset3, wallOffset1); + + List wallOffsetTransition_list = new ArrayList(); + wallOffsetTransition_list.add(wallOffsetTransition1); + wallOffsetTransition_list.add(wallOffsetTransition2); + wallOffsetTransition_list.add(wallOffsetTransition3); + + //used for ZoneOffsetTransitionRule + ZoneOffset ruleOffset = ZoneOffset.ofHours(3); + ZoneOffsetTransitionRule.TimeDefinition timeDefinition = ZoneOffsetTransitionRule.TimeDefinition.valueOf("WALL"); + ZoneOffsetTransitionRule rule1 = ZoneOffsetTransitionRule.of(Month.FEBRUARY, + 2, + DayOfWeek.MONDAY, + LocalTime.of(1, 0), + false, + timeDefinition, + ZoneOffset.UTC, + ZoneOffset.UTC, + ruleOffset + ); + List rule_list = new ArrayList(); + rule_list.add(rule1); + + //Begin verification + ZoneRules zoneRule = ZoneRules.of(stdOffset1, + wallOffset1, + stdOffsetTransition_list, + wallOffsetTransition_list, + rule_list + ); + + OffsetDateTime before_time_of_stdOffsetTransition1 = OffsetDateTime.of(time_of_stdOffsetTransition1, stdOffset1).minusSeconds(1); + OffsetDateTime after_time_of_stdOffsetTransition1 = OffsetDateTime.of(time_of_stdOffsetTransition1, stdOffset1).plusSeconds(1);; + assertEquals(zoneRule.getStandardOffset(before_time_of_stdOffsetTransition1.toInstant()), stdOffset1); + assertEquals(zoneRule.getStandardOffset(after_time_of_stdOffsetTransition1.toInstant()), stdOffset2); + + OffsetDateTime before_time_of_wallOffsetTransition1 = OffsetDateTime.of(time_of_wallOffsetTransition1, wallOffset1).minusSeconds(1); + OffsetDateTime after_time_of_wallOffsetTransition1 = OffsetDateTime.of(time_of_wallOffsetTransition1, wallOffset1).plusSeconds(1); + assertEquals(zoneRule.nextTransition(before_time_of_wallOffsetTransition1.toInstant()), wallOffsetTransition1); + assertEquals(zoneRule.nextTransition(after_time_of_wallOffsetTransition1.toInstant()), wallOffsetTransition2); + + OffsetDateTime before_time_of_wallOffsetTransition2 = OffsetDateTime.of(time_of_wallOffsetTransition2, wallOffset2).minusSeconds(1); + OffsetDateTime after_time_of_wallOffsetTransition2 = OffsetDateTime.of(time_of_wallOffsetTransition2, wallOffset2).plusSeconds(1); + assertEquals(zoneRule.nextTransition(before_time_of_wallOffsetTransition2.toInstant()), wallOffsetTransition2); + assertEquals(zoneRule.nextTransition(after_time_of_wallOffsetTransition2.toInstant()), wallOffsetTransition3); + + OffsetDateTime before_time_of_wallOffsetTransition3 = OffsetDateTime.of(time_of_wallOffsetTransition3, wallOffset3).minusSeconds(1); + OffsetDateTime after_time_of_wallOffsetTransition3 = OffsetDateTime.of(time_of_wallOffsetTransition3, wallOffset3).plusSeconds(1); + assertEquals(zoneRule.nextTransition(before_time_of_wallOffsetTransition3.toInstant()), wallOffsetTransition3); + assertEquals(zoneRule.nextTransition(after_time_of_wallOffsetTransition3.toInstant()), rule1.createTransition(2014)); + } + //----------------------------------------------------------------------- // equals() / hashCode() //----------------------------------------------------------------------- diff --git a/jdk/test/java/time/test/java/time/MockSimplePeriod.java b/jdk/test/java/time/test/java/time/MockSimplePeriod.java index 2d8f7d5ba9c..7df760847e2 100644 --- a/jdk/test/java/time/test/java/time/MockSimplePeriod.java +++ b/jdk/test/java/time/test/java/time/MockSimplePeriod.java @@ -176,7 +176,7 @@ public final class MockSimplePeriod @Override public String toString() { - return amount + " " + unit.getName(); + return amount + " " + unit; } } diff --git a/jdk/test/java/time/test/java/time/chrono/TestChronoLocalDate.java b/jdk/test/java/time/test/java/time/chrono/TestChronoLocalDate.java index 7865985998e..971b3157fe6 100644 --- a/jdk/test/java/time/test/java/time/chrono/TestChronoLocalDate.java +++ b/jdk/test/java/time/test/java/time/chrono/TestChronoLocalDate.java @@ -60,7 +60,9 @@ import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import java.time.LocalDate; +import java.time.LocalDateTime; import java.time.chrono.ChronoLocalDate; +import java.time.chrono.ChronoLocalDateTime; import java.time.chrono.Chronology; import java.time.chrono.ThaiBuddhistChronology; import java.time.chrono.ThaiBuddhistDate; @@ -80,8 +82,8 @@ public class TestChronoLocalDate { //----------------------------------------------------------------------- public void test_date_comparator_checkGenerics_ISO() { - List> dates = new ArrayList<>(); - ChronoLocalDate date = LocalDate.of(2013, 1, 1); + List dates = new ArrayList<>(); + ChronoLocalDate date = LocalDate.of(2013, 1, 1); // Insert dates in order, no duplicates dates.add(date.minus(10, ChronoUnit.YEARS)); @@ -96,55 +98,7 @@ public class TestChronoLocalDate { dates.add(date.plus(1, ChronoUnit.YEARS)); dates.add(date.plus(10, ChronoUnit.YEARS)); - List> copy = new ArrayList<>(dates); - Collections.shuffle(copy); - Collections.sort(copy, ChronoLocalDate.timeLineOrder()); - assertEquals(copy, dates); - assertTrue(ChronoLocalDate.timeLineOrder().compare(copy.get(0), copy.get(1)) < 0); - } - - public void test_date_comparator_checkGenerics_unknown() { - List> dates = new ArrayList<>(); - ChronoLocalDate date = LocalDate.of(2013, 1, 1); - - // Insert dates in order, no duplicates - dates.add(date.minus(10, ChronoUnit.YEARS)); - dates.add(date.minus(1, ChronoUnit.YEARS)); - dates.add(date.minus(1, ChronoUnit.MONTHS)); - dates.add(date.minus(1, ChronoUnit.WEEKS)); - dates.add(date.minus(1, ChronoUnit.DAYS)); - dates.add(date); - dates.add(date.plus(1, ChronoUnit.DAYS)); - dates.add(date.plus(1, ChronoUnit.WEEKS)); - dates.add(date.plus(1, ChronoUnit.MONTHS)); - dates.add(date.plus(1, ChronoUnit.YEARS)); - dates.add(date.plus(10, ChronoUnit.YEARS)); - - List> copy = new ArrayList<>(dates); - Collections.shuffle(copy); - Collections.sort(copy, ChronoLocalDate.timeLineOrder()); - assertEquals(copy, dates); - assertTrue(ChronoLocalDate.timeLineOrder().compare(copy.get(0), copy.get(1)) < 0); - } - - public > void test_date_comparator_checkGenerics_unknownExtends() { - List> dates = new ArrayList<>(); - ChronoLocalDate date = (ChronoLocalDate) LocalDate.of(2013, 1, 1); // TODO generics raw type - - // Insert dates in order, no duplicates - dates.add(date.minus(10, ChronoUnit.YEARS)); - dates.add(date.minus(1, ChronoUnit.YEARS)); - dates.add(date.minus(1, ChronoUnit.MONTHS)); - dates.add(date.minus(1, ChronoUnit.WEEKS)); - dates.add(date.minus(1, ChronoUnit.DAYS)); - dates.add(date); - dates.add(date.plus(1, ChronoUnit.DAYS)); - dates.add(date.plus(1, ChronoUnit.WEEKS)); - dates.add(date.plus(1, ChronoUnit.MONTHS)); - dates.add(date.plus(1, ChronoUnit.YEARS)); - dates.add(date.plus(10, ChronoUnit.YEARS)); - - List> copy = new ArrayList<>(dates); + List copy = new ArrayList<>(dates); Collections.shuffle(copy); Collections.sort(copy, ChronoLocalDate.timeLineOrder()); assertEquals(copy, dates); @@ -178,13 +132,12 @@ public class TestChronoLocalDate { //----------------------------------------------------------------------- public void test_date_checkGenerics_genericsMethod() { Chronology chrono = ThaiBuddhistChronology.INSTANCE; - ChronoLocalDate date = chrono.dateNow(); - // date = processOK(date); // does not compile + ChronoLocalDate date = chrono.dateNow(); + date = processOK(date); date = processClassOK(ThaiBuddhistDate.class); date = dateSupplier(); - // date = processWeird(date); // does not compile (correct) - // date = processClassWeird(ThaiBuddhistDate.class); // does not compile (correct) + date = processClassWeird(ThaiBuddhistDate.class); } public void test_date_checkGenerics_genericsMethod_concreteType() { @@ -195,12 +148,12 @@ public class TestChronoLocalDate { date = processClassOK(ThaiBuddhistDate.class); date = dateSupplier(); - // date = processWeird(date); // does not compile (correct) // date = processClassWeird(ThaiBuddhistDate.class); // does not compile (correct) } - public > void test_date_checkGenerics_genericsMethod_withType() { + public void test_date_checkGenerics_genericsMethod_withType() { Chronology chrono = ThaiBuddhistChronology.INSTANCE; + @SuppressWarnings("unchecked") D date = (D) chrono.dateNow(); date = processOK(date); // date = processClassOK(ThaiBuddhistDate.class); // does not compile (correct) @@ -210,24 +163,40 @@ public class TestChronoLocalDate { // date = processClassWeird(ThaiBuddhistDate.class); // does not compile (correct) } - private > D dateSupplier() { - return (D) (ChronoLocalDate) ThaiBuddhistChronology.INSTANCE.dateNow(); // TODO raw types + @SuppressWarnings("unchecked") + private D dateSupplier() { + return (D) ThaiBuddhistChronology.INSTANCE.dateNow(); } // decent generics signatures that need to work - private > D processOK(D date) { - return date; + @SuppressWarnings("unchecked") + private D processOK(D date) { + return (D) date.plus(1, ChronoUnit.DAYS); } - private > D processClassOK(Class cls) { + private D processClassOK(Class cls) { return null; } // weird generics signatures that shouldn't really work - private > ChronoLocalDate processWeird(ChronoLocalDate date) { - return date; - } - private > ChronoLocalDate processClassWeird(Class cls) { + private ChronoLocalDate processClassWeird(Class cls) { return null; } + public void test_date_checkGenerics_chronoLocalDateTime1() { + LocalDateTime now = LocalDateTime.now(); + Chronology chrono = ThaiBuddhistChronology.INSTANCE; + ChronoLocalDateTime ldt = chrono.localDateTime(now); + ldt = processCLDT(ldt); + } + + public void test_date_checkGenerics_chronoLocalDateTime2() { + LocalDateTime now = LocalDateTime.now(); + Chronology chrono = ThaiBuddhistChronology.INSTANCE; + ChronoLocalDateTime ldt = chrono.localDateTime(now); + ldt = processCLDT(ldt); + } + + private ChronoLocalDateTime processCLDT(ChronoLocalDateTime dt) { + return dt; + } } diff --git a/jdk/test/java/time/test/java/time/chrono/TestExampleCode.java b/jdk/test/java/time/test/java/time/chrono/TestExampleCode.java index cfa478f488d..434e272da33 100644 --- a/jdk/test/java/time/test/java/time/chrono/TestExampleCode.java +++ b/jdk/test/java/time/test/java/time/chrono/TestExampleCode.java @@ -59,10 +59,14 @@ package test.java.time.chrono; import static org.testng.Assert.assertEquals; +import java.time.LocalDate; import java.time.LocalTime; +import java.time.ZoneId; import java.time.chrono.ChronoLocalDate; import java.time.chrono.ChronoLocalDateTime; +import java.time.chrono.ChronoZonedDateTime; import java.time.chrono.Chronology; +import java.time.chrono.HijrahChronology; import java.time.chrono.HijrahDate; import java.time.chrono.ThaiBuddhistDate; import java.time.temporal.ChronoField; @@ -82,7 +86,7 @@ public class TestExampleCode { @Test public void test_chronoPackageExample() { // Print the Thai Buddhist date - ChronoLocalDate now1 = Chronology.of("ThaiBuddhist").dateNow(); + ChronoLocalDate now1 = Chronology.of("ThaiBuddhist").dateNow(); int day = now1.get(ChronoField.DAY_OF_MONTH); int dow = now1.get(ChronoField.DAY_OF_WEEK); int month = now1.get(ChronoField.MONTH_OF_YEAR); @@ -93,15 +97,15 @@ public class TestExampleCode { // Enumerate the list of available calendars and print today for each Set chronos = Chronology.getAvailableChronologies(); for (Chronology chrono : chronos) { - ChronoLocalDate date = chrono.dateNow(); + ChronoLocalDate date = chrono.dateNow(); System.out.printf(" %20s: %s%n", chrono.getId(), date.toString()); } // Print today's date and the last day of the year for the Thai Buddhist Calendar. - ChronoLocalDate first = now1 + ChronoLocalDate first = now1 .with(ChronoField.DAY_OF_MONTH, 1) .with(ChronoField.MONTH_OF_YEAR, 1); - ChronoLocalDate last = first + ChronoLocalDate last = first .plus(1, ChronoUnit.YEARS) .minus(1, ChronoUnit.DAYS); System.out.printf(" %s: 1st of year: %s; end of year: %s%n", last.getChronology().getId(), @@ -137,7 +141,7 @@ public class TestExampleCode { // Enumerate the list of available calendars and print today for each Set chronos = Chronology.getAvailableChronologies(); for (Chronology chrono : chronos) { - ChronoLocalDate date = chrono.dateNow(); + ChronoLocalDate date = chrono.dateNow(); System.out.printf(" %20s: %s%n", chrono.getId(), date.toString()); } @@ -161,11 +165,31 @@ public class TestExampleCode { first, last); } + void HijrahExample1() { + HijrahDate hd2 = HijrahChronology.INSTANCE.date(1200, 1, 1); + + ChronoLocalDateTime hdt = hd2.atTime(LocalTime.MIDNIGHT); + ChronoZonedDateTime zhdt = hdt.atZone(ZoneId.of("GMT")); + HijrahDate hd3 = zhdt.toLocalDate(); + ChronoLocalDateTime hdt2 = zhdt.toLocalDateTime(); + HijrahDate hd4 = hdt2.toLocalDate(); + + HijrahDate hd5 = next(hd2); + } + + void test_unknownChronologyWithDateTime() { + ChronoLocalDate date = LocalDate.now(); + ChronoLocalDateTime cldt = date.atTime(LocalTime.NOON); + ChronoLocalDate ld = cldt.toLocalDate(); + ChronoLocalDateTime noonTomorrow = tomorrowNoon(ld); + } + @Test public void test_library() { HijrahDate date = HijrahDate.now(); HijrahDate next = next(date); ChronoLocalDateTime noonTomorrow = tomorrowNoon(date); + HijrahDate hd3 = noonTomorrow.toLocalDate(); System.out.printf(" now: %s, noon tomorrow: %s%n", date, noonTomorrow); } @@ -175,8 +199,9 @@ public class TestExampleCode { * @param date a specific date extending ChronoLocalDate * @return a new date in the same chronology. */ - private > D next(D date) { - return date.plus(1, ChronoUnit.DAYS); + @SuppressWarnings("unchecked") + private D next(D date) { + return (D) date.plus(1, ChronoUnit.DAYS); } /** @@ -186,7 +211,8 @@ public class TestExampleCode { * @param date a specific date extending ChronoLocalDate * @return a [@code ChronoLocalDateTime} using the change chronology. */ - private > ChronoLocalDateTime tomorrowNoon(D date) { - return date.plus(1, ChronoUnit.DAYS).atTime(LocalTime.of(12, 0)); + @SuppressWarnings("unchecked") + private ChronoLocalDateTime tomorrowNoon(D date) { + return (ChronoLocalDateTime) date.plus(1, ChronoUnit.DAYS).atTime(LocalTime.of(12, 0)); } } diff --git a/jdk/test/java/time/test/java/time/chrono/TestJapaneseChronoImpl.java b/jdk/test/java/time/test/java/time/chrono/TestJapaneseChronoImpl.java index 282a9f2231d..bcde051e1b9 100644 --- a/jdk/test/java/time/test/java/time/chrono/TestJapaneseChronoImpl.java +++ b/jdk/test/java/time/test/java/time/chrono/TestJapaneseChronoImpl.java @@ -61,12 +61,15 @@ import static org.testng.Assert.assertEquals; import java.time.LocalDate; import java.time.LocalTime; import java.time.OffsetDateTime; +import java.time.ZonedDateTime; import java.time.ZoneOffset; import java.time.chrono.JapaneseChronology; +import java.time.chrono.JapaneseEra; import java.time.chrono.JapaneseDate; import java.time.temporal.ChronoField; import java.time.temporal.ChronoUnit; import java.util.Calendar; +import java.util.GregorianCalendar; import java.util.Locale; import java.util.TimeZone; @@ -85,7 +88,7 @@ public class TestJapaneseChronoImpl { @DataProvider(name="RangeVersusCalendar") Object[][] provider_rangeVersusCalendar() { return new Object[][] { - {LocalDate.of(1868, 1, 1), LocalDate.of(2100, 1, 1)}, + {LocalDate.of(1873, 1, 1), LocalDate.of(2100, 1, 1)}, }; } @@ -118,4 +121,32 @@ public class TestJapaneseChronoImpl { } } + //----------------------------------------------------------------------- + // Verify Japanese Calendar matches java.util.Calendar for number of days + // in years 1 and 2. + //----------------------------------------------------------------------- + @Test + public void test_dayOfYearVsCalendar() { + Locale locale = Locale.forLanguageTag("ja-JP-u-ca-japanese"); + Calendar cal = java.util.Calendar.getInstance(locale); + + for (JapaneseEra era : JapaneseEra.values()) { + for (int year : new int[] {6, 7}) { + JapaneseDate jd = JapaneseChronology.INSTANCE.dateYearDay(era, year, 1); + OffsetDateTime jodt = OffsetDateTime.of(LocalDate.from(jd), LocalTime.MIN, ZoneOffset.UTC); + long millis = jodt.toInstant().toEpochMilli(); + cal.setTimeZone(TimeZone.getTimeZone("GMT+00")); + cal.setTimeInMillis(millis); + + assertEquals(jd.get(ChronoField.DAY_OF_YEAR), cal.get(Calendar.DAY_OF_YEAR), + "different DAY_OF_YEAR values in " + era + ", year: " + year); + assertEquals(jd.range(ChronoField.DAY_OF_YEAR).getMaximum(), cal.getActualMaximum(Calendar.DAY_OF_YEAR), + "different maximum for DAY_OF_YEAR in " + era + ", year: " + year); + assertEquals(jd.range(ChronoField.DAY_OF_YEAR).getMinimum(), cal.getActualMinimum(Calendar.DAY_OF_YEAR), + "different minimum for DAY_OF_YEAR in " + era + ", year: " + year); + } + } + + } + } diff --git a/jdk/test/java/time/test/java/time/chrono/TestJapaneseChronology.java b/jdk/test/java/time/test/java/time/chrono/TestJapaneseChronology.java index b87555dcb51..3fbf8532318 100644 --- a/jdk/test/java/time/test/java/time/chrono/TestJapaneseChronology.java +++ b/jdk/test/java/time/test/java/time/chrono/TestJapaneseChronology.java @@ -47,9 +47,6 @@ public class TestJapaneseChronology { Object[][] transitionData() { return new Object[][] { // Japanese era, yearOfEra, month, dayOfMonth, gregorianYear - { JapaneseEra.SEIREKI, Year.MIN_VALUE, 1, 1, Year.MIN_VALUE }, - { JapaneseEra.SEIREKI, 1867, 12, 31, 1867 }, - { JapaneseEra.MEIJI, 1, 1, 25, 1868 }, // Note: the dates of Meiji 1 to 5 are incorrect { JapaneseEra.MEIJI, 6, 1, 1, 1873 }, // Meiji-Taisho transition isn't accurate. 1912-07-30 is the last day of Meiji // and the first day of Taisho. @@ -84,9 +81,10 @@ public class TestJapaneseChronology { Object[][] rangeData() { return new Object[][] { // field, minSmallest, minLargest, maxSmallest, maxLargest - { ChronoField.ERA, -999, -999, 2, 2}, - { ChronoField.YEAR_OF_ERA, -999999999, 1, 15, 999999999-1989 }, // depends on the current era + { ChronoField.ERA, -1, -1, 2, 2}, + { ChronoField.YEAR_OF_ERA, 1, 1, 15, 999999999-1989 }, // depends on the current era { ChronoField.DAY_OF_YEAR, 1, 1, 7, 366}, + { ChronoField.YEAR, 1873, 1873, 999999999, 999999999}, }; } @@ -94,9 +92,6 @@ public class TestJapaneseChronology { Object[][] invalidDatesData() { return new Object[][] { // Japanese era, yearOfEra, month, dayOfMonth - { JapaneseEra.SEIREKI, Year.MIN_VALUE - 1, 1, 1 }, - { JapaneseEra.SEIREKI, 1855, 2, 29 }, - { JapaneseEra.SEIREKI, 1868, 1, 25 }, { JapaneseEra.MEIJI, 6, 2, 29 }, { JapaneseEra.MEIJI, 45, 7, 30 }, { JapaneseEra.MEIJI, 46, 1, 1 }, @@ -118,8 +113,6 @@ public class TestJapaneseChronology { Object[][] invalidEraYearData() { return new Object[][] { // Japanese era, yearOfEra - { JapaneseEra.SEIREKI, Year.MIN_VALUE - 1 }, - { JapaneseEra.SEIREKI, 2012 }, { JapaneseEra.MEIJI, -1 }, { JapaneseEra.MEIJI, 0 }, { JapaneseEra.MEIJI, 46 }, diff --git a/jdk/test/java/time/test/java/time/chrono/TestUmmAlQuraChronology.java b/jdk/test/java/time/test/java/time/chrono/TestUmmAlQuraChronology.java index 3e1b8a85803..63e433f7ac4 100644 --- a/jdk/test/java/time/test/java/time/chrono/TestUmmAlQuraChronology.java +++ b/jdk/test/java/time/test/java/time/chrono/TestUmmAlQuraChronology.java @@ -28,27 +28,57 @@ package test.java.time.chrono; import static java.time.temporal.ChronoField.DAY_OF_MONTH; import static java.time.temporal.ChronoField.MONTH_OF_YEAR; import static java.time.temporal.ChronoField.YEAR; +import static java.time.temporal.ChronoField.DAY_OF_YEAR; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; import java.time.DateTimeException; +import java.time.DayOfWeek; import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.OffsetDateTime; +import java.time.Period; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.ChronoLocalDateTime; +import java.time.chrono.ChronoZonedDateTime; import java.time.chrono.Chronology; import java.time.chrono.HijrahChronology; import java.time.chrono.HijrahDate; +import java.time.chrono.JapaneseChronology; +import java.time.chrono.JapaneseDate; +import java.time.chrono.MinguoChronology; +import java.time.chrono.MinguoDate; +import java.time.chrono.ThaiBuddhistChronology; +import java.time.chrono.ThaiBuddhistDate; +import java.time.format.DateTimeFormatter; +import java.time.format.FormatStyle; import java.time.temporal.ChronoField; import java.time.temporal.ChronoUnit; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalAdjuster; import java.time.temporal.ValueRange; +import java.time.temporal.WeekFields; +import java.util.Locale; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; /** - * Tests for the Umm alQura chronology and data + * Tests for the Umm alQura chronology and data. + * Note: The dates used for testing are just a sample of calendar data. */ @Test public class TestUmmAlQuraChronology { + private static final ZoneOffset OFFSET_PTWO = ZoneOffset.ofHours(2); + private static final ZoneId ZONE_RIYADH = ZoneId.of("Asia/Riyadh"); + + // Test for HijrahChronology Aliases @Test public void test_aliases() { HijrahChronology hc = (HijrahChronology) Chronology.of("Hijrah"); @@ -57,49 +87,43 @@ public class TestUmmAlQuraChronology { assertEquals(hc, HijrahChronology.INSTANCE, "Alias for Hijrah-umalqura"); } - //----------------------------------------------------------------------- + // Test to check if the exception is thrown for an incorrect chronology id + @Test(expectedExceptions=DateTimeException.class) + public void test_badChronology() { + Chronology test = Chronology.of("Hijrah-ummalqura"); + } + + //-------------------------------------------------------------------------- // regular data factory for Umm alQura dates and the corresponding ISO dates - //----------------------------------------------------------------------- - @DataProvider(name = "UmmalQuraVsISODates") - Object[][] data_of_ummalqura() { - return new Object[][]{ - - //{1318, 01, 01, 1900, 04, 30}, - //{1318, 01, 02, 1900, 05, 01}, - - //{1318, 12, 29, 1901, 04, 18}, - //{1319, 01, 01, 1901, 04, 19}, - - //{1433, 12, 29, 2012, 11, 14}, - //{1434, 01, 01, 2012, 11, 15}, - - {1434, 02, 18, 2012, 12, 31}, - {1434, 02, 19, 2013, 01, 01}, - - //{1502, 12, 30, 2079, 10, 25}, - // not in Umm alQura data {1503, 01, 01, 2079, 10, 26}, - - // not in Umm alQura data {1503, 06, 28, 2080, 04, 18}, - // not in Umm alQura data ~/ws/Downloads + //-------------------------------------------------------------------------- + @DataProvider(name = "UmmAlQuraVsISODates") + Object[][] data_UmmAlQuraVsISODates() { + return new Object[][] { + {HijrahDate.of(1318, 1, 1), LocalDate.of(1900, 04, 30)}, + {HijrahDate.of(1318, 12, 29), LocalDate.of(1901, 04, 19)}, + {HijrahDate.of(1319, 01, 01), LocalDate.of(1901, 04, 20)}, + {HijrahDate.of(1433, 12, 29), LocalDate.of(2012, 11, 14)}, + {HijrahDate.of(1434, 01, 01), LocalDate.of(2012, 11, 15)}, + {HijrahDate.of(1434, 02, 18), LocalDate.of(2012, 12, 31)}, + {HijrahDate.of(1502, 12, 29), LocalDate.of(2079, 10, 25)}, }; } - @Test(dataProvider="UmmalQuraVsISODates") - public void Test_UmmAlQuraDatesVsISO(int h_year, int h_month, int h_day, int iso_year, int iso_month, int iso_day) { - HijrahDate hd = HijrahDate.of(h_year, h_month, h_day); - LocalDate ld = LocalDate.of(iso_year, iso_month, iso_day); + // Test to verify the epoch days for given Hijrah & ISO date instances + @Test(dataProvider="UmmAlQuraVsISODates") + public void Test_UmmAlQuraVsISODates(HijrahDate hd, LocalDate ld) { assertEquals(hd.toEpochDay(), ld.toEpochDay(), "Umm alQura date and ISO date should have same epochDay"); } - + // UmmAlQura chronology ranges for year, month and days for the HijrahChronology @Test public void Test_UmmAlQuraChronoRange() { HijrahChronology chrono = HijrahChronology.INSTANCE; ValueRange year = chrono.range(YEAR); - assertEquals(year.getMinimum(), 1432, "Minimum year"); - assertEquals(year.getLargestMinimum(), 1432, "Largest minimum year"); - assertEquals(year.getMaximum(), 1435, "Largest year"); - assertEquals(year.getSmallestMaximum(), 1435, "Smallest Maximum year"); + assertEquals(year.getMinimum(), 1300, "Minimum year"); + assertEquals(year.getLargestMinimum(), 1300, "Largest minimum year"); + assertEquals(year.getMaximum(), 1600, "Largest year"); + assertEquals(year.getSmallestMaximum(), 1600, "Smallest Maximum year"); ValueRange month = chrono.range(MONTH_OF_YEAR); assertEquals(month.getMinimum(), 1, "Minimum month"); @@ -118,13 +142,17 @@ public class TestUmmAlQuraChronology { // regular data factory for dates and the corresponding range values //----------------------------------------------------------------------- @DataProvider(name = "dates") - Object[][] data_of_calendars() { + Object[][] data_dates() { return new Object[][]{ - {HijrahDate.of(1434, 5, 1), 1432, 1435, 1, 12, 1, 29, 30}, - {HijrahDate.of(1434, 6, 1), 1432, 1435, 1, 12, 1, 30, 30}, + {HijrahDate.of(1300, 5, 1), 1300, 1600, 1, 12, 1, 30, 30}, + {HijrahDate.of(1300, 6, 1), 1300, 1600, 1, 12, 1, 29, 30}, + {HijrahDate.of(1434, 12, 1), 1300, 1600, 1, 12, 1, 29, 30}, + {HijrahDate.of(1500, 4, 1), 1300, 1600, 1, 12, 1, 30, 30}, + {HijrahDate.of(1600, 6, 1), 1300, 1600, 1, 12, 1, 29, 30}, }; } + // Test to verify the min/max field ranges for given dates @Test(dataProvider="dates") public void Test_UmmAlQuraRanges(HijrahDate date, int minYear, int maxYear, @@ -163,6 +191,7 @@ public class TestUmmAlQuraChronology { } + // Check the date limits @Test public void test_hijrahDateLimits() { HijrahChronology chrono = HijrahChronology.INSTANCE; @@ -193,33 +222,547 @@ public class TestUmmAlQuraChronology { } } - @DataProvider(name="badDates") - Object[][] data_badDates() { + // Data provider to verify the dateYearDay() method + @DataProvider(name="dateYearDay") + Object[][] data_dateYearDay() { return new Object[][] { - {1317, 12, 29}, - {1317, 12, 30}, - - {1320, 1, 29 + 1}, - {1320, 2, 30 + 1}, - {1320, 3, 29 + 1}, - {1320, 4, 29 + 1}, - {1320, 5, 30 + 1}, - {1320, 6, 29 + 1}, - {1320, 7, 30 + 1}, - {1320, 8, 30 + 1}, - {1320, 9, 29 + 1}, - {1320, 10, 30 + 1}, - {1320, 11, 30 + 1}, - {1320, 12, 30 + 1}, + {HijrahChronology.INSTANCE.dateYearDay(1434, 42), HijrahChronology.INSTANCE.date(1434, 02, 13)}, + {HijrahChronology.INSTANCE.dateYearDay(1330, 354), HijrahChronology.INSTANCE.date(1330, 12, 29)}, + {HijrahChronology.INSTANCE.dateYearDay(1600, 1), HijrahChronology.INSTANCE.date(1600, 1, 1)}, + {HijrahChronology.INSTANCE.dateYearDay(1400, 175), HijrahChronology.INSTANCE.date(1400, 6, 28)}, + {HijrahChronology.INSTANCE.dateYearDay(1520, 190), HijrahChronology.INSTANCE.date(1520, 7, 13)}, + {HijrahChronology.INSTANCE.dateYearDay(1521, 112), HijrahChronology.INSTANCE.date(1521, 4, 25)}, }; } - @Test(dataProvider="badDates", expectedExceptions=DateTimeException.class) - public void test_badDates(int year, int month, int dom) { - HijrahChronology.INSTANCE.date(year, month, dom); + // Test to verify the dateYearDay() method + @Test(dataProvider="dateYearDay") + public void test_DateYearDay(ChronoLocalDate date1, ChronoLocalDate date2) { + assertEquals(date1, date2); } - void printRange(ValueRange range, Object obj, ChronoField field) { - System.err.printf(" range: min: %d, max: %d; of: %s, field: %s%n", range.getMinimum(), range.getMaximum(), obj.toString(), field.toString()); + //----------------------------------------------------------------------- + // HijrahDate.with(DAY_OF_YEAR, n) + //----------------------------------------------------------------------- + @Test + public void test_getDayOfYear() { + HijrahDate hd1 = HijrahChronology.INSTANCE.dateYearDay(1434, 1); + for (int i = 1; i <= hd1.lengthOfYear(); i++) { + HijrahDate hd = HijrahChronology.INSTANCE.dateYearDay(1434, i); + int doy = hd.get(DAY_OF_YEAR); + assertEquals(doy, i, "get(DAY_OF_YEAR) incorrect for " + i); + } + } + + @Test + public void test_withDayOfYear() { + HijrahDate hd = HijrahChronology.INSTANCE.dateYearDay(1434, 1); + for (int i = 1; i <= hd.lengthOfYear(); i++) { + HijrahDate hd2 = hd.with(DAY_OF_YEAR, i); + int doy = hd2.get(DAY_OF_YEAR); + assertEquals(doy, i, "with(DAY_OF_YEAR) incorrect for " + i + " " + hd2); + } + } + + @Test(expectedExceptions=java.time.DateTimeException.class) + public void test_withDayOfYearTooSmall() { + HijrahDate hd = HijrahChronology.INSTANCE.dateYearDay(1435, 1); + HijrahDate hd2 = hd.with(DAY_OF_YEAR, 0); + } + + @Test(expectedExceptions=java.time.DateTimeException.class) + public void test_withDayOfYearTooLarge() { + HijrahDate hd = HijrahChronology.INSTANCE.dateYearDay(1435, 1); + HijrahDate hd2 = hd.with(DAY_OF_YEAR, hd.lengthOfYear() + 1); + } + + // Test to verify the with() method with ChronoField is set to DAY_OF_WEEK + @Test + public void test_adjustWithDayOfWeek() { + assertEquals(HijrahChronology.INSTANCE.date(1320, 1, 15).with(ChronoField.DAY_OF_WEEK, 4), HijrahDate.of(1320, 1, 15)); + assertEquals(HijrahChronology.INSTANCE.date(1421, 11, 15).with(ChronoField.DAY_OF_WEEK, 1), HijrahDate.of(1421, 11, 11)); + assertEquals(HijrahChronology.INSTANCE.date(1529, 7, 18).with(ChronoField.DAY_OF_WEEK, 6), HijrahDate.of(1529, 7, 20)); + assertEquals(HijrahChronology.INSTANCE.date(1534, 2, 10).with(ChronoField.DAY_OF_WEEK, 5), HijrahDate.of(1534, 2, 12)); + assertEquals(HijrahChronology.INSTANCE.date(1552, 4, 1).with(ChronoField.DAY_OF_WEEK, 2), HijrahDate.of(1552, 3, 26)); + } + + // Test to verify the with() method with ChronoField is set to DAY_OF_MONTH + @Test + public void test_adjustWithDayOfMonth() { + assertEquals(HijrahChronology.INSTANCE.date(1320, 1, 15).with(ChronoField.DAY_OF_MONTH, 2), HijrahDate.of(1320, 1, 2)); + assertEquals(HijrahChronology.INSTANCE.date(1421, 11, 15).with(ChronoField.DAY_OF_MONTH, 9), HijrahDate.of(1421, 11, 9)); + assertEquals(HijrahChronology.INSTANCE.date(1529, 7, 18).with(ChronoField.DAY_OF_MONTH, 13), HijrahDate.of(1529, 7, 13)); + assertEquals(HijrahChronology.INSTANCE.date(1534, 12, 10).with(ChronoField.DAY_OF_MONTH, 29), HijrahDate.of(1534, 12, 29)); + assertEquals(HijrahChronology.INSTANCE.date(1552, 4, 1).with(ChronoField.DAY_OF_MONTH, 6), HijrahDate.of(1552, 4, 6)); + } + + // Test to verify the with() method with ChronoField is set to DAY_OF_YEAR + @Test + public void test_adjustWithDayOfYear() { + assertEquals(HijrahChronology.INSTANCE.date(1320, 1, 15).with(ChronoField.DAY_OF_YEAR, 24), HijrahDate.of(1320, 1, 24)); + assertEquals(HijrahChronology.INSTANCE.date(1421, 11, 15).with(ChronoField.DAY_OF_YEAR, 135), HijrahDate.of(1421, 5, 18)); + assertEquals(HijrahChronology.INSTANCE.date(1529, 7, 18).with(ChronoField.DAY_OF_YEAR, 64), HijrahDate.of(1529, 3, 5)); + assertEquals(HijrahChronology.INSTANCE.date(1534, 2, 10).with(ChronoField.DAY_OF_YEAR, 354), HijrahDate.of(1534, 12, 29)); + assertEquals(HijrahChronology.INSTANCE.date(1552, 4, 1).with(ChronoField.DAY_OF_YEAR, 291), HijrahDate.of(1552, 10, 26)); + } + + // Data provider to get the difference between two dates in terms of days, months and years + @DataProvider(name="datesForDiff") + Object[][] data_datesForDiffs() { + return new Object[][] { + {HijrahDate.of(1350, 5, 15), HijrahDate.of(1351, 12, 29), 574, 19, 1}, + {HijrahDate.of(1434, 5, 1), HijrahDate.of(1434,6, 12), 40, 1, 0}, + {HijrahDate.of(1436, 1, 1), HijrahDate.of(1475, 12, 29), 14173, 479, 39}, + {HijrahDate.of(1500, 6, 12), HijrahDate.of(1551, 7, 12), 18102, 613, 51}, + {HijrahDate.of(1550, 3, 11), HijrahDate.of(1551, 4, 11), 384, 13, 1}, + }; + } + + // Test to verify the difference between two given dates in terms of days, months and years + @Test(dataProvider="datesForDiff") + public void test_diffBetweenDates(ChronoLocalDate from, ChronoLocalDate to, long days, long months, long years) { + assertEquals(from.until(to, ChronoUnit.DAYS), days); + assertEquals(from.until(to, ChronoUnit.MONTHS), months); + assertEquals(from.until(to, ChronoUnit.YEARS), years); + } + + // Data provider to get the difference between two dates as a period + @DataProvider(name="datesForPeriod") + Object[][] data_Period() { + return new Object[][] { + {HijrahDate.of(1350, 5, 15), HijrahDate.of(1434, 7, 20), Period.of(84, 2, 5)}, + {HijrahDate.of(1403, 5, 28), HijrahDate.of(1434, 7, 20), Period.of(31, 1, 22)}, + {HijrahDate.of(1434, 7, 20), HijrahDate.of(1484, 2, 15), Period.of(49, 6, 24)}, + {HijrahDate.of(1500, 6, 12), HijrahDate.of(1450, 4, 21), Period.of(-50, -1, -20)}, + {HijrahDate.of(1549, 3, 11), HijrahDate.of(1550, 3, 10), Period.of(0, 11, 28)}, + }; + } + + // Test to get the Period between two given dates + @Test(dataProvider="datesForPeriod") + public void test_until(HijrahDate h1, HijrahDate h2, Period p) { + Period period = h1.until(h2); + assertEquals(period, p); + } + + // Test to get the Period between dates in different chronologies + @Test(dataProvider="datesForPeriod") + public void test_periodUntilDiffChrono(HijrahDate h1, HijrahDate h2, Period p) { + MinguoDate m = MinguoChronology.INSTANCE.date(h2); + Period period = h1.until(m); + assertEquals(period, p); + } + + // Test to get the adjusted date from a given date using TemporalAdjuster methods + @Test + public void test_temporalDayAdjustments() { + HijrahDate date = HijrahDate.of(1554, 7, 21); + assertEquals(date.with(TemporalAdjuster.firstDayOfMonth()), HijrahDate.of(1554, 7, 1)); + assertEquals(date.with(TemporalAdjuster.lastDayOfMonth()), HijrahDate.of(1554, 7, 29)); + assertEquals(date.with(TemporalAdjuster.firstDayOfNextMonth()), HijrahDate.of(1554, 8, 1)); + assertEquals(date.with(TemporalAdjuster.firstDayOfNextYear()), HijrahDate.of(1555, 1, 1)); + assertEquals(date.with(TemporalAdjuster.firstDayOfYear()), HijrahDate.of(1554, 1, 1)); + assertEquals(date.with(TemporalAdjuster.lastDayOfYear()), HijrahDate.of(1554, 12, 30)); + } + + // Data provider for string representation of the date instances + @DataProvider(name="toString") + Object[][] data_toString() { + return new Object[][] { + {HijrahChronology.INSTANCE.date(1320, 1, 1), "Hijrah-umalqura AH 1320-01-01"}, + {HijrahChronology.INSTANCE.date(1500, 10, 28), "Hijrah-umalqura AH 1500-10-28"}, + {HijrahChronology.INSTANCE.date(1500, 10, 29), "Hijrah-umalqura AH 1500-10-29"}, + {HijrahChronology.INSTANCE.date(1434, 12, 5), "Hijrah-umalqura AH 1434-12-05"}, + {HijrahChronology.INSTANCE.date(1434, 12, 6), "Hijrah-umalqura AH 1434-12-06"}, + }; + } + + // Test to verify the returned string value of a given date instance + @Test(dataProvider="toString") + public void test_toString(ChronoLocalDate hijrahDate, String expected) { + assertEquals(hijrahDate.toString(), expected); + } + + // Data provider for maximum number of days + @DataProvider(name="monthDays") + Object[][] data_monthDays() { + return new Object[][] { + {1432, 1, 29}, + {1432, 4, 30}, + {1433, 12, 29}, + {1434, 1, 29}, + {1435, 8, 29}, + {1435, 9, 30}, + }; + } + + // Test to verify the maximum number of days by adding one month to a given date + @Test (dataProvider="monthDays") + public void test_valueRange_monthDays(int year, int month, int maxlength) { + ChronoLocalDate date = HijrahChronology.INSTANCE.date(year, month, 1); + ValueRange range = null; + for (int i=1; i<=12; i++) { + range = date.range(ChronoField.DAY_OF_MONTH); + date = date.plus(1, ChronoUnit.MONTHS); + assertEquals(range.getMaximum(), month, maxlength); + } + } + + // Test to get the last day of the month by adjusting the date with lastDayOfMonth() method + @Test(dataProvider="monthDays") + public void test_lastDayOfMonth(int year, int month, int numDays) { + HijrahDate hDate = HijrahChronology.INSTANCE.date(year, month, 1); + hDate = hDate.with(TemporalAdjuster.lastDayOfMonth()); + assertEquals(hDate.get(ChronoField.DAY_OF_MONTH), numDays); + } + + // Data provider for the 12 islamic month names in a formatted date + @DataProvider(name="patternMonthNames") + Object[][] data_patternMonthNames() { + return new Object[][] { + {1434, 1, 1, "01 AH Thu Muharram 1434"}, + {1434, 2, 1, "01 AH Fri Safar 1434"}, + {1434, 3, 1, "01 AH Sun Rabi\u02bb I 1434"},//the actual month name is Rabi Al-Awwal, but the locale data contains short form. + {1434, 4, 1, "01 AH Mon Rabi\u02bb II 1434"},//the actual month name is Rabi Al-Akhar, but the locale data contains short form. + {1434, 5, 1, "01 AH Wed Jumada I 1434"},//the actual month name is Jumada Al-Awwal, but the locale data contains short form. + {1434, 6, 1, "01 AH Thu Jumada II 1434"},//the actual month name is Jumada Al-Akhar, but the locale data contains short form. + {1434, 7, 1, "01 AH Sat Rajab 1434"}, + {1434, 8, 1, "01 AH Mon Sha\u02bbban 1434"}, + {1434, 9, 1, "01 AH Tue Ramadan 1434"}, + {1434, 10, 1, "01 AH Thu Shawwal 1434"}, + {1434, 11, 1, "01 AH Sat Dhu\u02bbl-Qi\u02bbdah 1434"}, + {1434, 12, 1, "01 AH Sun Dhu\u02bbl-Hijjah 1434"}, + }; + } + + // Test to verify the formatted dates + @Test(dataProvider="patternMonthNames") + public void test_ofPattern(int year, int month, int day, String expected) { + DateTimeFormatter test = DateTimeFormatter.ofPattern("dd G E MMMM yyyy"); + assertEquals(test.format(HijrahDate.of(year, month, day)), expected); + } + + // Data provider for localized dates + @DataProvider(name="chronoDateTimes") + Object[][] data_chronodatetimes() { + return new Object[][] { + {1432, 12, 29, "Safar 1, 1434 AH"}, + {1433, 1, 30, "Safar 30, 1434 AH"}, + {1434, 6, 30, "Rajab 30, 1435 AH"}, + }; + } + + // Test to verify the localized dates using ofLocalizedDate() method + @Test(dataProvider="chronoDateTimes") + public void test_formatterOfLocalizedDate(int year, int month, int day, String expected) { + HijrahDate hd = HijrahChronology.INSTANCE.date(year, month, day); + ChronoLocalDateTime hdt = hd.atTime(LocalTime.NOON); + hdt = hdt.plus(1, ChronoUnit.YEARS); + hdt = hdt.plus(1, ChronoUnit.MONTHS); + hdt = hdt.plus(1, ChronoUnit.DAYS); + hdt = hdt.plus(1, ChronoUnit.HOURS); + hdt = hdt.plus(1, ChronoUnit.MINUTES); + hdt = hdt.plus(1, ChronoUnit.SECONDS); + DateTimeFormatter df = DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG).withChronology(Chronology.of("Hijrah-umalqura")).withLocale(Locale.forLanguageTag("en-US")); + assertEquals(df.format(hdt), expected); + } + + // Data provider to get the day of the week in a given date + // The day of the week varies if the week starts with a saturday or sunday + @DataProvider(name="dayOfWeek") + Object[][] data_dayOfweek() { + return new Object[][] { + {HijrahDate.of(1434, 6, 24), 1, 7}, + {HijrahDate.of(1432, 9, 3), 5, 4}, + {HijrahDate.of(1334, 12, 29), 7, 6}, + {HijrahDate.of(1354, 5, 24), 1, 7}, + {HijrahDate.of(1465, 10, 2), 2, 1}, + }; + } + + // Test to get the day of the week based on a Saturday/Sunday as the first day of the week + @Test(dataProvider="dayOfWeek") + public void test_dayOfWeek(HijrahDate date, int satStart, int sunStart) { + assertEquals(date.get(WeekFields.of(DayOfWeek.SATURDAY, 7).dayOfWeek()), satStart); + assertEquals(date.get(WeekFields.of(DayOfWeek.SUNDAY, 7).dayOfWeek()), sunStart); + } + + // Data sample to get the epoch days of a date instance + @DataProvider(name="epochDays") + Object[][] data_epochdays() { + return new Object[][] { + {1332, -20486}, + {1334, -19777}, + {1336, -19068}, + {1432, 14950}, + {1434, 15659}, + {1534, 51096}, + {1535, 51450}, + }; + } + + // Test to verify the number of epoch days of a date instance + @Test(dataProvider="epochDays") + public void test_epochDays(int y, long epoch) { + HijrahDate date = HijrahDate.of(y, 1, 1); + assertEquals(date.toEpochDay(), epoch); + } + + // Data provider to verify whether a given hijrah year is a leap year or not + @DataProvider(name="leapYears") + Object[][] data_leapyears() { + return new Object[][] { + {1302, true}, + {1305, false}, + {1315, false}, + {1534, false}, + {1411, true}, + {1429, false}, + {1433, true}, + {1443, true}, + }; + } + + // Test to verify whether a given hijrah year is a leap year or not + @Test(dataProvider="leapYears") + public void test_leapYears(int y, boolean leapyear) { + HijrahDate date = HijrahDate.of(y, 1, 1); + assertEquals(date.isLeapYear(), leapyear); + } + + // Date samples to convert HijrahDate to LocalDate and vice versa + @DataProvider(name="samples") + Object[][] data_samples() { + return new Object[][] { + {HijrahChronology.INSTANCE.date(1319, 12, 30), LocalDate.of(1902, 4, 9)}, + {HijrahChronology.INSTANCE.date(1320, 1, 1), LocalDate.of(1902, 4, 10)}, + {HijrahChronology.INSTANCE.date(1321, 12, 30), LocalDate.of(1904, 3, 18)}, + {HijrahChronology.INSTANCE.date(1433, 7, 29), LocalDate.of(2012, 6, 19)}, + {HijrahChronology.INSTANCE.date(1434, 10, 12), LocalDate.of(2013, 8, 19)}, + {HijrahChronology.INSTANCE.date(1500, 3, 3), LocalDate.of(2077, 1, 28)}, + }; + } + + // Test to get LocalDate instance from a given HijrahDate + @Test(dataProvider="samples") + public void test_toLocalDate(ChronoLocalDate hijrahDate, LocalDate iso) { + assertEquals(LocalDate.from(hijrahDate), iso); + } + + // Test to adjust HijrahDate with a given LocalDate + @Test(dataProvider="samples") + public void test_adjust_toLocalDate(ChronoLocalDate hijrahDate, LocalDate iso) { + assertEquals(hijrahDate.with(iso), hijrahDate); + } + + // Test to get a HijrahDate from a calendrical + @Test(dataProvider="samples") + public void test_fromCalendrical(ChronoLocalDate hijrahDate, LocalDate iso) { + assertEquals(HijrahChronology.INSTANCE.date(iso), hijrahDate); + } + + // Test to verify the day of week of a given HijrahDate and LocalDate + @Test(dataProvider="samples") + public void test_dayOfWeekEqualIsoDayOfWeek(ChronoLocalDate hijrahDate, LocalDate iso) { + assertEquals(hijrahDate.get(ChronoField.DAY_OF_WEEK), iso.get(ChronoField.DAY_OF_WEEK), "Hijrah day of week should be same as ISO day of week"); + } + + // Test to get the local date by applying the MIN adjustment with hijrah date + @Test(dataProvider="samples") + public void test_LocalDate_adjustToHijrahDate(ChronoLocalDate hijrahDate, LocalDate localDate) { + LocalDate test = LocalDate.MIN.with(hijrahDate); + assertEquals(test, localDate); + } + + // Test to get the local date time by applying the MIN adjustment with hijrah date + @Test(dataProvider="samples") + public void test_LocalDateTime_adjustToHijrahDate(ChronoLocalDate hijrahDate, LocalDate localDate) { + LocalDateTime test = LocalDateTime.MIN.with(hijrahDate); + assertEquals(test, LocalDateTime.of(localDate, LocalTime.MIDNIGHT)); + } + + // Sample dates for comparison + @DataProvider(name="datesForComparison") + Object[][] data_datesForComparison() { + return new Object[][] { + {HijrahChronology.INSTANCE.date(1434, 6, 26), LocalDate.of(2013, 5, 5), -1, 1}, + {HijrahChronology.INSTANCE.date(1433, 4, 15), LocalDate.of(2012, 3, 15), 1, -1}, + {HijrahChronology.INSTANCE.date(1432, 5, 21), LocalDate.of(2011, 4, 22), -1, 1}, + {HijrahChronology.INSTANCE.date(1433, 7, 29), LocalDate.of(2012, 6, 2), -1, 1}, + {HijrahChronology.INSTANCE.date(1434, 10, 12), LocalDate.of(2013, 8, 2), -1, 1}, + }; + } + + // Test to compare dates in both forward and reverse order + @Test(dataProvider="datesForComparison") + public void test_compareDates(HijrahDate hdate, LocalDate ldate, int result1, int result2) { + assertEquals(ldate.compareTo(hdate), result1); + assertEquals(hdate.compareTo(ldate), result2); + } + + // Test to verify the values of various chrono fields for a given hijrah date instance + @Test + public void test_chronoFields() { + ChronoLocalDate hdate = HijrahChronology.INSTANCE.date(1434, 6, 28); + assertEquals(hdate.get(ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH), 3); + assertEquals(hdate.get(ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR), 7); + assertEquals(hdate.get(ChronoField.ALIGNED_WEEK_OF_MONTH), 4); + assertEquals(hdate.get(ChronoField.ALIGNED_WEEK_OF_YEAR), 25); + assertEquals(hdate.get(ChronoField.ERA), 1); + assertEquals(hdate.get(ChronoField.YEAR_OF_ERA), 1434); + assertEquals(hdate.get(ChronoField.MONTH_OF_YEAR), 6); + assertEquals(hdate.get(ChronoField.DAY_OF_MONTH), 28); + assertEquals(hdate.get(ChronoField.DAY_OF_WEEK), 3); + assertEquals(hdate.get(ChronoField.DAY_OF_YEAR), 175); + } + + // Test to verify the returned hijrah date after adjusting the day of week as Saturday + @Test + public void test_adjustInto() { + assertEquals(DayOfWeek.SATURDAY.adjustInto(HijrahDate.of(1434, 6, 28)), HijrahDate.of(1434, 7, 1)); + assertEquals(DayOfWeek.SATURDAY.adjustInto(HijrahDate.of(1432, 4, 13)), HijrahDate.of(1432, 4, 14)); + assertEquals(DayOfWeek.SATURDAY.adjustInto(HijrahDate.of(1433, 11, 29)), HijrahDate.of(1433, 12, 4)); + assertEquals(DayOfWeek.SATURDAY.adjustInto(HijrahDate.of(1434, 5, 10)), HijrahDate.of(1434, 5, 11)); + assertEquals(DayOfWeek.SATURDAY.adjustInto(HijrahDate.of(1434, 9, 11)), HijrahDate.of(1434, 9, 12)); + } + + //----------------------------------------------------------------------- + // zonedDateTime(TemporalAccessor) + //----------------------------------------------------------------------- + @DataProvider(name="zonedDateTime") + Object[][] data_zonedDateTime() { + return new Object[][] { + {ZonedDateTime.of(2012, 2, 29, 2, 7, 1, 1, ZONE_RIYADH), HijrahChronology.INSTANCE.date(1433, 4, 7), LocalTime.of(2, 7, 1, 1), null}, + {OffsetDateTime.of(2012, 2, 29, 2, 7, 1, 1, OFFSET_PTWO), HijrahChronology.INSTANCE.date(1433, 4, 7), LocalTime.of(2, 7, 1, 1), null}, + {LocalDateTime.of(2012, 2, 29, 2, 7), null, null, DateTimeException.class}, + {JapaneseDate.of(2012, 2, 29), null, null, DateTimeException.class}, + {ThaiBuddhistDate.of(2012 + 543, 2, 29), null, null, DateTimeException.class}, + {LocalDate.of(2012, 2, 29), null, null, DateTimeException.class}, + {LocalTime.of(20, 30, 29, 0), null, null, DateTimeException.class}, + }; + } + + // Test to check the zoned date times + @Test(dataProvider="zonedDateTime") + public void test_zonedDateTime(TemporalAccessor accessor, HijrahDate expectedDate, LocalTime expectedTime, Class expectedEx) { + if (expectedEx == null) { + ChronoZonedDateTime result = HijrahChronology.INSTANCE.zonedDateTime(accessor); + assertEquals(result.toLocalDate(), expectedDate); + assertEquals(HijrahDate.from(accessor), expectedDate); + assertEquals(result.toLocalTime(), expectedTime); + + } else { + try { + ChronoZonedDateTime result = HijrahChronology.INSTANCE.zonedDateTime(accessor); + fail(); + } catch (Exception ex) { + assertTrue(expectedEx.isInstance(ex)); + } + } + } + + //----------------------------------------------------------------------- + // zonedDateTime(Instant, ZoneId ) + //----------------------------------------------------------------------- + @Test + public void test_Instant_zonedDateTime() { + OffsetDateTime offsetDateTime = OffsetDateTime.of(2012, 2, 29, 2, 7, 1, 1, OFFSET_PTWO); + ZonedDateTime zonedDateTime = ZonedDateTime.of(2012, 2, 29, 2, 7, 1, 1, ZONE_RIYADH); + + ChronoZonedDateTime result = HijrahChronology.INSTANCE.zonedDateTime(offsetDateTime.toInstant(), offsetDateTime.getOffset()); + assertEquals(result.toLocalDate(), HijrahChronology.INSTANCE.date(1433, 4, 7)); + assertEquals(result.toLocalTime(), LocalTime.of(2, 7, 1, 1)); + + result = HijrahChronology.INSTANCE.zonedDateTime(zonedDateTime.toInstant(), zonedDateTime.getOffset()); + assertEquals(result.toLocalDate(), HijrahChronology.INSTANCE.date(1433, 4, 7)); + assertEquals(result.toLocalTime(), LocalTime.of(2, 7, 1, 1)); + } + + //----------------------------------------------------------------------- + // localDateTime() + //----------------------------------------------------------------------- + @DataProvider(name="localDateTime") + Object[][] data_localDateTime() { + return new Object[][] { + {LocalDateTime.of(2012, 2, 29, 2, 7), HijrahChronology.INSTANCE.date(1433, 4, 7), LocalTime.of(2, 7), null}, + {ZonedDateTime.of(2012, 2, 29, 2, 7, 1, 1, ZONE_RIYADH), HijrahChronology.INSTANCE.date(1433, 4, 7), LocalTime.of(2, 7, 1, 1), null}, + {OffsetDateTime.of(2012, 2, 29, 2, 7, 1, 1, OFFSET_PTWO), HijrahChronology.INSTANCE.date(1433, 4, 7), LocalTime.of(2, 7, 1, 1), null}, + {JapaneseDate.of(2012, 2, 29), null, null, DateTimeException.class}, + {ThaiBuddhistDate.of(2012 + 543, 2, 29), null, null, DateTimeException.class}, + {LocalDate.of(2012, 2, 29), null, null, DateTimeException.class}, + {LocalTime.of(20, 30, 29, 0), null, null, DateTimeException.class}, + }; + } + + // Test to verify local date time values from various date instances defined in the localDateTime data provider + @Test(dataProvider="localDateTime") + public void test_localDateTime(TemporalAccessor accessor, HijrahDate expectedDate, LocalTime expectedTime, Class expectedEx) { + if (expectedEx == null) { + ChronoLocalDateTime result = HijrahChronology.INSTANCE.localDateTime(accessor); + assertEquals(result.toLocalDate(), expectedDate); + assertEquals(HijrahDate.from(accessor), expectedDate); + assertEquals(result.toLocalTime(), expectedTime); + } else { + try { + ChronoLocalDateTime result = HijrahChronology.INSTANCE.localDateTime(accessor); + fail(); + } catch (Exception ex) { + assertTrue(expectedEx.isInstance(ex)); + } + } + } + + // Sample Hijrah & Minguo Dates + @DataProvider(name="hijrahToMinguo") + Object[][] data_hijrahToMinguo() { + return new Object[][] { + {HijrahDate.of(1350,5,15), MinguoDate.of(20,9,28)}, + {HijrahDate.of(1434,5,1), MinguoDate.of(102,3,13)}, + {HijrahDate.of(1436,1,1), MinguoDate.of(103,10,25)}, + {HijrahDate.of(1500,6,12), MinguoDate.of(166,5,5)}, + {HijrahDate.of(1550,3,11), MinguoDate.of(214,8,11)}, + }; + } + + // Test to verify the date conversion from Hijrah to Minguo chronology + @Test(dataProvider="hijrahToMinguo") + public void test_hijrahToMinguo(HijrahDate hijrah, MinguoDate minguo) { + assertEquals(MinguoChronology.INSTANCE.date(hijrah), minguo); + } + + // Sample Hijrah & Thai Dates + @DataProvider(name="hijrahToThai") + Object[][] data_hijrahToThai() { + return new Object[][] { + {HijrahDate.of(1350,5,15), ThaiBuddhistDate.of(2474,9,28)}, + {HijrahDate.of(1434,5,1), ThaiBuddhistDate.of(2556,3,13)}, + {HijrahDate.of(1436,1,1), ThaiBuddhistDate.of(2557,10,25)}, + {HijrahDate.of(1500,6,12), ThaiBuddhistDate.of(2620,5,5)}, + {HijrahDate.of(1550,3,11), ThaiBuddhistDate.of(2668,8,11)}, + }; + } + + // Test to verify the date conversion from Hijrah to Thai chronology + @Test(dataProvider="hijrahToThai") + public void test_hijrahToThai(HijrahDate hijrah, ThaiBuddhistDate thai) { + assertEquals(ThaiBuddhistChronology.INSTANCE.date(hijrah), thai); + } + + // Sample Hijrah & Japanese Dates + @DataProvider(name="hijrahToJapanese") + Object[][] data_hijrahToJapanese() { + return new Object[][] { + {HijrahDate.of(1350,5,15), "Japanese Showa 6-09-28"}, + {HijrahDate.of(1434,5,1), "Japanese Heisei 25-03-13"}, + {HijrahDate.of(1436,1,1), "Japanese Heisei 26-10-25"}, + {HijrahDate.of(1500,6,12), "Japanese Heisei 89-05-05"}, + {HijrahDate.of(1550,3,11), "Japanese Heisei 137-08-11"}, + }; + } + + // Test to verify the date conversion from Hijrah to Japanese chronology + @Test(dataProvider="hijrahToJapanese") + public void test_hijrahToJapanese(HijrahDate hijrah, String japanese) { + assertEquals(JapaneseChronology.INSTANCE.date(hijrah).toString(), japanese); } } diff --git a/jdk/test/java/time/test/java/time/format/TestDateTimeTextProvider.java b/jdk/test/java/time/test/java/time/format/TestDateTimeTextProvider.java index 056dfa22dcd..aebccfddc12 100644 --- a/jdk/test/java/time/test/java/time/format/TestDateTimeTextProvider.java +++ b/jdk/test/java/time/test/java/time/format/TestDateTimeTextProvider.java @@ -131,18 +131,18 @@ public class TestDateTimeTextProvider extends AbstractTestPrinterParser { {MONTH_OF_YEAR, 11, TextStyle.SHORT, enUS, "Nov"}, {MONTH_OF_YEAR, 12, TextStyle.SHORT, enUS, "Dec"}, - {MONTH_OF_YEAR, 1, TextStyle.SHORT, ptBR, "Jan"}, - {MONTH_OF_YEAR, 2, TextStyle.SHORT, ptBR, "Fev"}, - {MONTH_OF_YEAR, 3, TextStyle.SHORT, ptBR, "Mar"}, - {MONTH_OF_YEAR, 4, TextStyle.SHORT, ptBR, "Abr"}, - {MONTH_OF_YEAR, 5, TextStyle.SHORT, ptBR, "Mai"}, - {MONTH_OF_YEAR, 6, TextStyle.SHORT, ptBR, "Jun"}, - {MONTH_OF_YEAR, 7, TextStyle.SHORT, ptBR, "Jul"}, - {MONTH_OF_YEAR, 8, TextStyle.SHORT, ptBR, "Ago"}, - {MONTH_OF_YEAR, 9, TextStyle.SHORT, ptBR, "Set"}, - {MONTH_OF_YEAR, 10, TextStyle.SHORT, ptBR, "Out"}, - {MONTH_OF_YEAR, 11, TextStyle.SHORT, ptBR, "Nov"}, - {MONTH_OF_YEAR, 12, TextStyle.SHORT, ptBR, "Dez"}, + {MONTH_OF_YEAR, 1, TextStyle.SHORT, ptBR, "jan"}, + {MONTH_OF_YEAR, 2, TextStyle.SHORT, ptBR, "fev"}, + {MONTH_OF_YEAR, 3, TextStyle.SHORT, ptBR, "mar"}, + {MONTH_OF_YEAR, 4, TextStyle.SHORT, ptBR, "abr"}, + {MONTH_OF_YEAR, 5, TextStyle.SHORT, ptBR, "mai"}, + {MONTH_OF_YEAR, 6, TextStyle.SHORT, ptBR, "jun"}, + {MONTH_OF_YEAR, 7, TextStyle.SHORT, ptBR, "jul"}, + {MONTH_OF_YEAR, 8, TextStyle.SHORT, ptBR, "ago"}, + {MONTH_OF_YEAR, 9, TextStyle.SHORT, ptBR, "set"}, + {MONTH_OF_YEAR, 10, TextStyle.SHORT, ptBR, "out"}, + {MONTH_OF_YEAR, 11, TextStyle.SHORT, ptBR, "nov"}, + {MONTH_OF_YEAR, 12, TextStyle.SHORT, ptBR, "dez"}, {MONTH_OF_YEAR, 1, TextStyle.FULL, enUS, "January"}, {MONTH_OF_YEAR, 2, TextStyle.FULL, enUS, "February"}, diff --git a/jdk/test/java/time/test/java/time/format/TestNonIsoFormatter.java b/jdk/test/java/time/test/java/time/format/TestNonIsoFormatter.java index 49ec4d6554f..af6be84ef92 100644 --- a/jdk/test/java/time/test/java/time/format/TestNonIsoFormatter.java +++ b/jdk/test/java/time/test/java/time/format/TestNonIsoFormatter.java @@ -126,7 +126,7 @@ public class TestNonIsoFormatter { @Test(dataProvider="format_data") public void test_formatLocalizedDate(Chronology chrono, Locale formatLocale, Locale numberingLocale, - ChronoLocalDate date, String expected) { + ChronoLocalDate date, String expected) { DateTimeFormatter dtf = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL) .withChronology(chrono).withLocale(formatLocale) .withDecimalStyle(DecimalStyle.of(numberingLocale)); @@ -136,12 +136,12 @@ public class TestNonIsoFormatter { @Test(dataProvider="format_data") public void test_parseLocalizedText(Chronology chrono, Locale formatLocale, Locale numberingLocale, - ChronoLocalDate expected, String text) { + ChronoLocalDate expected, String text) { DateTimeFormatter dtf = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL) .withChronology(chrono).withLocale(formatLocale) .withDecimalStyle(DecimalStyle.of(numberingLocale)); TemporalAccessor temporal = dtf.parse(text); - ChronoLocalDate date = chrono.date(temporal); + ChronoLocalDate date = chrono.date(temporal); assertEquals(date, expected); } diff --git a/jdk/test/java/time/test/java/time/format/TestNumberPrinter.java b/jdk/test/java/time/test/java/time/format/TestNumberPrinter.java index 9d686472ab6..dedcc37e2ce 100644 --- a/jdk/test/java/time/test/java/time/format/TestNumberPrinter.java +++ b/jdk/test/java/time/test/java/time/format/TestNumberPrinter.java @@ -191,7 +191,7 @@ public class TestNumberPrinter extends AbstractTestPrinterParser { assertEquals(buf.toString(), result); } catch (DateTimeException ex) { if (result == null || value < 0) { - assertEquals(ex.getMessage().contains(DAY_OF_MONTH.getName()), true); + assertEquals(ex.getMessage().contains(DAY_OF_MONTH.toString()), true); } else { throw ex; } @@ -210,7 +210,7 @@ public class TestNumberPrinter extends AbstractTestPrinterParser { if (result != null) { throw ex; } - assertEquals(ex.getMessage().contains(DAY_OF_MONTH.getName()), true); + assertEquals(ex.getMessage().contains(DAY_OF_MONTH.toString()), true); } } @@ -226,7 +226,7 @@ public class TestNumberPrinter extends AbstractTestPrinterParser { if (result != null) { throw ex; } - assertEquals(ex.getMessage().contains(DAY_OF_MONTH.getName()), true); + assertEquals(ex.getMessage().contains(DAY_OF_MONTH.toString()), true); } } @@ -242,7 +242,7 @@ public class TestNumberPrinter extends AbstractTestPrinterParser { if (result != null) { throw ex; } - assertEquals(ex.getMessage().contains(DAY_OF_MONTH.getName()), true); + assertEquals(ex.getMessage().contains(DAY_OF_MONTH.toString()), true); } } @@ -262,7 +262,7 @@ public class TestNumberPrinter extends AbstractTestPrinterParser { if (result != null) { throw ex; } - assertEquals(ex.getMessage().contains(DAY_OF_MONTH.getName()), true); + assertEquals(ex.getMessage().contains(DAY_OF_MONTH.toString()), true); } } diff --git a/jdk/test/java/time/test/java/time/format/TestReducedPrinter.java b/jdk/test/java/time/test/java/time/format/TestReducedPrinter.java index 5ff2cd5eed8..c23cff27373 100644 --- a/jdk/test/java/time/test/java/time/format/TestReducedPrinter.java +++ b/jdk/test/java/time/test/java/time/format/TestReducedPrinter.java @@ -185,7 +185,7 @@ public class TestReducedPrinter extends AbstractTestPrinterParser { assertEquals(buf.toString(), result); } catch (DateTimeException ex) { if (result == null || value < 0) { - assertEquals(ex.getMessage().contains(YEAR.getName()), true); + assertEquals(ex.getMessage().contains(YEAR.toString()), true); } else { throw ex; } diff --git a/jdk/test/java/time/test/java/time/temporal/MockFieldNoValue.java b/jdk/test/java/time/test/java/time/temporal/MockFieldNoValue.java index eb97313ae19..ed2f6d59b10 100644 --- a/jdk/test/java/time/test/java/time/temporal/MockFieldNoValue.java +++ b/jdk/test/java/time/test/java/time/temporal/MockFieldNoValue.java @@ -76,11 +76,6 @@ public enum MockFieldNoValue implements TemporalField { INSTANCE; - @Override - public String getName() { - return null; - } - @Override public TemporalUnit getBaseUnit() { return WEEKS; @@ -96,6 +91,16 @@ public enum MockFieldNoValue implements TemporalField { return ValueRange.of(1, 20); } + @Override + public boolean isDateBased() { + return false; + } + + @Override + public boolean isTimeBased() { + return false; + } + //----------------------------------------------------------------------- @Override public boolean isSupportedBy(TemporalAccessor temporal) { @@ -117,4 +122,9 @@ public enum MockFieldNoValue implements TemporalField { throw new DateTimeException("Mock"); } + @Override + public String toString() { + return null; + } + } diff --git a/jdk/test/java/time/test/java/time/temporal/MockFieldValue.java b/jdk/test/java/time/test/java/time/temporal/MockFieldValue.java index 0cd79d7f1e9..7747bda7714 100644 --- a/jdk/test/java/time/test/java/time/temporal/MockFieldValue.java +++ b/jdk/test/java/time/test/java/time/temporal/MockFieldValue.java @@ -89,7 +89,7 @@ public final class MockFieldValue implements TemporalAccessor { if (isSupported(field)) { return field.range(); } - throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName()); + throw new UnsupportedTemporalTypeException("Unsupported field: " + field); } return field.rangeRefinedBy(this); }