OpenJDK / jdk / hs
changeset 23573:f42dcef4fb7f
8033662: DateTimeFormatter parsing ignores withZone()
Summary: to include the set "zone" in resolved result
Reviewed-by: sherman, chegar
Contributed-by: scolebourne@joda.org
author | sherman |
---|---|
date | Mon, 24 Mar 2014 12:47:02 -0700 |
parents | 0b4b0e183619 |
children | 089eeff81e86 |
files | jdk/src/share/classes/java/time/format/DateTimeFormatter.java jdk/src/share/classes/java/time/format/DateTimeParseContext.java jdk/src/share/classes/java/time/format/Parsed.java jdk/test/java/time/tck/java/time/format/TCKDateTimeParseResolver.java |
diffstat | 4 files changed, 300 insertions(+), 214 deletions(-) [+] |
line wrap: on
line diff
--- a/jdk/src/share/classes/java/time/format/DateTimeFormatter.java Mon Mar 24 17:07:08 2014 +0100 +++ b/jdk/src/share/classes/java/time/format/DateTimeFormatter.java Mon Mar 24 12:47:02 2014 -0700 @@ -1932,8 +1932,8 @@ */ private TemporalAccessor parseResolved0(final CharSequence text, final ParsePosition position) { ParsePosition pos = (position != null ? position : new ParsePosition(0)); - Parsed unresolved = parseUnresolved0(text, pos); - if (unresolved == null || pos.getErrorIndex() >= 0 || (position == null && pos.getIndex() < text.length())) { + DateTimeParseContext context = parseUnresolved0(text, pos); + if (context == null || pos.getErrorIndex() >= 0 || (position == null && pos.getIndex() < text.length())) { String abbr; if (text.length() > 64) { abbr = text.subSequence(0, 64).toString() + "..."; @@ -1948,7 +1948,7 @@ pos.getIndex(), text, pos.getIndex()); } } - return unresolved.resolve(resolverStyle, resolverFields); + return context.toResolved(resolverStyle, resolverFields); } /** @@ -1991,10 +1991,14 @@ * @throws IndexOutOfBoundsException if the position is invalid */ public TemporalAccessor parseUnresolved(CharSequence text, ParsePosition position) { - return parseUnresolved0(text, position); + DateTimeParseContext context = parseUnresolved0(text, position); + if (context == null) { + return null; + } + return context.toUnresolved(); } - private Parsed parseUnresolved0(CharSequence text, ParsePosition position) { + private DateTimeParseContext parseUnresolved0(CharSequence text, ParsePosition position) { Objects.requireNonNull(text, "text"); Objects.requireNonNull(position, "position"); DateTimeParseContext context = new DateTimeParseContext(this); @@ -2005,7 +2009,7 @@ return null; } position.setIndex(pos); // errorIndex not updated from input - return context.toParsed(); + return context; } //----------------------------------------------------------------------- @@ -2126,23 +2130,23 @@ @Override public Object parseObject(String text, ParsePosition pos) { Objects.requireNonNull(text, "text"); - Parsed unresolved; + DateTimeParseContext context; try { - unresolved = formatter.parseUnresolved0(text, pos); + context = formatter.parseUnresolved0(text, pos); } catch (IndexOutOfBoundsException ex) { if (pos.getErrorIndex() < 0) { pos.setErrorIndex(0); } return null; } - if (unresolved == null) { + if (context == null) { if (pos.getErrorIndex() < 0) { pos.setErrorIndex(0); } return null; } try { - TemporalAccessor resolved = unresolved.resolve(formatter.resolverStyle, formatter.resolverFields); + TemporalAccessor resolved = context.toResolved(formatter.resolverStyle, formatter.resolverFields); if (parseType == null) { return resolved; }
--- a/jdk/src/share/classes/java/time/format/DateTimeParseContext.java Mon Mar 24 17:07:08 2014 +0100 +++ b/jdk/src/share/classes/java/time/format/DateTimeParseContext.java Mon Mar 24 12:47:02 2014 -0700 @@ -64,10 +64,12 @@ import java.time.ZoneId; import java.time.chrono.Chronology; import java.time.chrono.IsoChronology; +import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalField; import java.util.ArrayList; import java.util.Locale; import java.util.Objects; +import java.util.Set; import java.util.function.Consumer; /** @@ -77,8 +79,8 @@ * It has the ability to store and retrieve the parsed values and manage optional segments. * It also provides key information to the parsing methods. * <p> - * Once parsing is complete, the {@link #toParsed()} is used to obtain the data. - * It contains a method to resolve the separate parsed fields into meaningful values. + * Once parsing is complete, the {@link #toUnresolved()} is used to obtain the unresolved + * result data. The {@link #toResolved()} is used to obtain the resolved result. * * @implSpec * This class is a mutable context intended for use from a single thread. @@ -309,16 +311,27 @@ } /** - * Gets the result of the parse. + * Gets the unresolved result of the parse. * * @return the result of the parse, not null */ - Parsed toParsed() { + Parsed toUnresolved() { + return currentParsed(); + } + + /** + * Gets the resolved result of the parse. + * + * @return the result of the parse, not null + */ + TemporalAccessor toResolved(ResolverStyle resolverStyle, Set<TemporalField> resolverFields) { Parsed parsed = currentParsed(); - parsed.effectiveChrono = getEffectiveChronology(); - return parsed; + parsed.chrono = getEffectiveChronology(); + parsed.zone = (parsed.zone != null ? parsed.zone : formatter.getZone()); + return parsed.resolve(resolverStyle, resolverFields); } + //----------------------------------------------------------------------- /** * Gets the first value that was parsed for the specified field.
--- a/jdk/src/share/classes/java/time/format/Parsed.java Mon Mar 24 17:07:08 2014 +0100 +++ b/jdk/src/share/classes/java/time/format/Parsed.java Mon Mar 24 12:47:02 2014 -0700 @@ -136,10 +136,6 @@ */ boolean leapSecond; /** - * The effective chronology. - */ - Chronology effectiveChrono; - /** * The resolver style to use. */ private ResolverStyle resolverStyle; @@ -241,7 +237,6 @@ fieldValues.keySet().retainAll(resolverFields); } this.resolverStyle = resolverStyle; - chrono = effectiveChrono; resolveFields(); resolveTimeLenient(); crossCheck(); @@ -266,14 +261,16 @@ TemporalAccessor resolvedObject = targetField.resolve(fieldValues, this, resolverStyle); if (resolvedObject != null) { if (resolvedObject instanceof ChronoZonedDateTime) { - ChronoZonedDateTime<?> czdt = (ChronoZonedDateTime) resolvedObject; - if (zone.equals(czdt.getZone()) == false) { + ChronoZonedDateTime<?> czdt = (ChronoZonedDateTime<?>) resolvedObject; + if (zone == null) { + zone = czdt.getZone(); + } else if (zone.equals(czdt.getZone()) == false) { throw new DateTimeException("ChronoZonedDateTime must use the effective parsed zone: " + zone); } resolvedObject = czdt.toLocalDateTime(); } if (resolvedObject instanceof ChronoLocalDateTime) { - ChronoLocalDateTime<?> cldt = (ChronoLocalDateTime) resolvedObject; + ChronoLocalDateTime<?> cldt = (ChronoLocalDateTime<?>) resolvedObject; updateCheckConflict(cldt.toLocalTime(), Period.ZERO); updateCheckConflict(cldt.toLocalDate()); changedCount++;
--- a/jdk/test/java/time/tck/java/time/format/TCKDateTimeParseResolver.java Mon Mar 24 17:07:08 2014 +0100 +++ b/jdk/test/java/time/tck/java/time/format/TCKDateTimeParseResolver.java Mon Mar 24 12:47:02 2014 -0700 @@ -90,9 +90,6 @@ 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.ChronoUnit.DAYS; -import static java.time.temporal.ChronoUnit.FOREVER; -import static java.time.temporal.ChronoUnit.NANOS; import static org.testng.Assert.assertEquals; import static org.testng.Assert.fail; @@ -102,13 +99,17 @@ import java.time.Period; import java.time.ZoneId; import java.time.ZonedDateTime; -import java.time.chrono.Chronology; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.ChronoLocalDateTime; +import java.time.chrono.ChronoZonedDateTime; +import java.time.chrono.IsoChronology; +import java.time.chrono.MinguoChronology; +import java.time.chrono.MinguoDate; import java.time.chrono.ThaiBuddhistChronology; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.format.DateTimeParseException; import java.time.format.ResolverStyle; -import java.time.temporal.ChronoUnit; import java.time.temporal.IsoFields; import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; @@ -129,6 +130,9 @@ // TODO: tests with weird TenporalField implementations // TODO: tests with non-ISO chronologies + private static final ZoneId EUROPE_ATHENS = ZoneId.of("Europe/Athens"); + private static final ZoneId EUROPE_PARIS = ZoneId.of("Europe/Paris"); + //----------------------------------------------------------------------- @DataProvider(name="resolveOneNoChange") Object[][] data_resolveOneNoChange() { @@ -886,205 +890,273 @@ } //----------------------------------------------------------------------- + // SPEC: DateTimeFormatter.withChronology() @Test - public void test_fieldResolvesToLocalTime() { - TemporalField field = new TemporalField() { - @Override - public TemporalUnit getBaseUnit() { - throw new UnsupportedOperationException(); - } - @Override - public TemporalUnit getRangeUnit() { - throw new UnsupportedOperationException(); - } - @Override - public ValueRange range() { - throw new UnsupportedOperationException(); - } - @Override - public boolean isDateBased() { - throw new UnsupportedOperationException(); - } - @Override - public boolean isTimeBased() { - throw new UnsupportedOperationException(); - } - @Override - public boolean isSupportedBy(TemporalAccessor temporal) { - throw new UnsupportedOperationException(); - } - @Override - public ValueRange rangeRefinedBy(TemporalAccessor temporal) { - throw new UnsupportedOperationException(); - } - @Override - public long getFrom(TemporalAccessor temporal) { - throw new UnsupportedOperationException(); - } - @Override - public <R extends Temporal> R adjustInto(R temporal, long newValue) { - throw new UnsupportedOperationException(); - } - @Override - public TemporalAccessor resolve( - Map<TemporalField, Long> fieldValues, TemporalAccessor partialTemporal, ResolverStyle resolverStyle) { - return LocalTime.MIDNIGHT.plusNanos(fieldValues.remove(this)); - } - }; - DateTimeFormatter f = new DateTimeFormatterBuilder().appendValue(field).toFormatter(); - TemporalAccessor accessor = f.parse("1234567890"); - assertEquals(accessor.query(TemporalQueries.localDate()), null); - assertEquals(accessor.query(TemporalQueries.localTime()), LocalTime.of(0, 0, 1, 234_567_890)); + public void test_withChronology_noOverride() { + DateTimeFormatter f = new DateTimeFormatterBuilder().parseDefaulting(EPOCH_DAY, 2).toFormatter(); + TemporalAccessor accessor = f.parse(""); + assertEquals(accessor.query(TemporalQueries.localDate()), LocalDate.of(1970, 1, 3)); + assertEquals(accessor.query(TemporalQueries.localTime()), null); + assertEquals(accessor.query(TemporalQueries.chronology()), IsoChronology.INSTANCE); } @Test - public void test_fieldResolvesToChronoLocalDateTime() { - TemporalField field = new TemporalField() { - @Override - public TemporalUnit getBaseUnit() { - throw new UnsupportedOperationException(); - } - @Override - public TemporalUnit getRangeUnit() { - throw new UnsupportedOperationException(); - } - @Override - public ValueRange range() { - throw new UnsupportedOperationException(); - } - @Override - public boolean isDateBased() { - throw new UnsupportedOperationException(); - } - @Override - public boolean isTimeBased() { - throw new UnsupportedOperationException(); - } - @Override - public boolean isSupportedBy(TemporalAccessor temporal) { - throw new UnsupportedOperationException(); - } - @Override - public ValueRange rangeRefinedBy(TemporalAccessor temporal) { - throw new UnsupportedOperationException(); - } - @Override - public long getFrom(TemporalAccessor temporal) { - throw new UnsupportedOperationException(); - } - @Override - public <R extends Temporal> R adjustInto(R temporal, long newValue) { - throw new UnsupportedOperationException(); - } - @Override - public TemporalAccessor resolve( - Map<TemporalField, Long> fieldValues, TemporalAccessor partialTemporal, ResolverStyle resolverStyle) { - fieldValues.remove(this); - return LocalDateTime.of(2010, 6, 30, 12, 30); - } - }; - DateTimeFormatter f = new DateTimeFormatterBuilder().appendValue(field).toFormatter(); + public void test_withChronology_override() { + DateTimeFormatter f = new DateTimeFormatterBuilder().parseDefaulting(EPOCH_DAY, 2).toFormatter(); + f = f.withChronology(MinguoChronology.INSTANCE); + TemporalAccessor accessor = f.parse(""); + assertEquals(accessor.query(TemporalQueries.localDate()), LocalDate.of(1970, 1, 3)); + assertEquals(accessor.query(TemporalQueries.localTime()), null); + assertEquals(accessor.query(TemporalQueries.chronology()), MinguoChronology.INSTANCE); + } + + @Test + public void test_withChronology_parsedChronology_noOverride() { + DateTimeFormatter f = new DateTimeFormatterBuilder().parseDefaulting(EPOCH_DAY, 2).appendChronologyId().toFormatter(); + TemporalAccessor accessor = f.parse("ThaiBuddhist"); + assertEquals(accessor.query(TemporalQueries.localDate()), LocalDate.of(1970, 1, 3)); + assertEquals(accessor.query(TemporalQueries.localTime()), null); + assertEquals(accessor.query(TemporalQueries.chronology()), ThaiBuddhistChronology.INSTANCE); + } + + @Test + public void test_withChronology_parsedChronology_override() { + DateTimeFormatter f = new DateTimeFormatterBuilder().parseDefaulting(EPOCH_DAY, 2).appendChronologyId().toFormatter(); + f = f.withChronology(MinguoChronology.INSTANCE); + TemporalAccessor accessor = f.parse("ThaiBuddhist"); + assertEquals(accessor.query(TemporalQueries.localDate()), LocalDate.of(1970, 1, 3)); + assertEquals(accessor.query(TemporalQueries.localTime()), null); + assertEquals(accessor.query(TemporalQueries.chronology()), ThaiBuddhistChronology.INSTANCE); + } + + //----------------------------------------------------------------------- + // SPEC: DateTimeFormatter.withZone() + @Test + public void test_withZone_noOverride() { + DateTimeFormatter f = new DateTimeFormatterBuilder().parseDefaulting(EPOCH_DAY, 2).toFormatter(); + TemporalAccessor accessor = f.parse(""); + assertEquals(accessor.query(TemporalQueries.localDate()), LocalDate.of(1970, 1, 3)); + assertEquals(accessor.query(TemporalQueries.localTime()), null); + assertEquals(accessor.query(TemporalQueries.zoneId()), null); + } + + @Test + public void test_withZone_override() { + DateTimeFormatter f = new DateTimeFormatterBuilder().parseDefaulting(EPOCH_DAY, 2).toFormatter(); + f = f.withZone(EUROPE_ATHENS); + TemporalAccessor accessor = f.parse(""); + assertEquals(accessor.query(TemporalQueries.localDate()), LocalDate.of(1970, 1, 3)); + assertEquals(accessor.query(TemporalQueries.localTime()), null); + assertEquals(accessor.query(TemporalQueries.zoneId()), EUROPE_ATHENS); + } + + @Test + public void test_withZone_parsedZone_noOverride() { + DateTimeFormatter f = new DateTimeFormatterBuilder().parseDefaulting(EPOCH_DAY, 2).appendZoneId().toFormatter(); + TemporalAccessor accessor = f.parse("Europe/Paris"); + assertEquals(accessor.query(TemporalQueries.localDate()), LocalDate.of(1970, 1, 3)); + assertEquals(accessor.query(TemporalQueries.localTime()), null); + assertEquals(accessor.query(TemporalQueries.zoneId()), EUROPE_PARIS); + } + + @Test + public void test_withZone_parsedZone_override() { + DateTimeFormatter f = new DateTimeFormatterBuilder().parseDefaulting(EPOCH_DAY, 2).appendZoneId().toFormatter(); + f = f.withZone(EUROPE_ATHENS); + TemporalAccessor accessor = f.parse("Europe/Paris"); + assertEquals(accessor.query(TemporalQueries.localDate()), LocalDate.of(1970, 1, 3)); + assertEquals(accessor.query(TemporalQueries.localTime()), null); + assertEquals(accessor.query(TemporalQueries.zoneId()), EUROPE_PARIS); + } + + //----------------------------------------------------------------------- + @Test + public void test_fieldResolvesToLocalTime() { + LocalTime lt = LocalTime.of(12, 30, 40); + DateTimeFormatter f = new DateTimeFormatterBuilder().appendValue(new ResolvingField(lt)).toFormatter(); + TemporalAccessor accessor = f.parse("1234567890"); + assertEquals(accessor.query(TemporalQueries.localDate()), null); + assertEquals(accessor.query(TemporalQueries.localTime()), lt); + } + + //------------------------------------------------------------------------- + @Test + public void test_fieldResolvesToChronoLocalDate_noOverrideChrono_matches() { + LocalDate ldt = LocalDate.of(2010, 6, 30); + DateTimeFormatter f = new DateTimeFormatterBuilder().appendValue(new ResolvingField(ldt)).toFormatter(); TemporalAccessor accessor = f.parse("1234567890"); assertEquals(accessor.query(TemporalQueries.localDate()), LocalDate.of(2010, 6, 30)); - assertEquals(accessor.query(TemporalQueries.localTime()), LocalTime.of(12, 30)); + assertEquals(accessor.query(TemporalQueries.localTime()), null); + assertEquals(accessor.query(TemporalQueries.chronology()), IsoChronology.INSTANCE); + } + + @Test + public void test_fieldResolvesToChronoLocalDate_overrideChrono_matches() { + MinguoDate mdt = MinguoDate.of(100, 6, 30); + DateTimeFormatter f = new DateTimeFormatterBuilder().appendValue(new ResolvingField(mdt)).toFormatter(); + f = f.withChronology(MinguoChronology.INSTANCE); + TemporalAccessor accessor = f.parse("1234567890"); + assertEquals(accessor.query(TemporalQueries.localDate()), LocalDate.from(mdt)); + assertEquals(accessor.query(TemporalQueries.localTime()), null); + assertEquals(accessor.query(TemporalQueries.chronology()), MinguoChronology.INSTANCE); } @Test(expectedExceptions = DateTimeParseException.class) - public void test_fieldResolvesWrongChrono() { - TemporalField field = new TemporalField() { - @Override - public TemporalUnit getBaseUnit() { - throw new UnsupportedOperationException(); - } - @Override - public TemporalUnit getRangeUnit() { - throw new UnsupportedOperationException(); - } - @Override - public ValueRange range() { - throw new UnsupportedOperationException(); - } - @Override - public boolean isDateBased() { - throw new UnsupportedOperationException(); - } - @Override - public boolean isTimeBased() { - throw new UnsupportedOperationException(); - } - @Override - public boolean isSupportedBy(TemporalAccessor temporal) { - throw new UnsupportedOperationException(); - } - @Override - public ValueRange rangeRefinedBy(TemporalAccessor temporal) { - throw new UnsupportedOperationException(); - } - @Override - public long getFrom(TemporalAccessor temporal) { - throw new UnsupportedOperationException(); - } - @Override - public <R extends Temporal> R adjustInto(R temporal, long newValue) { - throw new UnsupportedOperationException(); - } - @Override - public TemporalAccessor resolve( - Map<TemporalField, Long> fieldValues, TemporalAccessor partialTemporal, ResolverStyle resolverStyle) { - return ThaiBuddhistChronology.INSTANCE.dateNow(); - } - }; - DateTimeFormatter f = new DateTimeFormatterBuilder().appendValue(field).toFormatter(); + public void test_fieldResolvesToChronoLocalDate_noOverrideChrono_wrongChrono() { + ChronoLocalDate cld = ThaiBuddhistChronology.INSTANCE.dateNow(); + DateTimeFormatter f = new DateTimeFormatterBuilder().appendValue(new ResolvingField(cld)).toFormatter(); f.parse("1234567890"); } @Test(expectedExceptions = DateTimeParseException.class) - public void test_fieldResolvesWrongZone() { - TemporalField field = new TemporalField() { - @Override - public TemporalUnit getBaseUnit() { - throw new UnsupportedOperationException(); - } - @Override - public TemporalUnit getRangeUnit() { - throw new UnsupportedOperationException(); - } - @Override - public ValueRange range() { - throw new UnsupportedOperationException(); - } - @Override - public boolean isDateBased() { - throw new UnsupportedOperationException(); - } - @Override - public boolean isTimeBased() { - throw new UnsupportedOperationException(); - } - @Override - public boolean isSupportedBy(TemporalAccessor temporal) { - throw new UnsupportedOperationException(); - } - @Override - public ValueRange rangeRefinedBy(TemporalAccessor temporal) { - throw new UnsupportedOperationException(); - } - @Override - public long getFrom(TemporalAccessor temporal) { - throw new UnsupportedOperationException(); - } - @Override - public <R extends Temporal> R adjustInto(R temporal, long newValue) { - throw new UnsupportedOperationException(); - } - @Override - public TemporalAccessor resolve( - Map<TemporalField, Long> fieldValues, TemporalAccessor partialTemporal, ResolverStyle resolverStyle) { - return ZonedDateTime.of(2010, 6, 30, 12, 30, 0, 0, ZoneId.of("Europe/Paris")); - } - }; - DateTimeFormatter f = new DateTimeFormatterBuilder().appendValue(field).toFormatter().withZone(ZoneId.of("Europe/London")); + public void test_fieldResolvesToChronoLocalDate_overrideChrono_wrongChrono() { + ChronoLocalDate cld = ThaiBuddhistChronology.INSTANCE.dateNow(); + DateTimeFormatter f = new DateTimeFormatterBuilder().appendValue(new ResolvingField(cld)).toFormatter(); + f = f.withChronology(MinguoChronology.INSTANCE); f.parse("1234567890"); } + //------------------------------------------------------------------------- + @Test + public void test_fieldResolvesToChronoLocalDateTime_noOverrideChrono_matches() { + LocalDateTime ldt = LocalDateTime.of(2010, 6, 30, 12, 30); + DateTimeFormatter f = new DateTimeFormatterBuilder().appendValue(new ResolvingField(ldt)).toFormatter(); + TemporalAccessor accessor = f.parse("1234567890"); + assertEquals(accessor.query(TemporalQueries.localDate()), LocalDate.of(2010, 6, 30)); + assertEquals(accessor.query(TemporalQueries.localTime()), LocalTime.of(12, 30)); + assertEquals(accessor.query(TemporalQueries.chronology()), IsoChronology.INSTANCE); + } + + @Test + public void test_fieldResolvesToChronoLocalDateTime_overrideChrono_matches() { + MinguoDate mdt = MinguoDate.of(100, 6, 30); + DateTimeFormatter f = new DateTimeFormatterBuilder().appendValue(new ResolvingField(mdt.atTime(LocalTime.NOON))).toFormatter(); + f = f.withChronology(MinguoChronology.INSTANCE); + TemporalAccessor accessor = f.parse("1234567890"); + assertEquals(accessor.query(TemporalQueries.localDate()), LocalDate.from(mdt)); + assertEquals(accessor.query(TemporalQueries.localTime()), LocalTime.NOON); + assertEquals(accessor.query(TemporalQueries.chronology()), MinguoChronology.INSTANCE); + } + + @Test(expectedExceptions = DateTimeParseException.class) + public void test_fieldResolvesToChronoLocalDateTime_noOverrideChrono_wrongChrono() { + ChronoLocalDateTime<?> cldt = ThaiBuddhistChronology.INSTANCE.dateNow().atTime(LocalTime.NOON); + DateTimeFormatter f = new DateTimeFormatterBuilder().appendValue(new ResolvingField(cldt)).toFormatter(); + f.parse("1234567890"); + } + + @Test(expectedExceptions = DateTimeParseException.class) + public void test_fieldResolvesToChronoLocalDateTime_overrideChrono_wrongChrono() { + ChronoLocalDateTime<?> cldt = ThaiBuddhistChronology.INSTANCE.dateNow().atTime(LocalTime.NOON); + DateTimeFormatter f = new DateTimeFormatterBuilder().appendValue(new ResolvingField(cldt)).toFormatter(); + f = f.withChronology(MinguoChronology.INSTANCE); + f.parse("1234567890"); + } + + //------------------------------------------------------------------------- + @Test + public void test_fieldResolvesToChronoZonedDateTime_noOverrideChrono_matches() { + ZonedDateTime zdt = ZonedDateTime.of(2010, 6, 30, 12, 30, 0, 0, EUROPE_PARIS); + DateTimeFormatter f = new DateTimeFormatterBuilder().appendValue(new ResolvingField(zdt)).toFormatter(); + TemporalAccessor accessor = f.parse("1234567890"); + assertEquals(accessor.query(TemporalQueries.localDate()), LocalDate.of(2010, 6, 30)); + assertEquals(accessor.query(TemporalQueries.localTime()), LocalTime.of(12, 30)); + assertEquals(accessor.query(TemporalQueries.chronology()), IsoChronology.INSTANCE); + assertEquals(accessor.query(TemporalQueries.zoneId()), EUROPE_PARIS); + } + + @Test + public void test_fieldResolvesToChronoZonedDateTime_overrideChrono_matches() { + MinguoDate mdt = MinguoDate.of(100, 6, 30); + ChronoZonedDateTime<MinguoDate> mzdt = mdt.atTime(LocalTime.NOON).atZone(EUROPE_PARIS); + DateTimeFormatter f = new DateTimeFormatterBuilder().appendValue(new ResolvingField(mzdt)).toFormatter(); + f = f.withChronology(MinguoChronology.INSTANCE); + TemporalAccessor accessor = f.parse("1234567890"); + assertEquals(accessor.query(TemporalQueries.localDate()), LocalDate.from(mdt)); + assertEquals(accessor.query(TemporalQueries.localTime()), LocalTime.NOON); + assertEquals(accessor.query(TemporalQueries.chronology()), MinguoChronology.INSTANCE); + assertEquals(accessor.query(TemporalQueries.zoneId()), EUROPE_PARIS); + } + + @Test(expectedExceptions = DateTimeParseException.class) + public void test_fieldResolvesToChronoZonedDateTime_noOverrideChrono_wrongChrono() { + ChronoZonedDateTime<?> cldt = ThaiBuddhistChronology.INSTANCE.dateNow().atTime(LocalTime.NOON).atZone(EUROPE_PARIS); + DateTimeFormatter f = new DateTimeFormatterBuilder().appendValue(new ResolvingField(cldt)).toFormatter(); + f.parse("1234567890"); + } + + @Test(expectedExceptions = DateTimeParseException.class) + public void test_fieldResolvesToChronoZonedDateTime_overrideChrono_wrongChrono() { + ChronoZonedDateTime<?> cldt = ThaiBuddhistChronology.INSTANCE.dateNow().atTime(LocalTime.NOON).atZone(EUROPE_PARIS); + DateTimeFormatter f = new DateTimeFormatterBuilder().appendValue(new ResolvingField(cldt)).toFormatter(); + f = f.withChronology(MinguoChronology.INSTANCE); + f.parse("1234567890"); + } + + @Test + public void test_fieldResolvesToChronoZonedDateTime_overrideZone_matches() { + ZonedDateTime zdt = ZonedDateTime.of(2010, 6, 30, 12, 30, 0, 0, EUROPE_PARIS); + DateTimeFormatter f = new DateTimeFormatterBuilder().appendValue(new ResolvingField(zdt)).toFormatter(); + f = f.withZone(EUROPE_PARIS); + assertEquals(f.parse("1234567890", ZonedDateTime::from), zdt); + } + + @Test(expectedExceptions = DateTimeParseException.class) + public void test_fieldResolvesToChronoZonedDateTime_overrideZone_wrongZone() { + ZonedDateTime zdt = ZonedDateTime.of(2010, 6, 30, 12, 30, 0, 0, EUROPE_PARIS); + DateTimeFormatter f = new DateTimeFormatterBuilder().appendValue(new ResolvingField(zdt)).toFormatter(); + f = f.withZone(ZoneId.of("Europe/London")); + f.parse("1234567890"); + } + + //------------------------------------------------------------------------- + private static class ResolvingField implements TemporalField { + private final TemporalAccessor resolvedValue; + ResolvingField(TemporalAccessor resolvedValue) { + this.resolvedValue = resolvedValue; + } + @Override + public TemporalUnit getBaseUnit() { + throw new UnsupportedOperationException(); + } + @Override + public TemporalUnit getRangeUnit() { + throw new UnsupportedOperationException(); + } + @Override + public ValueRange range() { + throw new UnsupportedOperationException(); + } + @Override + public boolean isDateBased() { + throw new UnsupportedOperationException(); + } + @Override + public boolean isTimeBased() { + throw new UnsupportedOperationException(); + } + @Override + public boolean isSupportedBy(TemporalAccessor temporal) { + throw new UnsupportedOperationException(); + } + @Override + public ValueRange rangeRefinedBy(TemporalAccessor temporal) { + throw new UnsupportedOperationException(); + } + @Override + public long getFrom(TemporalAccessor temporal) { + throw new UnsupportedOperationException(); + } + @Override + public <R extends Temporal> R adjustInto(R temporal, long newValue) { + throw new UnsupportedOperationException(); + } + @Override + public TemporalAccessor resolve( + Map<TemporalField, Long> fieldValues, TemporalAccessor partialTemporal, ResolverStyle resolverStyle) { + fieldValues.remove(this); + return resolvedValue; + } + }; + }