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: int hours = pureMinutes / 60;
810: int minutes = pureMinutes % 60;
811: buffer.append(sign);
812: withLeadingZeros(hours, 2, buffer);
813: withLeadingZeros(minutes, 2, buffer);
814: break;
815: default:
816: throw new IllegalArgumentException ("Illegal pattern character " +
817: cf.getCharacter());
818: }
819: if (pos != null && (buffer.getDefaultAttribute() == pos.getFieldAttribute()
820: || cf.getField() == pos.getField()))
821: {
822: pos.setBeginIndex(beginIndex);
823: pos.setEndIndex(buffer.length());
824: }
825: }
826: else
827: {
828: buffer.append(o.toString(), null);
829: }
830: }
831: }
832:
833: public StringBuffer format(Date date, StringBuffer buffer, FieldPosition pos)
834: {
835: formatWithAttribute(date, new StringFormatBuffer (buffer), pos);
836:
837: return buffer;
838: }
839:
840: public AttributedCharacterIterator formatToCharacterIterator(Object date)
841: throws IllegalArgumentException
842: {
843: if (date == null)
844: throw new NullPointerException("null argument");
845: if (!(date instanceof Date))
846: throw new IllegalArgumentException("argument should be an instance of java.util.Date");
847:
848: AttributedFormatBuffer buf = new AttributedFormatBuffer();
849: formatWithAttribute((Date)date, buf,
850: null);
851: buf.sync();
852:
853: return new FormatCharacterIterator(buf.getBuffer().toString(),
854: buf.getRanges(),
855: buf.getAttributes());
856: }
857:
858: private void withLeadingZeros(int value, int length, FormatBuffer buffer)
859: {
860: String valStr = String.valueOf(value);
861: for (length -= valStr.length(); length > 0; length--)
862: buffer.append('0');
863: buffer.append(valStr);
864: }
865:
866: private boolean expect(String source, ParsePosition pos, char ch)
867: {
868: int x = pos.getIndex();
869: boolean r = x < source.length() && source.charAt(x) == ch;
870: if (r)
871: pos.setIndex(x + 1);
872: else
873: pos.setErrorIndex(x);
874: return r;
875: }
876:
877:
886: public Date parse (String dateStr, ParsePosition pos)
887: {
888: int fmt_index = 0;
889: int fmt_max = pattern.length();
890:
891: calendar.clear();
892: boolean saw_timezone = false;
893: int quote_start = -1;
894: boolean is2DigitYear = false;
895: try
896: {
897: for (; fmt_index < fmt_max; ++fmt_index)
898: {
899: char ch = pattern.charAt(fmt_index);
900: if (ch == '\'')
901: {
902: int index = pos.getIndex();
903: if (fmt_index < fmt_max - 1
904: && pattern.charAt(fmt_index + 1) == '\'')
905: {
906: if (! expect (dateStr, pos, ch))
907: return null;
908: ++fmt_index;
909: }
910: else
911: quote_start = quote_start < 0 ? fmt_index : -1;
912: continue;
913: }
914:
915: if (quote_start != -1
916: || ((ch < 'a' || ch > 'z')
917: && (ch < 'A' || ch > 'Z')))
918: {
919: if (! expect (dateStr, pos, ch))
920: return null;
921: continue;
922: }
923:
924:
925:
926: int fmt_count = 1;
927: while (++fmt_index < fmt_max && pattern.charAt(fmt_index) == ch)
928: {
929: ++fmt_count;
930: }
931:
932:
933:
934:
935: boolean limit_digits = false;
936: if (fmt_index < fmt_max
937: && standardChars.indexOf(pattern.charAt(fmt_index)) >= 0)
938: limit_digits = true;
939: --fmt_index;
940:
941:
942:
943:
944:
945:
946: int calendar_field;
947: boolean is_numeric = true;
948: int offset = 0;
949: boolean maybe2DigitYear = false;
950: boolean oneBasedHour = false;
951: boolean oneBasedHourOfDay = false;
952: Integer simpleOffset;
953: String[] set1 = null;
954: String[] set2 = null;
955: switch (ch)
956: {
957: case 'd':
958: calendar_field = Calendar.DATE;
959: break;
960: case 'D':
961: calendar_field = Calendar.DAY_OF_YEAR;
962: break;
963: case 'F':
964: calendar_field = Calendar.DAY_OF_WEEK_IN_MONTH;
965: break;
966: case 'E':
967: is_numeric = false;
968: offset = 1;
969: calendar_field = Calendar.DAY_OF_WEEK;
970: set1 = formatData.getWeekdays();
971: set2 = formatData.getShortWeekdays();
972: break;
973: case 'w':
974: calendar_field = Calendar.WEEK_OF_YEAR;
975: break;
976: case 'W':
977: calendar_field = Calendar.WEEK_OF_MONTH;
978: break;
979: case 'M':
980: calendar_field = Calendar.MONTH;
981: if (fmt_count <= 2)
982: offset = -1;
983: else
984: {
985: is_numeric = false;
986: set1 = formatData.getMonths();
987: set2 = formatData.getShortMonths();
988: }
989: break;
990: case 'y':
991: calendar_field = Calendar.YEAR;
992: if (fmt_count <= 2)
993: maybe2DigitYear = true;
994: break;
995: case 'K':
996: calendar_field = Calendar.HOUR;
997: break;
998: case 'h':
999: calendar_field = Calendar.HOUR;
1000: oneBasedHour = true;
1001: break;
1002: case 'H':
1003: calendar_field = Calendar.HOUR_OF_DAY;
1004: break;
1005: case 'k':
1006: calendar_field = Calendar.HOUR_OF_DAY;
1007: oneBasedHourOfDay = true;
1008: break;
1009: case 'm':
1010: calendar_field = Calendar.MINUTE;
1011: break;
1012: case 's':
1013: calendar_field = Calendar.SECOND;
1014: break;
1015: case 'S':
1016: calendar_field = Calendar.MILLISECOND;
1017: break;
1018: case 'a':
1019: is_numeric = false;
1020: calendar_field = Calendar.AM_PM;
1021: set1 = formatData.getAmPmStrings();
1022: break;
1023: case 'z':
1024: case 'Z':
1025:
1026:
1027: is_numeric = false;
1028: calendar_field = Calendar.ZONE_OFFSET;
1029: String[][] zoneStrings = formatData.getZoneStrings();
1030: int zoneCount = zoneStrings.length;
1031: int index = pos.getIndex();
1032: boolean found_zone = false;
1033: simpleOffset = computeOffset(dateStr.substring(index), pos);
1034: if (simpleOffset != null)
1035: {
1036: found_zone = true;
1037: saw_timezone = true;
1038: calendar.set(Calendar.DST_OFFSET, 0);
1039: offset = simpleOffset.intValue();
1040: }
1041: else
1042: {
1043: for (int j = 0; j < zoneCount; j++)
1044: {
1045: String[] strings = zoneStrings[j];
1046: int k;
1047: for (k = 0; k < strings.length; ++k)
1048: {
1049: if (dateStr.startsWith(strings[k], index))
1050: break;
1051: }
1052: if (k != strings.length)
1053: {
1054: found_zone = true;
1055: saw_timezone = true;
1056: TimeZone tz = TimeZone.getTimeZone (strings[0]);
1057:
1058: if(k == 3 || k == 4)
1059: calendar.set (Calendar.DST_OFFSET, tz.getDSTSavings());
1060: else
1061: calendar.set (Calendar.DST_OFFSET, 0);
1062: offset = tz.getRawOffset ();
1063: pos.setIndex(index + strings[k].length());
1064: break;
1065: }
1066: }
1067: }
1068: if (! found_zone)
1069: {
1070: pos.setErrorIndex(pos.getIndex());
1071: return null;
1072: }
1073: break;
1074: default:
1075: pos.setErrorIndex(pos.getIndex());
1076: return null;
1077: }
1078:
1079:
1080: int value;
1081: int index = -1;
1082: if (is_numeric)
1083: {
1084: numberFormat.setMinimumIntegerDigits(fmt_count);
1085: if (limit_digits)
1086: numberFormat.setMaximumIntegerDigits(fmt_count);
1087: if (maybe2DigitYear)
1088: index = pos.getIndex();
1089: Number n = numberFormat.parse(dateStr, pos);
1090: if (pos == null || ! (n instanceof Long))
1091: return null;
1092: value = n.intValue() + offset;
1093: }
1094: else if (set1 != null)
1095: {
1096: index = pos.getIndex();
1097: int i;
1098: boolean found = false;
1099: for (i = offset; i < set1.length; ++i)
1100: {
1101: if (set1[i] != null)
1102: if (dateStr.toUpperCase().startsWith(set1[i].toUpperCase(),
1103: index))
1104: {
1105: found = true;
1106: pos.setIndex(index + set1[i].length());
1107: break;
1108: }
1109: }
1110: if (!found && set2 != null)
1111: {
1112: for (i = offset; i < set2.length; ++i)
1113: {
1114: if (set2[i] != null)
1115: if (dateStr.toUpperCase().startsWith(set2[i].toUpperCase(),
1116: index))
1117: {
1118: found = true;
1119: pos.setIndex(index + set2[i].length());
1120: break;
1121: }
1122: }
1123: }
1124: if (!found)
1125: {
1126: pos.setErrorIndex(index);
1127: return null;
1128: }
1129: value = i;
1130: }
1131: else
1132: value = offset;
1133:
1134: if (maybe2DigitYear)
1135: {
1136:
1137:
1138: int digit_count = pos.getIndex() - index;
1139: if (digit_count == 2)
1140: {
1141: is2DigitYear = true;
1142: value += defaultCentury;
1143: }
1144: }
1145:
1146:
1147:
1148: if (oneBasedHour && value == 12)
1149: value = 0;
1150:
1151: if (oneBasedHourOfDay && value == 24)
1152: value = 0;
1153:
1154:
1155: calendar.set(calendar_field, value);
1156: }
1157:
1158: if (is2DigitYear)
1159: {
1160:
1161:
1162: int year = calendar.get(Calendar.YEAR);
1163: if (calendar.getTime().compareTo(defaultCenturyStart) < 0)
1164: calendar.set(Calendar.YEAR, year + 100);
1165: }
1166: if (! saw_timezone)
1167: {
1168:
1169:
1170: calendar.clear (Calendar.DST_OFFSET);
1171: calendar.clear (Calendar.ZONE_OFFSET);
1172: }
1173: return calendar.getTime();
1174: }
1175: catch (IllegalArgumentException x)
1176: {
1177: pos.setErrorIndex(pos.getIndex());
1178: return null;
1179: }
1180: }
1181:
1182:
1220: private Integer computeOffset(String zoneString, ParsePosition pos)
1221: {
1222: Pattern pattern =
1223: Pattern.compile("(GMT)?([+-])([012])?([0-9]):?([0-9]{2})");
1224: Matcher matcher = pattern.matcher(zoneString);
1225:
1226:
1227: boolean hasAll = matcher.lookingAt();
1228: try
1229: {
1230:
1231: matcher.group(2);
1232: matcher.group(4);
1233: matcher.group(5);
1234: }
1235: catch (IllegalStateException ise)
1236: {
1237: hasAll = false;
1238: }
1239: if (hasAll)
1240: {
1241: int sign = matcher.group(2).equals("+") ? 1 : -1;
1242: int hour = Integer.parseInt(matcher.group(4));
1243: if (!matcher.group(3).equals(""))
1244: hour += (Integer.parseInt(matcher.group(3)) * 10);
1245: int minutes = Integer.parseInt(matcher.group(5));
1246:
1247: if (hour > 23)
1248: return null;
1249: int offset = sign * ((hour * 60) + minutes) * 60000;
1250:
1251:
1252: pos.setIndex(pos.getIndex() + matcher.end());
1253: return new Integer(offset);
1254: }
1255: else if (zoneString.startsWith("GMT"))
1256: {
1257: pos.setIndex(pos.getIndex() + 3);
1258: return new Integer(0);
1259: }
1260: return null;
1261: }
1262:
1263:
1264:
1265: private void computeCenturyStart()
1266: {
1267: int year = calendar.get(Calendar.YEAR);
1268: calendar.set(Calendar.YEAR, year - 80);
1269: set2DigitYearStart(calendar.getTime());
1270: }
1271:
1272:
1278: public Object clone()
1279: {
1280: SimpleDateFormat clone = (SimpleDateFormat) super.clone();
1281: clone.setDateFormatSymbols((DateFormatSymbols) formatData.clone());
1282: clone.set2DigitYearStart((Date) defaultCenturyStart.clone());
1283: return clone;
1284: }
1285:
1286: }