1 7 8 20 21 package java.text; 22 23 import java.util.TimeZone ; 24 import java.util.Calendar ; 25 import java.util.Date ; 26 import java.util.Locale ; 27 import java.util.ResourceBundle ; 28 import java.util.SimpleTimeZone ; 29 import java.util.GregorianCalendar ; 30 import java.io.ObjectInputStream ; 31 import java.io.InvalidObjectException ; 32 import java.io.IOException ; 33 import java.lang.ClassNotFoundException ; 34 import java.util.Hashtable ; 35 import java.lang.StringIndexOutOfBoundsException ; 36 import sun.text.resources.LocaleData; 37 import sun.util.calendar.CalendarUtils; 38 import sun.util.calendar.ZoneInfoFile; 39 40 315 public class SimpleDateFormat extends DateFormat { 316 317 static final long serialVersionUID = 4774881970558875024L; 320 321 static final int currentSerialVersion = 1; 325 326 340 private int serialVersionOnStream = currentSerialVersion; 341 342 347 private String pattern; 348 349 352 transient private char[] compiledPattern; 353 354 357 private final static int TAG_QUOTE_ASCII_CHAR = 100; 358 private final static int TAG_QUOTE_CHARS = 101; 359 360 365 transient private char zeroDigit; 366 367 373 private DateFormatSymbols formatData; 374 375 382 private Date defaultCenturyStart; 383 384 transient private int defaultCenturyStartYear; 385 386 private static final int millisPerHour = 60 * 60 * 1000; 387 private static final int millisPerMinute = 60 * 1000; 388 389 private static final String GMT = "GMT"; 392 393 396 private static Hashtable cachedLocaleData = new Hashtable (3); 397 398 401 private static Hashtable cachedNumberFormatData = new Hashtable (3); 402 403 410 public SimpleDateFormat() { 411 this(SHORT, SHORT, Locale.getDefault()); 412 } 413 414 425 public SimpleDateFormat(String pattern) 426 { 427 this(pattern, Locale.getDefault()); 428 } 429 430 442 public SimpleDateFormat(String pattern, Locale locale) 443 { 444 this.pattern = pattern; 445 this.formatData = new DateFormatSymbols (locale); 446 initialize(locale); 447 } 448 449 458 public SimpleDateFormat(String pattern, DateFormatSymbols formatSymbols) 459 { 460 this.pattern = pattern; 461 this.formatData = (DateFormatSymbols ) formatSymbols.clone(); 462 initialize(Locale.getDefault()); 463 } 464 465 466 SimpleDateFormat(int timeStyle, int dateStyle, Locale loc) { 467 468 String [] dateTimePatterns = (String []) cachedLocaleData.get(loc); 469 if (dateTimePatterns == null) { 470 ResourceBundle r = LocaleData.getLocaleElements(loc); 471 dateTimePatterns = r.getStringArray("DateTimePatterns"); 472 473 cachedLocaleData.put(loc, dateTimePatterns); 474 } 475 formatData = new DateFormatSymbols (loc); 476 if ((timeStyle >= 0) && (dateStyle >= 0)) { 477 Object [] dateTimeArgs = {dateTimePatterns[timeStyle], 478 dateTimePatterns[dateStyle + 4]}; 479 pattern = MessageFormat.format(dateTimePatterns[8], dateTimeArgs); 480 } 481 else if (timeStyle >= 0) { 482 pattern = dateTimePatterns[timeStyle]; 483 } 484 else if (dateStyle >= 0) { 485 pattern = dateTimePatterns[dateStyle + 4]; 486 } 487 else { 488 throw new IllegalArgumentException ("No date or time style specified"); 489 } 490 491 initialize(loc); 492 } 493 494 495 private void initialize(Locale loc) { 496 compiledPattern = compile(pattern); 498 499 calendar = Calendar.getInstance(TimeZone.getDefault(), loc); 504 505 506 numberFormat = (NumberFormat ) cachedNumberFormatData.get(loc); 507 if (numberFormat == null) { 508 numberFormat = NumberFormat.getIntegerInstance(loc); 509 numberFormat.setGroupingUsed(false); 510 511 512 cachedNumberFormatData.put(loc, numberFormat); 513 } 514 numberFormat = (NumberFormat ) numberFormat.clone(); 515 516 initializeDefaultCentury(); 517 } 518 519 583 private char[] compile(String pattern) { 584 int length = pattern.length(); 585 boolean inQuote = false; 586 StringBuilder compiledPattern = new StringBuilder (length * 2); 587 StringBuilder tmpBuffer = null; 588 int count = 0; 589 int lastTag = -1; 590 591 for (int i = 0; i < length; i++) { 592 char c = pattern.charAt(i); 593 594 if (c == '\'') { 595 if ((i + 1) < length) { 598 c = pattern.charAt(i + 1); 599 if (c == '\'') { 600 i++; 601 if (count != 0) { 602 encode(lastTag, count, compiledPattern); 603 lastTag = -1; 604 count = 0; 605 } 606 if (inQuote) { 607 tmpBuffer.append(c); 608 } else { 609 compiledPattern.append((char)(TAG_QUOTE_ASCII_CHAR << 8 | c)); 610 } 611 continue; 612 } 613 } 614 if (!inQuote) { 615 if (count != 0) { 616 encode(lastTag, count, compiledPattern); 617 lastTag = -1; 618 count = 0; 619 } 620 if (tmpBuffer == null) { 621 tmpBuffer = new StringBuilder (length); 622 } else { 623 tmpBuffer.setLength(0); 624 } 625 inQuote = true; 626 } else { 627 int len = tmpBuffer.length(); 628 if (len == 1) { 629 char ch = tmpBuffer.charAt(0); 630 if (ch < 128) { 631 compiledPattern.append((char)(TAG_QUOTE_ASCII_CHAR << 8 | ch)); 632 } else { 633 compiledPattern.append((char)(TAG_QUOTE_CHARS << 8 | 1)); 634 compiledPattern.append(ch); 635 } 636 } else { 637 encode(TAG_QUOTE_CHARS, len, compiledPattern); 638 compiledPattern.append(tmpBuffer); 639 } 640 inQuote = false; 641 } 642 continue; 643 } 644 if (inQuote) { 645 tmpBuffer.append(c); 646 continue; 647 } 648 if (!(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z')) { 649 if (count != 0) { 650 encode(lastTag, count, compiledPattern); 651 lastTag = -1; 652 count = 0; 653 } 654 if (c < 128) { 655 compiledPattern.append((char)(TAG_QUOTE_ASCII_CHAR << 8 | c)); 657 } else { 658 int j; 661 for (j = i + 1; j < length; j++) { 662 char d = pattern.charAt(j); 663 if (d == '\'' || (d >= 'a' && d <= 'z' || d >= 'A' && d <= 'Z')) { 664 break; 665 } 666 } 667 compiledPattern.append((char)(TAG_QUOTE_CHARS << 8 | (j - i))); 668 for (; i < j; i++) { 669 compiledPattern.append(pattern.charAt(i)); 670 } 671 i--; 672 } 673 continue; 674 } 675 676 int tag; 677 if ((tag = formatData.patternChars.indexOf(c)) == -1) { 678 throw new IllegalArgumentException ("Illegal pattern character " + 679 "'" + c + "'"); 680 } 681 if (lastTag == -1 || lastTag == tag) { 682 lastTag = tag; 683 count++; 684 continue; 685 } 686 encode(lastTag, count, compiledPattern); 687 lastTag = tag; 688 count = 1; 689 } 690 691 if (inQuote) { 692 throw new IllegalArgumentException ("Unterminated quote"); 693 } 694 695 if (count != 0) { 696 encode(lastTag, count, compiledPattern); 697 } 698 699 int len = compiledPattern.length(); 701 char[] r = new char[len]; 702 compiledPattern.getChars(0, len, r, 0); 703 return r; 704 } 705 706 709 private static final void encode(int tag, int length, StringBuilder buffer) { 710 if (length < 255) { 711 buffer.append((char)(tag << 8 | length)); 712 } else { 713 buffer.append((char)((tag << 8) | 0xff)); 714 buffer.append((char)(length >>> 16)); 715 buffer.append((char)(length & 0xffff)); 716 } 717 } 718 719 722 private void initializeDefaultCentury() { 723 calendar.setTime( new Date () ); 724 calendar.add( Calendar.YEAR, -80 ); 725 parseAmbiguousDatesAsAfter(calendar.getTime()); 726 } 727 728 731 private void parseAmbiguousDatesAsAfter(Date startDate) { 732 defaultCenturyStart = startDate; 733 calendar.setTime(startDate); 734 defaultCenturyStartYear = calendar.get(Calendar.YEAR); 735 } 736 737 746 public void set2DigitYearStart(Date startDate) { 747 parseAmbiguousDatesAsAfter(startDate); 748 } 749 750 759 public Date get2DigitYearStart() { 760 return defaultCenturyStart; 761 } 762 763 774 public StringBuffer format(Date date, StringBuffer toAppendTo, 775 FieldPosition pos) 776 { 777 pos.beginIndex = pos.endIndex = 0; 778 return format(date, toAppendTo, pos.getFieldDelegate()); 779 } 780 781 private StringBuffer format(Date date, StringBuffer toAppendTo, 783 FieldDelegate delegate) { 784 calendar.setTime(date); 786 787 for (int i = 0; i < compiledPattern.length; ) { 788 int tag = compiledPattern[i] >>> 8; 789 int count = compiledPattern[i++] & 0xff; 790 if (count == 255) { 791 count = compiledPattern[i++] << 16; 792 count |= compiledPattern[i++]; 793 } 794 795 switch (tag) { 796 case TAG_QUOTE_ASCII_CHAR: 797 toAppendTo.append((char)count); 798 break; 799 800 case TAG_QUOTE_CHARS: 801 toAppendTo.append(compiledPattern, i, count); 802 i += count; 803 break; 804 805 default: 806 subFormat(tag, count, delegate, toAppendTo); 807 break; 808 } 809 } 810 return toAppendTo; 811 } 812 813 830 public AttributedCharacterIterator formatToCharacterIterator(Object obj) { 831 StringBuffer sb = new StringBuffer (); 832 CharacterIteratorFieldDelegate delegate = new 833 CharacterIteratorFieldDelegate (); 834 835 if (obj instanceof Date ) { 836 format((Date )obj, sb, delegate); 837 } 838 else if (obj instanceof Number ) { 839 format(new Date (((Number )obj).longValue()), sb, delegate); 840 } 841 else if (obj == null) { 842 throw new NullPointerException ( 843 "formatToCharacterIterator must be passed non-null object"); 844 } 845 else { 846 throw new IllegalArgumentException ( 847 "Cannot format given Object as a Date"); 848 } 849 return delegate.getIterator(sb.toString()); 850 } 851 852 private static final int[] PATTERN_INDEX_TO_CALENDAR_FIELD = 854 { 855 Calendar.ERA, Calendar.YEAR, Calendar.MONTH, Calendar.DATE, 856 Calendar.HOUR_OF_DAY, Calendar.HOUR_OF_DAY, Calendar.MINUTE, 857 Calendar.SECOND, Calendar.MILLISECOND, Calendar.DAY_OF_WEEK, 858 Calendar.DAY_OF_YEAR, Calendar.DAY_OF_WEEK_IN_MONTH, 859 Calendar.WEEK_OF_YEAR, Calendar.WEEK_OF_MONTH, 860 Calendar.AM_PM, Calendar.HOUR, Calendar.HOUR, Calendar.ZONE_OFFSET, 861 Calendar.ZONE_OFFSET 862 }; 863 864 private static final int[] PATTERN_INDEX_TO_DATE_FORMAT_FIELD = { 866 DateFormat.ERA_FIELD, DateFormat.YEAR_FIELD, DateFormat.MONTH_FIELD, 867 DateFormat.DATE_FIELD, DateFormat.HOUR_OF_DAY1_FIELD, 868 DateFormat.HOUR_OF_DAY0_FIELD, DateFormat.MINUTE_FIELD, 869 DateFormat.SECOND_FIELD, DateFormat.MILLISECOND_FIELD, 870 DateFormat.DAY_OF_WEEK_FIELD, DateFormat.DAY_OF_YEAR_FIELD, 871 DateFormat.DAY_OF_WEEK_IN_MONTH_FIELD, DateFormat.WEEK_OF_YEAR_FIELD, 872 DateFormat.WEEK_OF_MONTH_FIELD, DateFormat.AM_PM_FIELD, 873 DateFormat.HOUR1_FIELD, DateFormat.HOUR0_FIELD, 874 DateFormat.TIMEZONE_FIELD, DateFormat.TIMEZONE_FIELD, 875 }; 876 877 private static final Field[] PATTERN_INDEX_TO_DATE_FORMAT_FIELD_ID = { 879 Field.ERA, Field.YEAR, Field.MONTH, Field.DAY_OF_MONTH, 880 Field.HOUR_OF_DAY1, Field.HOUR_OF_DAY0, Field.MINUTE, 881 Field.SECOND, Field.MILLISECOND, Field.DAY_OF_WEEK, 882 Field.DAY_OF_YEAR, Field.DAY_OF_WEEK_IN_MONTH, 883 Field.WEEK_OF_YEAR, Field.WEEK_OF_MONTH, 884 Field.AM_PM, Field.HOUR1, Field.HOUR0, Field.TIME_ZONE, 885 Field.TIME_ZONE, 886 }; 887 888 891 private void subFormat(int patternCharIndex, int count, 892 FieldDelegate delegate, StringBuffer buffer) 893 { 894 int maxIntCount = Integer.MAX_VALUE; 895 String current = null; 896 int beginOffset = buffer.length(); 897 898 int field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex]; 899 int value = calendar.get(field); 900 901 905 switch (patternCharIndex) { 906 case 0: current = formatData.eras[value]; 908 break; 909 case 1: if (count >= 4) 911 zeroPaddingNumber(value, count, maxIntCount, buffer); 912 else zeroPaddingNumber(value, 2, 2, buffer); break; 915 case 2: if (count >= 4) 917 current = formatData.months[value]; 918 else if (count == 3) 919 current = formatData.shortMonths[value]; 920 else 921 zeroPaddingNumber(value+1, count, maxIntCount, buffer); 922 break; 923 case 4: if (value == 0) 925 zeroPaddingNumber(calendar.getMaximum(Calendar.HOUR_OF_DAY)+1, 926 count, maxIntCount, buffer); 927 else 928 zeroPaddingNumber(value, count, maxIntCount, buffer); 929 break; 930 case 9: if (count >= 4) 932 current = formatData.weekdays[value]; 933 else current = formatData.shortWeekdays[value]; 935 break; 936 case 14: current = formatData.ampms[value]; 938 break; 939 case 15: if (value == 0) 941 zeroPaddingNumber(calendar.getLeastMaximum(Calendar.HOUR)+1, 942 count, maxIntCount, buffer); 943 else 944 zeroPaddingNumber(value, count, maxIntCount, buffer); 945 break; 946 case 17: int zoneIndex = 948 formatData.getZoneIndex(calendar.getTimeZone().getID()); 949 if (zoneIndex == -1) { 950 value = calendar.get(Calendar.ZONE_OFFSET) + 951 calendar.get(Calendar.DST_OFFSET); 952 buffer.append(ZoneInfoFile.toCustomID(value)); 953 } else { 954 int index = (calendar.get(Calendar.DST_OFFSET) == 0) ? 1: 3; 955 if (count < 4) { 956 index++; 958 } 959 buffer.append(formatData.zoneStrings[zoneIndex][index]); 960 } 961 break; 962 case 18: value = (calendar.get(Calendar.ZONE_OFFSET) + 964 calendar.get(Calendar.DST_OFFSET)) / 60000; 965 966 int width = 4; 967 if (value >= 0) { 968 buffer.append('+'); 969 } else { 970 width++; 971 } 972 973 int num = (value / 60) * 100 + (value % 60); 974 CalendarUtils.sprintf0d(buffer, num, width); 975 break; 976 default: 977 zeroPaddingNumber(value, count, maxIntCount, buffer); 988 break; 989 } 991 if (current != null) { 992 buffer.append(current); 993 } 994 995 int fieldID = PATTERN_INDEX_TO_DATE_FORMAT_FIELD[patternCharIndex]; 996 Field f = PATTERN_INDEX_TO_DATE_FORMAT_FIELD_ID[patternCharIndex]; 997 998 delegate.formatted(fieldID, f, f, beginOffset, buffer.length(), buffer); 999 } 1000 1001 1004 private final void zeroPaddingNumber(int value, int minDigits, int maxDigits, StringBuffer buffer) 1005 { 1006 try { 1011 if (zeroDigit == 0) { 1012 zeroDigit = ((DecimalFormat )numberFormat).getDecimalFormatSymbols().getZeroDigit(); 1013 } 1014 if (value >= 0) { 1015 if (value < 100 && minDigits >= 1 && minDigits <= 2) { 1016 if (value < 10) { 1017 if (minDigits == 2) { 1018 buffer.append(zeroDigit); 1019 } 1020 buffer.append((char)(zeroDigit + value)); 1021 } else { 1022 buffer.append((char)(zeroDigit + value / 10)); 1023 buffer.append((char)(zeroDigit + value % 10)); 1024 } 1025 return; 1026 } else if (value >= 1000 && value < 10000) { 1027 if (minDigits == 4) { 1028 buffer.append((char)(zeroDigit + value / 1000)); 1029 value %= 1000; 1030 buffer.append((char)(zeroDigit + value / 100)); 1031 value %= 100; 1032 buffer.append((char)(zeroDigit + value / 10)); 1033 buffer.append((char)(zeroDigit + value % 10)); 1034 return; 1035 } 1036 if (minDigits == 2 && maxDigits == 2) { 1037 zeroPaddingNumber(value % 100, 2, 2, buffer); 1038 return; 1039 } 1040 } 1041 } 1042 } catch (Exception e) { 1043 } 1044 1045 numberFormat.setMinimumIntegerDigits(minDigits); 1046 numberFormat.setMaximumIntegerDigits(maxDigits); 1047 numberFormat.format((long)value, buffer, DontCareFieldPosition.INSTANCE); 1048 } 1049 1050 1051 1072 public Date parse(String text, ParsePosition pos) 1073 { 1074 int start = pos.index; 1075 int oldStart = start; 1076 int textLength = text.length(); 1077 1078 boolean[] ambiguousYear = {false}; 1079 1080 calendar.clear(); 1082 for (int i = 0; i < compiledPattern.length; ) { 1083 int tag = compiledPattern[i] >>> 8; 1084 int count = compiledPattern[i++] & 0xff; 1085 if (count == 255) { 1086 count = compiledPattern[i++] << 16; 1087 count |= compiledPattern[i++]; 1088 } 1089 1090 switch (tag) { 1091 case TAG_QUOTE_ASCII_CHAR: 1092 if (start >= textLength || text.charAt(start) != (char)count) { 1093 pos.index = oldStart; 1094 pos.errorIndex = start; 1095 return null; 1096 } 1097 start++; 1098 break; 1099 1100 case TAG_QUOTE_CHARS: 1101 while (count-- > 0) { 1102 if (start >= textLength || text.charAt(start) != compiledPattern[i++]) { 1103 pos.index = oldStart; 1104 pos.errorIndex = start; 1105 return null; 1106 } 1107 start++; 1108 } 1109 break; 1110 1111 default: 1112 boolean obeyCount = false; 1118 if (i < compiledPattern.length) { 1119 int nextTag = compiledPattern[i] >>> 8; 1120 if (!(nextTag == TAG_QUOTE_ASCII_CHAR || nextTag == TAG_QUOTE_CHARS)) { 1121 obeyCount = true; 1122 } 1123 } 1124 start = subParse(text, start, tag, count, obeyCount, 1125 ambiguousYear, pos); 1126 if (start < 0) { 1127 pos.index = oldStart; 1128 return null; 1129 } 1130 } 1131 } 1132 1133 1137 pos.index = start; 1138 1139 1154 Date parsedDate; 1162 try { 1163 if (ambiguousYear[0]) { 1165 Calendar savedCalendar = (Calendar )calendar.clone(); 1170 parsedDate = calendar.getTime(); 1171 if (parsedDate.before(defaultCenturyStart)) 1172 { 1173 savedCalendar.set(Calendar.YEAR, defaultCenturyStartYear + 100); 1175 parsedDate = savedCalendar.getTime(); 1176 } 1177 } 1178 else parsedDate = calendar.getTime(); 1179 } 1180 catch (IllegalArgumentException e) { 1183 pos.errorIndex = start; 1184 pos.index = oldStart; 1185 return null; 1186 } 1187 1188 return parsedDate; 1189 } 1190 1191 1200 private int matchString(String text, int start, int field, String [] data) 1201 { 1202 int i = 0; 1203 int count = data.length; 1204 1205 if (field == Calendar.DAY_OF_WEEK) i = 1; 1206 1207 int bestMatchLength = 0, bestMatch = -1; 1212 for (; i<count; ++i) 1213 { 1214 int length = data[i].length(); 1215 if (length > bestMatchLength && 1218 text.regionMatches(true, start, data[i], 0, length)) 1219 { 1220 bestMatch = i; 1221 bestMatchLength = length; 1222 } 1223 } 1224 if (bestMatch >= 0) 1225 { 1226 calendar.set(field, bestMatch); 1227 return start + bestMatchLength; 1228 } 1229 return -start; 1230 } 1231 1232 private int matchZoneString(String text, int start, int zoneIndex) { 1233 for (int j = 1; j <= 4; ++j) { 1234 String zoneName = formatData.zoneStrings[zoneIndex][j]; 1237 if (text.regionMatches(true, start, 1238 zoneName, 0, zoneName.length())) { 1239 return j; 1240 } 1241 } 1242 return -1; 1243 } 1244 1245 private boolean matchDSTString(String text, int start, int zoneIndex, int standardIndex) { 1246 int index = standardIndex + 2; 1247 String zoneName = formatData.zoneStrings[zoneIndex][index]; 1248 if (text.regionMatches(true, start, 1249 zoneName, 0, zoneName.length())) { 1250 return true; 1251 } 1252 return false; 1253 } 1254 1255 1259 private int subParseZoneString(String text, int start) { 1260 boolean useSameName = false; TimeZone currentTimeZone = getTimeZone(); 1262 1263 int zoneIndex = 1267 formatData.getZoneIndex (currentTimeZone.getID()); 1268 TimeZone tz = null; 1269 int j = 0, i = 0; 1270 if ((zoneIndex != -1) && ((j = matchZoneString(text, start, zoneIndex)) > 0)) { 1271 if (j <= 2) { 1272 useSameName = matchDSTString(text, start, zoneIndex, j); 1273 } 1274 tz = TimeZone.getTimeZone(formatData.zoneStrings[zoneIndex][0]); 1275 i = zoneIndex; 1276 } 1277 if (tz == null) { 1278 zoneIndex = 1279 formatData.getZoneIndex (TimeZone.getDefault().getID()); 1280 if ((zoneIndex != -1) && ((j = matchZoneString(text, start, zoneIndex)) > 0)) { 1281 if (j <= 2) { 1282 useSameName = matchDSTString(text, start, zoneIndex, j); 1283 } 1284 tz = TimeZone.getTimeZone(formatData.zoneStrings[zoneIndex][0]); 1285 i = zoneIndex; 1286 } 1287 } 1288 1289 if (tz == null) { 1290 for (i = 0; i < formatData.zoneStrings.length; i++) { 1291 if ((j = matchZoneString(text, start, i)) > 0) { 1292 if (j <= 2) { 1293 useSameName = matchDSTString(text, start, i, j); 1294 } 1295 tz = TimeZone.getTimeZone(formatData.zoneStrings[i][0]); 1296 break; 1297 } 1298 } 1299 } 1300 if (tz != null) { if (!tz.equals(currentTimeZone)) { 1302 setTimeZone(tz); 1303 } 1304 if (!useSameName) { 1308 calendar.set(Calendar.ZONE_OFFSET, tz.getRawOffset()); 1309 calendar.set(Calendar.DST_OFFSET, 1310 j >= 3 ? tz.getDSTSavings() : 0); 1311 } 1312 return (start + formatData.zoneStrings[i][j].length()); 1313 } 1314 return 0; 1315 } 1316 1317 1334 private int subParse(String text, int start, int patternCharIndex, int count, 1335 boolean obeyCount, boolean[] ambiguousYear, 1336 ParsePosition origPos) 1337 { 1338 Number number = null; 1339 int value = 0; 1340 ParsePosition pos = new ParsePosition (0); 1341 pos.index = start; 1342 int field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex]; 1343 1344 for (;;) { 1347 if (pos.index >= text.length()) { 1348 origPos.errorIndex = start; 1349 return -1; 1350 } 1351 char c = text.charAt(pos.index); 1352 if (c != ' ' && c != '\t') break; 1353 ++pos.index; 1354 } 1355 1356 if (patternCharIndex == 4 || 1361 patternCharIndex == 15 || 1362 (patternCharIndex == 2 && count <= 2) || 1363 patternCharIndex == 1) 1364 { 1365 if (obeyCount) 1368 { 1369 if ((start+count) > text.length()) { 1370 origPos.errorIndex = start; 1371 return -1; 1372 } 1373 number = numberFormat.parse(text.substring(0, start+count), pos); 1374 } 1375 else number = numberFormat.parse(text, pos); 1376 if (number == null) { 1377 origPos.errorIndex = pos.index; 1378 return -1; 1379 } 1380 value = number.intValue(); 1381 } 1382 1383 int index; 1384 switch (patternCharIndex) 1385 { 1386 case 0: if ((index = matchString(text, start, Calendar.ERA, formatData.eras)) > 0) { 1388 return index; 1389 } else { 1390 origPos.errorIndex = pos.index; 1391 return -1; 1392 } 1393 case 1: if (count <= 2 && (pos.index - start) == 2 1401 && Character.isDigit(text.charAt(start)) 1402 && Character.isDigit(text.charAt(start+1))) 1403 { 1404 int ambiguousTwoDigitYear = defaultCenturyStartYear % 100; 1413 ambiguousYear[0] = value == ambiguousTwoDigitYear; 1414 value += (defaultCenturyStartYear/100)*100 + 1415 (value < ambiguousTwoDigitYear ? 100 : 0); 1416 } 1417 calendar.set(Calendar.YEAR, value); 1418 return pos.index; 1419 case 2: if (count <= 2) { 1422 calendar.set(Calendar.MONTH, value - 1); 1426 return pos.index; 1427 } 1428 else 1429 { 1430 int newStart = 0; 1434 if ((newStart=matchString(text, start, Calendar.MONTH, 1435 formatData.months)) > 0) 1436 return newStart; 1437 else if ((index = matchString(text, start, Calendar.MONTH, 1439 formatData.shortMonths)) > 0) { 1440 return index; 1441 } else { 1442 origPos.errorIndex = pos.index; 1443 return -1; 1444 } 1445 } 1446 case 4: if (value == calendar.getMaximum(Calendar.HOUR_OF_DAY)+1) value = 0; 1449 calendar.set(Calendar.HOUR_OF_DAY, value); 1450 return pos.index; 1451 case 9: { int newStart = 0; 1455 if ((newStart=matchString(text, start, Calendar.DAY_OF_WEEK, 1456 formatData.weekdays)) > 0) 1457 return newStart; 1458 else if ((index = matchString(text, start, Calendar.DAY_OF_WEEK, 1460 formatData.shortWeekdays)) > 0) { 1461 return index; 1462 } else { 1463 origPos.errorIndex = pos.index; 1464 return -1; 1465 } 1466 } 1467 case 14: if ((index = matchString(text, start, Calendar.AM_PM, formatData.ampms)) > 0) { 1469 return index; 1470 } else { 1471 origPos.errorIndex = pos.index; 1472 return -1; 1473 } 1474 1475 case 15: if (value == calendar.getLeastMaximum(Calendar.HOUR)+1) value = 0; 1478 calendar.set(Calendar.HOUR, value); 1479 return pos.index; 1480 case 17: case 18: { 1487 int sign = 0; 1488 int offset; 1489 1490 if ((text.length() - start) >= GMT.length() && 1495 text.regionMatches(true, start, GMT, 0, GMT.length())) { 1496 int num; 1497 calendar.set(Calendar.DST_OFFSET, 0); 1498 pos.index = start + GMT.length(); 1499 1500 try { if( text.charAt(pos.index) == '+' ) { 1502 sign = 1; 1503 } else if( text.charAt(pos.index) == '-' ) { 1504 sign = -1; 1505 } 1506 } 1507 catch(StringIndexOutOfBoundsException e) {} 1508 1509 if (sign == 0) { 1510 calendar.set(Calendar.ZONE_OFFSET, 0 ); 1511 return pos.index; 1512 } 1513 1514 try { 1516 char c = text.charAt(++pos.index); 1517 if (c < '0' || c > '9') { 1518 origPos.errorIndex = pos.index; 1519 return -1; } else { 1521 num = c - '0'; 1522 } 1523 if (text.charAt(++pos.index) != ':') { 1524 c = text.charAt(pos.index); 1525 if (c < '0' || c > '9') { 1526 origPos.errorIndex = pos.index; 1527 return -1; } else { 1529 num *= 10; 1530 num += c - '0'; 1531 pos.index++; 1532 } 1533 } 1534 if (num > 23) { 1535 origPos.errorIndex = pos.index - 1; 1536 return -1; } 1538 if (text.charAt(pos.index) != ':') { 1539 origPos.errorIndex = pos.index; 1540 return -1; } 1542 } 1543 catch(StringIndexOutOfBoundsException e) { 1544 origPos.errorIndex = pos.index; 1545 return -1; } 1547 1548 offset = num * 60; 1550 try { 1551 char c = text.charAt(++pos.index); 1552 if (c < '0' || c > '9') { 1553 origPos.errorIndex = pos.index; 1554 return -1; } else { 1556 num = c - '0'; 1557 c = text.charAt(++pos.index); 1558 if (c < '0' || c > '9') { 1559 origPos.errorIndex = pos.index; 1560 return -1; } else { 1562 num *= 10; 1563 num += c - '0'; 1564 } 1565 } 1566 1567 if (num > 59) { 1568 origPos.errorIndex = pos.index; 1569 return -1; } 1571 } 1572 catch(StringIndexOutOfBoundsException e) { 1573 origPos.errorIndex = pos.index; 1574 return -1; } 1576 offset += num; 1577 1578 } 1580 else { 1581 int i = subParseZoneString(text, pos.index); 1585 if (i != 0) { 1586 return i; 1587 } 1588 1589 try { 1594 if( text.charAt(pos.index) == '+' ) { 1595 sign = 1; 1596 } else if( text.charAt(pos.index) == '-' ) { 1597 sign = -1; 1598 } 1599 if (sign == 0) { 1600 origPos.errorIndex = pos.index; 1601 return -1; 1602 } 1603 1604 int hours = 0; 1606 char c = text.charAt(++pos.index); 1607 if (c < '0' || c > '9') { 1608 origPos.errorIndex = pos.index; 1609 return -1; } else { 1611 hours = c - '0'; 1612 c = text.charAt(++pos.index); 1613 if (c < '0' || c > '9') { 1614 origPos.errorIndex = pos.index; 1615 return -1; } else { 1617 hours *= 10; 1618 hours += c - '0'; 1619 } 1620 } 1621 if (hours > 23) { 1622 origPos.errorIndex = pos.index; 1623 return -1; } 1625 1626 int minutes = 0; 1628 c = text.charAt(++pos.index); 1629 if (c < '0' || c > '9') { 1630 origPos.errorIndex = pos.index; 1631 return -1; } else { 1633 minutes = c - '0'; 1634 c = text.charAt(++pos.index); 1635 if (c < '0' || c > '9') { 1636 origPos.errorIndex = pos.index; 1637 return -1; } else { 1639 minutes *= 10; 1640 minutes += c - '0'; 1641 } 1642 } 1643 1644 if (minutes > 59) { 1645 origPos.errorIndex = pos.index; 1646 return -1; } 1648 1649 offset = hours * 60 + minutes; 1650 } catch(StringIndexOutOfBoundsException e) { 1651 origPos.errorIndex = pos.index; 1652 return -1; } 1654 } 1655 1656 if (sign != 0) 1659 { 1660 offset *= millisPerMinute * sign; 1661 calendar.set(Calendar.ZONE_OFFSET, offset); 1662 calendar.set(Calendar.DST_OFFSET, 0); 1663 return ++pos.index; 1664 } 1665 } 1666 1667 origPos.errorIndex = pos.index; 1669 return -1; 1670 1671 default: 1672 1683 if (obeyCount) 1685 { 1686 if ((start+count) > text.length()) { 1687 origPos.errorIndex = pos.index; 1688 return -1; 1689 } 1690 number = numberFormat.parse(text.substring(0, start+count), pos); 1691 } 1692 else number = numberFormat.parse(text, pos); 1693 if (number != null) { 1694 calendar.set(field, number.intValue()); 1695 return pos.index; 1696 } 1697 origPos.errorIndex = pos.index; 1698 return -1; 1699 } 1700 } 1701 1702 1703 1709 private String translatePattern(String pattern, String from, String to) { 1710 StringBuilder result = new StringBuilder (); 1711 boolean inQuote = false; 1712 for (int i = 0; i < pattern.length(); ++i) { 1713 char c = pattern.charAt(i); 1714 if (inQuote) { 1715 if (c == '\'') 1716 inQuote = false; 1717 } 1718 else { 1719 if (c == '\'') 1720 inQuote = true; 1721 else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { 1722 int ci = from.indexOf(c); 1723 if (ci == -1) 1724 throw new IllegalArgumentException ("Illegal pattern " + 1725 " character '" + 1726 c + "'"); 1727 c = to.charAt(ci); 1728 } 1729 } 1730 result.append(c); 1731 } 1732 if (inQuote) 1733 throw new IllegalArgumentException ("Unfinished quote in pattern"); 1734 return result.toString(); 1735 } 1736 1737 1742 public String toPattern() { 1743 return pattern; 1744 } 1745 1746 1751 public String toLocalizedPattern() { 1752 return translatePattern(pattern, 1753 formatData.patternChars, 1754 formatData.localPatternChars); 1755 } 1756 1757 1764 public void applyPattern (String pattern) 1765 { 1766 compiledPattern = compile(pattern); 1767 this.pattern = pattern; 1768 } 1769 1770 1778 public void applyLocalizedPattern(String pattern) { 1779 String p = translatePattern(pattern, 1780 formatData.localPatternChars, 1781 formatData.patternChars); 1782 compiledPattern = compile(p); 1783 this.pattern = p; 1784 } 1785 1786 1792 public DateFormatSymbols getDateFormatSymbols() 1793 { 1794 return (DateFormatSymbols )formatData.clone(); 1795 } 1796 1797 1804 public void setDateFormatSymbols(DateFormatSymbols newFormatSymbols) 1805 { 1806 this.formatData = (DateFormatSymbols )newFormatSymbols.clone(); 1807 } 1808 1809 1815 public Object clone() { 1816 SimpleDateFormat other = (SimpleDateFormat ) super.clone(); 1817 other.formatData = (DateFormatSymbols ) formatData.clone(); 1818 return other; 1819 } 1820 1821 1826 public int hashCode() 1827 { 1828 return pattern.hashCode(); 1829 } 1831 1832 1839 public boolean equals(Object obj) 1840 { 1841 if (!super.equals(obj)) return false; SimpleDateFormat that = (SimpleDateFormat ) obj; 1843 return (pattern.equals(that.pattern) 1844 && formatData.equals(that.formatData)); 1845 } 1846 1847 1853 private void readObject(ObjectInputStream stream) 1854 throws IOException , ClassNotFoundException { 1855 stream.defaultReadObject(); 1856 1857 try { 1858 compiledPattern = compile(pattern); 1859 } catch (Exception e) { 1860 throw new InvalidObjectException ("invalid pattern"); 1861 } 1862 1863 if (serialVersionOnStream < 1) { 1864 initializeDefaultCentury(); 1866 } 1867 else { 1868 parseAmbiguousDatesAsAfter(defaultCenturyStart); 1870 } 1871 serialVersionOnStream = currentSerialVersion; 1872 1873 TimeZone tz = getTimeZone(); 1878 if (tz instanceof SimpleTimeZone ) { 1879 String id = tz.getID(); 1880 TimeZone zi = TimeZone.getTimeZone(id); 1881 if (zi != null && zi.hasSameRules(tz) && zi.getID().equals(id)) { 1882 setTimeZone(zi); 1883 } 1884 } 1885 } 1886} 1887 | Popular Tags |