--- old/src/share/classes/java/time/format/DateTimePrintContext.java 2013-04-11 23:15:46.000000000 -0700 +++ new/src/share/classes/java/time/format/DateTimePrintContext.java 2013-04-11 23:15:45.000000000 -0700 @@ -63,14 +63,16 @@ import static java.time.temporal.ChronoField.EPOCH_DAY; import static java.time.temporal.ChronoField.INSTANT_SECONDS; +import static java.time.temporal.ChronoField.OFFSET_SECONDS; import java.time.DateTimeException; import java.time.Instant; import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.chrono.ChronoLocalDate; import java.time.chrono.Chronology; +import java.time.chrono.IsoChronology; import java.time.temporal.ChronoField; -import java.time.chrono.ChronoLocalDate; -import java.time.temporal.Queries; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalField; import java.time.temporal.TemporalQuery; @@ -118,20 +120,20 @@ } private static TemporalAccessor adjust(final TemporalAccessor temporal, DateTimeFormatter formatter) { - // normal case first + // normal case first (early return is an optimization) Chronology overrideChrono = formatter.getChronology(); ZoneId overrideZone = formatter.getZone(); if (overrideChrono == null && overrideZone == null) { return temporal; } - // ensure minimal change - Chronology temporalChrono = Chronology.from(temporal); // default to ISO, handles Instant - ZoneId temporalZone = temporal.query(Queries.zone()); // zone then offset, handles OffsetDateTime - if (temporal.isSupported(EPOCH_DAY) == false || Objects.equals(overrideChrono, temporalChrono)) { + // ensure minimal change (early return is an optimization) + Chronology temporalChrono = temporal.query(TemporalQuery.chronology()); + ZoneId temporalZone = temporal.query(TemporalQuery.zoneId()); + if (Objects.equals(overrideChrono, temporalChrono)) { overrideChrono = null; } - if (temporal.isSupported(INSTANT_SECONDS) == false || Objects.equals(overrideZone, temporalZone)) { + if (Objects.equals(overrideZone, temporalZone)) { overrideZone = null; } if (overrideChrono == null && overrideZone == null) { @@ -139,53 +141,83 @@ } // make adjustment - if (overrideChrono != null && overrideZone != null) { - return overrideChrono.zonedDateTime(Instant.from(temporal), overrideZone); - } else if (overrideZone != null) { - return temporalChrono.zonedDateTime(Instant.from(temporal), overrideZone); - } else { // overrideChrono != null - // need class here to handle non-standard cases - final ChronoLocalDate date = overrideChrono.date(temporal); - return new TemporalAccessor() { - @Override - public boolean isSupported(TemporalField field) { - return temporal.isSupported(field); - } - @Override - public ValueRange range(TemporalField field) { - if (field instanceof ChronoField) { - if (((ChronoField) field).isDateField()) { - return date.range(field); - } else { - return temporal.range(field); + final Chronology effectiveChrono = (overrideChrono != null ? overrideChrono : temporalChrono); + if (overrideZone != null) { + // if have zone and instant, calculation is simple, defaulting chrono if necessary + if (temporal.isSupported(INSTANT_SECONDS)) { + Chronology chrono = (effectiveChrono != null ? effectiveChrono : IsoChronology.INSTANCE); + return chrono.zonedDateTime(Instant.from(temporal), overrideZone); + } + // block changing zone on OffsetTime, and similar problem cases + if (overrideZone.normalized() instanceof ZoneOffset && temporal.isSupported(OFFSET_SECONDS) && + temporal.get(OFFSET_SECONDS) != overrideZone.getRules().getOffset(Instant.EPOCH).getTotalSeconds()) { + throw new DateTimeException("Unable to apply override zone '" + overrideZone + + "' because the temporal object being formatted has a different offset but" + + " does not represent an instant: " + temporal); + } + } + final ZoneId effectiveZone = (overrideZone != null ? overrideZone : temporalZone); + final ChronoLocalDate effectiveDate; + if (overrideChrono != null) { + if (temporal.isSupported(EPOCH_DAY)) { + effectiveDate = effectiveChrono.date(temporal); + } else { + // check for date fields other than epoch-day, ignoring case of converting null to ISO + if (!(overrideChrono == IsoChronology.INSTANCE && temporalChrono == null)) { + for (ChronoField f : ChronoField.values()) { + if (f.isDateBased() && temporal.isSupported(f)) { + throw new DateTimeException("Unable to apply override chronology '" + overrideChrono + + "' because the temporal object being formatted contains date fields but" + + " does not represent a whole date: " + temporal); } } - return field.rangeRefinedBy(this); } - @Override - public long getLong(TemporalField field) { - if (field instanceof ChronoField) { - if (((ChronoField) field).isDateField()) { - return date.getLong(field); - } else { - return temporal.getLong(field); - } - } - return field.getFrom(this); + effectiveDate = null; + } + } else { + effectiveDate = null; + } + + // combine available data + // this is a non-standard temporal that is almost a pure delegate + // this better handles map-like underlying temporal instances + return new TemporalAccessor() { + @Override + public boolean isSupported(TemporalField field) { + if (effectiveDate != null && field.isDateBased()) { + return effectiveDate.isSupported(field); } - @SuppressWarnings("unchecked") - @Override - public R query(TemporalQuery query) { - if (query == Queries.chronology()) { - return (R) date.getChronology(); - } - if (query == Queries.zoneId() || query == Queries.precision()) { - return temporal.query(query); - } - return query.queryFrom(this); + return temporal.isSupported(field); + } + @Override + public ValueRange range(TemporalField field) { + if (effectiveDate != null && field.isDateBased()) { + return effectiveDate.range(field); } - }; - } + return temporal.range(field); + } + @Override + public long getLong(TemporalField field) { + if (effectiveDate != null && field.isDateBased()) { + return effectiveDate.getLong(field); + } + return temporal.getLong(field); + } + @SuppressWarnings("unchecked") + @Override + public R query(TemporalQuery query) { + if (query == TemporalQuery.chronology()) { + return (R) effectiveChrono; + } + if (query == TemporalQuery.zoneId()) { + return (R) effectiveZone; + } + if (query == TemporalQuery.precision()) { + return temporal.query(query); + } + return query.queryFrom(this); + } + }; } //-----------------------------------------------------------------------