1:
39:
40:
41: package ;
42:
43: import ;
44: import ;
45: import ;
46: import ;
47:
48: import ;
49: import ;
50: import ;
51: import ;
52: import ;
53: import ;
54: import ;
55: import ;
56: import ;
57: import ;
58: import ;
59: import ;
60:
61:
65: public class SimpleDateFormat extends DateFormat
66: {
67:
73: private class CompiledField
74: {
75:
79: int field;
80:
81:
85: int size;
86:
87:
90: private char character;
91:
92:
101: public CompiledField(int f, int s, char c)
102: {
103: field = f;
104: size = s;
105: character = c;
106: }
107:
108:
112: public int getField()
113: {
114: return field;
115: }
116:
117:
120: public int getSize()
121: {
122: return size;
123: }
124:
125:
128: public char getCharacter()
129: {
130: return character;
131: }
132:
133:
140: public String toString()
141: {
142: StringBuffer builder;
143:
144: builder = new StringBuffer(getClass().getName());
145: builder.append("[field=");
146: builder.append(field);
147: builder.append(", size=");
148: builder.append(size);
149: builder.append(", character=");
150: builder.append(character);
151: builder.append("]");
152:
153: return builder.toString();
154: }
155: }
156:
157:
164: private transient ArrayList tokens;
165:
166:
174: private DateFormatSymbols formatData;
175:
176:
189: private Date defaultCenturyStart;
190:
191:
199: private transient int defaultCentury;
200:
201:
213: private String pattern;
214:
215:
227: private int serialVersionOnStream = 1;
228:
229:
232: private static final long serialVersionUID = 4774881970558875024L;
233:
234:
235:
236:
237: private static final String standardChars = "GyMdkHmsSEDFwWahKzYeugAZ";
238:
239:
253: private void readObject(ObjectInputStream stream)
254: throws IOException, ClassNotFoundException
255: {
256: stream.defaultReadObject();
257: if (serialVersionOnStream < 1)
258: {
259: computeCenturyStart ();
260: serialVersionOnStream = 1;
261: }
262: else
263:
264: set2DigitYearStart(defaultCenturyStart);
265:
266:
267: tokens = new ArrayList();
268: try
269: {
270: compileFormat(pattern);
271: }
272: catch (IllegalArgumentException e)
273: {
274: throw new InvalidObjectException("The stream pattern was invalid.");
275: }
276: }
277:
278:
287: private void compileFormat(String pattern)
288: {
289:
290:
291:
292: char thisChar;
293: int pos;
294: int field;
295: CompiledField current = null;
296:
297: for (int i = 0; i < pattern.length(); i++)
298: {
299: thisChar = pattern.charAt(i);
300: field = standardChars.indexOf(thisChar);
301: if (field == -1)
302: {
303: current = null;
304: if ((thisChar >= 'A' && thisChar <= 'Z')
305: || (thisChar >= 'a' && thisChar <= 'z'))
306: {
307:
308: throw new IllegalArgumentException("Invalid letter "
309: + thisChar +
310: " encountered at character "
311: + i + ".");
312: }
313: else if (thisChar == '\'')
314: {
315:
316: pos = pattern.indexOf('\'', i + 1);
317:
318: if (pos == i + 1)
319: tokens.add("'");
320: else
321: {
322:
323:
324:
325: StringBuffer buf = new StringBuffer();
326: int oldPos = i + 1;
327: do
328: {
329: if (pos == -1)
330: throw new IllegalArgumentException("Quotes starting at character "
331: + i +
332: " not closed.");
333: buf.append(pattern.substring(oldPos, pos));
334: if (pos + 1 >= pattern.length()
335: || pattern.charAt(pos + 1) != '\'')
336: break;
337: buf.append('\'');
338: oldPos = pos + 2;
339: pos = pattern.indexOf('\'', pos + 2);
340: }
341: while (true);
342: tokens.add(buf.toString());
343: }
344: i = pos;
345: }
346: else
347: {
348:
349: tokens.add(new Character(thisChar));
350: }
351: }
352: else
353: {
354:
355: if ((current != null) && (field == current.field))
356: current.size++;
357: else
358: {
359: current = new CompiledField(field, 1, thisChar);
360: tokens.add(current);
361: }
362: }
363: }
364: }
365:
366:
373: public String toString()
374: {
375: StringBuffer output = new StringBuffer(getClass().getName());
376: output.append("[tokens=");
377: output.append(tokens);
378: output.append(", formatData=");
379: output.append(formatData);
380: output.append(", defaultCenturyStart=");
381: output.append(defaultCenturyStart);
382: output.append(", defaultCentury=");
383: output.append(defaultCentury);
384: output.append(", pattern=");
385: output.append(pattern);
386: output.append(", serialVersionOnStream=");
387: output.append(serialVersionOnStream);
388: output.append(", standardChars=");
389: output.append(standardChars);
390: output.append("]");
391: return output.toString();
392: }
393:
394:
398: public SimpleDateFormat()
399: {
400:
405: super();
406: Locale locale = Locale.getDefault();
407: calendar = new GregorianCalendar(locale);
408: computeCenturyStart();
409: tokens = new ArrayList();
410: formatData = new DateFormatSymbols(locale);
411: pattern = (formatData.dateFormats[DEFAULT] + ' '
412: + formatData.timeFormats[DEFAULT]);
413: compileFormat(pattern);
414: numberFormat = NumberFormat.getInstance(locale);
415: numberFormat.setGroupingUsed (false);
416: numberFormat.setParseIntegerOnly (true);
417: numberFormat.setMaximumFractionDigits (0);
418: }
419:
420:
428: public SimpleDateFormat(String pattern)
429: {
430: this(pattern, Locale.getDefault());
431: }
432:
433:
442: public SimpleDateFormat(String pattern, Locale locale)
443: {
444: super();
445: calendar = new GregorianCalendar(locale);
446: computeCenturyStart();
447: tokens = new ArrayList();
448: formatData = new DateFormatSymbols(locale);
449: compileFormat(pattern);
450: this.pattern = pattern;
451: numberFormat = NumberFormat.getInstance(locale);
452: numberFormat.setGroupingUsed (false);
453: numberFormat.setParseIntegerOnly (true);
454: numberFormat.setMaximumFractionDigits (0);
455: }
456:
457:
467: public SimpleDateFormat(String pattern, DateFormatSymbols formatData)
468: {
469: super();
470: calendar = new GregorianCalendar();
471: computeCenturyStart ();
472: tokens = new ArrayList();
473: if (formatData == null)
474: throw new NullPointerException("formatData");
475: this.formatData = formatData;
476: compileFormat(pattern);
477: this.pattern = pattern;
478: numberFormat = NumberFormat.getInstance();
479: numberFormat.setGroupingUsed (false);
480: numberFormat.setParseIntegerOnly (true);
481: numberFormat.setMaximumFractionDigits (0);
482: }
483:
484:
490: public String toPattern()
491: {
492: return pattern;
493: }
494:
495:
501: public String toLocalizedPattern()
502: {
503: String localChars = formatData.getLocalPatternChars();
504: return translateLocalizedPattern(pattern, standardChars, localChars);
505: }
506:
507:
515: public void applyPattern(String pattern)
516: {
517: tokens = new ArrayList();
518: compileFormat(pattern);
519: this.pattern = pattern;
520: }
521:
522:
530: public void applyLocalizedPattern(String pattern)
531: {
532: String localChars = formatData.getLocalPatternChars();
533: pattern = translateLocalizedPattern(pattern, localChars, standardChars);
534: applyPattern(pattern);
535: }
536:
537:
553: private String translateLocalizedPattern(String pattern,
554: String oldChars, String newChars)
555: {
556: int len = pattern.length();
557: StringBuffer buf = new StringBuffer(len);
558: boolean quoted = false;
559: for (int i = 0; i < len; i++)
560: {
561: char ch = pattern.charAt(i);
562: if (ch == '\'')
563: quoted = ! quoted;
564: if (! quoted)
565: {
566: int j = oldChars.indexOf(ch);
567: if (j >= 0)
568: ch = newChars.charAt(j);
569: }
570: buf.append(ch);
571: }
572: return buf.toString();
573: }
574:
575:
581: public Date get2DigitYearStart()
582: {
583: return defaultCenturyStart;
584: }
585:
586:
592: public void set2DigitYearStart(Date date)
593: {
594: defaultCenturyStart = date;
595: calendar.clear();
596: calendar.setTime(date);
597: int year = calendar.get(Calendar.YEAR);
598: defaultCentury = year - (year % 100);
599: }
600:
601:
607: public DateFormatSymbols getDateFormatSymbols()
608: {
609: return (DateFormatSymbols) formatData.clone();
610: }
611:
612:
619: public void setDateFormatSymbols(DateFormatSymbols formatData)
620: {
621: if (formatData == null)
622: {
623: throw new
624: NullPointerException("The supplied format data was null.");
625: }
626: this.formatData = formatData;
627: }
628:
629:
648: public boolean equals(Object o)
649: {
650: if (!super.equals(o))
651: return false;
652:
653: if (!(o instanceof SimpleDateFormat))
654: return false;
655:
656: SimpleDateFormat sdf = (SimpleDateFormat)o;
657:
658: if (defaultCentury != sdf.defaultCentury)
659: return false;
660:
661: if (!toPattern().equals(sdf.toPattern()))
662: return false;
663:
664: if (!getDateFormatSymbols().equals(sdf.getDateFormatSymbols()))
665: return false;
666:
667: return true;
668: }
669:
670:
675: public int hashCode()
676: {
677: return super.hashCode() ^ toPattern().hashCode() ^ defaultCentury ^
678: getDateFormatSymbols().hashCode();
679: }
680:
681:
682:
687: private void formatWithAttribute(Date date, FormatBuffer buffer, FieldPosition pos)
688: {
689: String temp;
690: AttributedCharacterIterator.Attribute attribute;
691: calendar.setTime(date);
692:
693:
694: Iterator iter = tokens.iterator();
695: while (iter.hasNext())
696: {
697: Object o = iter.next();
698: if (o instanceof CompiledField)
699: {
700: CompiledField cf = (CompiledField) o;
701: int beginIndex = buffer.length();
702:
703: switch (cf.getField())
704: {
705: case ERA_FIELD:
706: buffer.append (formatData.eras[calendar.get (Calendar.ERA)], DateFormat.Field.ERA);
707: break;
708: case YEAR_FIELD:
709:
710:
711: buffer.setDefaultAttribute (DateFormat.Field.YEAR);
712: if (cf.getSize() == 2)
713: {
714: temp = "00"+String.valueOf (calendar.get (Calendar.YEAR));
715: buffer.append (temp.substring (temp.length() - 2));
716: }
717: else
718: withLeadingZeros (calendar.get (Calendar.YEAR), cf.getSize(), buffer);
719: break;
720: case MONTH_FIELD:
721: buffer.setDefaultAttribute (DateFormat.Field.MONTH);
722: if (cf.getSize() < 3)
723: withLeadingZeros (calendar.get (Calendar.MONTH) + 1, cf.getSize(), buffer);
724: else if (cf.getSize() < 4)
725: buffer.append (formatData.shortMonths[calendar.get (Calendar.MONTH)]);
726: else
727: buffer.append (formatData.months[calendar.get (Calendar.MONTH)]);
728: break;
729: case DATE_FIELD:
730: buffer.setDefaultAttribute (DateFormat.Field.DAY_OF_MONTH);
731: withLeadingZeros (calendar.get (Calendar.DATE), cf.getSize(), buffer);
732: break;
733: case HOUR_OF_DAY1_FIELD:
734: buffer.setDefaultAttribute(DateFormat.Field.HOUR_OF_DAY1);
735: withLeadingZeros ( ((calendar.get (Calendar.HOUR_OF_DAY) + 23) % 24) + 1,
736: cf.getSize(), buffer);
737: break;
738: case HOUR_OF_DAY0_FIELD:
739: buffer.setDefaultAttribute (DateFormat.Field.HOUR_OF_DAY0);
740: withLeadingZeros (calendar.get (Calendar.HOUR_OF_DAY), cf.getSize(), buffer);
741: break;
742: case MINUTE_FIELD:
743: buffer.setDefaultAttribute (DateFormat.Field.MINUTE);
744: withLeadingZeros (calendar.get (Calendar.MINUTE),
745: cf.getSize(), buffer);
746: break;
747: case SECOND_FIELD:
748: buffer.setDefaultAttribute (DateFormat.Field.SECOND);
749: withLeadingZeros(calendar.get (Calendar.SECOND),
750: cf.getSize(), buffer);
751: break;
752: case MILLISECOND_FIELD:
753: buffer.setDefaultAttribute (DateFormat.Field.MILLISECOND);
754: withLeadingZeros (calendar.get (Calendar.MILLISECOND), cf.getSize(), buffer);
755: break;
756: case DAY_OF_WEEK_FIELD:
757: buffer.setDefaultAttribute (DateFormat.Field.DAY_OF_WEEK);
758: if (cf.getSize() < 4)
759: buffer.append (formatData.shortWeekdays[calendar.get (Calendar.DAY_OF_WEEK)]);
760: else
761: buffer.append (formatData.weekdays[calendar.get (Calendar.DAY_OF_WEEK)]);
762: break;
763: case DAY_OF_YEAR_FIELD:
764: buffer.setDefaultAttribute (DateFormat.Field.DAY_OF_YEAR);
765: withLeadingZeros (calendar.get (Calendar.DAY_OF_YEAR), cf.getSize(), buffer);
766: break;
767: case DAY_OF_WEEK_IN_MONTH_FIELD:
768: buffer.setDefaultAttribute (DateFormat.Field.DAY_OF_WEEK_IN_MONTH);
769: withLeadingZeros (calendar.get (Calendar.DAY_OF_WEEK_IN_MONTH),
770: cf.getSize(), buffer);
771: break;
772: case WEEK_OF_YEAR_FIELD:
773: buffer.setDefaultAttribute (DateFormat.Field.WEEK_OF_YEAR);
774: withLeadingZeros (calendar.get (Calendar.WEEK_OF_YEAR),
775: cf.getSize(), buffer);
776: break;
777: case WEEK_OF_MONTH_FIELD:
778: buffer.setDefaultAttribute (DateFormat.Field.WEEK_OF_MONTH);
779: withLeadingZeros (calendar.get (Calendar.WEEK_OF_MONTH),
780: cf.getSize(), buffer);
781: break;
782: case AM_PM_FIELD:
783: buffer.setDefaultAttribute (DateFormat.Field.AM_PM);
784: buffer.append (formatData.ampms[calendar.get (Calendar.AM_PM)]);
785: break;
786: case HOUR1_FIELD:
787: buffer.setDefaultAttribute (DateFormat.Field.HOUR1);
788: withLeadingZeros (((calendar.get (Calendar.HOUR) + 11) % 12) + 1,
789: cf.getSize(), buffer);
790: break;
791: case HOUR0_FIELD:
792: buffer.setDefaultAttribute (DateFormat.Field.HOUR0);
793: withLeadingZeros (calendar.get (Calendar.HOUR), cf.getSize(), buffer);
794: break;
795: case TIMEZONE_FIELD:
796: buffer.setDefaultAttribute (DateFormat.Field.TIME_ZONE);
797: TimeZone zone = calendar.getTimeZone();
798: boolean isDST = calendar.get (Calendar.DST_OFFSET) != 0;
799:
800: String zoneID = zone.getDisplayName
801: (isDST, cf.getSize() > 3 ? TimeZone.LONG : TimeZone.SHORT);
802: buffer.append (zoneID);
803: break;
804: case RFC822_TIMEZONE_FIELD:
805: buffer.setDefaultAttribute(DateFormat.Field.RFC822_TIME_ZONE);
806: int pureMinutes = (calendar.get(Calendar.ZONE_OFFSET) +
807: calendar.get(Calendar.DST_OFFSET)) / (1000 * 60);
808: String sign = (pureMinutes < 0) ? "-" : "+";
809: pureMinutes = Math.abs(pureMinutes);
810: int hours = pureMinutes / 60;
811: int minutes = pureMinutes % 60;
812: buffer.append(sign);
813: withLeadingZeros(hours, 2, buffer);
814: withLeadingZeros(minutes, 2, buffer);
815: break;
816: default:
817: throw new IllegalArgumentException ("Illegal pattern character " +
818: cf.getCharacter());
819: }
820: if (pos != null && (buffer.getDefaultAttribute() == pos.getFieldAttribute()
821: || cf.getField() == pos.getField()))
822: {
823: pos.setBeginIndex(beginIndex);
824: pos.setEndIndex(buffer.length());
825: }
826: }
827: else
828: {
829: buffer.append(o.toString(), null);
830: }
831: }
832: }
833:
834: public StringBuffer format(Date date, StringBuffer buffer, FieldPosition pos)
835: {
836: formatWithAttribute(date, new StringFormatBuffer (buffer), pos);
837:
838: return buffer;
839: }
840:
841: public AttributedCharacterIterator formatToCharacterIterator(Object date)
842: throws IllegalArgumentException
843: {
844: if (date == null)
845: throw new NullPointerException("null argument");
846: if (!(date instanceof Date))
847: throw new IllegalArgumentException("argument should be an instance of java.util.Date");
848:
849: AttributedFormatBuffer buf = new AttributedFormatBuffer();
850: formatWithAttribute((Date)date, buf,
851: null);
852: buf.sync();
853:
854: return new FormatCharacterIterator(buf.getBuffer().toString(),
855: buf.getRanges(),
856: buf.getAttributes());
857: }
858:
859: private void withLeadingZeros(int value, int length, FormatBuffer buffer)
860: {
861: String valStr = String.valueOf(value);
862: for (length -= valStr.length(); length > 0; length--)
863: buffer.append('0');
864: buffer.append(valStr);
865: }
866:
867: private boolean expect(String source, ParsePosition pos, char ch)
868: {
869: int x = pos.getIndex();
870: boolean r = x < source.length() && source.charAt(x) == ch;
871: if (r)
872: pos.setIndex(x + 1);
873: else
874: pos.setErrorIndex(x);
875: return r;
876: }
877:
878:
887: public Date parse (String dateStr, ParsePosition pos)
888: {
889: int fmt_index = 0;
890: int fmt_max = pattern.length();
891:
892: calendar.clear();
893: boolean saw_timezone = false;
894: int quote_start = -1;
895: boolean is2DigitYear = false;
896: try
897: {
898: for (; fmt_index < fmt_max; ++fmt_index)
899: {
900: char ch = pattern.charAt(fmt_index);
901: if (ch == '\'')
902: {
903: int index = pos.getIndex();
904: if (fmt_index < fmt_max - 1
905: && pattern.charAt(fmt_index + 1) == '\'')
906: {
907: if (! expect (dateStr, pos, ch))
908: return null;
909: ++fmt_index;
910: }
911: else
912: quote_start = quote_start < 0 ? fmt_index : -1;
913: continue;
914: }
915:
916: if (quote_start != -1
917: || ((ch < 'a' || ch > 'z')
918: && (ch < 'A' || ch > 'Z')))
919: {
920: if (! expect (dateStr, pos, ch))
921: return null;
922: continue;
923: }
924:
925:
926:
927: int fmt_count = 1;
928: while (++fmt_index < fmt_max && pattern.charAt(fmt_index) == ch)
929: {
930: ++fmt_count;
931: }
932:
933:
934:
935:
936: boolean limit_digits = false;
937: if (fmt_index < fmt_max
938: && standardChars.indexOf(pattern.charAt(fmt_index)) >= 0)
939: limit_digits = true;
940: --fmt_index;
941:
942:
943:
944:
945:
946:
947: int calendar_field;
948: boolean is_numeric = true;
949: int offset = 0;
950: boolean maybe2DigitYear = false;
951: boolean oneBasedHour = false;
952: boolean oneBasedHourOfDay = false;
953: Integer simpleOffset;
954: String[] set1 = null;
955: String[] set2 = null;
956: switch (ch)
957: {
958: case 'd':
959: calendar_field = Calendar.DATE;
960: break;
961: case 'D':
962: calendar_field = Calendar.DAY_OF_YEAR;
963: break;
964: case 'F':
965: calendar_field = Calendar.DAY_OF_WEEK_IN_MONTH;
966: break;
967: case 'E':
968: is_numeric = false;
969: offset = 1;
970: calendar_field = Calendar.DAY_OF_WEEK;
971: set1 = formatData.getWeekdays();
972: set2 = formatData.getShortWeekdays();
973: break;
974: case 'w':
975: calendar_field = Calendar.WEEK_OF_YEAR;
976: break;
977: case 'W':
978: calendar_field = Calendar.WEEK_OF_MONTH;
979: break;
980: case 'M':
981: calendar_field = Calendar.MONTH;
982: if (fmt_count <= 2)
983: offset = -1;
984: else
985: {
986: is_numeric = false;
987: set1 = formatData.getMonths();
988: set2 = formatData.getShortMonths();
989: }
990: break;
991: case 'y':
992: calendar_field = Calendar.YEAR;
993: if (fmt_count <= 2)
994: maybe2DigitYear = true;
995: break;
996: case 'K':
997: calendar_field = Calendar.HOUR;
998: break;
999: case 'h':
1000: calendar_field = Calendar.HOUR;
1001: oneBasedHour = true;
1002: break;
1003: case 'H':
1004: calendar_field = Calendar.HOUR_OF_DAY;
1005: break;
1006: case 'k':
1007: calendar_field = Calendar.HOUR_OF_DAY;
1008: oneBasedHourOfDay = true;
1009: break;
1010: case 'm':
1011: calendar_field = Calendar.MINUTE;
1012: break;
1013: case 's':
1014: calendar_field = Calendar.SECOND;
1015: break;
1016: case 'S':
1017: calendar_field = Calendar.MILLISECOND;
1018: break;
1019: case 'a':
1020: is_numeric = false;
1021: calendar_field = Calendar.AM_PM;
1022: set1 = formatData.getAmPmStrings();
1023: break;
1024: case 'z':
1025: case 'Z':
1026:
1027:
1028: is_numeric = false;
1029: calendar_field = Calendar.ZONE_OFFSET;
1030: String[][] zoneStrings = formatData.getZoneStrings();
1031: int zoneCount = zoneStrings.length;
1032: int index = pos.getIndex();
1033: boolean found_zone = false;
1034: simpleOffset = computeOffset(dateStr.substring(index), pos);
1035: if (simpleOffset != null)
1036: {
1037: found_zone = true;
1038: saw_timezone = true;
1039: calendar.set(Calendar.DST_OFFSET, 0);
1040: offset = simpleOffset.intValue();
1041: }
1042: else
1043: {
1044: for (int j = 0; j < zoneCount; j++)
1045: {
1046: String[] strings = zoneStrings[j];
1047: int k;
1048: for (k = 0; k < strings.length; ++k)
1049: {
1050: if (dateStr.startsWith(strings[k], index))
1051: break;
1052: }
1053: if (k != strings.length)
1054: {
1055: found_zone = true;
1056: saw_timezone = true;
1057: TimeZone tz = TimeZone.getTimeZone (strings[0]);
1058:
1059: if(k == 3 || k == 4)
1060: calendar.set (Calendar.DST_OFFSET, tz.getDSTSavings());
1061: else
1062: calendar.set (Calendar.DST_OFFSET, 0);
1063: offset = tz.getRawOffset ();
1064: pos.setIndex(index + strings[k].length());
1065: break;
1066: }
1067: }
1068: }
1069: if (! found_zone)
1070: {
1071: pos.setErrorIndex(pos.getIndex());
1072: return null;
1073: }
1074: break;
1075: default:
1076: pos.setErrorIndex(pos.getIndex());
1077: return null;
1078: }
1079:
1080:
1081: int value;
1082: int index = -1;
1083: if (is_numeric)
1084: {
1085: numberFormat.setMinimumIntegerDigits(fmt_count);
1086: if (limit_digits)
1087: numberFormat.setMaximumIntegerDigits(fmt_count);
1088: if (maybe2DigitYear)
1089: index = pos.getIndex();
1090: Number n = numberFormat.parse(dateStr, pos);
1091: if (pos == null || ! (n instanceof Long))
1092: return null;
1093: value = n.intValue() + offset;
1094: }
1095: else if (set1 != null)
1096: {
1097: index = pos.getIndex();
1098: int i;
1099: boolean found = false;
1100: for (i = offset; i < set1.length; ++i)
1101: {
1102: if (set1[i] != null)
1103: if (dateStr.toUpperCase().startsWith(set1[i].toUpperCase(),
1104: index))
1105: {
1106: found = true;
1107: pos.setIndex(index + set1[i].length());
1108: break;
1109: }
1110: }
1111: if (!found && set2 != null)
1112: {
1113: for (i = offset; i < set2.length; ++i)
1114: {
1115: if (set2[i] != null)
1116: if (dateStr.toUpperCase().startsWith(set2[i].toUpperCase(),
1117: index))
1118: {
1119: found = true;
1120: pos.setIndex(index + set2[i].length());
1121: break;
1122: }
1123: }
1124: }
1125: if (!found)
1126: {
1127: pos.setErrorIndex(index);
1128: return null;
1129: }
1130: value = i;
1131: }
1132: else
1133: value = offset;
1134:
1135: if (maybe2DigitYear)
1136: {
1137:
1138:
1139: int digit_count = pos.getIndex() - index;
1140: if (digit_count == 2)
1141: {
1142: is2DigitYear = true;
1143: value += defaultCentury;
1144: }
1145: }
1146:
1147:
1148:
1149: if (oneBasedHour && value == 12)
1150: value = 0;
1151:
1152: if (oneBasedHourOfDay && value == 24)
1153: value = 0;
1154:
1155:
1156: calendar.set(calendar_field, value);
1157: }
1158:
1159: if (is2DigitYear)
1160: {
1161:
1162:
1163: int year = calendar.get(Calendar.YEAR);
1164: if (calendar.getTime().compareTo(defaultCenturyStart) < 0)
1165: calendar.set(Calendar.YEAR, year + 100);
1166: }
1167: if (! saw_timezone)
1168: {
1169:
1170:
1171: calendar.clear (Calendar.DST_OFFSET);
1172: calendar.clear (Calendar.ZONE_OFFSET);
1173: }
1174: return calendar.getTime();
1175: }
1176: catch (IllegalArgumentException x)
1177: {
1178: pos.setErrorIndex(pos.getIndex());
1179: return null;
1180: }
1181: }
1182:
1183:
1221: private Integer computeOffset(String zoneString, ParsePosition pos)
1222: {
1223: Pattern pattern =
1224: Pattern.compile("(GMT)?([+-])([012])?([0-9]):?([0-9]{2})");
1225: Matcher matcher = pattern.matcher(zoneString);
1226:
1227:
1228: boolean hasAll = matcher.lookingAt();
1229: try
1230: {
1231:
1232: matcher.group(2);
1233: matcher.group(4);
1234: matcher.group(5);
1235: }
1236: catch (IllegalStateException ise)
1237: {
1238: hasAll = false;
1239: }
1240: if (hasAll)
1241: {
1242: int sign = matcher.group(2).equals("+") ? 1 : -1;
1243: int hour = Integer.parseInt(matcher.group(4));
1244: if (!matcher.group(3).equals(""))
1245: hour += (Integer.parseInt(matcher.group(3)) * 10);
1246: int minutes = Integer.parseInt(matcher.group(5));
1247:
1248: if (hour > 23)
1249: return null;
1250: int offset = sign * ((hour * 60) + minutes) * 60000;
1251:
1252:
1253: pos.setIndex(pos.getIndex() + matcher.end());
1254: return new Integer(offset);
1255: }
1256: else if (zoneString.startsWith("GMT"))
1257: {
1258: pos.setIndex(pos.getIndex() + 3);
1259: return new Integer(0);
1260: }
1261: return null;
1262: }
1263:
1264:
1265:
1266: private void computeCenturyStart()
1267: {
1268: int year = calendar.get(Calendar.YEAR);
1269: calendar.set(Calendar.YEAR, year - 80);
1270: set2DigitYearStart(calendar.getTime());
1271: }
1272:
1273:
1279: public Object clone()
1280: {
1281: SimpleDateFormat clone = (SimpleDateFormat) super.clone();
1282: clone.setDateFormatSymbols((DateFormatSymbols) formatData.clone());
1283: clone.set2DigitYearStart((Date) defaultCenturyStart.clone());
1284: return clone;
1285: }
1286:
1287: }