📄 simpledateformat.java
字号:
} buffer.append(num); num = (value % millisPerHour) / millisPerMinute; if (num < 10) { buffer.append('0'); } buffer.append(num); break; default: // case 3: // 'd' - DATE // case 5: // 'H' - HOUR_OF_DAY:0-based. eg, 23:59 + 1 hour =>> 00:59 // case 6: // 'm' - MINUTE // case 7: // 's' - SECOND // case 8: // 'S' - MILLISECOND // case 10: // 'D' - DAY_OF_YEAR // case 11: // 'F' - DAY_OF_WEEK_IN_MONTH // case 12: // 'w' - WEEK_OF_YEAR // case 13: // 'W' - WEEK_OF_MONTH // case 16: // 'K' - HOUR: 0-based. eg, 11PM + 1 hour =>> 0 AM zeroPaddingNumber(value, count, maxIntCount, buffer); break; } // switch (patternCharIndex) if (current != null) { buffer.append(current); } int fieldID = PATTERN_INDEX_TO_DATE_FORMAT_FIELD[patternCharIndex]; Field f = PATTERN_INDEX_TO_DATE_FORMAT_FIELD_ID[patternCharIndex]; delegate.formatted(fieldID, f, f, beginOffset, buffer.length(), buffer); } /** * Formats a number with the specified minimum and maximum number of digits. */ private final void zeroPaddingNumber(int value, int minDigits, int maxDigits, StringBuffer buffer) { // Optimization for 1, 2 and 4 digit numbers. This should // cover most cases of formatting date/time related items. // Note: This optimization code assumes that maxDigits is // either 2 or Integer.MAX_VALUE (maxIntCount in format()). try { if (zeroDigit == 0) { zeroDigit = ((DecimalFormat)numberFormat).getDecimalFormatSymbols().getZeroDigit(); } if (value >= 0) { if (value < 100 && minDigits >= 1 && minDigits <= 2) { if (value < 10) { if (minDigits == 2) { buffer.append(zeroDigit); } buffer.append((char)(zeroDigit + value)); } else { buffer.append((char)(zeroDigit + value / 10)); buffer.append((char)(zeroDigit + value % 10)); } return; } else if (value >= 1000 && value < 10000) { if (minDigits == 4) { buffer.append((char)(zeroDigit + value / 1000)); value %= 1000; buffer.append((char)(zeroDigit + value / 100)); value %= 100; buffer.append((char)(zeroDigit + value / 10)); buffer.append((char)(zeroDigit + value % 10)); return; } if (minDigits == 2 && maxDigits == 2) { zeroPaddingNumber(value % 100, 2, 2, buffer); return; } } } } catch (Exception e) { } numberFormat.setMinimumIntegerDigits(minDigits); numberFormat.setMaximumIntegerDigits(maxDigits); numberFormat.format((long)value, buffer, DontCareFieldPosition.INSTANCE); } /** * Parses text from a string to produce a <code>Date</code>. * <p> * The method attempts to parse text starting at the index given by * <code>pos</code>. * If parsing succeeds, then the index of <code>pos</code> is updated * to the index after the last character used (parsing does not necessarily * use all characters up to the end of the string), and the parsed * date is returned. The updated <code>pos</code> can be used to * indicate the starting point for the next call to this method. * If an error occurs, then the index of <code>pos</code> is not * changed, the error index of <code>pos</code> is set to the index of * the character where the error occurred, and null is returned. * * @param text A <code>String</code>, part of which should be parsed. * @param pos A <code>ParsePosition</code> object with index and error * index information as described above. * @return A <code>Date</code> parsed from the string. In case of * error, returns null. * @exception NullPointerException if <code>text</code> or <code>pos</code> is null. */ public Date parse(String text, ParsePosition pos) { int start = pos.index; int oldStart = start; int textLength = text.length(); boolean[] ambiguousYear = {false}; calendar.clear(); // Clears all the time fields for (int i = 0; i < compiledPattern.length; ) { int tag = compiledPattern[i] >>> 8; int count = compiledPattern[i++] & 0xff; if (count == 255) { count = compiledPattern[i++] << 16; count |= compiledPattern[i++]; } switch (tag) { case TAG_QUOTE_ASCII_CHAR: if (start >= textLength || text.charAt(start) != (char)count) { pos.index = oldStart; pos.errorIndex = start; return null; } start++; break; case TAG_QUOTE_CHARS: while (count-- > 0) { if (start >= textLength || text.charAt(start) != compiledPattern[i++]) { pos.index = oldStart; pos.errorIndex = start; return null; } start++; } break; default: // Peek the next pattern to determine if we need to // obey the number of pattern letters for // parsing. It's required when parsing contiguous // digit text (e.g., "20010704") with a pattern which // has no delimiters between fields, like "yyyyMMdd". boolean obeyCount = false; if (i < compiledPattern.length) { int nextTag = compiledPattern[i] >>> 8; if (!(nextTag == TAG_QUOTE_ASCII_CHAR || nextTag == TAG_QUOTE_CHARS)) { obeyCount = true; } } start = subParse(text, start, tag, count, obeyCount, ambiguousYear, pos); if (start < 0) { pos.index = oldStart; return null; } } } // If only AM_PM has been set without any hour value, then // HOUR is set to 0 to force calendar to take the HOUR and // AM_PM fields. (bugid: 4736959) (Changing GregorianCalendar // to take a look at both the HOUR and AM_PM stamp values // breaks JCK GregorianCalendar2057.) if (calendar.isSet(Calendar.AM_PM) && !calendar.isSet(Calendar.HOUR) && !calendar.isSet(Calendar.HOUR_OF_DAY)) { calendar.set(Calendar.HOUR, 0); // force to update the stamp value } // At this point the fields of Calendar have been set. Calendar // will fill in default values for missing fields when the time // is computed. pos.index = start; // This part is a problem: When we call parsedDate.after, we compute the time. // Take the date April 3 2004 at 2:30 am. When this is first set up, the year // will be wrong if we're parsing a 2-digit year pattern. It will be 1904. // April 3 1904 is a Sunday (unlike 2004) so it is the DST onset day. 2:30 am // is therefore an "impossible" time, since the time goes from 1:59 to 3:00 am // on that day. It is therefore parsed out to fields as 3:30 am. Then we // add 100 years, and get April 3 2004 at 3:30 am. Note that April 3 2004 is // a Saturday, so it can have a 2:30 am -- and it should. [LIU] /* Date parsedDate = calendar.getTime(); if( ambiguousYear[0] && !parsedDate.after(defaultCenturyStart) ) { calendar.add(Calendar.YEAR, 100); parsedDate = calendar.getTime(); } */ // Because of the above condition, save off the fields in case we need to readjust. // The procedure we use here is not particularly efficient, but there is no other // way to do this given the API restrictions present in Calendar. We minimize // inefficiency by only performing this computation when it might apply, that is, // when the two-digit year is equal to the start year, and thus might fall at the // front or the back of the default century. This only works because we adjust // the year correctly to start with in other cases -- see subParse(). Date parsedDate; try { if (ambiguousYear[0]) // If this is true then the two-digit year == the default start year { // We need a copy of the fields, and we need to avoid triggering a call to // complete(), which will recalculate the fields. Since we can't access // the fields[] array in Calendar, we clone the entire object. This will // stop working if Calendar.clone() is ever rewritten to call complete(). Calendar savedCalendar = (Calendar)calendar.clone(); parsedDate = calendar.getTime(); if (parsedDate.before(defaultCenturyStart)) { // We can't use add here because that does a complete() first. savedCalendar.set(Calendar.YEAR, defaultCenturyStartYear + 100); parsedDate = savedCalendar.getTime(); } } else parsedDate = calendar.getTime(); } // An IllegalArgumentException will be thrown by Calendar.getTime() // if any fields are out of range, e.g., MONTH == 17. catch (IllegalArgumentException e) { pos.errorIndex = start; pos.index = oldStart; return null; } return parsedDate; } /** * Private code-size reduction function used by subParse. * @param text the time text being parsed. * @param start where to start parsing. * @param field the date field being parsed. * @param data the string array to parsed. * @return the new start position if matching succeeded; a negative number * indicating matching failure, otherwise. */ private int matchString(String text, int start, int field, String[] data) { int i = 0; int count = data.length; if (field == Calendar.DAY_OF_WEEK) i = 1; // There may be multiple strings in the data[] array which begin with // the same prefix (e.g., Cerven and Cervenec (June and July) in Czech). // We keep track of the longest match, and return that. Note that this // unfortunately requires us to test all array elements. int bestMatchLength = 0, bestMatch = -1; for (; i<count; ++i) { int length = data[i].length(); // Always compare if we have no match yet; otherwise only compare // against potentially better matches (longer strings). if (length > bestMatchLength && text.regionMatches(true, start, data[i], 0, length)) { bestMatch = i; bestMatchLength = length; } } if (bestMatch >= 0) { calendar.set(field, bestMatch); return start + bestMatchLength; } return -start; } private int matchZoneString(String text, int start, int zoneIndex) { int j; for (j = 1; j <= 4; ++j) { // Checking long and short zones [1 & 2], // and long and short daylight [3 & 4]. if (text.regionMatches(true, start, formatData.zoneStrings[zoneIndex][j], 0, formatData.zoneStrings[zoneIndex][j].length())) { break; } } return (j > 4) ? -1 : j; } /** * find time zone 'text' matched zoneStrings and set to internal * calendar. */ private int subParseZoneString(String text, int start) { // 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 zoneIndex = formatData.getZoneIndex (getTimeZone().getID()); TimeZone tz = null; int j = 0, i = 0; if ((zoneIndex != -1) && ((j = matchZoneString(text, start, zoneIndex)) > 0)) { tz = TimeZone.getTimeZone(formatData.zoneStrings[zoneIndex][0]); i = zoneIndex; } if (tz == null) { zoneIndex = formatData.getZoneIndex (TimeZone.getDefault().getID()); if ((zoneIndex != -1) && ((j = matchZoneString(text, start, zoneIndex)) > 0)) { tz = TimeZone.getTimeZone(formatData.zoneStrings[zoneIndex][0]); i = zoneIndex; } } if (tz == null) { for (i = 0; i < formatData.zoneStrings.length; i++) { if ((j = matchZoneString(text, start, i)) > 0) { tz = TimeZone.getTimeZone(formatData.zoneStrings[i][0]); break; } } } if (tz != null) { // Matched any ? calendar.set(Calendar.ZONE_OFFSET, tz.getRawOffset()); calendar.set(Calendar.DST_OFFSET, j >= 3 ? tz.getDSTSavings() : 0); return (start + formatData.zoneStrings[i][j].length()); } return 0; } /** * Private member function that converts the parsed date strings into * timeFields. Returns -start (for ParsePosition) if failed.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -