assert style == Style.SPECIFIC_SHORT;
nameTypes = EnumSet.of(NameType.SHORT_STANDARD, NameType.SHORT_DAYLIGHT);
}
Collection<MatchInfo> specificMatches = _tznames.find(text, startIdx, nameTypes);
if (specificMatches != null) {
MatchInfo specificMatch = null;
for (MatchInfo match : specificMatches) {
if (startIdx + match.matchLength() > parsedPos) {
specificMatch = match;
parsedPos = startIdx + match.matchLength();
}
}
if (specificMatch != null) {
timeType.value = getTimeType(specificMatch.nameType());
pos.setIndex(parsedPos);
return TimeZone.getTimeZone(getTimeZoneID(specificMatch.tzID(), specificMatch.mzID()));
}
}
break;
}
case GENERIC_LONG:
case GENERIC_SHORT:
case GENERIC_LOCATION: {
EnumSet<GenericNameType> genericNameTypes = null;
switch (style) {
case GENERIC_LOCATION:
genericNameTypes = EnumSet.of(GenericNameType.LOCATION);
break;
case GENERIC_LONG:
genericNameTypes = EnumSet.of(GenericNameType.LONG, GenericNameType.LOCATION);
break;
case GENERIC_SHORT:
genericNameTypes = EnumSet.of(GenericNameType.SHORT, GenericNameType.LOCATION);
break;
default:
break;
}
GenericMatchInfo bestGeneric = getTimeZoneGenericNames().findBestMatch(text, startIdx, genericNameTypes);
if (bestGeneric != null && (startIdx + bestGeneric.matchLength() > parsedPos)) {
timeType.value = bestGeneric.timeType();
pos.setIndex(startIdx + bestGeneric.matchLength());
return TimeZone.getTimeZone(bestGeneric.tzID());
}
break;
}
case ZONE_ID: {
tmpPos.setIndex(startIdx);
tmpPos.setErrorIndex(-1);
String id = parseZoneID(text, tmpPos);
if (tmpPos.getErrorIndex() == -1) {
pos.setIndex(tmpPos.getIndex());
return TimeZone.getTimeZone(id);
}
break;
}
case ZONE_ID_SHORT: {
tmpPos.setIndex(startIdx);
tmpPos.setErrorIndex(-1);
String id = parseShortZoneID(text, tmpPos);
if (tmpPos.getErrorIndex() == -1) {
pos.setIndex(tmpPos.getIndex());
return TimeZone.getTimeZone(id);
}
break;
}
case EXEMPLAR_LOCATION: {
tmpPos.setIndex(startIdx);
tmpPos.setErrorIndex(-1);
String id = parseExemplarLocation(text, tmpPos);
if (tmpPos.getErrorIndex() == -1) {
pos.setIndex(tmpPos.getIndex());
return TimeZone.getTimeZone(id);
}
break;
}
}
evaluated |= style.flag;
if (parsedPos > startIdx) {
// When the specified style is one of SPECIFIC_XXX or GENERIC_XXX, we tried to parse the input
// as localized GMT format earlier. If parsedOffset is positive, it means it was successfully
// parsed as localized GMT format, but offset digits were not detected (more specifically, GMT
// zero format). Then, it tried to find a match within the set of display names, but could not
// find a match. At this point, we can safely assume the input text contains the localized
// GMT format.
assert parsedOffset != UNKNOWN_OFFSET;
pos.setIndex(parsedPos);
return getTimeZoneForOffset(parsedOffset);
}
// Failed to parse the input text as the time zone format in the specified style.
// Check the longest match among other styles below.
String parsedID = null; // stores successfully parsed zone ID for later use
TimeType parsedTimeType = TimeType.UNKNOWN; // stores successfully parsed time type for later use
assert parsedPos < 0;
assert parsedOffset == UNKNOWN_OFFSET;
// ISO 8601
if (parsedPos < maxPos && ((evaluated & ISO_Z_STYLE_FLAG) == 0 || (evaluated & ISO_LOCAL_STYLE_FLAG) == 0)) {
tmpPos.setIndex(startIdx);
tmpPos.setErrorIndex(-1);
Output<Boolean> hasDigitOffset = new Output<Boolean>(false);
offset = parseOffsetISO8601(text, tmpPos, false, hasDigitOffset);
if (tmpPos.getErrorIndex() == -1) {
if (tmpPos.getIndex() == maxPos || hasDigitOffset.value) {
pos.setIndex(tmpPos.getIndex());
return getTimeZoneForOffset(offset);
}
// Note: When ISO 8601 format contains offset digits, it should not
// collide with other formats. However, ISO 8601 UTC format "Z" (single letter)
// may collide with other names. In this case, we need to evaluate other names.
if (parsedPos < tmpPos.getIndex()) {
parsedOffset = offset;
parsedID = null;
parsedTimeType = TimeType.UNKNOWN;
parsedPos = tmpPos.getIndex();
assert parsedPos == startIdx + 1; // only when "Z" is used
}
}
}
// Localized GMT format
if (parsedPos < maxPos && (evaluated & Style.LOCALIZED_GMT.flag) == 0) {
tmpPos.setIndex(startIdx);
tmpPos.setErrorIndex(-1);
Output<Boolean> hasDigitOffset = new Output<Boolean>(false);
offset = parseOffsetLocalizedGMT(text, tmpPos, false, hasDigitOffset);
if (tmpPos.getErrorIndex() == -1) {
if (tmpPos.getIndex() == maxPos || hasDigitOffset.value) {
pos.setIndex(tmpPos.getIndex());
return getTimeZoneForOffset(offset);
}
// Evaluate other names - see the comment earlier in this method.
if (parsedPos < tmpPos.getIndex()) {
parsedOffset = offset;
parsedID = null;
parsedTimeType = TimeType.UNKNOWN;
parsedPos = tmpPos.getIndex();
}
}
}
if (parsedPos < maxPos && (evaluated & Style.LOCALIZED_GMT_SHORT.flag) == 0) {
tmpPos.setIndex(startIdx);
tmpPos.setErrorIndex(-1);
Output<Boolean> hasDigitOffset = new Output<Boolean>(false);
offset = parseOffsetLocalizedGMT(text, tmpPos, true, hasDigitOffset);
if (tmpPos.getErrorIndex() == -1) {
if (tmpPos.getIndex() == maxPos || hasDigitOffset.value) {
pos.setIndex(tmpPos.getIndex());
return getTimeZoneForOffset(offset);
}
// Evaluate other names - see the comment earlier in this method.
if (parsedPos < tmpPos.getIndex()) {
parsedOffset = offset;
parsedID = null;
parsedTimeType = TimeType.UNKNOWN;
parsedPos = tmpPos.getIndex();
}
}
}
// When ParseOption.ALL_STYLES is available, we also try to look all possible display names and IDs.
// For example, when style is GENERIC_LONG, "EST" (SPECIFIC_SHORT) is never
// used for America/New_York. With parseAllStyles true, this code parses "EST"
// as America/New_York.
// Note: Adding all possible names into the trie used by the implementation is quite heavy operation,
// which we want to avoid normally (note that we cache the trie, so this is applicable to the
// first time only as long as the cache does not expire).
boolean parseAllStyles = (options == null) ? getDefaultParseOptions().contains(ParseOption.ALL_STYLES) : options
.contains(ParseOption.ALL_STYLES);
if (parseAllStyles) {
// Try all specific names and exemplar location names
if (parsedPos < maxPos) {
Collection<MatchInfo> specificMatches = _tznames.find(text, startIdx, ALL_SIMPLE_NAME_TYPES);
MatchInfo specificMatch = null;
int matchPos = -1;
if (specificMatches != null) {
for (MatchInfo match : specificMatches) {
if (startIdx + match.matchLength() > matchPos) {
specificMatch = match;
matchPos = startIdx + match.matchLength();
}
}
}
if (parsedPos < matchPos) {
parsedPos = matchPos;
parsedID = getTimeZoneID(specificMatch.tzID(), specificMatch.mzID());
parsedTimeType = getTimeType(specificMatch.nameType());
parsedOffset = UNKNOWN_OFFSET;
}
}
// Try generic names