Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/java/time/format/Parsed.java
38918 views
/*1* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425/*26* This file is available under and governed by the GNU General Public27* License version 2 only, as published by the Free Software Foundation.28* However, the following notice accompanied the original version of this29* file:30*31* Copyright (c) 2008-2013, Stephen Colebourne & Michael Nascimento Santos32*33* All rights reserved.34*35* Redistribution and use in source and binary forms, with or without36* modification, are permitted provided that the following conditions are met:37*38* * Redistributions of source code must retain the above copyright notice,39* this list of conditions and the following disclaimer.40*41* * Redistributions in binary form must reproduce the above copyright notice,42* this list of conditions and the following disclaimer in the documentation43* and/or other materials provided with the distribution.44*45* * Neither the name of JSR-310 nor the names of its contributors46* may be used to endorse or promote products derived from this software47* without specific prior written permission.48*49* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS50* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT51* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR52* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR53* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,54* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,55* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR56* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF57* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING58* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS59* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.60*/61package java.time.format;6263import static java.time.temporal.ChronoField.AMPM_OF_DAY;64import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_AMPM;65import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_DAY;66import static java.time.temporal.ChronoField.HOUR_OF_AMPM;67import static java.time.temporal.ChronoField.HOUR_OF_DAY;68import static java.time.temporal.ChronoField.INSTANT_SECONDS;69import static java.time.temporal.ChronoField.MICRO_OF_DAY;70import static java.time.temporal.ChronoField.MICRO_OF_SECOND;71import static java.time.temporal.ChronoField.MILLI_OF_DAY;72import static java.time.temporal.ChronoField.MILLI_OF_SECOND;73import static java.time.temporal.ChronoField.MINUTE_OF_DAY;74import static java.time.temporal.ChronoField.MINUTE_OF_HOUR;75import static java.time.temporal.ChronoField.NANO_OF_DAY;76import static java.time.temporal.ChronoField.NANO_OF_SECOND;77import static java.time.temporal.ChronoField.OFFSET_SECONDS;78import static java.time.temporal.ChronoField.SECOND_OF_DAY;79import static java.time.temporal.ChronoField.SECOND_OF_MINUTE;8081import java.time.DateTimeException;82import java.time.Instant;83import java.time.LocalDate;84import java.time.LocalTime;85import java.time.Period;86import java.time.ZoneId;87import java.time.ZoneOffset;88import java.time.chrono.ChronoLocalDate;89import java.time.chrono.ChronoLocalDateTime;90import java.time.chrono.ChronoZonedDateTime;91import java.time.chrono.Chronology;92import java.time.temporal.ChronoField;93import java.time.temporal.TemporalAccessor;94import java.time.temporal.TemporalField;95import java.time.temporal.TemporalQueries;96import java.time.temporal.TemporalQuery;97import java.time.temporal.UnsupportedTemporalTypeException;98import java.util.HashMap;99import java.util.Iterator;100import java.util.Map;101import java.util.Map.Entry;102import java.util.Objects;103import java.util.Set;104105/**106* A store of parsed data.107* <p>108* This class is used during parsing to collect the data. Part of the parsing process109* involves handling optional blocks and multiple copies of the data get created to110* support the necessary backtracking.111* <p>112* Once parsing is completed, this class can be used as the resultant {@code TemporalAccessor}.113* In most cases, it is only exposed once the fields have been resolved.114*115* @implSpec116* This class is a mutable context intended for use from a single thread.117* Usage of the class is thread-safe within standard parsing as a new instance of this class118* is automatically created for each parse and parsing is single-threaded119*120* @since 1.8121*/122final class Parsed implements TemporalAccessor {123// some fields are accessed using package scope from DateTimeParseContext124125/**126* The parsed fields.127*/128final Map<TemporalField, Long> fieldValues = new HashMap<>();129/**130* The parsed zone.131*/132ZoneId zone;133/**134* The parsed chronology.135*/136Chronology chrono;137/**138* Whether a leap-second is parsed.139*/140boolean leapSecond;141/**142* The resolver style to use.143*/144private ResolverStyle resolverStyle;145/**146* The resolved date.147*/148private ChronoLocalDate date;149/**150* The resolved time.151*/152private LocalTime time;153/**154* The excess period from time-only parsing.155*/156Period excessDays = Period.ZERO;157158/**159* Creates an instance.160*/161Parsed() {162}163164/**165* Creates a copy.166*/167Parsed copy() {168// only copy fields used in parsing stage169Parsed cloned = new Parsed();170cloned.fieldValues.putAll(this.fieldValues);171cloned.zone = this.zone;172cloned.chrono = this.chrono;173cloned.leapSecond = this.leapSecond;174return cloned;175}176177//-----------------------------------------------------------------------178@Override179public boolean isSupported(TemporalField field) {180if (fieldValues.containsKey(field) ||181(date != null && date.isSupported(field)) ||182(time != null && time.isSupported(field))) {183return true;184}185return field != null && (field instanceof ChronoField == false) && field.isSupportedBy(this);186}187188@Override189public long getLong(TemporalField field) {190Objects.requireNonNull(field, "field");191Long value = fieldValues.get(field);192if (value != null) {193return value;194}195if (date != null && date.isSupported(field)) {196return date.getLong(field);197}198if (time != null && time.isSupported(field)) {199return time.getLong(field);200}201if (field instanceof ChronoField) {202throw new UnsupportedTemporalTypeException("Unsupported field: " + field);203}204return field.getFrom(this);205}206207@SuppressWarnings("unchecked")208@Override209public <R> R query(TemporalQuery<R> query) {210if (query == TemporalQueries.zoneId()) {211return (R) zone;212} else if (query == TemporalQueries.chronology()) {213return (R) chrono;214} else if (query == TemporalQueries.localDate()) {215return (R) (date != null ? LocalDate.from(date) : null);216} else if (query == TemporalQueries.localTime()) {217return (R) time;218} else if (query == TemporalQueries.zone() || query == TemporalQueries.offset()) {219return query.queryFrom(this);220} else if (query == TemporalQueries.precision()) {221return null; // not a complete date/time222}223// inline TemporalAccessor.super.query(query) as an optimization224// non-JDK classes are not permitted to make this optimization225return query.queryFrom(this);226}227228//-----------------------------------------------------------------------229/**230* Resolves the fields in this context.231*232* @param resolverStyle the resolver style, not null233* @param resolverFields the fields to use for resolving, null for all fields234* @return this, for method chaining235* @throws DateTimeException if resolving one field results in a value for236* another field that is in conflict237*/238TemporalAccessor resolve(ResolverStyle resolverStyle, Set<TemporalField> resolverFields) {239if (resolverFields != null) {240fieldValues.keySet().retainAll(resolverFields);241}242this.resolverStyle = resolverStyle;243resolveFields();244resolveTimeLenient();245crossCheck();246resolvePeriod();247resolveFractional();248resolveInstant();249return this;250}251252//-----------------------------------------------------------------------253private void resolveFields() {254// resolve ChronoField255resolveInstantFields();256resolveDateFields();257resolveTimeFields();258259// if any other fields, handle them260// any lenient date resolution should return epoch-day261if (fieldValues.size() > 0) {262int changedCount = 0;263outer:264while (changedCount < 50) {265for (Map.Entry<TemporalField, Long> entry : fieldValues.entrySet()) {266TemporalField targetField = entry.getKey();267TemporalAccessor resolvedObject = targetField.resolve(fieldValues, this, resolverStyle);268if (resolvedObject != null) {269if (resolvedObject instanceof ChronoZonedDateTime) {270ChronoZonedDateTime<?> czdt = (ChronoZonedDateTime<?>) resolvedObject;271if (zone == null) {272zone = czdt.getZone();273} else if (zone.equals(czdt.getZone()) == false) {274throw new DateTimeException("ChronoZonedDateTime must use the effective parsed zone: " + zone);275}276resolvedObject = czdt.toLocalDateTime();277}278if (resolvedObject instanceof ChronoLocalDateTime) {279ChronoLocalDateTime<?> cldt = (ChronoLocalDateTime<?>) resolvedObject;280updateCheckConflict(cldt.toLocalTime(), Period.ZERO);281updateCheckConflict(cldt.toLocalDate());282changedCount++;283continue outer; // have to restart to avoid concurrent modification284}285if (resolvedObject instanceof ChronoLocalDate) {286updateCheckConflict((ChronoLocalDate) resolvedObject);287changedCount++;288continue outer; // have to restart to avoid concurrent modification289}290if (resolvedObject instanceof LocalTime) {291updateCheckConflict((LocalTime) resolvedObject, Period.ZERO);292changedCount++;293continue outer; // have to restart to avoid concurrent modification294}295throw new DateTimeException("Method resolve() can only return ChronoZonedDateTime, " +296"ChronoLocalDateTime, ChronoLocalDate or LocalTime");297} else if (fieldValues.containsKey(targetField) == false) {298changedCount++;299continue outer; // have to restart to avoid concurrent modification300}301}302break;303}304if (changedCount == 50) { // catch infinite loops305throw new DateTimeException("One of the parsed fields has an incorrectly implemented resolve method");306}307// if something changed then have to redo ChronoField resolve308if (changedCount > 0) {309resolveInstantFields();310resolveDateFields();311resolveTimeFields();312}313}314}315316private void updateCheckConflict(TemporalField targetField, TemporalField changeField, Long changeValue) {317Long old = fieldValues.put(changeField, changeValue);318if (old != null && old.longValue() != changeValue.longValue()) {319throw new DateTimeException("Conflict found: " + changeField + " " + old +320" differs from " + changeField + " " + changeValue +321" while resolving " + targetField);322}323}324325//-----------------------------------------------------------------------326private void resolveInstantFields() {327// resolve parsed instant seconds to date and time if zone available328if (fieldValues.containsKey(INSTANT_SECONDS)) {329if (zone != null) {330resolveInstantFields0(zone);331} else {332Long offsetSecs = fieldValues.get(OFFSET_SECONDS);333if (offsetSecs != null) {334ZoneOffset offset = ZoneOffset.ofTotalSeconds(offsetSecs.intValue());335resolveInstantFields0(offset);336}337}338}339}340341private void resolveInstantFields0(ZoneId selectedZone) {342Instant instant = Instant.ofEpochSecond(fieldValues.remove(INSTANT_SECONDS));343ChronoZonedDateTime<?> zdt = chrono.zonedDateTime(instant, selectedZone);344updateCheckConflict(zdt.toLocalDate());345updateCheckConflict(INSTANT_SECONDS, SECOND_OF_DAY, (long) zdt.toLocalTime().toSecondOfDay());346}347348//-----------------------------------------------------------------------349private void resolveDateFields() {350updateCheckConflict(chrono.resolveDate(fieldValues, resolverStyle));351}352353private void updateCheckConflict(ChronoLocalDate cld) {354if (date != null) {355if (cld != null && date.equals(cld) == false) {356throw new DateTimeException("Conflict found: Fields resolved to two different dates: " + date + " " + cld);357}358} else if (cld != null) {359if (chrono.equals(cld.getChronology()) == false) {360throw new DateTimeException("ChronoLocalDate must use the effective parsed chronology: " + chrono);361}362date = cld;363}364}365366//-----------------------------------------------------------------------367private void resolveTimeFields() {368// simplify fields369if (fieldValues.containsKey(CLOCK_HOUR_OF_DAY)) {370// lenient allows anything, smart allows 0-24, strict allows 1-24371long ch = fieldValues.remove(CLOCK_HOUR_OF_DAY);372if (resolverStyle == ResolverStyle.STRICT || (resolverStyle == ResolverStyle.SMART && ch != 0)) {373CLOCK_HOUR_OF_DAY.checkValidValue(ch);374}375updateCheckConflict(CLOCK_HOUR_OF_DAY, HOUR_OF_DAY, ch == 24 ? 0 : ch);376}377if (fieldValues.containsKey(CLOCK_HOUR_OF_AMPM)) {378// lenient allows anything, smart allows 0-12, strict allows 1-12379long ch = fieldValues.remove(CLOCK_HOUR_OF_AMPM);380if (resolverStyle == ResolverStyle.STRICT || (resolverStyle == ResolverStyle.SMART && ch != 0)) {381CLOCK_HOUR_OF_AMPM.checkValidValue(ch);382}383updateCheckConflict(CLOCK_HOUR_OF_AMPM, HOUR_OF_AMPM, ch == 12 ? 0 : ch);384}385if (fieldValues.containsKey(AMPM_OF_DAY) && fieldValues.containsKey(HOUR_OF_AMPM)) {386long ap = fieldValues.remove(AMPM_OF_DAY);387long hap = fieldValues.remove(HOUR_OF_AMPM);388if (resolverStyle == ResolverStyle.LENIENT) {389updateCheckConflict(AMPM_OF_DAY, HOUR_OF_DAY, Math.addExact(Math.multiplyExact(ap, 12), hap));390} else { // STRICT or SMART391AMPM_OF_DAY.checkValidValue(ap);392HOUR_OF_AMPM.checkValidValue(ap);393updateCheckConflict(AMPM_OF_DAY, HOUR_OF_DAY, ap * 12 + hap);394}395}396if (fieldValues.containsKey(NANO_OF_DAY)) {397long nod = fieldValues.remove(NANO_OF_DAY);398if (resolverStyle != ResolverStyle.LENIENT) {399NANO_OF_DAY.checkValidValue(nod);400}401updateCheckConflict(NANO_OF_DAY, HOUR_OF_DAY, nod / 3600_000_000_000L);402updateCheckConflict(NANO_OF_DAY, MINUTE_OF_HOUR, (nod / 60_000_000_000L) % 60);403updateCheckConflict(NANO_OF_DAY, SECOND_OF_MINUTE, (nod / 1_000_000_000L) % 60);404updateCheckConflict(NANO_OF_DAY, NANO_OF_SECOND, nod % 1_000_000_000L);405}406if (fieldValues.containsKey(MICRO_OF_DAY)) {407long cod = fieldValues.remove(MICRO_OF_DAY);408if (resolverStyle != ResolverStyle.LENIENT) {409MICRO_OF_DAY.checkValidValue(cod);410}411updateCheckConflict(MICRO_OF_DAY, SECOND_OF_DAY, cod / 1_000_000L);412updateCheckConflict(MICRO_OF_DAY, MICRO_OF_SECOND, cod % 1_000_000L);413}414if (fieldValues.containsKey(MILLI_OF_DAY)) {415long lod = fieldValues.remove(MILLI_OF_DAY);416if (resolverStyle != ResolverStyle.LENIENT) {417MILLI_OF_DAY.checkValidValue(lod);418}419updateCheckConflict(MILLI_OF_DAY, SECOND_OF_DAY, lod / 1_000);420updateCheckConflict(MILLI_OF_DAY, MILLI_OF_SECOND, lod % 1_000);421}422if (fieldValues.containsKey(SECOND_OF_DAY)) {423long sod = fieldValues.remove(SECOND_OF_DAY);424if (resolverStyle != ResolverStyle.LENIENT) {425SECOND_OF_DAY.checkValidValue(sod);426}427updateCheckConflict(SECOND_OF_DAY, HOUR_OF_DAY, sod / 3600);428updateCheckConflict(SECOND_OF_DAY, MINUTE_OF_HOUR, (sod / 60) % 60);429updateCheckConflict(SECOND_OF_DAY, SECOND_OF_MINUTE, sod % 60);430}431if (fieldValues.containsKey(MINUTE_OF_DAY)) {432long mod = fieldValues.remove(MINUTE_OF_DAY);433if (resolverStyle != ResolverStyle.LENIENT) {434MINUTE_OF_DAY.checkValidValue(mod);435}436updateCheckConflict(MINUTE_OF_DAY, HOUR_OF_DAY, mod / 60);437updateCheckConflict(MINUTE_OF_DAY, MINUTE_OF_HOUR, mod % 60);438}439440// combine partial second fields strictly, leaving lenient expansion to later441if (fieldValues.containsKey(NANO_OF_SECOND)) {442long nos = fieldValues.get(NANO_OF_SECOND);443if (resolverStyle != ResolverStyle.LENIENT) {444NANO_OF_SECOND.checkValidValue(nos);445}446if (fieldValues.containsKey(MICRO_OF_SECOND)) {447long cos = fieldValues.remove(MICRO_OF_SECOND);448if (resolverStyle != ResolverStyle.LENIENT) {449MICRO_OF_SECOND.checkValidValue(cos);450}451nos = cos * 1000 + (nos % 1000);452updateCheckConflict(MICRO_OF_SECOND, NANO_OF_SECOND, nos);453}454if (fieldValues.containsKey(MILLI_OF_SECOND)) {455long los = fieldValues.remove(MILLI_OF_SECOND);456if (resolverStyle != ResolverStyle.LENIENT) {457MILLI_OF_SECOND.checkValidValue(los);458}459updateCheckConflict(MILLI_OF_SECOND, NANO_OF_SECOND, los * 1_000_000L + (nos % 1_000_000L));460}461}462463// convert to time if all four fields available (optimization)464if (fieldValues.containsKey(HOUR_OF_DAY) && fieldValues.containsKey(MINUTE_OF_HOUR) &&465fieldValues.containsKey(SECOND_OF_MINUTE) && fieldValues.containsKey(NANO_OF_SECOND)) {466long hod = fieldValues.remove(HOUR_OF_DAY);467long moh = fieldValues.remove(MINUTE_OF_HOUR);468long som = fieldValues.remove(SECOND_OF_MINUTE);469long nos = fieldValues.remove(NANO_OF_SECOND);470resolveTime(hod, moh, som, nos);471}472}473474private void resolveTimeLenient() {475// leniently create a time from incomplete information476// done after everything else as it creates information from nothing477// which would break updateCheckConflict(field)478479if (time == null) {480// NANO_OF_SECOND merged with MILLI/MICRO above481if (fieldValues.containsKey(MILLI_OF_SECOND)) {482long los = fieldValues.remove(MILLI_OF_SECOND);483if (fieldValues.containsKey(MICRO_OF_SECOND)) {484// merge milli-of-second and micro-of-second for better error message485long cos = los * 1_000 + (fieldValues.get(MICRO_OF_SECOND) % 1_000);486updateCheckConflict(MILLI_OF_SECOND, MICRO_OF_SECOND, cos);487fieldValues.remove(MICRO_OF_SECOND);488fieldValues.put(NANO_OF_SECOND, cos * 1_000L);489} else {490// convert milli-of-second to nano-of-second491fieldValues.put(NANO_OF_SECOND, los * 1_000_000L);492}493} else if (fieldValues.containsKey(MICRO_OF_SECOND)) {494// convert micro-of-second to nano-of-second495long cos = fieldValues.remove(MICRO_OF_SECOND);496fieldValues.put(NANO_OF_SECOND, cos * 1_000L);497}498499// merge hour/minute/second/nano leniently500Long hod = fieldValues.get(HOUR_OF_DAY);501if (hod != null) {502Long moh = fieldValues.get(MINUTE_OF_HOUR);503Long som = fieldValues.get(SECOND_OF_MINUTE);504Long nos = fieldValues.get(NANO_OF_SECOND);505506// check for invalid combinations that cannot be defaulted507if ((moh == null && (som != null || nos != null)) ||508(moh != null && som == null && nos != null)) {509return;510}511512// default as necessary and build time513long mohVal = (moh != null ? moh : 0);514long somVal = (som != null ? som : 0);515long nosVal = (nos != null ? nos : 0);516resolveTime(hod, mohVal, somVal, nosVal);517fieldValues.remove(HOUR_OF_DAY);518fieldValues.remove(MINUTE_OF_HOUR);519fieldValues.remove(SECOND_OF_MINUTE);520fieldValues.remove(NANO_OF_SECOND);521}522}523524// validate remaining525if (resolverStyle != ResolverStyle.LENIENT && fieldValues.size() > 0) {526for (Entry<TemporalField, Long> entry : fieldValues.entrySet()) {527TemporalField field = entry.getKey();528if (field instanceof ChronoField && field.isTimeBased()) {529((ChronoField) field).checkValidValue(entry.getValue());530}531}532}533}534535private void resolveTime(long hod, long moh, long som, long nos) {536if (resolverStyle == ResolverStyle.LENIENT) {537long totalNanos = Math.multiplyExact(hod, 3600_000_000_000L);538totalNanos = Math.addExact(totalNanos, Math.multiplyExact(moh, 60_000_000_000L));539totalNanos = Math.addExact(totalNanos, Math.multiplyExact(som, 1_000_000_000L));540totalNanos = Math.addExact(totalNanos, nos);541int excessDays = (int) Math.floorDiv(totalNanos, 86400_000_000_000L); // safe int cast542long nod = Math.floorMod(totalNanos, 86400_000_000_000L);543updateCheckConflict(LocalTime.ofNanoOfDay(nod), Period.ofDays(excessDays));544} else { // STRICT or SMART545int mohVal = MINUTE_OF_HOUR.checkValidIntValue(moh);546int nosVal = NANO_OF_SECOND.checkValidIntValue(nos);547// handle 24:00 end of day548if (resolverStyle == ResolverStyle.SMART && hod == 24 && mohVal == 0 && som == 0 && nosVal == 0) {549updateCheckConflict(LocalTime.MIDNIGHT, Period.ofDays(1));550} else {551int hodVal = HOUR_OF_DAY.checkValidIntValue(hod);552int somVal = SECOND_OF_MINUTE.checkValidIntValue(som);553updateCheckConflict(LocalTime.of(hodVal, mohVal, somVal, nosVal), Period.ZERO);554}555}556}557558private void resolvePeriod() {559// add whole days if we have both date and time560if (date != null && time != null && excessDays.isZero() == false) {561date = date.plus(excessDays);562excessDays = Period.ZERO;563}564}565566private void resolveFractional() {567// ensure fractional seconds available as ChronoField requires568// resolveTimeLenient() will have merged MICRO_OF_SECOND/MILLI_OF_SECOND to NANO_OF_SECOND569if (time == null &&570(fieldValues.containsKey(INSTANT_SECONDS) ||571fieldValues.containsKey(SECOND_OF_DAY) ||572fieldValues.containsKey(SECOND_OF_MINUTE))) {573if (fieldValues.containsKey(NANO_OF_SECOND)) {574long nos = fieldValues.get(NANO_OF_SECOND);575fieldValues.put(MICRO_OF_SECOND, nos / 1000);576fieldValues.put(MILLI_OF_SECOND, nos / 1000000);577} else {578fieldValues.put(NANO_OF_SECOND, 0L);579fieldValues.put(MICRO_OF_SECOND, 0L);580fieldValues.put(MILLI_OF_SECOND, 0L);581}582}583}584585private void resolveInstant() {586// add instant seconds if we have date, time and zone587if (date != null && time != null) {588if (zone != null) {589long instant = date.atTime(time).atZone(zone).getLong(ChronoField.INSTANT_SECONDS);590fieldValues.put(INSTANT_SECONDS, instant);591} else {592Long offsetSecs = fieldValues.get(OFFSET_SECONDS);593if (offsetSecs != null) {594ZoneOffset offset = ZoneOffset.ofTotalSeconds(offsetSecs.intValue());595long instant = date.atTime(time).atZone(offset).getLong(ChronoField.INSTANT_SECONDS);596fieldValues.put(INSTANT_SECONDS, instant);597}598}599}600}601602private void updateCheckConflict(LocalTime timeToSet, Period periodToSet) {603if (time != null) {604if (time.equals(timeToSet) == false) {605throw new DateTimeException("Conflict found: Fields resolved to different times: " + time + " " + timeToSet);606}607if (excessDays.isZero() == false && periodToSet.isZero() == false && excessDays.equals(periodToSet) == false) {608throw new DateTimeException("Conflict found: Fields resolved to different excess periods: " + excessDays + " " + periodToSet);609} else {610excessDays = periodToSet;611}612} else {613time = timeToSet;614excessDays = periodToSet;615}616}617618//-----------------------------------------------------------------------619private void crossCheck() {620// only cross-check date, time and date-time621// avoid object creation if possible622if (date != null) {623crossCheck(date);624}625if (time != null) {626crossCheck(time);627if (date != null && fieldValues.size() > 0) {628crossCheck(date.atTime(time));629}630}631}632633private void crossCheck(TemporalAccessor target) {634for (Iterator<Entry<TemporalField, Long>> it = fieldValues.entrySet().iterator(); it.hasNext(); ) {635Entry<TemporalField, Long> entry = it.next();636TemporalField field = entry.getKey();637if (target.isSupported(field)) {638long val1;639try {640val1 = target.getLong(field);641} catch (RuntimeException ex) {642continue;643}644long val2 = entry.getValue();645if (val1 != val2) {646throw new DateTimeException("Conflict found: Field " + field + " " + val1 +647" differs from " + field + " " + val2 + " derived from " + target);648}649it.remove();650}651}652}653654//-----------------------------------------------------------------------655@Override656public String toString() {657StringBuilder buf = new StringBuilder(64);658buf.append(fieldValues).append(',').append(chrono);659if (zone != null) {660buf.append(',').append(zone);661}662if (date != null || time != null) {663buf.append(" resolved to ");664if (date != null) {665buf.append(date);666if (time != null) {667buf.append('T').append(time);668}669} else {670buf.append(time);671}672}673return buf.toString();674}675676}677678679