001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package java.text;
019:
020: import java.io.IOException;
021: import java.io.ObjectInputStream;
022: import java.io.ObjectOutputStream;
023: import java.io.ObjectStreamField;
024: import java.util.Calendar;
025: import java.util.Date;
026: import java.util.GregorianCalendar;
027: import java.util.Locale;
028: import java.util.Vector;
029:
030: import org.apache.harmony.text.internal.nls.Messages;
031:
032: /**
033: * SimpleDateFormat is used to format and parse Gregorian calendar dates and
034: * times based on a pattern of date and time fields. Each date and time field is
035: * specified in the pattern by a specific character. The characters used can be
036: * either localized or non-localized. For some fields, which have both numeric
037: * and text representations or abbreviated as well as full names, the number of
038: * grouped characters specifies how the field is formatted or parsed.
039: */
040: public class SimpleDateFormat extends DateFormat {
041:
042: private static final long serialVersionUID = 4774881970558875024L;
043:
044: private static final String patternChars = "GyMdkHmsSEDFwWahKzYeugAZvcLQqV"; //$NON-NLS-1$
045:
046: private String pattern;
047:
048: private DateFormatSymbols formatData;
049:
050: transient private int creationYear;
051:
052: private Date defaultCenturyStart;
053:
054: private transient com.ibm.icu.text.SimpleDateFormat icuFormat;
055:
056: /**
057: * Constructs a new SimpleDateFormat for formatting and parsing dates and
058: * times in the SHORT style for the default Locale.
059: */
060: public SimpleDateFormat() {
061: this (Locale.getDefault());
062: icuFormat = new com.ibm.icu.text.SimpleDateFormat();
063: pattern = (String) getInternalField("pattern", icuFormat);
064: formatData = new DateFormatSymbols(Locale.getDefault());
065: }
066:
067: /**
068: * Constructs a new SimpleDateFormat using the specified non-localized
069: * pattern and the DateFormatSymbols and Calendar for the default Locale.
070: *
071: * @param pattern
072: * the pattern
073: *
074: * @exception NullPointerException
075: * if a <code>null</code> value of <code>pattern</code>
076: * is supplied.
077: * @exception IllegalArgumentException
078: * if <code>pattern</code> is not considered to be useable
079: * by this formatter.
080: */
081: public SimpleDateFormat(String pattern) {
082: this (pattern, Locale.getDefault());
083: }
084:
085: /**
086: * Validate the format character.
087: *
088: * @param format
089: * the format character
090: *
091: * @throws IllegalArgumentException
092: * when the format character is invalid
093: */
094: private void validateFormat(char format) {
095: int index = patternChars.indexOf(format);
096: if (index == -1) {
097: // text.03=Unknown pattern character - '{0}'
098: throw new IllegalArgumentException(Messages.getString(
099: "text.03", format)); //$NON-NLS-1$
100: }
101: }
102:
103: /**
104: * Validate the pattern.
105: *
106: * @param template
107: * the pattern to validate.
108: *
109: * @throws NullPointerException
110: * if the pattern is null
111: * @throws IllegalArgumentException
112: * if the pattern is invalid
113: */
114: private void validatePattern(String template) {
115: boolean quote = false;
116: int next, last = -1, count = 0;
117:
118: final int patternLength = template.length();
119: for (int i = 0; i < patternLength; i++) {
120: next = (template.charAt(i));
121: if (next == '\'') {
122: if (count > 0) {
123: validateFormat((char) last);
124: count = 0;
125: }
126: if (last == next) {
127: last = -1;
128: } else {
129: last = next;
130: }
131: quote = !quote;
132: continue;
133: }
134: if (!quote
135: && (last == next || (next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z'))) {
136: if (last == next) {
137: count++;
138: } else {
139: if (count > 0) {
140: validateFormat((char) last);
141: }
142: last = next;
143: count = 1;
144: }
145: } else {
146: if (count > 0) {
147: validateFormat((char) last);
148: count = 0;
149: }
150: last = -1;
151: }
152: }
153: if (count > 0) {
154: validateFormat((char) last);
155: }
156:
157: if (quote) {
158: // text.04=Unterminated quote {0}
159: throw new IllegalArgumentException(Messages
160: .getString("text.04")); //$NON-NLS-1$
161: }
162:
163: }
164:
165: /**
166: * Constructs a new SimpleDateFormat using the specified non-localized
167: * pattern and DateFormatSymbols and the Calendar for the default Locale.
168: *
169: * @param template
170: * the pattern
171: * @param value
172: * the DateFormatSymbols
173: *
174: * @exception NullPointerException
175: * if the pattern is null
176: * @exception IllegalArgumentException
177: * if the pattern is invalid
178: */
179: public SimpleDateFormat(String template, DateFormatSymbols value) {
180: this (Locale.getDefault());
181: validatePattern(template);
182: icuFormat = new com.ibm.icu.text.SimpleDateFormat(template,
183: Locale.getDefault());
184: pattern = template;
185: formatData = (DateFormatSymbols) value.clone();
186: }
187:
188: private void copySymbols(DateFormatSymbols value,
189: com.ibm.icu.text.DateFormatSymbols icuSymbols) {
190: icuSymbols.setAmPmStrings(value.getAmPmStrings());
191: icuSymbols.setEras(value.getEras());
192: icuSymbols.setLocalPatternChars(value.getLocalPatternChars());
193: icuSymbols.setMonths(value.getMonths());
194: icuSymbols.setShortMonths(value.getShortMonths());
195: icuSymbols.setShortWeekdays(value.getShortWeekdays());
196: icuSymbols.setWeekdays(value.getWeekdays());
197: icuSymbols.setZoneStrings(value.getZoneStrings());
198: }
199:
200: /**
201: * Constructs a new SimpleDateFormat using the specified non-localized
202: * pattern and the DateFormatSymbols and Calendar for the specified Locale.
203: *
204: * @param template
205: * the pattern
206: * @param locale
207: * the Locale
208: *
209: * @exception NullPointerException
210: * if the pattern is null
211: * @exception IllegalArgumentException
212: * if the pattern is invalid
213: */
214: public SimpleDateFormat(String template, Locale locale) {
215: this (locale);
216: validatePattern(template);
217: icuFormat = new com.ibm.icu.text.SimpleDateFormat(template,
218: locale);
219: pattern = template;
220: formatData = new DateFormatSymbols(locale);
221: }
222:
223: SimpleDateFormat(Locale locale,
224: com.ibm.icu.text.SimpleDateFormat icuFormat) {
225: this (locale);
226: this .icuFormat = icuFormat;
227: pattern = (String) Format
228: .getInternalField("pattern", icuFormat);
229: formatData = new DateFormatSymbols(locale);
230: }
231:
232: private SimpleDateFormat(Locale locale) {
233: numberFormat = NumberFormat.getInstance(locale);
234: numberFormat.setParseIntegerOnly(true);
235: numberFormat.setGroupingUsed(false);
236: calendar = new GregorianCalendar(locale);
237: calendar.add(Calendar.YEAR, -80);
238: creationYear = calendar.get(Calendar.YEAR);
239: defaultCenturyStart = calendar.getTime();
240: }
241:
242: /**
243: * Changes the pattern of this SimpleDateFormat to the specified pattern
244: * which uses localized pattern characters.
245: *
246: * @param template
247: * the localized pattern
248: */
249: public void applyLocalizedPattern(String template) {
250: icuFormat.applyLocalizedPattern(template);
251: pattern = icuFormat.toPattern();
252: }
253:
254: /**
255: * Changes the pattern of this SimpleDateFormat to the specified pattern
256: * which uses non-localized pattern characters.
257: *
258: * @param template
259: * the non-localized pattern
260: *
261: * @exception NullPointerException
262: * if the pattern is null
263: * @exception IllegalArgumentException
264: * if the pattern is invalid
265: */
266: public void applyPattern(String template) {
267: validatePattern(template);
268: icuFormat.applyPattern(template);
269: pattern = template;
270: }
271:
272: /**
273: * Answers a new SimpleDateFormat with the same pattern and properties as
274: * this SimpleDateFormat.
275: *
276: * @return a shallow copy of this SimpleDateFormat
277: *
278: * @see java.lang.Cloneable
279: */
280: @Override
281: public Object clone() {
282: SimpleDateFormat clone = (SimpleDateFormat) super .clone();
283: clone.formatData = (DateFormatSymbols) formatData.clone();
284: clone.defaultCenturyStart = new Date(defaultCenturyStart
285: .getTime());
286: return clone;
287: }
288:
289: /**
290: * Compares the specified object to this SimpleDateFormat and answer if they
291: * are equal. The object must be an instance of SimpleDateFormat and have
292: * the same DateFormat properties, pattern, DateFormatSymbols, and creation
293: * year.
294: *
295: * @param object
296: * the object to compare with this object
297: * @return true if the specified object is equal to this SimpleDateFormat,
298: * false otherwise
299: *
300: * @see #hashCode
301: */
302: @Override
303: public boolean equals(Object object) {
304: if (this == object) {
305: return true;
306: }
307: if (!(object instanceof SimpleDateFormat)) {
308: return false;
309: }
310: SimpleDateFormat simple = (SimpleDateFormat) object;
311: return super .equals(object) && pattern.equals(simple.pattern)
312: && formatData.equals(simple.formatData);
313: }
314:
315: /**
316: * Formats the specified object using the rules of this SimpleDateFormat and
317: * returns an AttributedCharacterIterator with the formatted Date and
318: * attributes.
319: *
320: * @param object
321: * the object to format
322: * @return an AttributedCharacterIterator with the formatted date and
323: * attributes
324: *
325: * @exception NullPointerException
326: * when the object is null
327: * @exception IllegalArgumentException
328: * when the object cannot be formatted by this Format
329: */
330: @Override
331: public AttributedCharacterIterator formatToCharacterIterator(
332: Object object) {
333: if (object == null) {
334: throw new NullPointerException();
335: }
336: if (object instanceof Date) {
337: return formatToCharacterIteratorImpl((Date) object);
338: }
339: if (object instanceof Number) {
340: return formatToCharacterIteratorImpl(new Date(
341: ((Number) object).longValue()));
342: }
343: throw new IllegalArgumentException();
344:
345: }
346:
347: private AttributedCharacterIterator formatToCharacterIteratorImpl(
348: Date date) {
349: StringBuffer buffer = new StringBuffer();
350: Vector<FieldPosition> fields = new Vector<FieldPosition>();
351:
352: // format the date, and find fields
353: formatImpl(date, buffer, null, fields);
354:
355: // create and AttributedString with the formatted buffer
356: AttributedString as = new AttributedString(buffer.toString());
357:
358: // add DateFormat field attributes to the AttributedString
359: for (int i = 0; i < fields.size(); i++) {
360: FieldPosition pos = fields.elementAt(i);
361: Format.Field attribute = pos.getFieldAttribute();
362: as.addAttribute(attribute, attribute, pos.getBeginIndex(),
363: pos.getEndIndex());
364: }
365:
366: // return the CharacterIterator from AttributedString
367: return as.getIterator();
368: }
369:
370: /**
371: * Formats the date.
372: * <p>
373: * If the FieldPosition <code>field</code> is not null, and the field
374: * specified by this FieldPosition is formatted, set the begin and end index
375: * of the formatted field in the FieldPosition.
376: * <p>
377: * If the Vector <code>fields</code> is not null, find fields of this
378: * date, set FieldPositions with these fields, and add them to the fields
379: * vector.
380: *
381: * @param date
382: * Date to Format
383: * @param buffer
384: * StringBuffer to store the resulting formatted String
385: * @param field
386: * FieldPosition to set begin and end index of the field
387: * specified, if it is part of the format for this date
388: * @param fields
389: * Vector used to store the FieldPositions for each field in this
390: * date
391: *
392: * @return the formatted Date
393: *
394: * @exception IllegalArgumentException
395: * when the object cannot be formatted by this Format
396: */
397: private StringBuffer formatImpl(Date date, StringBuffer buffer,
398: FieldPosition field, Vector<FieldPosition> fields) {
399:
400: boolean quote = false;
401: int next, last = -1, count = 0;
402: calendar.setTime(date);
403: if (field != null) {
404: field.clear();
405: }
406:
407: final int patternLength = pattern.length();
408: for (int i = 0; i < patternLength; i++) {
409: next = (pattern.charAt(i));
410: if (next == '\'') {
411: if (count > 0) {
412: append(buffer, field, fields, (char) last, count);
413: count = 0;
414: }
415: if (last == next) {
416: buffer.append('\'');
417: last = -1;
418: } else {
419: last = next;
420: }
421: quote = !quote;
422: continue;
423: }
424: if (!quote
425: && (last == next || (next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z'))) {
426: if (last == next) {
427: count++;
428: } else {
429: if (count > 0) {
430: append(buffer, field, fields, (char) last,
431: count);
432: }
433: last = next;
434: count = 1;
435: }
436: } else {
437: if (count > 0) {
438: append(buffer, field, fields, (char) last, count);
439: count = 0;
440: }
441: last = -1;
442: buffer.append((char) next);
443: }
444: }
445: if (count > 0) {
446: append(buffer, field, fields, (char) last, count);
447: }
448: return buffer;
449: }
450:
451: private void append(StringBuffer buffer, FieldPosition position,
452: Vector<FieldPosition> fields, char format, int count) {
453: int field = -1;
454: int index = patternChars.indexOf(format);
455: if (index == -1) {
456: // text.03=Unknown pattern character - '{0}'
457: throw new IllegalArgumentException(Messages.getString(
458: "text.03", format)); //$NON-NLS-1$
459: }
460:
461: int beginPosition = buffer.length();
462: Field dateFormatField = null;
463: System.out.println("index:" + index);
464: switch (index) {
465: case ERA_FIELD:
466: dateFormatField = Field.ERA;
467: buffer.append(formatData.eras[calendar.get(Calendar.ERA)]);
468: break;
469: case YEAR_FIELD:
470: dateFormatField = Field.YEAR;
471: int year = calendar.get(Calendar.YEAR);
472: if (count < 4) {
473: appendNumber(buffer, 2, year %= 100);
474: } else {
475: appendNumber(buffer, count, year);
476: }
477: break;
478: case MONTH_FIELD:
479: dateFormatField = Field.MONTH;
480: int month = calendar.get(Calendar.MONTH);
481: if (count <= 2) {
482: appendNumber(buffer, count, month + 1);
483: } else if (count == 3) {
484: buffer.append(formatData.shortMonths[month]);
485: } else {
486: buffer.append(formatData.months[month]);
487: }
488: break;
489: case DATE_FIELD:
490: dateFormatField = Field.DAY_OF_MONTH;
491: field = Calendar.DATE;
492: break;
493: case HOUR_OF_DAY1_FIELD: // k
494: dateFormatField = Field.HOUR_OF_DAY1;
495: int hour = calendar.get(Calendar.HOUR_OF_DAY);
496: appendNumber(buffer, count, hour == 0 ? 24 : hour);
497: break;
498: case HOUR_OF_DAY0_FIELD: // H
499: dateFormatField = Field.HOUR_OF_DAY0;
500: field = Calendar.HOUR_OF_DAY;
501: break;
502: case MINUTE_FIELD:
503: dateFormatField = Field.MINUTE;
504: field = Calendar.MINUTE;
505: break;
506: case SECOND_FIELD:
507: dateFormatField = Field.SECOND;
508: field = Calendar.SECOND;
509: break;
510: case MILLISECOND_FIELD:
511: dateFormatField = Field.MILLISECOND;
512: int value = calendar.get(Calendar.MILLISECOND);
513: appendNumber(buffer, count, value);
514: break;
515: case DAY_OF_WEEK_FIELD:
516: dateFormatField = Field.DAY_OF_WEEK;
517: int day = calendar.get(Calendar.DAY_OF_WEEK);
518: if (count < 4) {
519: buffer.append(formatData.shortWeekdays[day]);
520: } else {
521: buffer.append(formatData.weekdays[day]);
522: }
523: break;
524: case DAY_OF_YEAR_FIELD:
525: dateFormatField = Field.DAY_OF_YEAR;
526: field = Calendar.DAY_OF_YEAR;
527: break;
528: case DAY_OF_WEEK_IN_MONTH_FIELD:
529: dateFormatField = Field.DAY_OF_WEEK_IN_MONTH;
530: field = Calendar.DAY_OF_WEEK_IN_MONTH;
531: break;
532: case WEEK_OF_YEAR_FIELD:
533: dateFormatField = Field.WEEK_OF_YEAR;
534: field = Calendar.WEEK_OF_YEAR;
535: break;
536: case WEEK_OF_MONTH_FIELD:
537: dateFormatField = Field.WEEK_OF_MONTH;
538: field = Calendar.WEEK_OF_MONTH;
539: break;
540: case AM_PM_FIELD:
541: dateFormatField = Field.AM_PM;
542: buffer
543: .append(formatData.ampms[calendar
544: .get(Calendar.AM_PM)]);
545: break;
546: case HOUR1_FIELD: // h
547: dateFormatField = Field.HOUR1;
548: hour = calendar.get(Calendar.HOUR);
549: appendNumber(buffer, count, hour == 0 ? 12 : hour);
550: break;
551: case HOUR0_FIELD: // K
552: dateFormatField = Field.HOUR0;
553: field = Calendar.HOUR;
554: break;
555: case TIMEZONE_FIELD: // z
556: dateFormatField = Field.TIME_ZONE;
557: appendTimeZone(buffer, count, true);
558: break;
559: case com.ibm.icu.text.DateFormat.TIMEZONE_RFC_FIELD: // Z
560: dateFormatField = Field.TIME_ZONE;
561: appendTimeZone(buffer, count, false);
562: break;
563: }
564: if (field != -1) {
565: appendNumber(buffer, count, calendar.get(field));
566: }
567:
568: if (fields != null) {
569: position = new FieldPosition(dateFormatField);
570: position.setBeginIndex(beginPosition);
571: position.setEndIndex(buffer.length());
572: fields.add(position);
573: } else {
574: // Set to the first occurrence
575: if ((position.getFieldAttribute() == dateFormatField || (position
576: .getFieldAttribute() == null && position.getField() == index))
577: && position.getEndIndex() == 0) {
578: position.setBeginIndex(beginPosition);
579: position.setEndIndex(buffer.length());
580: }
581: }
582: }
583:
584: private void appendTimeZone(StringBuffer buffer, int count,
585: boolean generalTimezone) {
586: // cannot call TimeZone.getDisplayName() because it would not use
587: // the DateFormatSymbols of this SimpleDateFormat
588:
589: if (generalTimezone) {
590: String id = calendar.getTimeZone().getID();
591: String[][] zones = formatData.zoneStrings;
592: String[] zone = null;
593: for (String[] element : zones) {
594: if (id.equals(element[0])) {
595: zone = element;
596: break;
597: }
598: }
599: if (zone == null) {
600: int offset = calendar.get(Calendar.ZONE_OFFSET)
601: + calendar.get(Calendar.DST_OFFSET);
602: char sign = '+';
603: if (offset < 0) {
604: sign = '-';
605: offset = -offset;
606: }
607: buffer.append("GMT"); //$NON-NLS-1$
608: buffer.append(sign);
609: appendNumber(buffer, 2, offset / 3600000);
610: buffer.append(':');
611: appendNumber(buffer, 2, (offset % 3600000) / 60000);
612: } else {
613: int daylight = calendar.get(Calendar.DST_OFFSET) == 0 ? 0
614: : 2;
615: if (count < 4) {
616: buffer.append(zone[2 + daylight]);
617: } else {
618: buffer.append(zone[1 + daylight]);
619: }
620: }
621: } else {
622: int offset = calendar.get(Calendar.ZONE_OFFSET)
623: + calendar.get(Calendar.DST_OFFSET);
624: char sign = '+';
625: if (offset < 0) {
626: sign = '-';
627: offset = -offset;
628: }
629: buffer.append(sign);
630: appendNumber(buffer, 2, offset / 3600000);
631: appendNumber(buffer, 2, (offset % 3600000) / 60000);
632: }
633: }
634:
635: private void appendNumber(StringBuffer buffer, int count, int value) {
636: int minimumIntegerDigits = numberFormat
637: .getMinimumIntegerDigits();
638: numberFormat.setMinimumIntegerDigits(count);
639: numberFormat.format(new Integer(value), buffer,
640: new FieldPosition(0));
641: numberFormat.setMinimumIntegerDigits(minimumIntegerDigits);
642: }
643:
644: /**
645: * Formats the specified Date into the specified StringBuffer using the
646: * pattern of this SimpleDateFormat. If the field specified by the
647: * FieldPosition is formatted, set the begin and end index of the formatted
648: * field in the FieldPosition.
649: *
650: * @param date
651: * the Date to format
652: * @param buffer
653: * the StringBuffer
654: * @param field
655: * the FieldPosition
656: * @return the StringBuffer parameter <code>buffer</code>
657: *
658: * @exception IllegalArgumentException
659: * when there are invalid characters in the pattern
660: */
661: @Override
662: public StringBuffer format(Date date, StringBuffer buffer,
663: FieldPosition field) {
664: icuFormat.setTimeZone(com.ibm.icu.util.TimeZone
665: .getTimeZone(calendar.getTimeZone().getID()));
666: return icuFormat.format(date, buffer, field);
667: }
668:
669: /**
670: * Answers the Date which is the start of the one hundred year period for
671: * two digits year values.
672: *
673: * @return a Date
674: */
675: public Date get2DigitYearStart() {
676: return defaultCenturyStart;
677: }
678:
679: /**
680: * Answers the DateFormatSymbols used by this SimpleDateFormat.
681: *
682: * @return a DateFormatSymbols
683: */
684: public DateFormatSymbols getDateFormatSymbols() {
685: // Return a clone so the arrays in the ResourceBundle are not modified
686: return (DateFormatSymbols) formatData.clone();
687: }
688:
689: /**
690: * Answers an integer hash code for the receiver. Objects which are equal
691: * answer the same value for this method.
692: *
693: * @return the receiver's hash
694: *
695: * @see #equals
696: */
697: @Override
698: public int hashCode() {
699: return super .hashCode() + pattern.hashCode()
700: + formatData.hashCode() + creationYear;
701: }
702:
703: /**
704: * Parse a Date from the specified String starting at the index specified by
705: * the ParsePosition. If the string is successfully parsed, the index of the
706: * ParsePosition is updated to the index following the parsed text.
707: *
708: * @param string
709: * the String to parse according to the pattern of this
710: * SimpleDateFormat
711: * @param position
712: * the ParsePosition, updated on return with the index following
713: * the parsed text, or on error the index is unchanged and the
714: * error index is set to the index where the error occurred
715: * @return the Date resulting from the parse, or null if there is an error
716: *
717: * @exception IllegalArgumentException
718: * when there are invalid characters in the pattern
719: */
720: @Override
721: public Date parse(String string, ParsePosition position) {
722: icuFormat.setTimeZone(com.ibm.icu.util.TimeZone
723: .getTimeZone(calendar.getTimeZone().getID()));
724: return icuFormat.parse(string, position);
725: }
726:
727: /**
728: * Sets the Date which is the start of the one hundred year period for two
729: * digits year values.
730: *
731: * @param date
732: * the Date
733: */
734: public void set2DigitYearStart(Date date) {
735: icuFormat.set2DigitYearStart(date);
736: defaultCenturyStart = date;
737: Calendar cal = new GregorianCalendar();
738: cal.setTime(date);
739: creationYear = cal.get(Calendar.YEAR);
740: }
741:
742: /**
743: * Sets the DateFormatSymbols used by this SimpleDateFormat.
744: *
745: * @param value
746: * the DateFormatSymbols
747: */
748: public void setDateFormatSymbols(DateFormatSymbols value) {
749: com.ibm.icu.text.DateFormatSymbols icuSymbols = new com.ibm.icu.text.DateFormatSymbols();
750: copySymbols(value, icuSymbols);
751: icuFormat.setDateFormatSymbols(icuSymbols);
752: formatData = (DateFormatSymbols) value.clone();
753: }
754:
755: /**
756: * Answers the pattern of this SimpleDateFormat using localized pattern
757: * characters.
758: *
759: * @return the localized pattern
760: */
761: public String toLocalizedPattern() {
762: return icuFormat.toLocalizedPattern();
763: }
764:
765: /**
766: * Answers the pattern of this SimpleDateFormat using non-localized pattern
767: * characters.
768: *
769: * @return the non-localized pattern
770: */
771: public String toPattern() {
772: return pattern;
773: }
774:
775: private static final ObjectStreamField[] serialPersistentFields = {
776: new ObjectStreamField("defaultCenturyStart", Date.class), //$NON-NLS-1$
777: new ObjectStreamField("formatData", DateFormatSymbols.class), //$NON-NLS-1$
778: new ObjectStreamField("pattern", String.class), //$NON-NLS-1$
779: new ObjectStreamField("serialVersionOnStream", Integer.TYPE), }; //$NON-NLS-1$
780:
781: private void writeObject(ObjectOutputStream stream)
782: throws IOException {
783: ObjectOutputStream.PutField fields = stream.putFields();
784: fields.put("defaultCenturyStart", defaultCenturyStart); //$NON-NLS-1$
785: fields.put("formatData", formatData); //$NON-NLS-1$
786: fields.put("pattern", pattern); //$NON-NLS-1$
787: fields.put("serialVersionOnStream", 1); //$NON-NLS-1$
788: stream.writeFields();
789: }
790:
791: private void readObject(ObjectInputStream stream)
792: throws IOException, ClassNotFoundException {
793: ObjectInputStream.GetField fields = stream.readFields();
794: int version = fields.get("serialVersionOnStream", 0); //$NON-NLS-1$
795: Date date;
796: if (version > 0) {
797: date = (Date) fields.get("defaultCenturyStart", new Date()); //$NON-NLS-1$
798: } else {
799: date = new Date();
800: }
801: set2DigitYearStart(date);
802: formatData = (DateFormatSymbols) fields.get("formatData", null); //$NON-NLS-1$
803: pattern = (String) fields.get("pattern", ""); //$NON-NLS-1$ //$NON-NLS-2$
804: }
805: }
|