001: package com.ibm.webdav;
002:
003: /*
004: * (C) Copyright IBM Corp. 2000 All rights reserved.
005: *
006: * The program is provided "AS IS" without any warranty express or
007: * implied, including the warranty of non-infringement and the implied
008: * warranties of merchantibility and fitness for a particular purpose.
009: * IBM will not be liable for any damages suffered by you as a result
010: * of using the Program. In no event will IBM be liable for any
011: * special, indirect or consequential damages or lost profits even if
012: * IBM has been advised of the possibility of their occurrence. IBM
013: * will not be liable for any third party claims against you.
014: *
015: * Portions Copyright (C) Simulacra Media Ltd, 2004.
016: */
017:
018: import java.io.*;
019: import java.text.*;
020: import java.util.*;
021:
022: /**
023: * <code>SimpleISO8601DateFormat</code> is a concrete class for formatting and
024: * parsing ISO 8601 format dates. It allows for formatting
025: * (date -> text), parsing (text -> date), and normalization.
026: *
027: * @see java.util.Calendar
028: * @see java.util.GregorianCalendar
029: * @see java.util.TimeZone
030: * @see DateFormat
031: * @see DateFormatSymbols
032: * @see DecimalFormat
033: * @version 1.31 04/22/98
034: * @author Mark Davis, Chen-Lieh Huang, Alan Liu
035: */
036: public class SimpleISO8601DateFormat extends DateFormat {
037:
038: // the official serial version ID which says cryptically
039: // which version we're compatible with
040: static final long serialVersionUID = 4774881970558875024L;
041:
042: // the internal serial version which says which version was written
043: // - 0 (default) for version up to JDK 1.1.3
044: // - 1 for version from JDK 1.1.4, which includes a new field
045: static final int currentSerialVersion = 1;
046: private int serialVersionOnStream = currentSerialVersion;
047:
048: /**
049: * Construct a SimpleDateFormat using the default pattern for the default
050: * locale. <b>Note:</b> Not all locales support SimpleDateFormat; for full
051: * generality, use the factory methods in the DateFormat class.
052: *
053: * @see java.text.DateFormat
054: */
055: public SimpleISO8601DateFormat() {
056: initialize();
057: }
058:
059: /**
060: * Overrides Cloneable
061: */
062: public Object clone() {
063: SimpleISO8601DateFormat other = (SimpleISO8601DateFormat) super
064: .clone();
065: // other.formatData = (DateFormatSymbols) formatData.clone();
066: return other;
067: }
068:
069: /**
070: * Override equals.
071: */
072: public boolean equals(Object obj) {
073: if (!super .equals(obj))
074: return false; // super does class check
075:
076: // todo: I think we are supposed to check if they are equivalent, but for now a class check will do. In fact I think
077: // just being the same class is adequate.
078:
079: return true;
080: }
081:
082: /**
083: * Overrides DateFormat
084: * <p>Formats a date or time, which is the standard millis
085: * since January 1, 1970, 00:00:00 GMT.
086: * @param date the date-time value to be formatted into a date-time string.
087: * @param toAppendTo where the new date-time text is to be appended.
088: * @param pos the formatting position. On input: an alignment field,
089: * if desired. On output: the offsets of the alignment field.
090: * @return the formatted date-time string.
091: * @see java.util.DateFormat
092: */
093: public StringBuffer format(Date date, StringBuffer toAppendTo,
094: FieldPosition pos) {
095: java.text.SimpleDateFormat df = new java.text.SimpleDateFormat(
096: "yyyy-MM-dd'T'HH:mm:ss");
097: df.setTimeZone(TimeZone.getTimeZone("GMT"));
098: df.format(date, toAppendTo, pos);
099: Calendar calendar = Calendar.getInstance();
100: calendar.setTime(date);
101: int dstoff = calendar.get(Calendar.DST_OFFSET);
102: int tzoff = calendar.get(Calendar.ZONE_OFFSET);
103:
104: tzoff += dstoff;
105: tzoff /= (1000 * 60);
106: if (tzoff != 0) {
107: if (tzoff < 0) {
108: toAppendTo.append("-");
109: tzoff *= -1;
110: } else {
111: toAppendTo.append("+");
112: }
113: int hr = tzoff / 60;
114: if (hr < 10)
115: toAppendTo.append("0");
116: toAppendTo.append("" + hr + ":");
117: int mn = tzoff % 60;
118: if (mn < 10)
119: toAppendTo.append("0");
120: toAppendTo.append(mn);
121: } else {
122: toAppendTo.append("Z");
123: }
124: //System.out.println( toAppendTo );
125: /*
126: Calendar calendar = getCalendar();
127: // Initialize
128: pos.beginIndex = pos.endIndex = 0;
129: int posfield = pos.getField();
130:
131: // Convert input date to time field list
132: calendar.setTime(date);
133:
134:
135: int tval = calendar.get(Calendar.YEAR );
136: if (posfield==DateFormat.YEAR_FIELD) {
137: pos.beginIndex = toAppendTo.length();
138: pos.endIndex = pos.beginIndex+4;
139: }
140: toAppendTo.append( tval );
141: toAppendTo.append( '-' );
142: if (posfield==DateFormat.MONTH_FIELD) {
143: pos.beginIndex = toAppendTo.length();
144: pos.endIndex = pos.beginIndex+2;
145: }
146: tval = calendar.get(Calendar.MONTH ) + 1 ; // apparently we need to increment these
147: if (tval<10) toAppendTo.append( '0' );
148: toAppendTo.append( tval );
149:
150: toAppendTo.append( '-' );
151: if (posfield==DateFormat.DATE_FIELD) {
152: pos.beginIndex = toAppendTo.length();
153: pos.endIndex = pos.beginIndex+2;
154: }
155: tval = calendar.get(Calendar.DAY_OF_MONTH );
156: if (tval<10) toAppendTo.append( '0' );
157: toAppendTo.append( tval );
158:
159: toAppendTo.append( 'T' );
160: if (posfield==DateFormat.HOUR_OF_DAY0_FIELD) {
161: pos.beginIndex = toAppendTo.length();
162: pos.endIndex = pos.beginIndex+2;
163: }
164: tval = calendar.get(Calendar.HOUR );
165: if (tval<10) toAppendTo.append( '0' );
166: toAppendTo.append( tval );
167:
168: toAppendTo.append( ':' );
169: if (posfield==DateFormat.MINUTE_FIELD) {
170: pos.beginIndex = toAppendTo.length();
171: pos.endIndex = pos.beginIndex+2;
172: }
173: tval = calendar.get(Calendar.MINUTE );
174: if (tval<10) toAppendTo.append( '0' );
175: toAppendTo.append( tval );
176:
177: toAppendTo.append( ':' );
178: if (posfield==DateFormat.SECOND_FIELD) {
179: pos.beginIndex = toAppendTo.length();
180: pos.endIndex = pos.beginIndex+2;
181: }
182: tval = calendar.get(Calendar.SECOND );
183: if (tval<10) toAppendTo.append( '0' );
184: toAppendTo.append( tval );
185:
186: toAppendTo.append( 'Z' );
187: */
188: return toAppendTo;
189: }
190:
191: /* Initialize calendar and numberFormat fields */
192:
193: private void initialize() {
194: // The format object must be constructed using the symbols for this zone.
195: // However, the calendar should use the current default TimeZone.
196: // If this is not contained in the locale zone strings, then the zone
197: // will be formatted using generic GMT+/-H:MM nomenclature.
198: TimeZone tz = TimeZone.getTimeZone("UDT");
199: calendar = Calendar.getInstance(tz);
200: // numberFormat isn't used by us, but we inherit behavior that we have to respect.
201: NumberFormat numberFormat = NumberFormat.getInstance();
202: /*
203: numberFormat.setGroupingUsed(false);
204: if (numberFormat instanceof DecimalFormat)
205: ((DecimalFormat)numberFormat).setDecimalSeparatorAlwaysShown(false);
206: numberFormat.setParseIntegerOnly(true); // So that dd.mm.yy can be parsed
207: numberFormat.setMinimumFractionDigits(0); // To prevent "Jan 1.00, 1997.00"
208: */
209: setNumberFormat(numberFormat);
210: /*
211: initializeDefaultCentury();
212: */
213: }
214:
215: /**
216: * Overrides DateFormat
217: * @see java.util.DateFormat
218: */
219: public Date parse(String text, java.text.ParsePosition pos) {
220: int start = pos.getIndex();
221: Calendar calendar = getCalendar();
222: calendar.clear(); // Clears all the time fields
223:
224: int year = Integer.parseInt(text.substring(start, start + 4));
225: int month = Integer.parseInt(text.substring(start + 5,
226: start + 7));
227: int day = Integer.parseInt(text
228: .substring(start + 8, start + 10));
229: int hour = Integer.parseInt(text.substring(start + 11,
230: start + 13));
231: int minute = Integer.parseInt(text.substring(start + 14,
232: start + 16));
233: int second = Integer.parseInt(text.substring(start + 17,
234: start + 19));
235: if (text.substring(start + 19, start + 20).equals("Z")) {
236: // GMT
237: pos.setIndex(start + 20);
238: } else {
239: int offhour = Integer.parseInt(text.substring(start + 20,
240: start + 22));
241: int offmin = Integer.parseInt(text.substring(start + 23,
242: start + 25));
243: int sum = (offhour * 60 + offmin) * 60 * 1000; // in millis
244: if (text.substring(start + 19, start + 20).equals("-"))
245: sum *= -1; // NYC is "-04:00"
246: calendar.set(Calendar.ZONE_OFFSET, sum); // NYC is ZONE_OFFSET=5 or 4
247: //calendar.set( Calendar.DST_OFFSET, sum );
248: pos.setIndex(start + 25);
249: }
250:
251: // todo: return position.
252:
253: calendar.set(year, month - 1, day, hour, minute, second);
254: Date retval = calendar.getTime();
255: //System.out.println( " "+ text + "******" + retval );
256: return retval;
257: }
258:
259: /**
260: * Override readObject.
261: */
262: private void readObject(ObjectInputStream stream)
263: throws IOException, ClassNotFoundException {
264: stream.defaultReadObject();
265: /*
266: if (serialVersionOnStream < 1) {
267: // didn't have defaultCenturyStart field
268: initializeDefaultCentury();
269: }
270: else {
271: // fill in dependent transient field
272: parseAmbiguousDatesAsAfter(defaultCenturyStart);
273: }
274: */
275: serialVersionOnStream = currentSerialVersion;
276: }
277: }
|