feat(jdk8): move files to new folder to avoid resources compiled.

This commit is contained in:
2025-09-07 15:25:52 +08:00
parent 3f0047bf6f
commit 8c35cfb1c0
17415 changed files with 217 additions and 213 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,438 @@
/*
* 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.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* 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 java.time.format;
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;
/**
* Context object used during date and time parsing.
* <p>
* This class represents the current state of the parse.
* 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 #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.
* Usage of the class is thread-safe within standard parsing as a new instance of this class
* is automatically created for each parse and parsing is single-threaded
*
* @since 1.8
*/
final class DateTimeParseContext {
/**
* The formatter, not null.
*/
private DateTimeFormatter formatter;
/**
* Whether to parse using case sensitively.
*/
private boolean caseSensitive = true;
/**
* Whether to parse using strict rules.
*/
private boolean strict = true;
/**
* The list of parsed data.
*/
private final ArrayList<Parsed> parsed = new ArrayList<>();
/**
* List of Consumers<Chronology> to be notified if the Chronology changes.
*/
private ArrayList<Consumer<Chronology>> chronoListeners = null;
/**
* Creates a new instance of the context.
*
* @param formatter the formatter controlling the parse, not null
*/
DateTimeParseContext(DateTimeFormatter formatter) {
super();
this.formatter = formatter;
parsed.add(new Parsed());
}
/**
* Creates a copy of this context.
* This retains the case sensitive and strict flags.
*/
DateTimeParseContext copy() {
DateTimeParseContext newContext = new DateTimeParseContext(formatter);
newContext.caseSensitive = caseSensitive;
newContext.strict = strict;
return newContext;
}
//-----------------------------------------------------------------------
/**
* Gets the locale.
* <p>
* This locale is used to control localization in the parse except
* where localization is controlled by the DecimalStyle.
*
* @return the locale, not null
*/
Locale getLocale() {
return formatter.getLocale();
}
/**
* Gets the DecimalStyle.
* <p>
* The DecimalStyle controls the numeric parsing.
*
* @return the DecimalStyle, not null
*/
DecimalStyle getDecimalStyle() {
return formatter.getDecimalStyle();
}
/**
* Gets the effective chronology during parsing.
*
* @return the effective parsing chronology, not null
*/
Chronology getEffectiveChronology() {
Chronology chrono = currentParsed().chrono;
if (chrono == null) {
chrono = formatter.getChronology();
if (chrono == null) {
chrono = IsoChronology.INSTANCE;
}
}
return chrono;
}
//-----------------------------------------------------------------------
/**
* Checks if parsing is case sensitive.
*
* @return true if parsing is case sensitive, false if case insensitive
*/
boolean isCaseSensitive() {
return caseSensitive;
}
/**
* Sets whether the parsing is case sensitive or not.
*
* @param caseSensitive changes the parsing to be case sensitive or not from now on
*/
void setCaseSensitive(boolean caseSensitive) {
this.caseSensitive = caseSensitive;
}
//-----------------------------------------------------------------------
/**
* Helper to compare two {@code CharSequence} instances.
* This uses {@link #isCaseSensitive()}.
*
* @param cs1 the first character sequence, not null
* @param offset1 the offset into the first sequence, valid
* @param cs2 the second character sequence, not null
* @param offset2 the offset into the second sequence, valid
* @param length the length to check, valid
* @return true if equal
*/
boolean subSequenceEquals(CharSequence cs1, int offset1, CharSequence cs2, int offset2, int length) {
if (offset1 + length > cs1.length() || offset2 + length > cs2.length()) {
return false;
}
if (isCaseSensitive()) {
for (int i = 0; i < length; i++) {
char ch1 = cs1.charAt(offset1 + i);
char ch2 = cs2.charAt(offset2 + i);
if (ch1 != ch2) {
return false;
}
}
} else {
for (int i = 0; i < length; i++) {
char ch1 = cs1.charAt(offset1 + i);
char ch2 = cs2.charAt(offset2 + i);
if (ch1 != ch2 && Character.toUpperCase(ch1) != Character.toUpperCase(ch2) &&
Character.toLowerCase(ch1) != Character.toLowerCase(ch2)) {
return false;
}
}
}
return true;
}
/**
* Helper to compare two {@code char}.
* This uses {@link #isCaseSensitive()}.
*
* @param ch1 the first character
* @param ch2 the second character
* @return true if equal
*/
boolean charEquals(char ch1, char ch2) {
if (isCaseSensitive()) {
return ch1 == ch2;
}
return charEqualsIgnoreCase(ch1, ch2);
}
/**
* Compares two characters ignoring case.
*
* @param c1 the first
* @param c2 the second
* @return true if equal
*/
static boolean charEqualsIgnoreCase(char c1, char c2) {
return c1 == c2 ||
Character.toUpperCase(c1) == Character.toUpperCase(c2) ||
Character.toLowerCase(c1) == Character.toLowerCase(c2);
}
//-----------------------------------------------------------------------
/**
* Checks if parsing is strict.
* <p>
* Strict parsing requires exact matching of the text and sign styles.
*
* @return true if parsing is strict, false if lenient
*/
boolean isStrict() {
return strict;
}
/**
* Sets whether parsing is strict or lenient.
*
* @param strict changes the parsing to be strict or lenient from now on
*/
void setStrict(boolean strict) {
this.strict = strict;
}
//-----------------------------------------------------------------------
/**
* Starts the parsing of an optional segment of the input.
*/
void startOptional() {
parsed.add(currentParsed().copy());
}
/**
* Ends the parsing of an optional segment of the input.
*
* @param successful whether the optional segment was successfully parsed
*/
void endOptional(boolean successful) {
if (successful) {
parsed.remove(parsed.size() - 2);
} else {
parsed.remove(parsed.size() - 1);
}
}
//-----------------------------------------------------------------------
/**
* Gets the currently active temporal objects.
*
* @return the current temporal objects, not null
*/
private Parsed currentParsed() {
return parsed.get(parsed.size() - 1);
}
/**
* Gets the unresolved result of the parse.
*
* @return the result of the parse, not null
*/
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.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.
* <p>
* This searches the results of the parse, returning the first value found
* for the specified field. No attempt is made to derive a value.
* The field may have an out of range value.
* For example, the day-of-month might be set to 50, or the hour to 1000.
*
* @param field the field to query from the map, null returns null
* @return the value mapped to the specified field, null if field was not parsed
*/
Long getParsed(TemporalField field) {
return currentParsed().fieldValues.get(field);
}
/**
* Stores the parsed field.
* <p>
* This stores a field-value pair that has been parsed.
* The value stored may be out of range for the field - no checks are performed.
*
* @param field the field to set in the field-value map, not null
* @param value the value to set in the field-value map
* @param errorPos the position of the field being parsed
* @param successPos the position after the field being parsed
* @return the new position
*/
int setParsedField(TemporalField field, long value, int errorPos, int successPos) {
Objects.requireNonNull(field, "field");
Long old = currentParsed().fieldValues.put(field, value);
return (old != null && old.longValue() != value) ? ~errorPos : successPos;
}
/**
* Stores the parsed chronology.
* <p>
* This stores the chronology that has been parsed.
* No validation is performed other than ensuring it is not null.
* <p>
* The list of listeners is copied and cleared so that each
* listener is called only once. A listener can add itself again
* if it needs to be notified of future changes.
*
* @param chrono the parsed chronology, not null
*/
void setParsed(Chronology chrono) {
Objects.requireNonNull(chrono, "chrono");
currentParsed().chrono = chrono;
if (chronoListeners != null && !chronoListeners.isEmpty()) {
@SuppressWarnings({"rawtypes", "unchecked"})
Consumer<Chronology>[] tmp = new Consumer[1];
Consumer<Chronology>[] listeners = chronoListeners.toArray(tmp);
chronoListeners.clear();
for (Consumer<Chronology> l : listeners) {
l.accept(chrono);
}
}
}
/**
* Adds a Consumer<Chronology> to the list of listeners to be notified
* if the Chronology changes.
* @param listener a Consumer<Chronology> to be called when Chronology changes
*/
void addChronoChangedListener(Consumer<Chronology> listener) {
if (chronoListeners == null) {
chronoListeners = new ArrayList<Consumer<Chronology>>();
}
chronoListeners.add(listener);
}
/**
* Stores the parsed zone.
* <p>
* This stores the zone that has been parsed.
* No validation is performed other than ensuring it is not null.
*
* @param zone the parsed zone, not null
*/
void setParsed(ZoneId zone) {
Objects.requireNonNull(zone, "zone");
currentParsed().zone = zone;
}
/**
* Stores the parsed leap second.
*/
void setParsedLeapSecond() {
currentParsed().leapSecond = true;
}
//-----------------------------------------------------------------------
/**
* Returns a string version of the context for debugging.
*
* @return a string representation of the context data, not null
*/
@Override
public String toString() {
return currentParsed().toString();
}
}

View File

@@ -0,0 +1,138 @@
/*
* 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.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* 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 java.time.format;
import java.time.DateTimeException;
/**
* An exception thrown when an error occurs during parsing.
* <p>
* This exception includes the text being parsed and the error index.
*
* @implSpec
* This class is intended for use in a single thread.
*
* @since 1.8
*/
public class DateTimeParseException extends DateTimeException {
/**
* Serialization version.
*/
private static final long serialVersionUID = 4304633501674722597L;
/**
* The text that was being parsed.
*/
private final String parsedString;
/**
* The error index in the text.
*/
private final int errorIndex;
/**
* Constructs a new exception with the specified message.
*
* @param message the message to use for this exception, may be null
* @param parsedData the parsed text, should not be null
* @param errorIndex the index in the parsed string that was invalid, should be a valid index
*/
public DateTimeParseException(String message, CharSequence parsedData, int errorIndex) {
super(message);
this.parsedString = parsedData.toString();
this.errorIndex = errorIndex;
}
/**
* Constructs a new exception with the specified message and cause.
*
* @param message the message to use for this exception, may be null
* @param parsedData the parsed text, should not be null
* @param errorIndex the index in the parsed string that was invalid, should be a valid index
* @param cause the cause exception, may be null
*/
public DateTimeParseException(String message, CharSequence parsedData, int errorIndex, Throwable cause) {
super(message, cause);
this.parsedString = parsedData.toString();
this.errorIndex = errorIndex;
}
//-----------------------------------------------------------------------
/**
* Returns the string that was being parsed.
*
* @return the string that was being parsed, should not be null.
*/
public String getParsedString() {
return parsedString;
}
/**
* Returns the index where the error was found.
*
* @return the index in the parsed string that was invalid, should be a valid index
*/
public int getErrorIndex() {
return errorIndex;
}
}

View File

@@ -0,0 +1,318 @@
/*
* 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.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Copyright (c) 2011-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 java.time.format;
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.temporal.TemporalAccessor;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalQueries;
import java.time.temporal.TemporalQuery;
import java.time.temporal.ValueRange;
import java.util.Locale;
import java.util.Objects;
/**
* Context object used during date and time printing.
* <p>
* This class provides a single wrapper to items used in the format.
*
* @implSpec
* This class is a mutable context intended for use from a single thread.
* Usage of the class is thread-safe within standard printing as the framework creates
* a new instance of the class for each format and printing is single-threaded.
*
* @since 1.8
*/
final class DateTimePrintContext {
/**
* The temporal being output.
*/
private TemporalAccessor temporal;
/**
* The formatter, not null.
*/
private DateTimeFormatter formatter;
/**
* Whether the current formatter is optional.
*/
private int optional;
/**
* Creates a new instance of the context.
*
* @param temporal the temporal object being output, not null
* @param formatter the formatter controlling the format, not null
*/
DateTimePrintContext(TemporalAccessor temporal, DateTimeFormatter formatter) {
super();
this.temporal = adjust(temporal, formatter);
this.formatter = formatter;
}
private static TemporalAccessor adjust(final TemporalAccessor temporal, DateTimeFormatter formatter) {
// 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 (early return is an optimization)
Chronology temporalChrono = temporal.query(TemporalQueries.chronology());
ZoneId temporalZone = temporal.query(TemporalQueries.zoneId());
if (Objects.equals(overrideChrono, temporalChrono)) {
overrideChrono = null;
}
if (Objects.equals(overrideZone, temporalZone)) {
overrideZone = null;
}
if (overrideChrono == null && overrideZone == null) {
return temporal;
}
// make adjustment
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);
}
}
}
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);
}
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> R query(TemporalQuery<R> query) {
if (query == TemporalQueries.chronology()) {
return (R) effectiveChrono;
}
if (query == TemporalQueries.zoneId()) {
return (R) effectiveZone;
}
if (query == TemporalQueries.precision()) {
return temporal.query(query);
}
return query.queryFrom(this);
}
};
}
//-----------------------------------------------------------------------
/**
* Gets the temporal object being output.
*
* @return the temporal object, not null
*/
TemporalAccessor getTemporal() {
return temporal;
}
/**
* Gets the locale.
* <p>
* This locale is used to control localization in the format output except
* where localization is controlled by the DecimalStyle.
*
* @return the locale, not null
*/
Locale getLocale() {
return formatter.getLocale();
}
/**
* Gets the DecimalStyle.
* <p>
* The DecimalStyle controls the localization of numeric output.
*
* @return the DecimalStyle, not null
*/
DecimalStyle getDecimalStyle() {
return formatter.getDecimalStyle();
}
//-----------------------------------------------------------------------
/**
* Starts the printing of an optional segment of the input.
*/
void startOptional() {
this.optional++;
}
/**
* Ends the printing of an optional segment of the input.
*/
void endOptional() {
this.optional--;
}
/**
* Gets a value using a query.
*
* @param query the query to use, not null
* @return the result, null if not found and optional is true
* @throws DateTimeException if the type is not available and the section is not optional
*/
<R> R getValue(TemporalQuery<R> query) {
R result = temporal.query(query);
if (result == null && optional == 0) {
throw new DateTimeException("Unable to extract value: " + temporal.getClass());
}
return result;
}
/**
* Gets the value of the specified field.
* <p>
* This will return the value for the specified field.
*
* @param field the field to find, not null
* @return the value, null if not found and optional is true
* @throws DateTimeException if the field is not available and the section is not optional
*/
Long getValue(TemporalField field) {
try {
return temporal.getLong(field);
} catch (DateTimeException ex) {
if (optional > 0) {
return null;
}
throw ex;
}
}
//-----------------------------------------------------------------------
/**
* Returns a string version of the context for debugging.
*
* @return a string representation of the context, not null
*/
@Override
public String toString() {
return temporal.toString();
}
}

View File

@@ -0,0 +1,558 @@
/*
* 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.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Copyright (c) 2011-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 java.time.format;
import static java.time.temporal.ChronoField.AMPM_OF_DAY;
import static java.time.temporal.ChronoField.DAY_OF_WEEK;
import static java.time.temporal.ChronoField.ERA;
import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
import java.time.chrono.Chronology;
import java.time.chrono.IsoChronology;
import java.time.chrono.JapaneseChronology;
import java.time.temporal.ChronoField;
import java.time.temporal.IsoFields;
import java.time.temporal.TemporalField;
import java.util.AbstractMap.SimpleImmutableEntry;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.ResourceBundle;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import sun.util.locale.provider.CalendarDataUtility;
import sun.util.locale.provider.LocaleProviderAdapter;
import sun.util.locale.provider.LocaleResources;
/**
* A provider to obtain the textual form of a date-time field.
*
* @implSpec
* Implementations must be thread-safe.
* Implementations should cache the textual information.
*
* @since 1.8
*/
class DateTimeTextProvider {
/** Cache. */
private static final ConcurrentMap<Entry<TemporalField, Locale>, Object> CACHE = new ConcurrentHashMap<>(16, 0.75f, 2);
/** Comparator. */
private static final Comparator<Entry<String, Long>> COMPARATOR = new Comparator<Entry<String, Long>>() {
@Override
public int compare(Entry<String, Long> obj1, Entry<String, Long> obj2) {
return obj2.getKey().length() - obj1.getKey().length(); // longest to shortest
}
};
DateTimeTextProvider() {}
/**
* Gets the provider of text.
*
* @return the provider, not null
*/
static DateTimeTextProvider getInstance() {
return new DateTimeTextProvider();
}
/**
* Gets the text for the specified field, locale and style
* for the purpose of formatting.
* <p>
* The text associated with the value is returned.
* The null return value should be used if there is no applicable text, or
* if the text would be a numeric representation of the value.
*
* @param field the field to get text for, not null
* @param value the field value to get text for, not null
* @param style the style to get text for, not null
* @param locale the locale to get text for, not null
* @return the text for the field value, null if no text found
*/
public String getText(TemporalField field, long value, TextStyle style, Locale locale) {
Object store = findStore(field, locale);
if (store instanceof LocaleStore) {
return ((LocaleStore) store).getText(value, style);
}
return null;
}
/**
* Gets the text for the specified chrono, field, locale and style
* for the purpose of formatting.
* <p>
* The text associated with the value is returned.
* The null return value should be used if there is no applicable text, or
* if the text would be a numeric representation of the value.
*
* @param chrono the Chronology to get text for, not null
* @param field the field to get text for, not null
* @param value the field value to get text for, not null
* @param style the style to get text for, not null
* @param locale the locale to get text for, not null
* @return the text for the field value, null if no text found
*/
public String getText(Chronology chrono, TemporalField field, long value,
TextStyle style, Locale locale) {
if (chrono == IsoChronology.INSTANCE
|| !(field instanceof ChronoField)) {
return getText(field, value, style, locale);
}
int fieldIndex;
int fieldValue;
if (field == ERA) {
fieldIndex = Calendar.ERA;
if (chrono == JapaneseChronology.INSTANCE) {
if (value == -999) {
fieldValue = 0;
} else {
fieldValue = (int) value + 2;
}
} else {
fieldValue = (int) value;
}
} else if (field == MONTH_OF_YEAR) {
fieldIndex = Calendar.MONTH;
fieldValue = (int) value - 1;
} else if (field == DAY_OF_WEEK) {
fieldIndex = Calendar.DAY_OF_WEEK;
fieldValue = (int) value + 1;
if (fieldValue > 7) {
fieldValue = Calendar.SUNDAY;
}
} else if (field == AMPM_OF_DAY) {
fieldIndex = Calendar.AM_PM;
fieldValue = (int) value;
} else {
return null;
}
return CalendarDataUtility.retrieveJavaTimeFieldValueName(
chrono.getCalendarType(), fieldIndex, fieldValue, style.toCalendarStyle(), locale);
}
/**
* Gets an iterator of text to field for the specified field, locale and style
* for the purpose of parsing.
* <p>
* The iterator must be returned in order from the longest text to the shortest.
* <p>
* The null return value should be used if there is no applicable parsable text, or
* if the text would be a numeric representation of the value.
* Text can only be parsed if all the values for that field-style-locale combination are unique.
*
* @param field the field to get text for, not null
* @param style the style to get text for, null for all parsable text
* @param locale the locale to get text for, not null
* @return the iterator of text to field pairs, in order from longest text to shortest text,
* null if the field or style is not parsable
*/
public Iterator<Entry<String, Long>> getTextIterator(TemporalField field, TextStyle style, Locale locale) {
Object store = findStore(field, locale);
if (store instanceof LocaleStore) {
return ((LocaleStore) store).getTextIterator(style);
}
return null;
}
/**
* Gets an iterator of text to field for the specified chrono, field, locale and style
* for the purpose of parsing.
* <p>
* The iterator must be returned in order from the longest text to the shortest.
* <p>
* The null return value should be used if there is no applicable parsable text, or
* if the text would be a numeric representation of the value.
* Text can only be parsed if all the values for that field-style-locale combination are unique.
*
* @param chrono the Chronology to get text for, not null
* @param field the field to get text for, not null
* @param style the style to get text for, null for all parsable text
* @param locale the locale to get text for, not null
* @return the iterator of text to field pairs, in order from longest text to shortest text,
* null if the field or style is not parsable
*/
public Iterator<Entry<String, Long>> getTextIterator(Chronology chrono, TemporalField field,
TextStyle style, Locale locale) {
if (chrono == IsoChronology.INSTANCE
|| !(field instanceof ChronoField)) {
return getTextIterator(field, style, locale);
}
int fieldIndex;
switch ((ChronoField)field) {
case ERA:
fieldIndex = Calendar.ERA;
break;
case MONTH_OF_YEAR:
fieldIndex = Calendar.MONTH;
break;
case DAY_OF_WEEK:
fieldIndex = Calendar.DAY_OF_WEEK;
break;
case AMPM_OF_DAY:
fieldIndex = Calendar.AM_PM;
break;
default:
return null;
}
int calendarStyle = (style == null) ? Calendar.ALL_STYLES : style.toCalendarStyle();
Map<String, Integer> map = CalendarDataUtility.retrieveJavaTimeFieldValueNames(
chrono.getCalendarType(), fieldIndex, calendarStyle, locale);
if (map == null) {
return null;
}
List<Entry<String, Long>> list = new ArrayList<>(map.size());
switch (fieldIndex) {
case Calendar.ERA:
for (Map.Entry<String, Integer> entry : map.entrySet()) {
int era = entry.getValue();
if (chrono == JapaneseChronology.INSTANCE) {
if (era == 0) {
era = -999;
} else {
era -= 2;
}
}
list.add(createEntry(entry.getKey(), (long)era));
}
break;
case Calendar.MONTH:
for (Map.Entry<String, Integer> entry : map.entrySet()) {
list.add(createEntry(entry.getKey(), (long)(entry.getValue() + 1)));
}
break;
case Calendar.DAY_OF_WEEK:
for (Map.Entry<String, Integer> entry : map.entrySet()) {
list.add(createEntry(entry.getKey(), (long)toWeekDay(entry.getValue())));
}
break;
default:
for (Map.Entry<String, Integer> entry : map.entrySet()) {
list.add(createEntry(entry.getKey(), (long)entry.getValue()));
}
break;
}
return list.iterator();
}
private Object findStore(TemporalField field, Locale locale) {
Entry<TemporalField, Locale> key = createEntry(field, locale);
Object store = CACHE.get(key);
if (store == null) {
store = createStore(field, locale);
CACHE.putIfAbsent(key, store);
store = CACHE.get(key);
}
return store;
}
private static int toWeekDay(int calWeekDay) {
if (calWeekDay == Calendar.SUNDAY) {
return 7;
} else {
return calWeekDay - 1;
}
}
private Object createStore(TemporalField field, Locale locale) {
Map<TextStyle, Map<Long, String>> styleMap = new HashMap<>();
if (field == ERA) {
for (TextStyle textStyle : TextStyle.values()) {
if (textStyle.isStandalone()) {
// Stand-alone isn't applicable to era names.
continue;
}
Map<String, Integer> displayNames = CalendarDataUtility.retrieveJavaTimeFieldValueNames(
"gregory", Calendar.ERA, textStyle.toCalendarStyle(), locale);
if (displayNames != null) {
Map<Long, String> map = new HashMap<>();
for (Entry<String, Integer> entry : displayNames.entrySet()) {
map.put((long) entry.getValue(), entry.getKey());
}
if (!map.isEmpty()) {
styleMap.put(textStyle, map);
}
}
}
return new LocaleStore(styleMap);
}
if (field == MONTH_OF_YEAR) {
for (TextStyle textStyle : TextStyle.values()) {
Map<String, Integer> displayNames = CalendarDataUtility.retrieveJavaTimeFieldValueNames(
"gregory", Calendar.MONTH, textStyle.toCalendarStyle(), locale);
Map<Long, String> map = new HashMap<>();
if (displayNames != null) {
for (Entry<String, Integer> entry : displayNames.entrySet()) {
map.put((long) (entry.getValue() + 1), entry.getKey());
}
} else {
// Narrow names may have duplicated names, such as "J" for January, Jun, July.
// Get names one by one in that case.
for (int month = Calendar.JANUARY; month <= Calendar.DECEMBER; month++) {
String name;
name = CalendarDataUtility.retrieveJavaTimeFieldValueName(
"gregory", Calendar.MONTH, month, textStyle.toCalendarStyle(), locale);
if (name == null) {
break;
}
map.put((long) (month + 1), name);
}
}
if (!map.isEmpty()) {
styleMap.put(textStyle, map);
}
}
return new LocaleStore(styleMap);
}
if (field == DAY_OF_WEEK) {
for (TextStyle textStyle : TextStyle.values()) {
Map<String, Integer> displayNames = CalendarDataUtility.retrieveJavaTimeFieldValueNames(
"gregory", Calendar.DAY_OF_WEEK, textStyle.toCalendarStyle(), locale);
Map<Long, String> map = new HashMap<>();
if (displayNames != null) {
for (Entry<String, Integer> entry : displayNames.entrySet()) {
map.put((long)toWeekDay(entry.getValue()), entry.getKey());
}
} else {
// Narrow names may have duplicated names, such as "S" for Sunday and Saturday.
// Get names one by one in that case.
for (int wday = Calendar.SUNDAY; wday <= Calendar.SATURDAY; wday++) {
String name;
name = CalendarDataUtility.retrieveJavaTimeFieldValueName(
"gregory", Calendar.DAY_OF_WEEK, wday, textStyle.toCalendarStyle(), locale);
if (name == null) {
break;
}
map.put((long)toWeekDay(wday), name);
}
}
if (!map.isEmpty()) {
styleMap.put(textStyle, map);
}
}
return new LocaleStore(styleMap);
}
if (field == AMPM_OF_DAY) {
for (TextStyle textStyle : TextStyle.values()) {
if (textStyle.isStandalone()) {
// Stand-alone isn't applicable to AM/PM.
continue;
}
Map<String, Integer> displayNames = CalendarDataUtility.retrieveJavaTimeFieldValueNames(
"gregory", Calendar.AM_PM, textStyle.toCalendarStyle(), locale);
if (displayNames != null) {
Map<Long, String> map = new HashMap<>();
for (Entry<String, Integer> entry : displayNames.entrySet()) {
map.put((long) entry.getValue(), entry.getKey());
}
if (!map.isEmpty()) {
styleMap.put(textStyle, map);
}
}
}
return new LocaleStore(styleMap);
}
if (field == IsoFields.QUARTER_OF_YEAR) {
// The order of keys must correspond to the TextStyle.values() order.
final String[] keys = {
"QuarterNames",
"standalone.QuarterNames",
"QuarterAbbreviations",
"standalone.QuarterAbbreviations",
"QuarterNarrows",
"standalone.QuarterNarrows",
};
for (int i = 0; i < keys.length; i++) {
String[] names = getLocalizedResource(keys[i], locale);
if (names != null) {
Map<Long, String> map = new HashMap<>();
for (int q = 0; q < names.length; q++) {
map.put((long) (q + 1), names[q]);
}
styleMap.put(TextStyle.values()[i], map);
}
}
return new LocaleStore(styleMap);
}
return ""; // null marker for map
}
/**
* Helper method to create an immutable entry.
*
* @param text the text, not null
* @param field the field, not null
* @return the entry, not null
*/
private static <A, B> Entry<A, B> createEntry(A text, B field) {
return new SimpleImmutableEntry<>(text, field);
}
/**
* Returns the localized resource of the given key and locale, or null
* if no localized resource is available.
*
* @param key the key of the localized resource, not null
* @param locale the locale, not null
* @return the localized resource, or null if not available
* @throws NullPointerException if key or locale is null
*/
@SuppressWarnings("unchecked")
static <T> T getLocalizedResource(String key, Locale locale) {
LocaleResources lr = LocaleProviderAdapter.getResourceBundleBased()
.getLocaleResources(locale);
ResourceBundle rb = lr.getJavaTimeFormatData();
return rb.containsKey(key) ? (T) rb.getObject(key) : null;
}
/**
* Stores the text for a single locale.
* <p>
* Some fields have a textual representation, such as day-of-week or month-of-year.
* These textual representations can be captured in this class for printing
* and parsing.
* <p>
* This class is immutable and thread-safe.
*/
static final class LocaleStore {
/**
* Map of value to text.
*/
private final Map<TextStyle, Map<Long, String>> valueTextMap;
/**
* Parsable data.
*/
private final Map<TextStyle, List<Entry<String, Long>>> parsable;
/**
* Constructor.
*
* @param valueTextMap the map of values to text to store, assigned and not altered, not null
*/
LocaleStore(Map<TextStyle, Map<Long, String>> valueTextMap) {
this.valueTextMap = valueTextMap;
Map<TextStyle, List<Entry<String, Long>>> map = new HashMap<>();
List<Entry<String, Long>> allList = new ArrayList<>();
for (Map.Entry<TextStyle, Map<Long, String>> vtmEntry : valueTextMap.entrySet()) {
Map<String, Entry<String, Long>> reverse = new HashMap<>();
for (Map.Entry<Long, String> entry : vtmEntry.getValue().entrySet()) {
if (reverse.put(entry.getValue(), createEntry(entry.getValue(), entry.getKey())) != null) {
// TODO: BUG: this has no effect
continue; // not parsable, try next style
}
}
List<Entry<String, Long>> list = new ArrayList<>(reverse.values());
Collections.sort(list, COMPARATOR);
map.put(vtmEntry.getKey(), list);
allList.addAll(list);
map.put(null, allList);
}
Collections.sort(allList, COMPARATOR);
this.parsable = map;
}
/**
* Gets the text for the specified field value, locale and style
* for the purpose of printing.
*
* @param value the value to get text for, not null
* @param style the style to get text for, not null
* @return the text for the field value, null if no text found
*/
String getText(long value, TextStyle style) {
Map<Long, String> map = valueTextMap.get(style);
return map != null ? map.get(value) : null;
}
/**
* Gets an iterator of text to field for the specified style for the purpose of parsing.
* <p>
* The iterator must be returned in order from the longest text to the shortest.
*
* @param style the style to get text for, null for all parsable text
* @return the iterator of text to field pairs, in order from longest text to shortest text,
* null if the style is not parsable
*/
Iterator<Entry<String, Long>> getTextIterator(TextStyle style) {
List<Entry<String, Long>> list = parsable.get(style);
return list != null ? list.iterator() : null;
}
}
}

View File

@@ -0,0 +1,381 @@
/*
* Copyright (c) 2012, 2015, 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 file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* 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 java.time.format;
import java.text.DecimalFormatSymbols;
import java.util.Collections;
import java.util.HashSet;
import java.util.Locale;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* Localized decimal style used in date and time formatting.
* <p>
* A significant part of dealing with dates and times is the localization.
* This class acts as a central point for accessing the information.
*
* @implSpec
* This class is immutable and thread-safe.
*
* @since 1.8
*/
public final class DecimalStyle {
/**
* The standard set of non-localized decimal style symbols.
* <p>
* This uses standard ASCII characters for zero, positive, negative and a dot for the decimal point.
*/
public static final DecimalStyle STANDARD = new DecimalStyle('0', '+', '-', '.');
/**
* The cache of DecimalStyle instances.
*/
private static final ConcurrentMap<Locale, DecimalStyle> CACHE = new ConcurrentHashMap<>(16, 0.75f, 2);
/**
* The zero digit.
*/
private final char zeroDigit;
/**
* The positive sign.
*/
private final char positiveSign;
/**
* The negative sign.
*/
private final char negativeSign;
/**
* The decimal separator.
*/
private final char decimalSeparator;
//-----------------------------------------------------------------------
/**
* Lists all the locales that are supported.
* <p>
* The locale 'en_US' will always be present.
*
* @return a Set of Locales for which localization is supported
*/
public static Set<Locale> getAvailableLocales() {
Locale[] l = DecimalFormatSymbols.getAvailableLocales();
Set<Locale> locales = new HashSet<>(l.length);
Collections.addAll(locales, l);
return locales;
}
/**
* Obtains the DecimalStyle for the default
* {@link java.util.Locale.Category#FORMAT FORMAT} locale.
* <p>
* This method provides access to locale sensitive decimal style symbols.
* <p>
* This is equivalent to calling
* {@link #of(Locale)
* of(Locale.getDefault(Locale.Category.FORMAT))}.
*
* @see java.util.Locale.Category#FORMAT
* @return the decimal style, not null
*/
public static DecimalStyle ofDefaultLocale() {
return of(Locale.getDefault(Locale.Category.FORMAT));
}
/**
* Obtains the DecimalStyle for the specified locale.
* <p>
* This method provides access to locale sensitive decimal style symbols.
*
* @param locale the locale, not null
* @return the decimal style, not null
*/
public static DecimalStyle of(Locale locale) {
Objects.requireNonNull(locale, "locale");
DecimalStyle info = CACHE.get(locale);
if (info == null) {
info = create(locale);
CACHE.putIfAbsent(locale, info);
info = CACHE.get(locale);
}
return info;
}
private static DecimalStyle create(Locale locale) {
DecimalFormatSymbols oldSymbols = DecimalFormatSymbols.getInstance(locale);
char zeroDigit = oldSymbols.getZeroDigit();
char positiveSign = '+';
char negativeSign = oldSymbols.getMinusSign();
char decimalSeparator = oldSymbols.getDecimalSeparator();
if (zeroDigit == '0' && negativeSign == '-' && decimalSeparator == '.') {
return STANDARD;
}
return new DecimalStyle(zeroDigit, positiveSign, negativeSign, decimalSeparator);
}
//-----------------------------------------------------------------------
/**
* Restricted constructor.
*
* @param zeroChar the character to use for the digit of zero
* @param positiveSignChar the character to use for the positive sign
* @param negativeSignChar the character to use for the negative sign
* @param decimalPointChar the character to use for the decimal point
*/
private DecimalStyle(char zeroChar, char positiveSignChar, char negativeSignChar, char decimalPointChar) {
this.zeroDigit = zeroChar;
this.positiveSign = positiveSignChar;
this.negativeSign = negativeSignChar;
this.decimalSeparator = decimalPointChar;
}
//-----------------------------------------------------------------------
/**
* Gets the character that represents zero.
* <p>
* The character used to represent digits may vary by culture.
* This method specifies the zero character to use, which implies the characters for one to nine.
*
* @return the character for zero
*/
public char getZeroDigit() {
return zeroDigit;
}
/**
* Returns a copy of the info with a new character that represents zero.
* <p>
* The character used to represent digits may vary by culture.
* This method specifies the zero character to use, which implies the characters for one to nine.
*
* @param zeroDigit the character for zero
* @return a copy with a new character that represents zero, not null
*/
public DecimalStyle withZeroDigit(char zeroDigit) {
if (zeroDigit == this.zeroDigit) {
return this;
}
return new DecimalStyle(zeroDigit, positiveSign, negativeSign, decimalSeparator);
}
//-----------------------------------------------------------------------
/**
* Gets the character that represents the positive sign.
* <p>
* The character used to represent a positive number may vary by culture.
* This method specifies the character to use.
*
* @return the character for the positive sign
*/
public char getPositiveSign() {
return positiveSign;
}
/**
* Returns a copy of the info with a new character that represents the positive sign.
* <p>
* The character used to represent a positive number may vary by culture.
* This method specifies the character to use.
*
* @param positiveSign the character for the positive sign
* @return a copy with a new character that represents the positive sign, not null
*/
public DecimalStyle withPositiveSign(char positiveSign) {
if (positiveSign == this.positiveSign) {
return this;
}
return new DecimalStyle(zeroDigit, positiveSign, negativeSign, decimalSeparator);
}
//-----------------------------------------------------------------------
/**
* Gets the character that represents the negative sign.
* <p>
* The character used to represent a negative number may vary by culture.
* This method specifies the character to use.
*
* @return the character for the negative sign
*/
public char getNegativeSign() {
return negativeSign;
}
/**
* Returns a copy of the info with a new character that represents the negative sign.
* <p>
* The character used to represent a negative number may vary by culture.
* This method specifies the character to use.
*
* @param negativeSign the character for the negative sign
* @return a copy with a new character that represents the negative sign, not null
*/
public DecimalStyle withNegativeSign(char negativeSign) {
if (negativeSign == this.negativeSign) {
return this;
}
return new DecimalStyle(zeroDigit, positiveSign, negativeSign, decimalSeparator);
}
//-----------------------------------------------------------------------
/**
* Gets the character that represents the decimal point.
* <p>
* The character used to represent a decimal point may vary by culture.
* This method specifies the character to use.
*
* @return the character for the decimal point
*/
public char getDecimalSeparator() {
return decimalSeparator;
}
/**
* Returns a copy of the info with a new character that represents the decimal point.
* <p>
* The character used to represent a decimal point may vary by culture.
* This method specifies the character to use.
*
* @param decimalSeparator the character for the decimal point
* @return a copy with a new character that represents the decimal point, not null
*/
public DecimalStyle withDecimalSeparator(char decimalSeparator) {
if (decimalSeparator == this.decimalSeparator) {
return this;
}
return new DecimalStyle(zeroDigit, positiveSign, negativeSign, decimalSeparator);
}
//-----------------------------------------------------------------------
/**
* Checks whether the character is a digit, based on the currently set zero character.
*
* @param ch the character to check
* @return the value, 0 to 9, of the character, or -1 if not a digit
*/
int convertToDigit(char ch) {
int val = ch - zeroDigit;
return (val >= 0 && val <= 9) ? val : -1;
}
/**
* Converts the input numeric text to the internationalized form using the zero character.
*
* @param numericText the text, consisting of digits 0 to 9, to convert, not null
* @return the internationalized text, not null
*/
String convertNumberToI18N(String numericText) {
if (zeroDigit == '0') {
return numericText;
}
int diff = zeroDigit - '0';
char[] array = numericText.toCharArray();
for (int i = 0; i < array.length; i++) {
array[i] = (char) (array[i] + diff);
}
return new String(array);
}
//-----------------------------------------------------------------------
/**
* Checks if this DecimalStyle is equal to another DecimalStyle.
*
* @param obj the object to check, null returns false
* @return true if this is equal to the other date
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof DecimalStyle) {
DecimalStyle other = (DecimalStyle) obj;
return (zeroDigit == other.zeroDigit && positiveSign == other.positiveSign &&
negativeSign == other.negativeSign && decimalSeparator == other.decimalSeparator);
}
return false;
}
/**
* A hash code for this DecimalStyle.
*
* @return a suitable hash code
*/
@Override
public int hashCode() {
return zeroDigit + positiveSign + negativeSign + decimalSeparator;
}
//-----------------------------------------------------------------------
/**
* Returns a string describing this DecimalStyle.
*
* @return a string description, not null
*/
@Override
public String toString() {
return "DecimalStyle[" + zeroDigit + positiveSign + negativeSign + decimalSeparator + "]";
}
}

View File

@@ -0,0 +1,99 @@
/*
* 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.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* 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 java.time.format;
/**
* Enumeration of the style of a localized date, time or date-time formatter.
* <p>
* These styles are used when obtaining a date-time style from configuration.
* See {@link DateTimeFormatter} and {@link DateTimeFormatterBuilder} for usage.
*
* @implSpec
* This is an immutable and thread-safe enum.
*
* @since 1.8
*/
public enum FormatStyle {
// ordered from large to small
/**
* Full text style, with the most detail.
* For example, the format might be 'Tuesday, April 12, 1952 AD' or '3:30:42pm PST'.
*/
FULL,
/**
* Long text style, with lots of detail.
* For example, the format might be 'January 12, 1952'.
*/
LONG,
/**
* Medium text style, with some detail.
* For example, the format might be 'Jan 12, 1952'.
*/
MEDIUM,
/**
* Short text style, typically numeric.
* For example, the format might be '12.13.52' or '3:30pm'.
*/
SHORT;
}

View File

@@ -0,0 +1,677 @@
/*
* 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.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Copyright (c) 2008-2013, 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 java.time.format;
import static java.time.temporal.ChronoField.AMPM_OF_DAY;
import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_AMPM;
import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_DAY;
import static java.time.temporal.ChronoField.HOUR_OF_AMPM;
import static java.time.temporal.ChronoField.HOUR_OF_DAY;
import static java.time.temporal.ChronoField.INSTANT_SECONDS;
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.NANO_OF_DAY;
import static java.time.temporal.ChronoField.NANO_OF_SECOND;
import static java.time.temporal.ChronoField.OFFSET_SECONDS;
import static java.time.temporal.ChronoField.SECOND_OF_DAY;
import static java.time.temporal.ChronoField.SECOND_OF_MINUTE;
import java.time.DateTimeException;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.Period;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.chrono.ChronoLocalDate;
import java.time.chrono.ChronoLocalDateTime;
import java.time.chrono.ChronoZonedDateTime;
import java.time.chrono.Chronology;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalQueries;
import java.time.temporal.TemporalQuery;
import java.time.temporal.UnsupportedTemporalTypeException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
/**
* A store of parsed data.
* <p>
* This class is used during parsing to collect the data. Part of the parsing process
* involves handling optional blocks and multiple copies of the data get created to
* support the necessary backtracking.
* <p>
* Once parsing is completed, this class can be used as the resultant {@code TemporalAccessor}.
* In most cases, it is only exposed once the fields have been resolved.
*
* @implSpec
* This class is a mutable context intended for use from a single thread.
* Usage of the class is thread-safe within standard parsing as a new instance of this class
* is automatically created for each parse and parsing is single-threaded
*
* @since 1.8
*/
final class Parsed implements TemporalAccessor {
// some fields are accessed using package scope from DateTimeParseContext
/**
* The parsed fields.
*/
final Map<TemporalField, Long> fieldValues = new HashMap<>();
/**
* The parsed zone.
*/
ZoneId zone;
/**
* The parsed chronology.
*/
Chronology chrono;
/**
* Whether a leap-second is parsed.
*/
boolean leapSecond;
/**
* The resolver style to use.
*/
private ResolverStyle resolverStyle;
/**
* The resolved date.
*/
private ChronoLocalDate date;
/**
* The resolved time.
*/
private LocalTime time;
/**
* The excess period from time-only parsing.
*/
Period excessDays = Period.ZERO;
/**
* Creates an instance.
*/
Parsed() {
}
/**
* Creates a copy.
*/
Parsed copy() {
// only copy fields used in parsing stage
Parsed cloned = new Parsed();
cloned.fieldValues.putAll(this.fieldValues);
cloned.zone = this.zone;
cloned.chrono = this.chrono;
cloned.leapSecond = this.leapSecond;
return cloned;
}
//-----------------------------------------------------------------------
@Override
public boolean isSupported(TemporalField field) {
if (fieldValues.containsKey(field) ||
(date != null && date.isSupported(field)) ||
(time != null && time.isSupported(field))) {
return true;
}
return field != null && (field instanceof ChronoField == false) && field.isSupportedBy(this);
}
@Override
public long getLong(TemporalField field) {
Objects.requireNonNull(field, "field");
Long value = fieldValues.get(field);
if (value != null) {
return value;
}
if (date != null && date.isSupported(field)) {
return date.getLong(field);
}
if (time != null && time.isSupported(field)) {
return time.getLong(field);
}
if (field instanceof ChronoField) {
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
}
return field.getFrom(this);
}
@SuppressWarnings("unchecked")
@Override
public <R> R query(TemporalQuery<R> query) {
if (query == TemporalQueries.zoneId()) {
return (R) zone;
} else if (query == TemporalQueries.chronology()) {
return (R) chrono;
} else if (query == TemporalQueries.localDate()) {
return (R) (date != null ? LocalDate.from(date) : null);
} else if (query == TemporalQueries.localTime()) {
return (R) time;
} else if (query == TemporalQueries.zone() || query == TemporalQueries.offset()) {
return query.queryFrom(this);
} else if (query == TemporalQueries.precision()) {
return null; // not a complete date/time
}
// inline TemporalAccessor.super.query(query) as an optimization
// non-JDK classes are not permitted to make this optimization
return query.queryFrom(this);
}
//-----------------------------------------------------------------------
/**
* Resolves the fields in this context.
*
* @param resolverStyle the resolver style, not null
* @param resolverFields the fields to use for resolving, null for all fields
* @return this, for method chaining
* @throws DateTimeException if resolving one field results in a value for
* another field that is in conflict
*/
TemporalAccessor resolve(ResolverStyle resolverStyle, Set<TemporalField> resolverFields) {
if (resolverFields != null) {
fieldValues.keySet().retainAll(resolverFields);
}
this.resolverStyle = resolverStyle;
resolveFields();
resolveTimeLenient();
crossCheck();
resolvePeriod();
resolveFractional();
resolveInstant();
return this;
}
//-----------------------------------------------------------------------
private void resolveFields() {
// resolve ChronoField
resolveInstantFields();
resolveDateFields();
resolveTimeFields();
// if any other fields, handle them
// any lenient date resolution should return epoch-day
if (fieldValues.size() > 0) {
int changedCount = 0;
outer:
while (changedCount < 50) {
for (Map.Entry<TemporalField, Long> entry : fieldValues.entrySet()) {
TemporalField targetField = entry.getKey();
TemporalAccessor resolvedObject = targetField.resolve(fieldValues, this, resolverStyle);
if (resolvedObject != null) {
if (resolvedObject instanceof ChronoZonedDateTime) {
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;
updateCheckConflict(cldt.toLocalTime(), Period.ZERO);
updateCheckConflict(cldt.toLocalDate());
changedCount++;
continue outer; // have to restart to avoid concurrent modification
}
if (resolvedObject instanceof ChronoLocalDate) {
updateCheckConflict((ChronoLocalDate) resolvedObject);
changedCount++;
continue outer; // have to restart to avoid concurrent modification
}
if (resolvedObject instanceof LocalTime) {
updateCheckConflict((LocalTime) resolvedObject, Period.ZERO);
changedCount++;
continue outer; // have to restart to avoid concurrent modification
}
throw new DateTimeException("Method resolve() can only return ChronoZonedDateTime, " +
"ChronoLocalDateTime, ChronoLocalDate or LocalTime");
} 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 (changedCount > 0) {
resolveInstantFields();
resolveDateFields();
resolveTimeFields();
}
}
}
private void updateCheckConflict(TemporalField targetField, TemporalField changeField, Long changeValue) {
Long old = fieldValues.put(changeField, changeValue);
if (old != null && old.longValue() != changeValue.longValue()) {
throw new DateTimeException("Conflict found: " + changeField + " " + old +
" differs from " + changeField + " " + changeValue +
" while resolving " + targetField);
}
}
//-----------------------------------------------------------------------
private void resolveInstantFields() {
// resolve parsed instant seconds to date and time if zone available
if (fieldValues.containsKey(INSTANT_SECONDS)) {
if (zone != null) {
resolveInstantFields0(zone);
} else {
Long offsetSecs = fieldValues.get(OFFSET_SECONDS);
if (offsetSecs != null) {
ZoneOffset offset = ZoneOffset.ofTotalSeconds(offsetSecs.intValue());
resolveInstantFields0(offset);
}
}
}
}
private void resolveInstantFields0(ZoneId selectedZone) {
Instant instant = Instant.ofEpochSecond(fieldValues.remove(INSTANT_SECONDS));
ChronoZonedDateTime<?> zdt = chrono.zonedDateTime(instant, selectedZone);
updateCheckConflict(zdt.toLocalDate());
updateCheckConflict(INSTANT_SECONDS, SECOND_OF_DAY, (long) zdt.toLocalTime().toSecondOfDay());
}
//-----------------------------------------------------------------------
private void resolveDateFields() {
updateCheckConflict(chrono.resolveDate(fieldValues, resolverStyle));
}
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);
}
} else if (cld != null) {
if (chrono.equals(cld.getChronology()) == false) {
throw new DateTimeException("ChronoLocalDate must use the effective parsed chronology: " + chrono);
}
date = cld;
}
}
//-----------------------------------------------------------------------
private void resolveTimeFields() {
// simplify fields
if (fieldValues.containsKey(CLOCK_HOUR_OF_DAY)) {
// lenient allows anything, smart allows 0-24, strict allows 1-24
long ch = fieldValues.remove(CLOCK_HOUR_OF_DAY);
if (resolverStyle == ResolverStyle.STRICT || (resolverStyle == ResolverStyle.SMART && ch != 0)) {
CLOCK_HOUR_OF_DAY.checkValidValue(ch);
}
updateCheckConflict(CLOCK_HOUR_OF_DAY, HOUR_OF_DAY, ch == 24 ? 0 : ch);
}
if (fieldValues.containsKey(CLOCK_HOUR_OF_AMPM)) {
// lenient allows anything, smart allows 0-12, strict allows 1-12
long ch = fieldValues.remove(CLOCK_HOUR_OF_AMPM);
if (resolverStyle == ResolverStyle.STRICT || (resolverStyle == ResolverStyle.SMART && ch != 0)) {
CLOCK_HOUR_OF_AMPM.checkValidValue(ch);
}
updateCheckConflict(CLOCK_HOUR_OF_AMPM, HOUR_OF_AMPM, ch == 12 ? 0 : ch);
}
if (fieldValues.containsKey(AMPM_OF_DAY) && fieldValues.containsKey(HOUR_OF_AMPM)) {
long ap = fieldValues.remove(AMPM_OF_DAY);
long hap = fieldValues.remove(HOUR_OF_AMPM);
if (resolverStyle == ResolverStyle.LENIENT) {
updateCheckConflict(AMPM_OF_DAY, HOUR_OF_DAY, Math.addExact(Math.multiplyExact(ap, 12), hap));
} else { // STRICT or SMART
AMPM_OF_DAY.checkValidValue(ap);
HOUR_OF_AMPM.checkValidValue(ap);
updateCheckConflict(AMPM_OF_DAY, HOUR_OF_DAY, ap * 12 + hap);
}
}
if (fieldValues.containsKey(NANO_OF_DAY)) {
long nod = fieldValues.remove(NANO_OF_DAY);
if (resolverStyle != ResolverStyle.LENIENT) {
NANO_OF_DAY.checkValidValue(nod);
}
updateCheckConflict(NANO_OF_DAY, HOUR_OF_DAY, nod / 3600_000_000_000L);
updateCheckConflict(NANO_OF_DAY, MINUTE_OF_HOUR, (nod / 60_000_000_000L) % 60);
updateCheckConflict(NANO_OF_DAY, SECOND_OF_MINUTE, (nod / 1_000_000_000L) % 60);
updateCheckConflict(NANO_OF_DAY, NANO_OF_SECOND, nod % 1_000_000_000L);
}
if (fieldValues.containsKey(MICRO_OF_DAY)) {
long cod = fieldValues.remove(MICRO_OF_DAY);
if (resolverStyle != ResolverStyle.LENIENT) {
MICRO_OF_DAY.checkValidValue(cod);
}
updateCheckConflict(MICRO_OF_DAY, SECOND_OF_DAY, cod / 1_000_000L);
updateCheckConflict(MICRO_OF_DAY, MICRO_OF_SECOND, cod % 1_000_000L);
}
if (fieldValues.containsKey(MILLI_OF_DAY)) {
long lod = fieldValues.remove(MILLI_OF_DAY);
if (resolverStyle != ResolverStyle.LENIENT) {
MILLI_OF_DAY.checkValidValue(lod);
}
updateCheckConflict(MILLI_OF_DAY, SECOND_OF_DAY, lod / 1_000);
updateCheckConflict(MILLI_OF_DAY, MILLI_OF_SECOND, lod % 1_000);
}
if (fieldValues.containsKey(SECOND_OF_DAY)) {
long sod = fieldValues.remove(SECOND_OF_DAY);
if (resolverStyle != ResolverStyle.LENIENT) {
SECOND_OF_DAY.checkValidValue(sod);
}
updateCheckConflict(SECOND_OF_DAY, HOUR_OF_DAY, sod / 3600);
updateCheckConflict(SECOND_OF_DAY, MINUTE_OF_HOUR, (sod / 60) % 60);
updateCheckConflict(SECOND_OF_DAY, SECOND_OF_MINUTE, sod % 60);
}
if (fieldValues.containsKey(MINUTE_OF_DAY)) {
long mod = fieldValues.remove(MINUTE_OF_DAY);
if (resolverStyle != ResolverStyle.LENIENT) {
MINUTE_OF_DAY.checkValidValue(mod);
}
updateCheckConflict(MINUTE_OF_DAY, HOUR_OF_DAY, mod / 60);
updateCheckConflict(MINUTE_OF_DAY, MINUTE_OF_HOUR, mod % 60);
}
// combine partial second fields strictly, leaving lenient expansion to later
if (fieldValues.containsKey(NANO_OF_SECOND)) {
long nos = fieldValues.get(NANO_OF_SECOND);
if (resolverStyle != ResolverStyle.LENIENT) {
NANO_OF_SECOND.checkValidValue(nos);
}
if (fieldValues.containsKey(MICRO_OF_SECOND)) {
long cos = fieldValues.remove(MICRO_OF_SECOND);
if (resolverStyle != ResolverStyle.LENIENT) {
MICRO_OF_SECOND.checkValidValue(cos);
}
nos = cos * 1000 + (nos % 1000);
updateCheckConflict(MICRO_OF_SECOND, NANO_OF_SECOND, nos);
}
if (fieldValues.containsKey(MILLI_OF_SECOND)) {
long los = fieldValues.remove(MILLI_OF_SECOND);
if (resolverStyle != ResolverStyle.LENIENT) {
MILLI_OF_SECOND.checkValidValue(los);
}
updateCheckConflict(MILLI_OF_SECOND, NANO_OF_SECOND, los * 1_000_000L + (nos % 1_000_000L));
}
}
// convert to time if all four fields available (optimization)
if (fieldValues.containsKey(HOUR_OF_DAY) && fieldValues.containsKey(MINUTE_OF_HOUR) &&
fieldValues.containsKey(SECOND_OF_MINUTE) && fieldValues.containsKey(NANO_OF_SECOND)) {
long hod = fieldValues.remove(HOUR_OF_DAY);
long moh = fieldValues.remove(MINUTE_OF_HOUR);
long som = fieldValues.remove(SECOND_OF_MINUTE);
long nos = fieldValues.remove(NANO_OF_SECOND);
resolveTime(hod, moh, som, nos);
}
}
private void resolveTimeLenient() {
// leniently create a time from incomplete information
// done after everything else as it creates information from nothing
// which would break updateCheckConflict(field)
if (time == null) {
// NANO_OF_SECOND merged with MILLI/MICRO above
if (fieldValues.containsKey(MILLI_OF_SECOND)) {
long los = fieldValues.remove(MILLI_OF_SECOND);
if (fieldValues.containsKey(MICRO_OF_SECOND)) {
// merge milli-of-second and micro-of-second for better error message
long cos = los * 1_000 + (fieldValues.get(MICRO_OF_SECOND) % 1_000);
updateCheckConflict(MILLI_OF_SECOND, MICRO_OF_SECOND, cos);
fieldValues.remove(MICRO_OF_SECOND);
fieldValues.put(NANO_OF_SECOND, cos * 1_000L);
} else {
// convert milli-of-second to nano-of-second
fieldValues.put(NANO_OF_SECOND, los * 1_000_000L);
}
} else if (fieldValues.containsKey(MICRO_OF_SECOND)) {
// convert micro-of-second to nano-of-second
long cos = fieldValues.remove(MICRO_OF_SECOND);
fieldValues.put(NANO_OF_SECOND, cos * 1_000L);
}
// merge hour/minute/second/nano leniently
Long hod = fieldValues.get(HOUR_OF_DAY);
if (hod != null) {
Long moh = fieldValues.get(MINUTE_OF_HOUR);
Long som = fieldValues.get(SECOND_OF_MINUTE);
Long nos = fieldValues.get(NANO_OF_SECOND);
// check for invalid combinations that cannot be defaulted
if ((moh == null && (som != null || nos != null)) ||
(moh != null && som == null && nos != null)) {
return;
}
// default as necessary and build time
long mohVal = (moh != null ? moh : 0);
long somVal = (som != null ? som : 0);
long nosVal = (nos != null ? nos : 0);
resolveTime(hod, mohVal, somVal, nosVal);
fieldValues.remove(HOUR_OF_DAY);
fieldValues.remove(MINUTE_OF_HOUR);
fieldValues.remove(SECOND_OF_MINUTE);
fieldValues.remove(NANO_OF_SECOND);
}
}
// validate remaining
if (resolverStyle != ResolverStyle.LENIENT && fieldValues.size() > 0) {
for (Entry<TemporalField, Long> entry : fieldValues.entrySet()) {
TemporalField field = entry.getKey();
if (field instanceof ChronoField && field.isTimeBased()) {
((ChronoField) field).checkValidValue(entry.getValue());
}
}
}
}
private void resolveTime(long hod, long moh, long som, long nos) {
if (resolverStyle == ResolverStyle.LENIENT) {
long totalNanos = Math.multiplyExact(hod, 3600_000_000_000L);
totalNanos = Math.addExact(totalNanos, Math.multiplyExact(moh, 60_000_000_000L));
totalNanos = Math.addExact(totalNanos, Math.multiplyExact(som, 1_000_000_000L));
totalNanos = Math.addExact(totalNanos, nos);
int excessDays = (int) Math.floorDiv(totalNanos, 86400_000_000_000L); // safe int cast
long nod = Math.floorMod(totalNanos, 86400_000_000_000L);
updateCheckConflict(LocalTime.ofNanoOfDay(nod), Period.ofDays(excessDays));
} else { // STRICT or SMART
int mohVal = MINUTE_OF_HOUR.checkValidIntValue(moh);
int nosVal = NANO_OF_SECOND.checkValidIntValue(nos);
// handle 24:00 end of day
if (resolverStyle == ResolverStyle.SMART && hod == 24 && mohVal == 0 && som == 0 && nosVal == 0) {
updateCheckConflict(LocalTime.MIDNIGHT, Period.ofDays(1));
} else {
int hodVal = HOUR_OF_DAY.checkValidIntValue(hod);
int somVal = SECOND_OF_MINUTE.checkValidIntValue(som);
updateCheckConflict(LocalTime.of(hodVal, mohVal, somVal, nosVal), Period.ZERO);
}
}
}
private void resolvePeriod() {
// add whole days if we have both date and time
if (date != null && time != null && excessDays.isZero() == false) {
date = date.plus(excessDays);
excessDays = Period.ZERO;
}
}
private void resolveFractional() {
// ensure fractional seconds available as ChronoField requires
// resolveTimeLenient() will have merged MICRO_OF_SECOND/MILLI_OF_SECOND to NANO_OF_SECOND
if (time == null &&
(fieldValues.containsKey(INSTANT_SECONDS) ||
fieldValues.containsKey(SECOND_OF_DAY) ||
fieldValues.containsKey(SECOND_OF_MINUTE))) {
if (fieldValues.containsKey(NANO_OF_SECOND)) {
long nos = fieldValues.get(NANO_OF_SECOND);
fieldValues.put(MICRO_OF_SECOND, nos / 1000);
fieldValues.put(MILLI_OF_SECOND, nos / 1000000);
} else {
fieldValues.put(NANO_OF_SECOND, 0L);
fieldValues.put(MICRO_OF_SECOND, 0L);
fieldValues.put(MILLI_OF_SECOND, 0L);
}
}
}
private void resolveInstant() {
// add instant seconds if we have date, time and zone
if (date != null && time != null) {
if (zone != null) {
long instant = date.atTime(time).atZone(zone).getLong(ChronoField.INSTANT_SECONDS);
fieldValues.put(INSTANT_SECONDS, instant);
} else {
Long offsetSecs = fieldValues.get(OFFSET_SECONDS);
if (offsetSecs != null) {
ZoneOffset offset = ZoneOffset.ofTotalSeconds(offsetSecs.intValue());
long instant = date.atTime(time).atZone(offset).getLong(ChronoField.INSTANT_SECONDS);
fieldValues.put(INSTANT_SECONDS, instant);
}
}
}
}
private void updateCheckConflict(LocalTime timeToSet, Period periodToSet) {
if (time != null) {
if (time.equals(timeToSet) == false) {
throw new DateTimeException("Conflict found: Fields resolved to different times: " + time + " " + timeToSet);
}
if (excessDays.isZero() == false && periodToSet.isZero() == false && excessDays.equals(periodToSet) == false) {
throw new DateTimeException("Conflict found: Fields resolved to different excess periods: " + excessDays + " " + periodToSet);
} else {
excessDays = periodToSet;
}
} else {
time = timeToSet;
excessDays = periodToSet;
}
}
//-----------------------------------------------------------------------
private void crossCheck() {
// only cross-check date, time and date-time
// avoid object creation if possible
if (date != null) {
crossCheck(date);
}
if (time != null) {
crossCheck(time);
if (date != null && fieldValues.size() > 0) {
crossCheck(date.atTime(time));
}
}
}
private void crossCheck(TemporalAccessor target) {
for (Iterator<Entry<TemporalField, Long>> it = fieldValues.entrySet().iterator(); it.hasNext(); ) {
Entry<TemporalField, Long> entry = it.next();
TemporalField field = entry.getKey();
if (target.isSupported(field)) {
long val1;
try {
val1 = target.getLong(field);
} catch (RuntimeException ex) {
continue;
}
long val2 = entry.getValue();
if (val1 != val2) {
throw new DateTimeException("Conflict found: Field " + field + " " + val1 +
" differs from " + field + " " + val2 + " derived from " + target);
}
it.remove();
}
}
}
//-----------------------------------------------------------------------
@Override
public String toString() {
StringBuilder buf = new StringBuilder(64);
buf.append(fieldValues).append(',').append(chrono);
if (zone != null) {
buf.append(',').append(zone);
}
if (date != null || time != null) {
buf.append(" resolved to ");
if (date != null) {
buf.append(date);
if (time != null) {
buf.append('T').append(time);
}
} else {
buf.append(time);
}
}
return buf.toString();
}
}

View File

@@ -0,0 +1,116 @@
/*
* 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 file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Copyright (c) 2008-2013, 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 java.time.format;
/**
* Enumeration of different ways to resolve dates and times.
* <p>
* Parsing a text string occurs in two phases.
* Phase 1 is a basic text parse according to the fields added to the builder.
* Phase 2 resolves the parsed field-value pairs into date and/or time objects.
* This style is used to control how phase 2, resolving, happens.
*
* @implSpec
* This is an immutable and thread-safe enum.
*
* @since 1.8
*/
public enum ResolverStyle {
/**
* Style to resolve dates and times strictly.
* <p>
* Using strict resolution will ensure that all parsed values are within
* the outer range of valid values for the field. Individual fields may
* be further processed for strictness.
* <p>
* For example, resolving year-month and day-of-month in the ISO calendar
* system using strict mode will ensure that the day-of-month is valid
* for the year-month, rejecting invalid values.
*/
STRICT,
/**
* Style to resolve dates and times in a smart, or intelligent, manner.
* <p>
* Using smart resolution will perform the sensible default for each
* field, which may be the same as strict, the same as lenient, or a third
* behavior. Individual fields will interpret this differently.
* <p>
* For example, resolving year-month and day-of-month in the ISO calendar
* system using smart mode will ensure that the day-of-month is from
* 1 to 31, converting any value beyond the last valid day-of-month to be
* the last valid day-of-month.
*/
SMART,
/**
* Style to resolve dates and times leniently.
* <p>
* Using lenient resolution will resolve the values in an appropriate
* lenient manner. Individual fields will interpret this differently.
* <p>
* For example, lenient mode allows the month in the ISO calendar system
* to be outside the range 1 to 12.
* For example, month 15 is treated as being 3 months after month 12.
*/
LENIENT;
}

View File

@@ -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.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* 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 java.time.format;
/**
* Enumeration of ways to handle the positive/negative sign.
* <p>
* The formatting engine allows the positive and negative signs of numbers
* to be controlled using this enum.
* See {@link DateTimeFormatterBuilder} for usage.
*
* @implSpec
* This is an immutable and thread-safe enum.
*
* @since 1.8
*/
public enum SignStyle {
/**
* Style to output the sign only if the value is negative.
* <p>
* In strict parsing, the negative sign will be accepted and the positive sign rejected.
* In lenient parsing, any sign will be accepted.
*/
NORMAL,
/**
* Style to always output the sign, where zero will output '+'.
* <p>
* In strict parsing, the absence of a sign will be rejected.
* In lenient parsing, any sign will be accepted, with the absence
* of a sign treated as a positive number.
*/
ALWAYS,
/**
* Style to never output sign, only outputting the absolute value.
* <p>
* In strict parsing, any sign will be rejected.
* In lenient parsing, any sign will be accepted unless the width is fixed.
*/
NEVER,
/**
* Style to block negative values, throwing an exception on printing.
* <p>
* In strict parsing, any sign will be rejected.
* In lenient parsing, any sign will be accepted unless the width is fixed.
*/
NOT_NEGATIVE,
/**
* Style to always output the sign if the value exceeds the pad width.
* A negative value will always output the '-' sign.
* <p>
* In strict parsing, the sign will be rejected unless the pad width is exceeded.
* In lenient parsing, any sign will be accepted, with the absence
* of a sign treated as a positive number.
*/
EXCEEDS_PAD;
/**
* Parse helper.
*
* @param positive true if positive sign parsed, false for negative sign
* @param strict true if strict, false if lenient
* @param fixedWidth true if fixed width, false if not
* @return
*/
boolean parse(boolean positive, boolean strict, boolean fixedWidth) {
switch (ordinal()) {
case 0: // NORMAL
// valid if negative or (positive and lenient)
return !positive || !strict;
case 1: // ALWAYS
case 4: // EXCEEDS_PAD
return true;
default:
// valid if lenient and not fixed width
return !strict && !fixedWidth;
}
}
}

View File

@@ -0,0 +1,175 @@
/*
* 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.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* 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 java.time.format;
import java.util.Calendar;
/**
* Enumeration of the style of text formatting and parsing.
* <p>
* Text styles define three sizes for the formatted text - 'full', 'short' and 'narrow'.
* Each of these three sizes is available in both 'standard' and 'stand-alone' variations.
* <p>
* The difference between the three sizes is obvious in most languages.
* For example, in English the 'full' month is 'January', the 'short' month is 'Jan'
* and the 'narrow' month is 'J'. Note that the narrow size is often not unique.
* For example, 'January', 'June' and 'July' all have the 'narrow' text 'J'.
* <p>
* The difference between the 'standard' and 'stand-alone' forms is trickier to describe
* as there is no difference in English. However, in other languages there is a difference
* in the word used when the text is used alone, as opposed to in a complete date.
* For example, the word used for a month when used alone in a date picker is different
* to the word used for month in association with a day and year in a date.
*
* @implSpec
* This is immutable and thread-safe enum.
*/
public enum TextStyle {
// ordered from large to small
// ordered so that bit 0 of the ordinal indicates stand-alone.
/**
* Full text, typically the full description.
* For example, day-of-week Monday might output "Monday".
*/
FULL(Calendar.LONG_FORMAT, 0),
/**
* Full text for stand-alone use, typically the full description.
* For example, day-of-week Monday might output "Monday".
*/
FULL_STANDALONE(Calendar.LONG_STANDALONE, 0),
/**
* Short text, typically an abbreviation.
* For example, day-of-week Monday might output "Mon".
*/
SHORT(Calendar.SHORT_FORMAT, 1),
/**
* Short text for stand-alone use, typically an abbreviation.
* For example, day-of-week Monday might output "Mon".
*/
SHORT_STANDALONE(Calendar.SHORT_STANDALONE, 1),
/**
* Narrow text, typically a single letter.
* For example, day-of-week Monday might output "M".
*/
NARROW(Calendar.NARROW_FORMAT, 1),
/**
* Narrow text for stand-alone use, typically a single letter.
* For example, day-of-week Monday might output "M".
*/
NARROW_STANDALONE(Calendar.NARROW_STANDALONE, 1);
private final int calendarStyle;
private final int zoneNameStyleIndex;
private TextStyle(int calendarStyle, int zoneNameStyleIndex) {
this.calendarStyle = calendarStyle;
this.zoneNameStyleIndex = zoneNameStyleIndex;
}
/**
* Returns true if the Style is a stand-alone style.
* @return true if the style is a stand-alone style.
*/
public boolean isStandalone() {
return (ordinal() & 1) == 1;
}
/**
* Returns the stand-alone style with the same size.
* @return the stand-alone style with the same size
*/
public TextStyle asStandalone() {
return TextStyle.values()[ordinal() | 1];
}
/**
* Returns the normal style with the same size.
*
* @return the normal style with the same size
*/
public TextStyle asNormal() {
return TextStyle.values()[ordinal() & ~1];
}
/**
* Returns the {@code Calendar} style corresponding to this {@code TextStyle}.
*
* @return the corresponding {@code Calendar} style
*/
int toCalendarStyle() {
return calendarStyle;
}
/**
* Returns the relative index value to an element of the {@link
* java.text.DateFormatSymbols#getZoneStrings() DateFormatSymbols.getZoneStrings()}
* value, 0 for long names and 1 for short names (abbreviations). Note that these values
* do <em>not</em> correspond to the {@link java.util.TimeZone#LONG} and {@link
* java.util.TimeZone#SHORT} values.
*
* @return the relative index value to time zone names array
*/
int zoneNameStyleIndex() {
return zoneNameStyleIndex;
}
}

View File

@@ -0,0 +1,798 @@
/*
* Copyright (c) 2013, 2018, 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.
*/
package java.time.format;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
/**
* A helper class to map a zone name to metazone and back to the
* appropriate zone id for the particular locale.
* <p>
* The zid<->metazone mappings are based on CLDR metaZones.xml.
* The alias mappings are based on Link entries in tzdb data files.
*/
class ZoneName {
public static String toZid(String zid, Locale locale) {
String mzone = zidToMzone.get(zid);
if (mzone == null && aliases.containsKey(zid)) {
zid = aliases.get(zid);
mzone = zidToMzone.get(zid);
}
if (mzone != null) {
Map<String, String> map = mzoneToZidL.get(mzone);
if (map != null && map.containsKey(locale.getCountry())) {
zid = map.get(locale.getCountry());
} else {
zid = mzoneToZid.get(mzone);
}
}
return toZid(zid);
}
public static String toZid(String zid) {
if (aliases.containsKey(zid)) {
return aliases.get(zid);
}
return zid;
}
private static final String[] zidMap = new String[] {
"Pacific/Rarotonga", "Cook", "Pacific/Rarotonga",
"Europe/Tirane", "Europe_Central", "Europe/Paris",
"America/Recife", "Brasilia", "America/Sao_Paulo",
"America/Argentina/San_Juan", "Argentina", "America/Buenos_Aires",
"Asia/Kolkata", "India", "Asia/Calcutta",
"America/Guayaquil", "Ecuador", "America/Guayaquil",
"Europe/Samara", "Moscow", "Europe/Moscow",
"Indian/Antananarivo", "Africa_Eastern", "Africa/Nairobi",
"America/Santa_Isabel", "America_Pacific", "America/Los_Angeles",
"America/Montserrat", "Atlantic", "America/Halifax",
"Pacific/Port_Moresby", "Papua_New_Guinea", "Pacific/Port_Moresby",
"Europe/Paris", "Europe_Central", "Europe/Paris",
"America/Argentina/Salta", "Argentina", "America/Buenos_Aires",
"Asia/Omsk", "Omsk", "Asia/Omsk",
"Africa/Ceuta", "Europe_Central", "Europe/Paris",
"America/Argentina/San_Luis", "Argentina_Western", "America/Argentina/San_Luis",
"America/Atikokan", "America_Eastern", "America/New_York",
"Asia/Vladivostok", "Vladivostok", "Asia/Vladivostok",
"America/Argentina/Jujuy", "Argentina", "America/Buenos_Aires",
"Asia/Almaty", "Kazakhstan_Eastern", "Asia/Almaty",
"Atlantic/Canary", "Europe_Western", "Atlantic/Canary",
"Asia/Bangkok", "Indochina", "Asia/Saigon",
"America/Caracas", "Venezuela", "America/Caracas",
"Australia/Hobart", "Australia_Eastern", "Australia/Sydney",
"America/Havana", "Cuba", "America/Havana",
"Africa/Malabo", "Africa_Western", "Africa/Lagos",
"Australia/Lord_Howe", "Lord_Howe", "Australia/Lord_Howe",
"Pacific/Fakaofo", "Tokelau", "Pacific/Fakaofo",
"America/Matamoros", "America_Central", "America/Chicago",
"America/Guadeloupe", "Atlantic", "America/Halifax",
"Europe/Helsinki", "Europe_Eastern", "Europe/Bucharest",
"Asia/Calcutta", "India", "Asia/Calcutta",
"Africa/Kinshasa", "Africa_Western", "Africa/Lagos",
"America/Miquelon", "Pierre_Miquelon", "America/Miquelon",
"Europe/Athens", "Europe_Eastern", "Europe/Bucharest",
"Asia/Novosibirsk", "Novosibirsk", "Asia/Novosibirsk",
"Indian/Cocos", "Cocos", "Indian/Cocos",
"Africa/Bujumbura", "Africa_Central", "Africa/Maputo",
"Europe/Mariehamn", "Europe_Eastern", "Europe/Bucharest",
"America/Winnipeg", "America_Central", "America/Chicago",
"America/Buenos_Aires", "Argentina", "America/Buenos_Aires",
"America/Yellowknife", "America_Mountain", "America/Denver",
"Pacific/Midway", "Samoa", "Pacific/Apia",
"Africa/Dar_es_Salaam", "Africa_Eastern", "Africa/Nairobi",
"Pacific/Tahiti", "Tahiti", "Pacific/Tahiti",
"Asia/Gaza", "Europe_Eastern", "Europe/Bucharest",
"Australia/Lindeman", "Australia_Eastern", "Australia/Sydney",
"Europe/Kaliningrad", "Europe_Eastern", "Europe/Bucharest",
"Europe/Bucharest", "Europe_Eastern", "Europe/Bucharest",
"America/Lower_Princes", "Atlantic", "America/Halifax",
"Pacific/Chuuk", "Truk", "Pacific/Truk",
"America/Anchorage", "Alaska", "America/Juneau",
"America/Rankin_Inlet", "America_Central", "America/Chicago",
"America/Marigot", "Atlantic", "America/Halifax",
"Africa/Juba", "Africa_Eastern", "Africa/Nairobi",
"Africa/Algiers", "Europe_Central", "Europe/Paris",
"Europe/Kiev", "Europe_Eastern", "Europe/Bucharest",
"America/Santarem", "Brasilia", "America/Sao_Paulo",
"Africa/Brazzaville", "Africa_Western", "Africa/Lagos",
"Asia/Choibalsan", "Choibalsan", "Asia/Choibalsan",
"Indian/Christmas", "Christmas", "Indian/Christmas",
"America/Nassau", "America_Eastern", "America/New_York",
"Africa/Tunis", "Europe_Central", "Europe/Paris",
"Pacific/Noumea", "New_Caledonia", "Pacific/Noumea",
"Africa/El_Aaiun", "Europe_Western", "Atlantic/Canary",
"Europe/Sarajevo", "Europe_Central", "Europe/Paris",
"America/Campo_Grande", "Amazon", "America/Manaus",
"America/Puerto_Rico", "Atlantic", "America/Halifax",
"Antarctica/Mawson", "Mawson", "Antarctica/Mawson",
"Pacific/Galapagos", "Galapagos", "Pacific/Galapagos",
"Asia/Tehran", "Iran", "Asia/Tehran",
"America/Port-au-Prince", "America_Eastern", "America/New_York",
"America/Scoresbysund", "Greenland_Eastern", "America/Scoresbysund",
"Africa/Harare", "Africa_Central", "Africa/Maputo",
"America/Dominica", "Atlantic", "America/Halifax",
"Europe/Chisinau", "Europe_Eastern", "Europe/Bucharest",
"America/Chihuahua", "America_Mountain", "America/Denver",
"America/La_Paz", "Bolivia", "America/La_Paz",
"Indian/Chagos", "Indian_Ocean", "Indian/Chagos",
"Australia/Broken_Hill", "Australia_Central", "Australia/Adelaide",
"America/Grenada", "Atlantic", "America/Halifax",
"America/North_Dakota/New_Salem", "America_Central", "America/Chicago",
"Pacific/Majuro", "Marshall_Islands", "Pacific/Majuro",
"Australia/Adelaide", "Australia_Central", "Australia/Adelaide",
"Europe/Warsaw", "Europe_Central", "Europe/Paris",
"Europe/Vienna", "Europe_Central", "Europe/Paris",
"Atlantic/Cape_Verde", "Cape_Verde", "Atlantic/Cape_Verde",
"America/Mendoza", "Argentina", "America/Buenos_Aires",
"Pacific/Gambier", "Gambier", "Pacific/Gambier",
"Europe/Istanbul", "Europe_Eastern", "Europe/Bucharest",
"America/Kentucky/Monticello", "America_Eastern", "America/New_York",
"America/Chicago", "America_Central", "America/Chicago",
"Asia/Ulaanbaatar", "Mongolia", "Asia/Ulaanbaatar",
"Indian/Maldives", "Maldives", "Indian/Maldives",
"America/Mexico_City", "America_Central", "America/Chicago",
"Africa/Asmara", "Africa_Eastern", "Africa/Nairobi",
"Asia/Chongqing", "China", "Asia/Shanghai",
"America/Argentina/La_Rioja", "Argentina", "America/Buenos_Aires",
"America/Tijuana", "America_Pacific", "America/Los_Angeles",
"Asia/Harbin", "China", "Asia/Shanghai",
"Pacific/Honolulu", "Hawaii_Aleutian", "Pacific/Honolulu",
"Atlantic/Azores", "Azores", "Atlantic/Azores",
"Indian/Mayotte", "Africa_Eastern", "Africa/Nairobi",
"America/Guatemala", "America_Central", "America/Chicago",
"America/Indianapolis", "America_Eastern", "America/New_York",
"America/Halifax", "Atlantic", "America/Halifax",
"America/Resolute", "America_Central", "America/Chicago",
"Europe/London", "GMT", "Atlantic/Reykjavik",
"America/Hermosillo", "America_Mountain", "America/Denver",
"Atlantic/Madeira", "Europe_Western", "Atlantic/Canary",
"Europe/Zagreb", "Europe_Central", "Europe/Paris",
"America/Boa_Vista", "Amazon", "America/Manaus",
"America/Regina", "America_Central", "America/Chicago",
"America/Cordoba", "Argentina", "America/Buenos_Aires",
"America/Shiprock", "America_Mountain", "America/Denver",
"Europe/Luxembourg", "Europe_Central", "Europe/Paris",
"America/Cancun", "America_Central", "America/Chicago",
"Pacific/Enderbury", "Phoenix_Islands", "Pacific/Enderbury",
"Africa/Bissau", "GMT", "Atlantic/Reykjavik",
"Antarctica/Vostok", "Vostok", "Antarctica/Vostok",
"Pacific/Apia", "Samoa", "Pacific/Apia",
"Australia/Perth", "Australia_Western", "Australia/Perth",
"America/Juneau", "Alaska", "America/Juneau",
"Africa/Mbabane", "Africa_Southern", "Africa/Johannesburg",
"Pacific/Niue", "Niue", "Pacific/Niue",
"Europe/Zurich", "Europe_Central", "Europe/Paris",
"America/Rio_Branco", "Amazon", "America/Manaus",
"Africa/Ndjamena", "Africa_Western", "Africa/Lagos",
"Asia/Macau", "China", "Asia/Shanghai",
"America/Lima", "Peru", "America/Lima",
"Africa/Windhoek", "Africa_Central", "Africa/Maputo",
"America/Sitka", "Alaska", "America/Juneau",
"America/Mazatlan", "America_Mountain", "America/Denver",
"Asia/Saigon", "Indochina", "Asia/Saigon",
"Asia/Kamchatka", "Magadan", "Asia/Magadan",
"America/Menominee", "America_Central", "America/Chicago",
"America/Belize", "America_Central", "America/Chicago",
"America/Sao_Paulo", "Brasilia", "America/Sao_Paulo",
"America/Barbados", "Atlantic", "America/Halifax",
"America/Porto_Velho", "Amazon", "America/Manaus",
"America/Costa_Rica", "America_Central", "America/Chicago",
"Europe/Monaco", "Europe_Central", "Europe/Paris",
"Europe/Riga", "Europe_Eastern", "Europe/Bucharest",
"Europe/Vatican", "Europe_Central", "Europe/Paris",
"Europe/Madrid", "Europe_Central", "Europe/Paris",
"Africa/Dakar", "GMT", "Atlantic/Reykjavik",
"Asia/Damascus", "Europe_Eastern", "Europe/Bucharest",
"Asia/Hong_Kong", "Hong_Kong", "Asia/Hong_Kong",
"America/Adak", "Hawaii_Aleutian", "Pacific/Honolulu",
"Europe/Vilnius", "Europe_Eastern", "Europe/Bucharest",
"America/Indiana/Indianapolis", "America_Eastern", "America/New_York",
"Africa/Freetown", "GMT", "Atlantic/Reykjavik",
"Atlantic/Reykjavik", "GMT", "Atlantic/Reykjavik",
"Asia/Ho_Chi_Minh", "Indochina", "Asia/Saigon",
"America/St_Kitts", "Atlantic", "America/Halifax",
"America/Martinique", "Atlantic", "America/Halifax",
"America/Thule", "Atlantic", "America/Halifax",
"America/Asuncion", "Paraguay", "America/Asuncion",
"Africa/Luanda", "Africa_Western", "Africa/Lagos",
"America/Monterrey", "America_Central", "America/Chicago",
"Pacific/Fiji", "Fiji", "Pacific/Fiji",
"Africa/Banjul", "GMT", "Atlantic/Reykjavik",
"America/Grand_Turk", "America_Eastern", "America/New_York",
"Pacific/Pitcairn", "Pitcairn", "Pacific/Pitcairn",
"America/Montevideo", "Uruguay", "America/Montevideo",
"America/Bahia_Banderas", "America_Central", "America/Chicago",
"America/Cayman", "America_Eastern", "America/New_York",
"Pacific/Norfolk", "Norfolk", "Pacific/Norfolk",
"Africa/Ouagadougou", "GMT", "Atlantic/Reykjavik",
"America/Maceio", "Brasilia", "America/Sao_Paulo",
"Pacific/Guam", "Chamorro", "Pacific/Saipan",
"Africa/Monrovia", "GMT", "Atlantic/Reykjavik",
"Africa/Bamako", "GMT", "Atlantic/Reykjavik",
"Asia/Colombo", "India", "Asia/Calcutta",
"Asia/Urumqi", "China", "Asia/Shanghai",
"Asia/Kabul", "Afghanistan", "Asia/Kabul",
"America/Yakutat", "Alaska", "America/Juneau",
"America/Phoenix", "America_Mountain", "America/Denver",
"Asia/Nicosia", "Europe_Eastern", "Europe/Bucharest",
"Asia/Phnom_Penh", "Indochina", "Asia/Saigon",
"America/Rainy_River", "America_Central", "America/Chicago",
"Europe/Uzhgorod", "Europe_Eastern", "Europe/Bucharest",
"Pacific/Saipan", "Chamorro", "Pacific/Saipan",
"America/St_Vincent", "Atlantic", "America/Halifax",
"Europe/Rome", "Europe_Central", "Europe/Paris",
"America/Nome", "Alaska", "America/Juneau",
"Africa/Mogadishu", "Africa_Eastern", "Africa/Nairobi",
"Europe/Zaporozhye", "Europe_Eastern", "Europe/Bucharest",
"Pacific/Funafuti", "Tuvalu", "Pacific/Funafuti",
"Atlantic/South_Georgia", "South_Georgia", "Atlantic/South_Georgia",
"Europe/Skopje", "Europe_Central", "Europe/Paris",
"Asia/Yekaterinburg", "Yekaterinburg", "Asia/Yekaterinburg",
"Australia/Melbourne", "Australia_Eastern", "Australia/Sydney",
"America/Argentina/Cordoba", "Argentina", "America/Buenos_Aires",
"Africa/Kigali", "Africa_Central", "Africa/Maputo",
"Africa/Blantyre", "Africa_Central", "Africa/Maputo",
"Africa/Tripoli", "Europe_Eastern", "Europe/Bucharest",
"Africa/Gaborone", "Africa_Central", "Africa/Maputo",
"Asia/Kuching", "Malaysia", "Asia/Kuching",
"Pacific/Nauru", "Nauru", "Pacific/Nauru",
"America/Aruba", "Atlantic", "America/Halifax",
"America/Antigua", "Atlantic", "America/Halifax",
"Europe/Volgograd", "Volgograd", "Europe/Volgograd",
"Africa/Djibouti", "Africa_Eastern", "Africa/Nairobi",
"America/Catamarca", "Argentina", "America/Buenos_Aires",
"Asia/Manila", "Philippines", "Asia/Manila",
"Pacific/Kiritimati", "Line_Islands", "Pacific/Kiritimati",
"Asia/Shanghai", "China", "Asia/Shanghai",
"Pacific/Truk", "Truk", "Pacific/Truk",
"Pacific/Tarawa", "Gilbert_Islands", "Pacific/Tarawa",
"Africa/Conakry", "GMT", "Atlantic/Reykjavik",
"Asia/Bishkek", "Kyrgystan", "Asia/Bishkek",
"Europe/Gibraltar", "Europe_Central", "Europe/Paris",
"Asia/Rangoon", "Myanmar", "Asia/Rangoon",
"Asia/Baku", "Azerbaijan", "Asia/Baku",
"America/Santiago", "Chile", "America/Santiago",
"America/El_Salvador", "America_Central", "America/Chicago",
"America/Noronha", "Noronha", "America/Noronha",
"America/St_Thomas", "Atlantic", "America/Halifax",
"Atlantic/St_Helena", "GMT", "Atlantic/Reykjavik",
"Asia/Krasnoyarsk", "Krasnoyarsk", "Asia/Krasnoyarsk",
"America/Vancouver", "America_Pacific", "America/Los_Angeles",
"Europe/Belgrade", "Europe_Central", "Europe/Paris",
"America/St_Barthelemy", "Atlantic", "America/Halifax",
"Asia/Pontianak", "Indonesia_Western", "Asia/Jakarta",
"Africa/Lusaka", "Africa_Central", "Africa/Maputo",
"America/Godthab", "Greenland_Western", "America/Godthab",
"Asia/Dhaka", "Bangladesh", "Asia/Dhaka",
"Asia/Dubai", "Gulf", "Asia/Dubai",
"Europe/Moscow", "Moscow", "Europe/Moscow",
"America/Louisville", "America_Eastern", "America/New_York",
"Australia/Darwin", "Australia_Central", "Australia/Adelaide",
"America/Santo_Domingo", "Atlantic", "America/Halifax",
"America/Argentina/Ushuaia", "Argentina", "America/Buenos_Aires",
"America/Tegucigalpa", "America_Central", "America/Chicago",
"Asia/Aden", "Arabian", "Asia/Riyadh",
"America/Inuvik", "America_Mountain", "America/Denver",
"Asia/Beirut", "Europe_Eastern", "Europe/Bucharest",
"Asia/Qatar", "Arabian", "Asia/Riyadh",
"Europe/Oslo", "Europe_Central", "Europe/Paris",
"Asia/Anadyr", "Magadan", "Asia/Magadan",
"Pacific/Palau", "Palau", "Pacific/Palau",
"Arctic/Longyearbyen", "Europe_Central", "Europe/Paris",
"America/Anguilla", "Atlantic", "America/Halifax",
"Asia/Aqtau", "Kazakhstan_Western", "Asia/Aqtobe",
"Asia/Yerevan", "Armenia", "Asia/Yerevan",
"Africa/Lagos", "Africa_Western", "Africa/Lagos",
"America/Denver", "America_Mountain", "America/Denver",
"Antarctica/Palmer", "Chile", "America/Santiago",
"Europe/Stockholm", "Europe_Central", "Europe/Paris",
"America/Bahia", "Brasilia", "America/Sao_Paulo",
"America/Danmarkshavn", "GMT", "Atlantic/Reykjavik",
"Indian/Mauritius", "Mauritius", "Indian/Mauritius",
"Pacific/Chatham", "Chatham", "Pacific/Chatham",
"Europe/Prague", "Europe_Central", "Europe/Paris",
"America/Blanc-Sablon", "Atlantic", "America/Halifax",
"America/Bogota", "Colombia", "America/Bogota",
"America/Managua", "America_Central", "America/Chicago",
"Pacific/Auckland", "New_Zealand", "Pacific/Auckland",
"Atlantic/Faroe", "Europe_Western", "Atlantic/Canary",
"America/Cambridge_Bay", "America_Mountain", "America/Denver",
"America/Los_Angeles", "America_Pacific", "America/Los_Angeles",
"Africa/Khartoum", "Africa_Central", "Africa/Maputo",
"Europe/Simferopol", "Europe_Eastern", "Europe/Bucharest",
"Australia/Currie", "Australia_Eastern", "Australia/Sydney",
"Europe/Guernsey", "GMT", "Atlantic/Reykjavik",
"Asia/Thimphu", "Bhutan", "Asia/Thimphu",
"America/Eirunepe", "Amazon", "America/Manaus",
"Africa/Nairobi", "Africa_Eastern", "Africa/Nairobi",
"Asia/Yakutsk", "Yakutsk", "Asia/Yakutsk",
"Asia/Yangon", "Myanmar", "Asia/Rangoon",
"America/Goose_Bay", "Atlantic", "America/Halifax",
"Africa/Maseru", "Africa_Southern", "Africa/Johannesburg",
"America/Swift_Current", "America_Central", "America/Chicago",
"America/Guyana", "Guyana", "America/Guyana",
"Asia/Tokyo", "Japan", "Asia/Tokyo",
"Indian/Kerguelen", "French_Southern", "Indian/Kerguelen",
"America/Belem", "Brasilia", "America/Sao_Paulo",
"Pacific/Wallis", "Wallis", "Pacific/Wallis",
"America/Whitehorse", "America_Pacific", "America/Los_Angeles",
"America/North_Dakota/Beulah", "America_Central", "America/Chicago",
"Asia/Jerusalem", "Israel", "Asia/Jerusalem",
"Antarctica/Syowa", "Syowa", "Antarctica/Syowa",
"America/Thunder_Bay", "America_Eastern", "America/New_York",
"Asia/Brunei", "Brunei", "Asia/Brunei",
"America/Metlakatla", "America_Pacific", "America/Los_Angeles",
"Asia/Dushanbe", "Tajikistan", "Asia/Dushanbe",
"Pacific/Kosrae", "Kosrae", "Pacific/Kosrae",
"America/Coral_Harbour", "America_Eastern", "America/New_York",
"America/Tortola", "Atlantic", "America/Halifax",
"Asia/Karachi", "Pakistan", "Asia/Karachi",
"Indian/Reunion", "Reunion", "Indian/Reunion",
"America/Detroit", "America_Eastern", "America/New_York",
"Australia/Eucla", "Australia_CentralWestern", "Australia/Eucla",
"Asia/Seoul", "Korea", "Asia/Seoul",
"Asia/Singapore", "Singapore", "Asia/Singapore",
"Africa/Casablanca", "Europe_Western", "Atlantic/Canary",
"Asia/Dili", "East_Timor", "Asia/Dili",
"America/Indiana/Vincennes", "America_Eastern", "America/New_York",
"Europe/Dublin", "GMT", "Atlantic/Reykjavik",
"America/St_Johns", "Newfoundland", "America/St_Johns",
"Antarctica/Macquarie", "Macquarie", "Antarctica/Macquarie",
"America/Port_of_Spain", "Atlantic", "America/Halifax",
"Europe/Budapest", "Europe_Central", "Europe/Paris",
"America/Fortaleza", "Brasilia", "America/Sao_Paulo",
"Australia/Brisbane", "Australia_Eastern", "Australia/Sydney",
"Atlantic/Bermuda", "Atlantic", "America/Halifax",
"Asia/Amman", "Europe_Eastern", "Europe/Bucharest",
"Asia/Tashkent", "Uzbekistan", "Asia/Tashkent",
"Antarctica/DumontDUrville", "DumontDUrville", "Antarctica/DumontDUrville",
"Antarctica/Casey", "Australia_Western", "Australia/Perth",
"Asia/Vientiane", "Indochina", "Asia/Saigon",
"Pacific/Johnston", "Hawaii_Aleutian", "Pacific/Honolulu",
"America/Jamaica", "America_Eastern", "America/New_York",
"Africa/Addis_Ababa", "Africa_Eastern", "Africa/Nairobi",
"Pacific/Ponape", "Ponape", "Pacific/Ponape",
"Europe/Jersey", "GMT", "Atlantic/Reykjavik",
"Africa/Lome", "GMT", "Atlantic/Reykjavik",
"America/Manaus", "Amazon", "America/Manaus",
"Africa/Niamey", "Africa_Western", "Africa/Lagos",
"Asia/Kashgar", "China", "Asia/Shanghai",
"Pacific/Tongatapu", "Tonga", "Pacific/Tongatapu",
"Europe/Minsk", "Europe_Eastern", "Europe/Bucharest",
"America/Edmonton", "America_Mountain", "America/Denver",
"Asia/Baghdad", "Arabian", "Asia/Riyadh",
"Asia/Kathmandu", "Nepal", "Asia/Katmandu",
"America/Ojinaga", "America_Mountain", "America/Denver",
"Africa/Abidjan", "GMT", "Atlantic/Reykjavik",
"America/Indiana/Winamac", "America_Eastern", "America/New_York",
"Asia/Qyzylorda", "Kazakhstan_Eastern", "Asia/Almaty",
"Australia/Sydney", "Australia_Eastern", "Australia/Sydney",
"Asia/Ashgabat", "Turkmenistan", "Asia/Ashgabat",
"Europe/Amsterdam", "Europe_Central", "Europe/Paris",
"America/Dawson_Creek", "America_Mountain", "America/Denver",
"Africa/Cairo", "Europe_Eastern", "Europe/Bucharest",
"Asia/Pyongyang", "Korea", "Asia/Seoul",
"Africa/Kampala", "Africa_Eastern", "Africa/Nairobi",
"America/Araguaina", "Brasilia", "America/Sao_Paulo",
"Asia/Novokuznetsk", "Novosibirsk", "Asia/Novosibirsk",
"Pacific/Kwajalein", "Marshall_Islands", "Pacific/Majuro",
"Africa/Lubumbashi", "Africa_Central", "Africa/Maputo",
"Asia/Sakhalin", "Sakhalin", "Asia/Sakhalin",
"America/Indiana/Vevay", "America_Eastern", "America/New_York",
"Africa/Maputo", "Africa_Central", "Africa/Maputo",
"Atlantic/Faeroe", "Europe_Western", "Atlantic/Canary",
"America/North_Dakota/Center", "America_Central", "America/Chicago",
"Pacific/Wake", "Wake", "Pacific/Wake",
"Pacific/Pago_Pago", "Samoa", "Pacific/Apia",
"America/Moncton", "Atlantic", "America/Halifax",
"Africa/Sao_Tome", "Africa_Western", "Africa/Lagos",
"America/Glace_Bay", "Atlantic", "America/Halifax",
"Asia/Jakarta", "Indonesia_Western", "Asia/Jakarta",
"Africa/Asmera", "Africa_Eastern", "Africa/Nairobi",
"Europe/Lisbon", "Europe_Western", "Atlantic/Canary",
"America/Dawson", "America_Pacific", "America/Los_Angeles",
"America/Cayenne", "French_Guiana", "America/Cayenne",
"Asia/Bahrain", "Arabian", "Asia/Riyadh",
"Europe/Malta", "Europe_Central", "Europe/Paris",
"America/Indiana/Tell_City", "America_Central", "America/Chicago",
"America/Indiana/Petersburg", "America_Eastern", "America/New_York",
"Antarctica/Rothera", "Rothera", "Antarctica/Rothera",
"Asia/Aqtobe", "Kazakhstan_Western", "Asia/Aqtobe",
"Europe/Vaduz", "Europe_Central", "Europe/Paris",
"America/Indiana/Marengo", "America_Eastern", "America/New_York",
"Europe/Brussels", "Europe_Central", "Europe/Paris",
"Europe/Andorra", "Europe_Central", "Europe/Paris",
"America/Indiana/Knox", "America_Central", "America/Chicago",
"Pacific/Easter", "Easter", "Pacific/Easter",
"America/Argentina/Rio_Gallegos", "Argentina", "America/Buenos_Aires",
"Asia/Oral", "Kazakhstan_Western", "Asia/Aqtobe",
"Europe/Copenhagen", "Europe_Central", "Europe/Paris",
"Africa/Johannesburg", "Africa_Southern", "Africa/Johannesburg",
"Pacific/Pohnpei", "Ponape", "Pacific/Ponape",
"America/Argentina/Tucuman", "Argentina", "America/Buenos_Aires",
"America/Toronto", "America_Eastern", "America/New_York",
"Asia/Makassar", "Indonesia_Central", "Asia/Makassar",
"Europe/Berlin", "Europe_Central", "Europe/Paris",
"America/Argentina/Mendoza", "Argentina", "America/Buenos_Aires",
"America/Cuiaba", "Amazon", "America/Manaus",
"America/Creston", "America_Mountain", "America/Denver",
"Asia/Samarkand", "Uzbekistan", "Asia/Tashkent",
"Asia/Hovd", "Hovd", "Asia/Hovd",
"Europe/Bratislava", "Europe_Central", "Europe/Paris",
"Africa/Accra", "GMT", "Atlantic/Reykjavik",
"Africa/Douala", "Africa_Western", "Africa/Lagos",
"Africa/Nouakchott", "GMT", "Atlantic/Reykjavik",
"Europe/Sofia", "Europe_Eastern", "Europe/Bucharest",
"Antarctica/Davis", "Davis", "Antarctica/Davis",
"Antarctica/McMurdo", "New_Zealand", "Pacific/Auckland",
"Europe/San_Marino", "Europe_Central", "Europe/Paris",
"Africa/Porto-Novo", "Africa_Western", "Africa/Lagos",
"Asia/Jayapura", "Indonesia_Eastern", "Asia/Jayapura",
"America/St_Lucia", "Atlantic", "America/Halifax",
"America/Nipigon", "America_Eastern", "America/New_York",
"America/Argentina/Catamarca", "Argentina", "America/Buenos_Aires",
"Europe/Isle_of_Man", "GMT", "Atlantic/Reykjavik",
"America/Kentucky/Louisville", "America_Eastern", "America/New_York",
"America/Merida", "America_Central", "America/Chicago",
"Pacific/Marquesas", "Marquesas", "Pacific/Marquesas",
"Asia/Magadan", "Magadan", "Asia/Magadan",
"Africa/Libreville", "Africa_Western", "Africa/Lagos",
"Pacific/Efate", "Vanuatu", "Pacific/Efate",
"Asia/Kuala_Lumpur", "Malaysia", "Asia/Kuching",
"America/Iqaluit", "America_Eastern", "America/New_York",
"Indian/Comoro", "Africa_Eastern", "Africa/Nairobi",
"America/Panama", "America_Eastern", "America/New_York",
"Asia/Hebron", "Europe_Eastern", "Europe/Bucharest",
"America/Jujuy", "Argentina", "America/Buenos_Aires",
"America/Pangnirtung", "America_Eastern", "America/New_York",
"Asia/Tbilisi", "Georgia", "Asia/Tbilisi",
"Europe/Podgorica", "Europe_Central", "Europe/Paris",
"America/Boise", "America_Mountain", "America/Denver",
"Asia/Muscat", "Gulf", "Asia/Dubai",
"Indian/Mahe", "Seychelles", "Indian/Mahe",
"America/Montreal", "America_Eastern", "America/New_York",
"Africa/Bangui", "Africa_Western", "Africa/Lagos",
"America/Curacao", "Atlantic", "America/Halifax",
"Asia/Taipei", "Taipei", "Asia/Taipei",
"Europe/Ljubljana", "Europe_Central", "Europe/Paris",
"Atlantic/Stanley", "Falkland", "Atlantic/Stanley",
"Pacific/Guadalcanal", "Solomon", "Pacific/Guadalcanal",
"Asia/Kuwait", "Arabian", "Asia/Riyadh",
"Asia/Riyadh", "Arabian", "Asia/Riyadh",
"Europe/Tallinn", "Europe_Eastern", "Europe/Bucharest",
"America/New_York", "America_Eastern", "America/New_York",
"America/Paramaribo", "Suriname", "America/Paramaribo",
"America/Argentina/Buenos_Aires", "Argentina", "America/Buenos_Aires",
"Asia/Irkutsk", "Irkutsk", "Asia/Irkutsk",
"Asia/Katmandu", "Nepal", "Asia/Katmandu",
"America/Kralendijk", "Atlantic", "America/Halifax",
};
private static final String[] mzoneMap = new String[] {
"GMT", "ML", "Africa/Bamako",
"GMT", "IE", "Europe/Dublin",
"GMT", "SN", "Africa/Dakar",
"GMT", "GH", "Africa/Accra",
"GMT", "CI", "Africa/Abidjan",
"GMT", "BF", "Africa/Ouagadougou",
"GMT", "MR", "Africa/Nouakchott",
"GMT", "GM", "Africa/Banjul",
"GMT", "SL", "Africa/Freetown",
"GMT", "GN", "Africa/Conakry",
"GMT", "SH", "Atlantic/St_Helena",
"GMT", "GB", "Europe/London",
"GMT", "LR", "Africa/Monrovia",
"GMT", "TG", "Africa/Lome",
"Africa_Western", "ST", "Africa/Sao_Tome",
"Africa_Western", "CF", "Africa/Bangui",
"Africa_Western", "NE", "Africa/Niamey",
"Africa_Western", "CM", "Africa/Douala",
"Africa_Western", "CD", "Africa/Kinshasa",
"Africa_Western", "CG", "Africa/Brazzaville",
"Africa_Western", "GA", "Africa/Libreville",
"Africa_Western", "TD", "Africa/Ndjamena",
"Africa_Western", "AO", "Africa/Luanda",
"Africa_Western", "GQ", "Africa/Malabo",
"Africa_Eastern", "YT", "Indian/Mayotte",
"Africa_Eastern", "UG", "Africa/Kampala",
"Africa_Eastern", "ET", "Africa/Addis_Ababa",
"Africa_Eastern", "MG", "Indian/Antananarivo",
"Africa_Eastern", "TZ", "Africa/Dar_es_Salaam",
"Africa_Eastern", "SO", "Africa/Mogadishu",
"Africa_Eastern", "ER", "Africa/Asmera",
"Africa_Eastern", "KM", "Indian/Comoro",
"Africa_Eastern", "DJ", "Africa/Djibouti",
"Europe_Central", "GI", "Europe/Gibraltar",
"Europe_Central", "DK", "Europe/Copenhagen",
"Europe_Central", "SE", "Europe/Stockholm",
"Europe_Central", "CH", "Europe/Zurich",
"Europe_Central", "AL", "Europe/Tirane",
"Europe_Central", "RS", "Europe/Belgrade",
"Europe_Central", "HU", "Europe/Budapest",
"Europe_Central", "MT", "Europe/Malta",
"Europe_Central", "PL", "Europe/Warsaw",
"Europe_Central", "ME", "Europe/Podgorica",
"Europe_Central", "ES", "Europe/Madrid",
"Europe_Central", "CZ", "Europe/Prague",
"Europe_Central", "IT", "Europe/Rome",
"Europe_Central", "SI", "Europe/Ljubljana",
"Europe_Central", "LI", "Europe/Vaduz",
"Europe_Central", "AT", "Europe/Vienna",
"Europe_Central", "VA", "Europe/Vatican",
"Europe_Central", "DE", "Europe/Berlin",
"Europe_Central", "NO", "Europe/Oslo",
"Europe_Central", "SK", "Europe/Bratislava",
"Europe_Central", "AD", "Europe/Andorra",
"Europe_Central", "SM", "Europe/San_Marino",
"Europe_Central", "MK", "Europe/Skopje",
"Europe_Central", "TN", "Africa/Tunis",
"Europe_Central", "HR", "Europe/Zagreb",
"Europe_Central", "NL", "Europe/Amsterdam",
"Europe_Central", "BE", "Europe/Brussels",
"Europe_Central", "MC", "Europe/Monaco",
"Europe_Central", "LU", "Europe/Luxembourg",
"Europe_Central", "BA", "Europe/Sarajevo",
"China", "MO", "Asia/Macau",
"America_Pacific", "MX", "America/Tijuana",
"America_Pacific", "CA", "America/Vancouver",
"Indochina", "LA", "Asia/Vientiane",
"Indochina", "KH", "Asia/Phnom_Penh",
"Indochina", "TH", "Asia/Bangkok",
"Korea", "KP", "Asia/Pyongyang",
"America_Mountain", "MX", "America/Hermosillo",
"America_Mountain", "CA", "America/Edmonton",
"Africa_Southern", "LS", "Africa/Maseru",
"Africa_Southern", "SZ", "Africa/Mbabane",
"Chile", "AQ", "Antarctica/Palmer",
"New_Zealand", "AQ", "Antarctica/McMurdo",
"Gulf", "OM", "Asia/Muscat",
"Europe_Western", "FO", "Atlantic/Faeroe",
"America_Eastern", "TC", "America/Grand_Turk",
"America_Eastern", "CA", "America/Toronto",
"America_Eastern", "BS", "America/Nassau",
"America_Eastern", "PA", "America/Panama",
"America_Eastern", "JM", "America/Jamaica",
"America_Eastern", "KY", "America/Cayman",
"Africa_Central", "BI", "Africa/Bujumbura",
"Africa_Central", "ZM", "Africa/Lusaka",
"Africa_Central", "ZW", "Africa/Harare",
"Africa_Central", "CD", "Africa/Lubumbashi",
"Africa_Central", "BW", "Africa/Gaborone",
"Africa_Central", "RW", "Africa/Kigali",
"Africa_Central", "MW", "Africa/Blantyre",
"America_Central", "MX", "America/Mexico_City",
"America_Central", "HN", "America/Tegucigalpa",
"America_Central", "CA", "America/Winnipeg",
"America_Central", "GT", "America/Guatemala",
"America_Central", "SV", "America/El_Salvador",
"America_Central", "CR", "America/Costa_Rica",
"America_Central", "BZ", "America/Belize",
"Atlantic", "MS", "America/Montserrat",
"Atlantic", "AG", "America/Antigua",
"Atlantic", "TT", "America/Port_of_Spain",
"Atlantic", "MQ", "America/Martinique",
"Atlantic", "DM", "America/Dominica",
"Atlantic", "KN", "America/St_Kitts",
"Atlantic", "BM", "Atlantic/Bermuda",
"Atlantic", "PR", "America/Puerto_Rico",
"Atlantic", "AW", "America/Aruba",
"Atlantic", "VG", "America/Tortola",
"Atlantic", "GD", "America/Grenada",
"Atlantic", "GL", "America/Thule",
"Atlantic", "BB", "America/Barbados",
"Atlantic", "BQ", "America/Kralendijk",
"Atlantic", "SX", "America/Lower_Princes",
"Atlantic", "VI", "America/St_Thomas",
"Atlantic", "MF", "America/Marigot",
"Atlantic", "AI", "America/Anguilla",
"Atlantic", "AN", "America/Curacao",
"Atlantic", "LC", "America/St_Lucia",
"Atlantic", "GP", "America/Guadeloupe",
"Atlantic", "VC", "America/St_Vincent",
"Arabian", "QA", "Asia/Qatar",
"Arabian", "YE", "Asia/Aden",
"Arabian", "KW", "Asia/Kuwait",
"Arabian", "BH", "Asia/Bahrain",
"Arabian", "IQ", "Asia/Baghdad",
"India", "LK", "Asia/Colombo",
"Europe_Eastern", "SY", "Asia/Damascus",
"Europe_Eastern", "BG", "Europe/Sofia",
"Europe_Eastern", "GR", "Europe/Athens",
"Europe_Eastern", "JO", "Asia/Amman",
"Europe_Eastern", "CY", "Asia/Nicosia",
"Europe_Eastern", "AX", "Europe/Mariehamn",
"Europe_Eastern", "LB", "Asia/Beirut",
"Europe_Eastern", "FI", "Europe/Helsinki",
"Europe_Eastern", "EG", "Africa/Cairo",
"Chamorro", "GU", "Pacific/Guam",
};
private static final String[] aliasMap = new String[] {
"Brazil/Acre", "America/Rio_Branco",
"US/Indiana-Starke", "America/Indiana/Knox",
"America/Atka", "America/Adak",
"America/St_Barthelemy", "America/Guadeloupe",
"Australia/North", "Australia/Darwin",
"Europe/Zagreb", "Europe/Belgrade",
"Etc/Universal", "Etc/UTC",
"NZ-CHAT", "Pacific/Chatham",
"Asia/Macao", "Asia/Macau",
"Pacific/Yap", "Pacific/Chuuk",
"Egypt", "Africa/Cairo",
"US/Central", "America/Chicago",
"Canada/Atlantic", "America/Halifax",
"Brazil/East", "America/Sao_Paulo",
"America/Cordoba", "America/Argentina/Cordoba",
"US/Hawaii", "Pacific/Honolulu",
"America/Louisville", "America/Kentucky/Louisville",
"America/Shiprock", "America/Denver",
"Australia/Canberra", "Australia/Sydney",
"Asia/Chungking", "Asia/Chongqing",
"Universal", "Etc/UTC",
"US/Alaska", "America/Anchorage",
"Asia/Ujung_Pandang", "Asia/Makassar",
"Japan", "Asia/Tokyo",
"Atlantic/Faeroe", "Atlantic/Faroe",
"Asia/Istanbul", "Europe/Istanbul",
"US/Pacific", "America/Los_Angeles",
"Mexico/General", "America/Mexico_City",
"Poland", "Europe/Warsaw",
"Africa/Asmera", "Africa/Asmara",
"Asia/Saigon", "Asia/Ho_Chi_Minh",
"US/Michigan", "America/Detroit",
"America/Argentina/ComodRivadavia", "America/Argentina/Catamarca",
"W-SU", "Europe/Moscow",
"Australia/ACT", "Australia/Sydney",
"Asia/Calcutta", "Asia/Kolkata",
"Arctic/Longyearbyen", "Europe/Oslo",
"America/Knox_IN", "America/Indiana/Knox",
"ROC", "Asia/Taipei",
"Zulu", "Etc/UTC",
"Australia/Yancowinna", "Australia/Broken_Hill",
"Australia/West", "Australia/Perth",
"Singapore", "Asia/Singapore",
"Europe/Mariehamn", "Europe/Helsinki",
"ROK", "Asia/Seoul",
"America/Porto_Acre", "America/Rio_Branco",
"Etc/Zulu", "Etc/UTC",
"Canada/Yukon", "America/Whitehorse",
"Europe/Vatican", "Europe/Rome",
"Africa/Timbuktu", "Africa/Bamako",
"America/Buenos_Aires", "America/Argentina/Buenos_Aires",
"Canada/Pacific", "America/Vancouver",
"US/Pacific-New", "America/Los_Angeles",
"Mexico/BajaNorte", "America/Tijuana",
"Europe/Guernsey", "Europe/London",
"Asia/Tel_Aviv", "Asia/Jerusalem",
"Chile/Continental", "America/Santiago",
"Jamaica", "America/Jamaica",
"Mexico/BajaSur", "America/Mazatlan",
"Canada/Eastern", "America/Toronto",
"Australia/Tasmania", "Australia/Hobart",
"NZ", "Pacific/Auckland",
"America/Lower_Princes", "America/Curacao",
"GMT-", "Etc/GMT",
"America/Rosario", "America/Argentina/Cordoba",
"Libya", "Africa/Tripoli",
"Asia/Ashkhabad", "Asia/Ashgabat",
"Australia/NSW", "Australia/Sydney",
"America/Marigot", "America/Guadeloupe",
"Europe/Bratislava", "Europe/Prague",
"Portugal", "Europe/Lisbon",
"Etc/GMT-", "Etc/GMT",
"Europe/San_Marino", "Europe/Rome",
"Europe/Sarajevo", "Europe/Belgrade",
"Antarctica/South_Pole", "Antarctica/McMurdo",
"Canada/Central", "America/Winnipeg",
"Etc/GMT", "Etc/GMT",
"Europe/Isle_of_Man", "Europe/London",
"America/Fort_Wayne", "America/Indiana/Indianapolis",
"Eire", "Europe/Dublin",
"America/Coral_Harbour", "America/Atikokan",
"Europe/Nicosia", "Asia/Nicosia",
"US/Samoa", "Pacific/Pago_Pago",
"Hongkong", "Asia/Hong_Kong",
"Canada/Saskatchewan", "America/Regina",
"Asia/Thimbu", "Asia/Thimphu",
"Kwajalein", "Pacific/Kwajalein",
"GB", "Europe/London",
"Chile/EasterIsland", "Pacific/Easter",
"US/East-Indiana", "America/Indiana/Indianapolis",
"Australia/LHI", "Australia/Lord_Howe",
"Cuba", "America/Havana",
"America/Jujuy", "America/Argentina/Jujuy",
"US/Mountain", "America/Denver",
"Atlantic/Jan_Mayen", "Europe/Oslo",
"Europe/Tiraspol", "Europe/Chisinau",
"Europe/Podgorica", "Europe/Belgrade",
"US/Arizona", "America/Phoenix",
"Navajo", "America/Denver",
"Etc/Greenwich", "Etc/GMT",
"Canada/Mountain", "America/Edmonton",
"Iceland", "Atlantic/Reykjavik",
"Australia/Victoria", "Australia/Melbourne",
"Australia/South", "Australia/Adelaide",
"Brazil/West", "America/Manaus",
"Pacific/Ponape", "Pacific/Pohnpei",
"Europe/Ljubljana", "Europe/Belgrade",
"Europe/Jersey", "Europe/London",
"Australia/Queensland", "Australia/Brisbane",
"UTC", "Etc/UTC",
"Canada/Newfoundland", "America/St_Johns",
"Europe/Skopje", "Europe/Belgrade",
"PRC", "Asia/Shanghai",
"UCT", "Etc/UCT",
"America/Mendoza", "America/Argentina/Mendoza",
"Israel", "Asia/Jerusalem",
"US/Eastern", "America/New_York",
"Asia/Ulan_Bator", "Asia/Ulaanbaatar",
"Turkey", "Europe/Istanbul",
"GMT", "Etc/GMT",
"US/Aleutian", "America/Adak",
"Brazil/DeNoronha", "America/Noronha",
"GB-Eire", "Europe/London",
"Asia/Dacca", "Asia/Dhaka",
"America/Ensenada", "America/Tijuana",
"America/Catamarca", "America/Argentina/Catamarca",
"Iran", "Asia/Tehran",
"Greenwich", "Etc/GMT",
"Pacific/Truk", "Pacific/Chuuk",
"Pacific/Samoa", "Pacific/Pago_Pago",
"America/Virgin", "America/St_Thomas",
"Asia/Katmandu", "Asia/Kathmandu",
"America/Indianapolis", "America/Indiana/Indianapolis",
"Europe/Belfast", "Europe/London",
"America/Kralendijk", "America/Curacao",
"Asia/Rangoon", "Asia/Yangon",
};
private static final Map<String, String> zidToMzone = new HashMap<>();
private static final Map<String, String> mzoneToZid = new HashMap<>();
private static final Map<String, Map<String, String>> mzoneToZidL = new HashMap<>();
private static final Map<String, String> aliases = new HashMap<>();
static {
for (int i = 0; i < zidMap.length; i += 3) {
zidToMzone.put(zidMap[i], zidMap[i + 1]);
mzoneToZid.put(zidMap[i + 1], zidMap[i + 2]);
}
for (int i = 0; i < mzoneMap.length; i += 3) {
String mzone = mzoneMap[i];
Map<String, String> map = mzoneToZidL.get(mzone);
if (map == null) {
map = new HashMap<>();
mzoneToZidL.put(mzone, map);
}
map.put(mzoneMap[i + 1], mzoneMap[i + 2]);
}
for (int i = 0; i < aliasMap.length; i += 2) {
aliases.put(aliasMap[i], aliasMap[i + 1]);
}
}
}

View File

@@ -0,0 +1,95 @@
/*
* 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.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Copyright (c) 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.
*/
/**
* <p>
* Provides classes to print and parse dates and times.
* </p>
* <p>
* Printing and parsing is based around the
* {@link java.time.format.DateTimeFormatter DateTimeFormatter} class.
* Instances are generally obtained from
* {@link java.time.format.DateTimeFormatter DateTimeFormatter}, however
* {@link java.time.format.DateTimeFormatterBuilder DateTimeFormatterBuilder}
* can be used if more power is needed.
* </p>
* <p>
* Localization occurs by calling
* {@link java.time.format.DateTimeFormatter#withLocale(java.util.Locale) withLocale(Locale)}
* on the formatter. Further customization is possible using
* {@link java.time.format.DecimalStyle DecimalStyle}.
* </p>
*
* <h3>Package specification</h3>
* <p>
* Unless otherwise noted, passing a null argument to a constructor or method in any class or interface
* in this package will cause a {@link java.lang.NullPointerException NullPointerException} to be thrown.
* The Javadoc "@param" definition is used to summarise the null-behavior.
* The "@throws {@link java.lang.NullPointerException}" is not explicitly documented in each method.
* </p>
* <p>
* All calculations should check for numeric overflow and throw either an {@link java.lang.ArithmeticException}
* or a {@link java.time.DateTimeException}.
* </p>
* @since JDK1.8
*/
package java.time.format;