8187443: Forest Consolidation: Move files to unified layout

Reviewed-by: darcy, ihse
This commit is contained in:
Erik Joelsson 2017-09-12 19:03:39 +02:00
parent 270fe13182
commit 3789983e89
56923 changed files with 3 additions and 15727 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<>();
}
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,322 @@
/*
* Copyright (c) 2012, 2016, 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 = Objects.requireNonNullElse(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);
}
@Override
public String toString() {
return temporal +
(effectiveChrono != null ? " with chronology " + effectiveChrono : "") +
(effectiveZone != null ? " with zone " + effectiveZone : "");
}
};
}
//-----------------------------------------------------------------------
/**
* 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 " +
query + " from temporal " + temporal);
}
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) {
if (optional > 0 && !temporal.isSupported(field)) {
return null;
}
return temporal.getLong(field);
}
//-----------------------------------------------------------------------
/**
* 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,591 @@
/*
* Copyright (c) 2012, 2017, 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
}
};
// Singleton instance
private static final DateTimeTextProvider INSTANCE = new DateTimeTextProvider();
DateTimeTextProvider() {}
/**
* Gets the provider of text.
*
* @return the provider, not null
*/
static DateTimeTextProvider getInstance() {
return INSTANCE;
}
/**
* 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<Long, String> map = new HashMap<>();
// Narrow names may have duplicated names, such as "J" for January, June, July.
// Get names one by one in that case.
if ((textStyle.equals(TextStyle.NARROW) ||
textStyle.equals(TextStyle.NARROW_STANDALONE))) {
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((month + 1L), name);
}
} else {
Map<String, Integer> displayNames = CalendarDataUtility.retrieveJavaTimeFieldValueNames(
"gregory", Calendar.MONTH, textStyle.toCalendarStyle(), locale);
if (displayNames != null) {
for (Entry<String, Integer> entry : displayNames.entrySet()) {
map.put((long)(entry.getValue() + 1), entry.getKey());
}
} else {
// Although probability is very less, but if other styles have duplicate names.
// 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((month + 1L), name);
}
}
}
if (!map.isEmpty()) {
styleMap.put(textStyle, map);
}
}
return new LocaleStore(styleMap);
}
if (field == DAY_OF_WEEK) {
for (TextStyle textStyle : TextStyle.values()) {
Map<Long, String> map = new HashMap<>();
// Narrow names may have duplicated names, such as "S" for Sunday and Saturday.
// Get names one by one in that case.
if ((textStyle.equals(TextStyle.NARROW) ||
textStyle.equals(TextStyle.NARROW_STANDALONE))) {
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);
}
} else {
Map<String, Integer> displayNames = CalendarDataUtility.retrieveJavaTimeFieldValueNames(
"gregory", Calendar.DAY_OF_WEEK, textStyle.toCalendarStyle(), locale);
if (displayNames != null) {
for (Entry<String, Integer> entry : displayNames.entrySet()) {
map.put((long)toWeekDay(entry.getValue()), entry.getKey());
}
} else {
// Although probability is very less, but if other styles have duplicate names.
// 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, 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.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,687 @@
/*
* 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-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.offset()) {
Long offsetSecs = fieldValues.get(OFFSET_SECONDS);
if (offsetSecs != null) {
return (R) ZoneOffset.ofTotalSeconds(offsetSecs.intValue());
}
if (zone instanceof ZoneOffset) {
return (R)zone;
}
return query.queryFrom(this);
} else if (query == TemporalQueries.zone()) {
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
// Offset (if present) will be given priority over the zone.
if (date != null && time != null) {
Long offsetSecs = fieldValues.get(OFFSET_SECONDS);
if (offsetSecs != null) {
ZoneOffset offset = ZoneOffset.ofTotalSeconds(offsetSecs.intValue());
long instant = date.atTime(time).atZone(offset).toEpochSecond();
fieldValues.put(INSTANT_SECONDS, instant);
} else {
if (zone != null) {
long instant = date.atTime(time).atZone(zone).toEpochSecond();
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,177 @@
/*
* 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.
*
* @since 1.8
*/
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,799 @@
/*
* Copyright (c) 2013, 2016, 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_Western", "Africa/Lagos",
"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_Eastern", "Africa/Nairobi",
"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", "GMT", "Atlantic/Reykjavik",
"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", "ST", "Africa/Sao_Tome",
"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", "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",
"Canada/East-Saskatchewan", "America/Regina",
"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 1.8
*/
package java.time.format;