📄 simpledateformat.java
字号:
* @param text the time text to be parsed. * @param start where to start parsing. * @param ch the pattern character for the date field text to be parsed. * @param count the count of a pattern character. * @param obeyCount if true, then the next field directly abuts this one, * and we should use the count to know when to stop parsing. * @param ambiguousYear return parameter; upon return, if ambiguousYear[0] * is true, then a two-digit year was parsed and may need to be readjusted. * @param origPos origPos.errorIndex is used to return an error index * at which a parse error occurred, if matching failure occurs. * @return the new start position if matching succeeded; -1 indicating * matching failure, otherwise. In case matching failure occurred, * an error index is set to origPos.errorIndex. */ private int subParse(String text, int start, int patternCharIndex, int count, boolean obeyCount, boolean[] ambiguousYear, ParsePosition origPos) { Number number = null; int value = 0; ParsePosition pos = new ParsePosition(0); pos.index = start; int field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex]; // If there are any spaces here, skip over them. If we hit the end // of the string, then fail. for (;;) { if (pos.index >= text.length()) { origPos.errorIndex = start; return -1; } char c = text.charAt(pos.index); if (c != ' ' && c != '\t') break; ++pos.index; } // We handle a few special cases here where we need to parse // a number value. We handle further, more generic cases below. We need // to handle some of them here because some fields require extra processing on // the parsed value. if (patternCharIndex == 4 /*HOUR_OF_DAY1_FIELD*/ || patternCharIndex == 15 /*HOUR1_FIELD*/ || (patternCharIndex == 2 /*MONTH_FIELD*/ && count <= 2) || patternCharIndex == 1) { // It would be good to unify this with the obeyCount logic below, // but that's going to be difficult. if (obeyCount) { if ((start+count) > text.length()) { origPos.errorIndex = start; return -1; } number = numberFormat.parse(text.substring(0, start+count), pos); } else number = numberFormat.parse(text, pos); if (number == null) { origPos.errorIndex = pos.index; return -1; } value = number.intValue(); } int index; switch (patternCharIndex) { case 0: // 'G' - ERA if ((index = matchString(text, start, Calendar.ERA, formatData.eras)) > 0) { return index; } else { origPos.errorIndex = pos.index; return -1; } case 1: // 'y' - YEAR // If there are 3 or more YEAR pattern characters, this indicates // that the year value is to be treated literally, without any // two-digit year adjustments (e.g., from "01" to 2001). Otherwise // we made adjustments to place the 2-digit year in the proper // century, for parsed strings from "00" to "99". Any other string // is treated literally: "2250", "-1", "1", "002". if (count <= 2 && (pos.index - start) == 2 && Character.isDigit(text.charAt(start)) && Character.isDigit(text.charAt(start+1))) { // Assume for example that the defaultCenturyStart is 6/18/1903. // This means that two-digit years will be forced into the range // 6/18/1903 to 6/17/2003. As a result, years 00, 01, and 02 // correspond to 2000, 2001, and 2002. Years 04, 05, etc. correspond // to 1904, 1905, etc. If the year is 03, then it is 2003 if the // other fields specify a date before 6/18, or 1903 if they specify a // date afterwards. As a result, 03 is an ambiguous year. All other // two-digit years are unambiguous. int ambiguousTwoDigitYear = defaultCenturyStartYear % 100; ambiguousYear[0] = value == ambiguousTwoDigitYear; value += (defaultCenturyStartYear/100)*100 + (value < ambiguousTwoDigitYear ? 100 : 0); } calendar.set(Calendar.YEAR, value); return pos.index; case 2: // 'M' - MONTH if (count <= 2) // i.e., M or MM. { // Don't want to parse the month if it is a string // while pattern uses numeric style: M or MM. // [We computed 'value' above.] calendar.set(Calendar.MONTH, value - 1); return pos.index; } else { // count >= 3 // i.e., MMM or MMMM // Want to be able to parse both short and long forms. // Try count == 4 first: int newStart = 0; if ((newStart=matchString(text, start, Calendar.MONTH, formatData.months)) > 0) return newStart; else // count == 4 failed, now try count == 3 if ((index = matchString(text, start, Calendar.MONTH, formatData.shortMonths)) > 0) { return index; } else { origPos.errorIndex = pos.index; return -1; } } case 4: // 'k' - HOUR_OF_DAY: 1-based. eg, 23:59 + 1 hour =>> 24:59 // [We computed 'value' above.] if (value == calendar.getMaximum(Calendar.HOUR_OF_DAY)+1) value = 0; calendar.set(Calendar.HOUR_OF_DAY, value); return pos.index; case 9: { // 'E' - DAY_OF_WEEK // Want to be able to parse both short and long forms. // Try count == 4 (DDDD) first: int newStart = 0; if ((newStart=matchString(text, start, Calendar.DAY_OF_WEEK, formatData.weekdays)) > 0) return newStart; else // DDDD failed, now try DDD if ((index = matchString(text, start, Calendar.DAY_OF_WEEK, formatData.shortWeekdays)) > 0) { return index; } else { origPos.errorIndex = pos.index; return -1; } } case 14: // 'a' - AM_PM if ((index = matchString(text, start, Calendar.AM_PM, formatData.ampms)) > 0) { return index; } else { origPos.errorIndex = pos.index; return -1; } case 15: // 'h' - HOUR:1-based. eg, 11PM + 1 hour =>> 12 AM // [We computed 'value' above.] if (value == calendar.getLeastMaximum(Calendar.HOUR)+1) value = 0; calendar.set(Calendar.HOUR, value); return pos.index; case 17: // 'z' - ZONE_OFFSET case 18: // 'Z' - ZONE_OFFSET // First try to parse generic forms such as GMT-07:00. Do this first // in case localized DateFormatZoneData contains the string "GMT" // for a zone; in that case, we don't want to match the first three // characters of GMT+/-hh:mm etc. { int sign = 0; int offset; // For time zones that have no known names, look for strings // of the form: // GMT[+-]hours:minutes or // GMT. if ((text.length() - start) >= GMT.length() && text.regionMatches(true, start, GMT, 0, GMT.length())) { int num; calendar.set(Calendar.DST_OFFSET, 0); pos.index = start + GMT.length(); try { // try-catch for "GMT" only time zone string if( text.charAt(pos.index) == '+' ) { sign = 1; } else if( text.charAt(pos.index) == '-' ) { sign = -1; } } catch(StringIndexOutOfBoundsException e) {} if (sign == 0) { /* "GMT" without offset */ calendar.set(Calendar.ZONE_OFFSET, 0 ); return pos.index; } // Look for hours. try { char c = text.charAt(++pos.index); if (c < '0' || c > '9') { /* must be from '0' to '9'. */ origPos.errorIndex = pos.index; return -1; // Wasn't actually a number. } else { num = c - '0'; } if (text.charAt(++pos.index) != ':') { c = text.charAt(pos.index); if (c < '0' || c > '9') { /* must be from '0' to '9'. */ origPos.errorIndex = pos.index; return -1; // Wasn't actually a number. } else { num *= 10; num += c - '0'; pos.index++; } } if (num > 23) { origPos.errorIndex = pos.index - 1; return -1; // Wasn't actually a number. } if (text.charAt(pos.index) != ':') { origPos.errorIndex = pos.index; return -1; // Wasn't actually a number. } } catch(StringIndexOutOfBoundsException e) { origPos.errorIndex = pos.index; return -1; // Wasn't actually a number. } // Look for minutes. offset = num * 60; try { char c = text.charAt(++pos.index); if (c < '0' || c > '9') { /* must be from '0' to '9'. */ origPos.errorIndex = pos.index; return -1; // Wasn't actually a number. } else { num = c - '0'; c = text.charAt(++pos.index); if (c < '0' || c > '9') { /* must be from '0' to '9'. */ origPos.errorIndex = pos.index; return -1; // Wasn't actually a number. } else { num *= 10; num += c - '0'; } } if (num > 59) { origPos.errorIndex = pos.index; return -1; // Wasn't actually a number. } } catch(StringIndexOutOfBoundsException e) { origPos.errorIndex = pos.index; return -1; // Wasn't actually a number. } offset += num; // Fall through for final processing below of 'offset' and 'sign'. } else { // At this point, check for named time zones by looking through // the locale data from the DateFormatZoneData strings. // Want to be able to parse both short and long forms. int i = subParseZoneString(text, pos.index); if (i != 0) { return i; } // As a last resort, look for numeric timezones of the form // [+-]hhmm as specified by RFC 822. This code is actually // a little more permissive than RFC 822. It will try to do // its best with numbers that aren't strictly 4 digits long. try { if( text.charAt(pos.index) == '+' ) { sign = 1; } else if( text.charAt(pos.index) == '-' ) { sign = -1; } if (sign == 0) { origPos.errorIndex = pos.index; return -1; } // Look for hh. int hours = 0; char c = text.charAt(++pos.index); if (c < '0' || c > '9') { /* must be from '0' to '9'. */ origPos.errorIndex = pos.index; return -1; // Wasn't actually a number. } else { hours = c - '0'; c = text.charAt(++pos.index); if (c < '0' || c > '9') { /* must be from '0' to '9'. */ origPos.errorIndex = pos.index; return -1; // Wasn't actually a number. } else { hours *= 10; hours += c - '0'; } } if (hours > 23) { origPos.errorIndex = pos.index; return -1; // Wasn't actually a number. } // Look for mm. int minutes = 0; c = text.charAt(++pos.index); if (c < '0' || c > '9') { /* must be from '0' to '9'. */ origPos.errorIndex = pos.index; return -1; // Wasn't actually a number. } else { minutes = c - '0'; c = text.charAt(++pos.index); if (c < '0' || c > '9') { /* must be from '0' to '9'. */ origPos.errorIndex = pos.index; return -1; // Wasn't actually a number. } else { minutes *= 10; minutes += c - '0'; } } if (minutes > 59) { origPos.errorIndex = pos.index; return -1; // Wasn't actually a number. } offset = hours * 60 + minutes; } catch(StringIndexOutOfBoundsExcept
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -