1:
39:
40:
41: package ;
42:
43: import ;
44:
45: import ;
46: import ;
47: import ;
48: import ;
49:
50: import ;
51: import ;
52: import ;
53: import ;
54: import ;
55: import ;
56: import ;
57: import ;
58: import ;
59: import ;
60: import ;
61: import ;
62:
63:
69: public class SimpleDateFormat extends DateFormat
70: {
71:
77: private class CompiledField
78: {
79:
83: int field;
84:
85:
89: int size;
90:
91:
94: private char character;
95:
96:
105: public CompiledField(int f, int s, char c)
106: {
107: field = f;
108: size = s;
109: character = c;
110: }
111:
112:
116: public int getField()
117: {
118: return field;
119: }
120:
121:
124: public int getSize()
125: {
126: return size;
127: }
128:
129:
132: public char getCharacter()
133: {
134: return character;
135: }
136:
137:
144: public String toString()
145: {
146: CPStringBuilder builder;
147:
148: builder = new CPStringBuilder(getClass().getName());
149: builder.append("[field=");
150: builder.append(field);
151: builder.append(", size=");
152: builder.append(size);
153: builder.append(", character=");
154: builder.append(character);
155: builder.append("]");
156:
157: return builder.toString();
158: }
159: }
160:
161:
168: private transient ArrayList<Object> tokens;
169:
170:
178: private DateFormatSymbols formatData;
179:
180:
193: private Date defaultCenturyStart;
194:
195:
203: private transient int defaultCentury;
204:
205:
217: private String pattern;
218:
219:
231: private int serialVersionOnStream = 1;
232:
233:
236: private static final long serialVersionUID = 4774881970558875024L;
237:
238:
239: private static final String standardChars = "GyMdkHmsSEDFwWahKzYeugAZvcL";
240:
241:
247: private static final int RFC822_TIMEZONE_FIELD = 23;
248:
249:
263: private void readObject(ObjectInputStream stream)
264: throws IOException, ClassNotFoundException
265: {
266: stream.defaultReadObject();
267: if (serialVersionOnStream < 1)
268: {
269: computeCenturyStart ();
270: serialVersionOnStream = 1;
271: }
272: else
273:
274: set2DigitYearStart(defaultCenturyStart);
275:
276:
277: tokens = new ArrayList<Object>();
278: try
279: {
280: compileFormat(pattern);
281: }
282: catch (IllegalArgumentException e)
283: {
284: throw new InvalidObjectException("The stream pattern was invalid.");
285: }
286: }
287:
288:
297: private void compileFormat(String pattern)
298: {
299:
300:
301:
302: char thisChar;
303: int pos;
304: int field;
305: CompiledField current = null;
306:
307: for (int i = 0; i < pattern.length(); i++)
308: {
309: thisChar = pattern.charAt(i);
310: field = standardChars.indexOf(thisChar);
311: if (field == -1)
312: {
313: current = null;
314: if ((thisChar >= 'A' && thisChar <= 'Z')
315: || (thisChar >= 'a' && thisChar <= 'z'))
316: {
317:
318: throw new IllegalArgumentException("Invalid letter "
319: + thisChar +
320: " encountered at character "
321: + i + ".");
322: }
323: else if (thisChar == '\'')
324: {
325:
326: pos = pattern.indexOf('\'', i + 1);
327:
328: if (pos == i + 1)
329: tokens.add("'");
330: else
331: {
332:
333:
334:
335: CPStringBuilder buf = new CPStringBuilder();
336: int oldPos = i + 1;
337: do
338: {
339: if (pos == -1)
340: throw new IllegalArgumentException("Quotes starting at character "
341: + i +
342: " not closed.");
343: buf.append(pattern.substring(oldPos, pos));
344: if (pos + 1 >= pattern.length()
345: || pattern.charAt(pos + 1) != '\'')
346: break;
347: buf.append('\'');
348: oldPos = pos + 2;
349: pos = pattern.indexOf('\'', pos + 2);
350: }
351: while (true);
352: tokens.add(buf.toString());
353: }
354: i = pos;
355: }
356: else
357: {
358:
359: tokens.add(Character.valueOf(thisChar));
360: }
361: }
362: else
363: {
364:
365: if ((current != null) && (field == current.field))
366: current.size++;
367: else
368: {
369: current = new CompiledField(field, 1, thisChar);
370: tokens.add(current);
371: }
372: }
373: }
374: }
375:
376:
383: public String toString()
384: {
385: CPStringBuilder output = new CPStringBuilder(getClass().getName());
386: output.append("[tokens=");
387: output.append(tokens);
388: output.append(", formatData=");
389: output.append(formatData);
390: output.append(", defaultCenturyStart=");
391: output.append(defaultCenturyStart);
392: output.append(", defaultCentury=");
393: output.append(defaultCentury);
394: output.append(", pattern=");
395: output.append(pattern);
396: output.append(", serialVersionOnStream=");
397: output.append(serialVersionOnStream);
398: output.append(", standardChars=");
399: output.append(standardChars);
400: output.append("]");
401: return output.toString();
402: }
403:
404:
408: public SimpleDateFormat()
409: {
410:
415: super();
416: Locale locale = Locale.getDefault();
417: calendar = new GregorianCalendar(locale);
418: computeCenturyStart();
419: tokens = new ArrayList<Object>();
420: formatData = new DateFormatSymbols(locale);
421: pattern = (formatData.dateFormats[DEFAULT] + ' '
422: + formatData.timeFormats[DEFAULT]);
423: compileFormat(pattern);
424: numberFormat = NumberFormat.getInstance(locale);
425: numberFormat.setGroupingUsed (false);
426: numberFormat.setParseIntegerOnly (true);
427: numberFormat.setMaximumFractionDigits (0);
428: }
429:
430:
438: public SimpleDateFormat(String pattern)
439: {
440: this(pattern, Locale.getDefault());
441: }
442:
443:
452: public SimpleDateFormat(String pattern, Locale locale)
453: {
454: super();
455: calendar = new GregorianCalendar(locale);
456: computeCenturyStart();
457: tokens = new ArrayList<Object>();
458: formatData = new DateFormatSymbols(locale);
459: compileFormat(pattern);
460: this.pattern = pattern;
461: numberFormat = NumberFormat.getInstance(locale);
462: numberFormat.setGroupingUsed (false);
463: numberFormat.setParseIntegerOnly (true);
464: numberFormat.setMaximumFractionDigits (0);
465: }
466:
467:
477: public SimpleDateFormat(String pattern, DateFormatSymbols formatData)
478: {
479: super();
480: calendar = new GregorianCalendar();
481: computeCenturyStart ();
482: tokens = new ArrayList<Object>();
483: if (formatData == null)
484: throw new NullPointerException("formatData");
485: this.formatData = formatData;
486: compileFormat(pattern);
487: this.pattern = pattern;
488: numberFormat = NumberFormat.getInstance();
489: numberFormat.setGroupingUsed (false);
490: numberFormat.setParseIntegerOnly (true);
491: numberFormat.setMaximumFractionDigits (0);
492: }
493:
494:
500: public String toPattern()
501: {
502: return pattern;
503: }
504:
505:
511: public String toLocalizedPattern()
512: {
513: String localChars = formatData.getLocalPatternChars();
514: return translateLocalizedPattern(pattern, standardChars, localChars);
515: }
516:
517:
525: public void applyPattern(String pattern)
526: {
527: tokens.clear();
528: compileFormat(pattern);
529: this.pattern = pattern;
530: }
531:
532:
540: public void applyLocalizedPattern(String pattern)
541: {
542: String localChars = formatData.getLocalPatternChars();
543: pattern = translateLocalizedPattern(pattern, localChars, standardChars);
544: applyPattern(pattern);
545: }
546:
547:
563: private String translateLocalizedPattern(String pattern,
564: String oldChars, String newChars)
565: {
566: int len = pattern.length();
567: CPStringBuilder buf = new CPStringBuilder(len);
568: boolean quoted = false;
569: for (int i = 0; i < len; i++)
570: {
571: char ch = pattern.charAt(i);
572: if (ch == '\'')
573: quoted = ! quoted;
574: if (! quoted)
575: {
576: int j = oldChars.indexOf(ch);
577: if (j >= 0)
578: ch = newChars.charAt(j);
579: }
580: buf.append(ch);
581: }
582: return buf.toString();
583: }
584:
585:
591: public Date get2DigitYearStart()
592: {
593: return defaultCenturyStart;
594: }
595:
596:
602: public void set2DigitYearStart(Date date)
603: {
604: defaultCenturyStart = date;
605: calendar.clear();
606: calendar.setTime(date);
607: int year = calendar.get(Calendar.YEAR);
608: defaultCentury = year - (year % 100);
609: }
610:
611:
617: public DateFormatSymbols getDateFormatSymbols()
618: {
619: return (DateFormatSymbols) formatData.clone();
620: }
621:
622:
629: public void setDateFormatSymbols(DateFormatSymbols formatData)
630: {
631: if (formatData == null)
632: {
633: throw new
634: NullPointerException("The supplied format data was null.");
635: }
636: this.formatData = formatData;
637: }
638:
639:
658: public boolean equals(Object o)
659: {
660: if (!super.equals(o))
661: return false;
662:
663: if (!(o instanceof SimpleDateFormat))
664: return false;
665:
666: SimpleDateFormat sdf = (SimpleDateFormat)o;
667:
668: if (defaultCentury != sdf.defaultCentury)
669: return false;
670:
671: if (!toPattern().equals(sdf.toPattern()))
672: return false;
673:
674: if (!getDateFormatSymbols().equals(sdf.getDateFormatSymbols()))
675: return false;
676:
677: return true;
678: }
679:
680:
685: public int hashCode()
686: {
687: return super.hashCode() ^ toPattern().hashCode() ^ defaultCentury ^
688: getDateFormatSymbols().hashCode();
689: }
690:
691:
692:
697: private void formatWithAttribute(Date date, FormatBuffer buffer, FieldPosition pos)
698: {
699: String temp;
700: calendar.setTime(date);
701:
702:
703: Iterator<Object> iter = tokens.iterator();
704: while (iter.hasNext())
705: {
706: Object o = iter.next();
707: if (o instanceof CompiledField)
708: {
709: CompiledField cf = (CompiledField) o;
710: int beginIndex = buffer.length();
711:
712: switch (cf.getField())
713: {
714: case ERA_FIELD:
715: buffer.append (formatData.eras[calendar.get (Calendar.ERA)], DateFormat.Field.ERA);
716: break;
717: case YEAR_FIELD:
718:
719:
720: buffer.setDefaultAttribute (DateFormat.Field.YEAR);
721: if (cf.getSize() == 2)
722: {
723: temp = "00"+String.valueOf (calendar.get (Calendar.YEAR));
724: buffer.append (temp.substring (temp.length() - 2));
725: }
726: else
727: withLeadingZeros (calendar.get (Calendar.YEAR), cf.getSize(), buffer);
728: break;
729: case MONTH_FIELD:
730: buffer.setDefaultAttribute (DateFormat.Field.MONTH);
731: if (cf.getSize() < 3)
732: withLeadingZeros (calendar.get (Calendar.MONTH) + 1, cf.getSize(), buffer);
733: else if (cf.getSize() < 4)
734: buffer.append (formatData.shortMonths[calendar.get (Calendar.MONTH)]);
735: else
736: buffer.append (formatData.months[calendar.get (Calendar.MONTH)]);
737: break;
738: case DATE_FIELD:
739: buffer.setDefaultAttribute (DateFormat.Field.DAY_OF_MONTH);
740: withLeadingZeros (calendar.get (Calendar.DATE), cf.getSize(), buffer);
741: break;
742: case HOUR_OF_DAY1_FIELD:
743: buffer.setDefaultAttribute(DateFormat.Field.HOUR_OF_DAY1);
744: withLeadingZeros ( ((calendar.get (Calendar.HOUR_OF_DAY) + 23) % 24) + 1,
745: cf.getSize(), buffer);
746: break;
747: case HOUR_OF_DAY0_FIELD:
748: buffer.setDefaultAttribute (DateFormat.Field.HOUR_OF_DAY0);
749: withLeadingZeros (calendar.get (Calendar.HOUR_OF_DAY), cf.getSize(), buffer);
750: break;
751: case MINUTE_FIELD:
752: buffer.setDefaultAttribute (DateFormat.Field.MINUTE);
753: withLeadingZeros (calendar.get (Calendar.MINUTE),
754: cf.getSize(), buffer);
755: break;
756: case SECOND_FIELD:
757: buffer.setDefaultAttribute (DateFormat.Field.SECOND);
758: withLeadingZeros(calendar.get (Calendar.SECOND),
759: cf.getSize(), buffer);
760: break;
761: case MILLISECOND_FIELD:
762: buffer.setDefaultAttribute (DateFormat.Field.MILLISECOND);
763: withLeadingZeros (calendar.get (Calendar.MILLISECOND), cf.getSize(), buffer);
764: break;
765: case DAY_OF_WEEK_FIELD:
766: buffer.setDefaultAttribute (DateFormat.Field.DAY_OF_WEEK);
767: if (cf.getSize() < 4)
768: buffer.append (formatData.shortWeekdays[calendar.get (Calendar.DAY_OF_WEEK)]);
769: else
770: buffer.append (formatData.weekdays[calendar.get (Calendar.DAY_OF_WEEK)]);
771: break;
772: case DAY_OF_YEAR_FIELD:
773: buffer.setDefaultAttribute (DateFormat.Field.DAY_OF_YEAR);
774: withLeadingZeros (calendar.get (Calendar.DAY_OF_YEAR), cf.getSize(), buffer);
775: break;
776: case DAY_OF_WEEK_IN_MONTH_FIELD:
777: buffer.setDefaultAttribute (DateFormat.Field.DAY_OF_WEEK_IN_MONTH);
778: withLeadingZeros (calendar.get (Calendar.DAY_OF_WEEK_IN_MONTH),
779: cf.getSize(), buffer);
780: break;
781: case WEEK_OF_YEAR_FIELD:
782: buffer.setDefaultAttribute (DateFormat.Field.WEEK_OF_YEAR);
783: withLeadingZeros (calendar.get (Calendar.WEEK_OF_YEAR),
784: cf.getSize(), buffer);
785: break;
786: case WEEK_OF_MONTH_FIELD:
787: buffer.setDefaultAttribute (DateFormat.Field.WEEK_OF_MONTH);
788: withLeadingZeros (calendar.get (Calendar.WEEK_OF_MONTH),
789: cf.getSize(), buffer);
790: break;
791: case AM_PM_FIELD:
792: buffer.setDefaultAttribute (DateFormat.Field.AM_PM);
793: buffer.append (formatData.ampms[calendar.get (Calendar.AM_PM)]);
794: break;
795: case HOUR1_FIELD:
796: buffer.setDefaultAttribute (DateFormat.Field.HOUR1);
797: withLeadingZeros (((calendar.get (Calendar.HOUR) + 11) % 12) + 1,
798: cf.getSize(), buffer);
799: break;
800: case HOUR0_FIELD:
801: buffer.setDefaultAttribute (DateFormat.Field.HOUR0);
802: withLeadingZeros (calendar.get (Calendar.HOUR), cf.getSize(), buffer);
803: break;
804: case TIMEZONE_FIELD:
805: buffer.setDefaultAttribute (DateFormat.Field.TIME_ZONE);
806: TimeZone zone = calendar.getTimeZone();
807: boolean isDST = calendar.get (Calendar.DST_OFFSET) != 0;
808:
809: String zoneID = zone.getDisplayName
810: (isDST, cf.getSize() > 3 ? TimeZone.LONG : TimeZone.SHORT);
811: buffer.append (zoneID);
812: break;
813: case RFC822_TIMEZONE_FIELD:
814: buffer.setDefaultAttribute(DateFormat.Field.TIME_ZONE);
815: int pureMinutes = (calendar.get(Calendar.ZONE_OFFSET) +
816: calendar.get(Calendar.DST_OFFSET)) / (1000 * 60);
817: String sign = (pureMinutes < 0) ? "-" : "+";
818: pureMinutes = Math.abs(pureMinutes);
819: int hours = pureMinutes / 60;
820: int minutes = pureMinutes % 60;
821: buffer.append(sign);
822: withLeadingZeros(hours, 2, buffer);
823: withLeadingZeros(minutes, 2, buffer);
824: break;
825: default:
826: throw new IllegalArgumentException ("Illegal pattern character " +
827: cf.getCharacter());
828: }
829: if (pos != null && (buffer.getDefaultAttribute() == pos.getFieldAttribute()
830: || cf.getField() == pos.getField()))
831: {
832: pos.setBeginIndex(beginIndex);
833: pos.setEndIndex(buffer.length());
834: }
835: }
836: else
837: {
838: buffer.append(o.toString(), null);
839: }
840: }
841: }
842:
843: public StringBuffer format(Date date, StringBuffer buffer, FieldPosition pos)
844: {
845: formatWithAttribute(date, new StringFormatBuffer (buffer), pos);
846:
847: return buffer;
848: }
849:
850: public AttributedCharacterIterator formatToCharacterIterator(Object date)
851: throws IllegalArgumentException
852: {
853: if (date == null)
854: throw new NullPointerException("null argument");
855: if (!(date instanceof Date))
856: throw new IllegalArgumentException("argument should be an instance of java.util.Date");
857:
858: AttributedFormatBuffer buf = new AttributedFormatBuffer();
859: formatWithAttribute((Date)date, buf,
860: null);
861: buf.sync();
862:
863: return new FormatCharacterIterator(buf.getBuffer().toString(),
864: buf.getRanges(),
865: buf.getAttributes());
866: }
867:
868: private void withLeadingZeros(int value, int length, FormatBuffer buffer)
869: {
870: String valStr = String.valueOf(value);
871: for (length -= valStr.length(); length > 0; length--)
872: buffer.append('0');
873: buffer.append(valStr);
874: }
875:
876: private boolean expect(String source, ParsePosition pos, char ch)
877: {
878: int x = pos.getIndex();
879: boolean r = x < source.length() && source.charAt(x) == ch;
880: if (r)
881: pos.setIndex(x + 1);
882: else
883: pos.setErrorIndex(x);
884: return r;
885: }
886:
887:
896: public Date parse (String dateStr, ParsePosition pos)
897: {
898: int fmt_index = 0;
899: int fmt_max = pattern.length();
900:
901: calendar.clear();
902: boolean saw_timezone = false;
903: int quote_start = -1;
904: boolean is2DigitYear = false;
905: try
906: {
907: for (; fmt_index < fmt_max; ++fmt_index)
908: {
909: char ch = pattern.charAt(fmt_index);
910: if (ch == '\'')
911: {
912: if (fmt_index < fmt_max - 1
913: && pattern.charAt(fmt_index + 1) == '\'')
914: {
915: if (! expect (dateStr, pos, ch))
916: return null;
917: ++fmt_index;
918: }
919: else
920: quote_start = quote_start < 0 ? fmt_index : -1;
921: continue;
922: }
923:
924: if (quote_start != -1
925: || ((ch < 'a' || ch > 'z')
926: && (ch < 'A' || ch > 'Z')))
927: {
928: if (quote_start == -1 && ch == ' ')
929: {
930:
931:
932: int index = pos.getIndex();
933: int save = index;
934: while (index < dateStr.length()
935: && Character.isWhitespace(dateStr.charAt(index)))
936: ++index;
937: if (index > save)
938: pos.setIndex(index);
939: else
940: {
941:
942: pos.setErrorIndex(index);
943: return null;
944: }
945: }
946: else if (! expect (dateStr, pos, ch))
947: return null;
948: continue;
949: }
950:
951:
952:
953: int fmt_count = 1;
954: while (++fmt_index < fmt_max && pattern.charAt(fmt_index) == ch)
955: {
956: ++fmt_count;
957: }
958:
959:
960:
961:
962: boolean limit_digits = false;
963: if (fmt_index < fmt_max
964: && standardChars.indexOf(pattern.charAt(fmt_index)) >= 0)
965: limit_digits = true;
966: --fmt_index;
967:
968:
969:
970:
971:
972:
973: int calendar_field;
974: boolean is_numeric = true;
975: int offset = 0;
976: boolean maybe2DigitYear = false;
977: boolean oneBasedHour = false;
978: boolean oneBasedHourOfDay = false;
979: Integer simpleOffset;
980: String[] set1 = null;
981: String[] set2 = null;
982: switch (ch)
983: {
984: case 'd':
985: calendar_field = Calendar.DATE;
986: break;
987: case 'D':
988: calendar_field = Calendar.DAY_OF_YEAR;
989: break;
990: case 'F':
991: calendar_field = Calendar.DAY_OF_WEEK_IN_MONTH;
992: break;
993: case 'E':
994: is_numeric = false;
995: offset = 1;
996: calendar_field = Calendar.DAY_OF_WEEK;
997: set1 = formatData.getWeekdays();
998: set2 = formatData.getShortWeekdays();
999: break;
1000: case 'w':
1001: calendar_field = Calendar.WEEK_OF_YEAR;
1002: break;
1003: case 'W':
1004: calendar_field = Calendar.WEEK_OF_MONTH;
1005: break;
1006: case 'M':
1007: calendar_field = Calendar.MONTH;
1008: if (fmt_count <= 2)
1009: offset = -1;
1010: else
1011: {
1012: is_numeric = false;
1013: set1 = formatData.getMonths();
1014: set2 = formatData.getShortMonths();
1015: }
1016: break;
1017: case 'y':
1018: calendar_field = Calendar.YEAR;
1019: if (fmt_count <= 2)
1020: maybe2DigitYear = true;
1021: break;
1022: case 'K':
1023: calendar_field = Calendar.HOUR;
1024: break;
1025: case 'h':
1026: calendar_field = Calendar.HOUR;
1027: oneBasedHour = true;
1028: break;
1029: case 'H':
1030: calendar_field = Calendar.HOUR_OF_DAY;
1031: break;
1032: case 'k':
1033: calendar_field = Calendar.HOUR_OF_DAY;
1034: oneBasedHourOfDay = true;
1035: break;
1036: case 'm':
1037: calendar_field = Calendar.MINUTE;
1038: break;
1039: case 's':
1040: calendar_field = Calendar.SECOND;
1041: break;
1042: case 'S':
1043: calendar_field = Calendar.MILLISECOND;
1044: break;
1045: case 'a':
1046: is_numeric = false;
1047: calendar_field = Calendar.AM_PM;
1048: set1 = formatData.getAmPmStrings();
1049: break;
1050: case 'z':
1051: case 'Z':
1052:
1053:
1054: is_numeric = false;
1055: calendar_field = Calendar.ZONE_OFFSET;
1056: String[][] zoneStrings = formatData.getZoneStrings();
1057: int zoneCount = zoneStrings.length;
1058: int index = pos.getIndex();
1059: boolean found_zone = false;
1060: simpleOffset = computeOffset(dateStr.substring(index), pos);
1061: if (simpleOffset != null)
1062: {
1063: found_zone = true;
1064: saw_timezone = true;
1065: calendar.set(Calendar.DST_OFFSET, 0);
1066: offset = simpleOffset.intValue();
1067: }
1068: else
1069: {
1070: for (int j = 0; j < zoneCount; j++)
1071: {
1072: String[] strings = zoneStrings[j];
1073: int k;
1074: for (k = 0; k < strings.length; ++k)
1075: {
1076: if (dateStr.startsWith(strings[k], index))
1077: break;
1078: }
1079: if (k != strings.length)
1080: {
1081: found_zone = true;
1082: saw_timezone = true;
1083: TimeZone tz = TimeZone.getTimeZone (strings[0]);
1084:
1085: if(k == 3 || k == 4)
1086: calendar.set (Calendar.DST_OFFSET, tz.getDSTSavings());
1087: else
1088: calendar.set (Calendar.DST_OFFSET, 0);
1089: offset = tz.getRawOffset ();
1090: pos.setIndex(index + strings[k].length());
1091: break;
1092: }
1093: }
1094: }
1095: if (! found_zone)
1096: {
1097: pos.setErrorIndex(pos.getIndex());
1098: return null;
1099: }
1100: break;
1101: default:
1102: pos.setErrorIndex(pos.getIndex());
1103: return null;
1104: }
1105:
1106:
1107: int value;
1108: int index = -1;
1109: if (is_numeric)
1110: {
1111: numberFormat.setMinimumIntegerDigits(fmt_count);
1112: if (maybe2DigitYear)
1113: index = pos.getIndex();
1114: Number n = null;
1115: if (limit_digits)
1116: {
1117:
1118:
1119:
1120: int origPos = pos.getIndex();
1121: pos.setIndex(0);
1122: n = numberFormat.parse(dateStr.substring(origPos, origPos + fmt_count), pos);
1123: pos.setIndex(origPos + pos.getIndex());
1124: }
1125: else
1126: n = numberFormat.parse(dateStr, pos);
1127: if (pos == null || ! (n instanceof Long))
1128: return null;
1129: value = n.intValue() + offset;
1130: }
1131: else if (set1 != null)
1132: {
1133: index = pos.getIndex();
1134: int i;
1135: boolean found = false;
1136: for (i = offset; i < set1.length; ++i)
1137: {
1138: if (set1[i] != null)
1139: if (dateStr.toUpperCase().startsWith(set1[i].toUpperCase(),
1140: index))
1141: {
1142: found = true;
1143: pos.setIndex(index + set1[i].length());
1144: break;
1145: }
1146: }
1147: if (!found && set2 != null)
1148: {
1149: for (i = offset; i < set2.length; ++i)
1150: {
1151: if (set2[i] != null)
1152: if (dateStr.toUpperCase().startsWith(set2[i].toUpperCase(),
1153: index))
1154: {
1155: found = true;
1156: pos.setIndex(index + set2[i].length());
1157: break;
1158: }
1159: }
1160: }
1161: if (!found)
1162: {
1163: pos.setErrorIndex(index);
1164: return null;
1165: }
1166: value = i;
1167: }
1168: else
1169: value = offset;
1170:
1171: if (maybe2DigitYear)
1172: {
1173:
1174:
1175: int digit_count = pos.getIndex() - index;
1176: if (digit_count == 2)
1177: {
1178: is2DigitYear = true;
1179: value += defaultCentury;
1180: }
1181: }
1182:
1183:
1184:
1185: if (oneBasedHour && value == 12)
1186: value = 0;
1187:
1188: if (oneBasedHourOfDay && value == 24)
1189: value = 0;
1190:
1191:
1192: calendar.set(calendar_field, value);
1193: }
1194:
1195: if (is2DigitYear)
1196: {
1197:
1198:
1199: int year = calendar.get(Calendar.YEAR);
1200: if (calendar.getTime().compareTo(defaultCenturyStart) < 0)
1201: calendar.set(Calendar.YEAR, year + 100);
1202: }
1203: if (! saw_timezone)
1204: {
1205:
1206:
1207: calendar.clear (Calendar.DST_OFFSET);
1208: calendar.clear (Calendar.ZONE_OFFSET);
1209: }
1210: return calendar.getTime();
1211: }
1212: catch (IllegalArgumentException x)
1213: {
1214: pos.setErrorIndex(pos.getIndex());
1215: return null;
1216: }
1217: }
1218:
1219:
1257: private Integer computeOffset(String zoneString, ParsePosition pos)
1258: {
1259: Pattern pattern =
1260: Pattern.compile("(GMT)?([+-])([012])?([0-9]):?([0-9]{2})");
1261: Matcher matcher = pattern.matcher(zoneString);
1262:
1263:
1264: boolean hasAll = matcher.lookingAt();
1265: try
1266: {
1267:
1268: matcher.group(2);
1269: matcher.group(4);
1270: matcher.group(5);
1271: }
1272: catch (IllegalStateException ise)
1273: {
1274: hasAll = false;
1275: }
1276: if (hasAll)
1277: {
1278: int sign = matcher.group(2).equals("+") ? 1 : -1;
1279: int hour = Integer.parseInt(matcher.group(4));
1280: if (!matcher.group(3).equals(""))
1281: hour += (Integer.parseInt(matcher.group(3)) * 10);
1282: int minutes = Integer.parseInt(matcher.group(5));
1283:
1284: if (hour > 23)
1285: return null;
1286: int offset = sign * ((hour * 60) + minutes) * 60000;
1287:
1288:
1289: pos.setIndex(pos.getIndex() + matcher.end());
1290: return Integer.valueOf(offset);
1291: }
1292: else if (zoneString.startsWith("GMT"))
1293: {
1294: pos.setIndex(pos.getIndex() + 3);
1295: return Integer.valueOf(0);
1296: }
1297: return null;
1298: }
1299:
1300:
1301:
1302: private void computeCenturyStart()
1303: {
1304: int year = calendar.get(Calendar.YEAR);
1305: calendar.set(Calendar.YEAR, year - 80);
1306: set2DigitYearStart(calendar.getTime());
1307: }
1308:
1309:
1315: public Object clone()
1316: {
1317: SimpleDateFormat clone = (SimpleDateFormat) super.clone();
1318: clone.setDateFormatSymbols((DateFormatSymbols) formatData.clone());
1319: clone.set2DigitYearStart((Date) defaultCenturyStart.clone());
1320: return clone;
1321: }
1322:
1323: }