1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.codehaus.xfire.util.date;
17
18 import java.text.FieldPosition;
19 import java.text.Format;
20 import java.text.ParsePosition;
21 import java.util.Calendar;
22 import java.util.TimeZone;
23
24 /***
25 * <p>
26 * An instance of {@link java.text.Format}, which may be used to parse and
27 * format <code>xs:dateTime</code> values.
28 * </p>
29 */
30 public class XsDateTimeFormat
31 extends Format
32 {
33 private static final long serialVersionUID = 3258131340871479609L;
34
35 final boolean parseDate;
36
37 final boolean parseTime;
38
39 XsDateTimeFormat(boolean pParseDate, boolean pParseTime)
40 {
41 parseDate = pParseDate;
42 parseTime = pParseTime;
43 }
44
45 /***
46 * Creates a new instance.
47 */
48 public XsDateTimeFormat()
49 {
50 this(true, true);
51 }
52
53 private int parseInt(String pString, int pOffset, StringBuffer pDigits)
54 {
55 int length = pString.length();
56 pDigits.setLength(0);
57 while (pOffset < length)
58 {
59 char c = pString.charAt(pOffset);
60 if (Character.isDigit(c))
61 {
62 pDigits.append(c);
63 ++pOffset;
64 }
65 else
66 {
67 break;
68 }
69 }
70 return pOffset;
71 }
72
73 public Object parseObject(String pString, ParsePosition pParsePosition)
74 {
75 if (pString == null)
76 {
77 throw new NullPointerException("The String argument must not be null.");
78 }
79 if (pParsePosition == null)
80 {
81 throw new NullPointerException("The ParsePosition argument must not be null.");
82 }
83 int offset = pParsePosition.getIndex();
84 int length = pString.length();
85
86 boolean isMinus = false;
87 StringBuffer digits = new StringBuffer();
88 int year, month, mday;
89 if (parseDate)
90 {
91
92 if (offset < length)
93 {
94 char c = pString.charAt(offset);
95 if (c == '+')
96 {
97 ++offset;
98 }
99 else if (c == '-')
100 {
101 ++offset;
102 isMinus = true;
103 }
104 }
105
106 offset = parseInt(pString, offset, digits);
107 if (digits.length() < 4)
108 {
109 pParsePosition.setErrorIndex(offset);
110 return null;
111 }
112 year = Integer.parseInt(digits.toString());
113
114 if (offset < length && pString.charAt(offset) == '-')
115 {
116 ++offset;
117 }
118 else
119 {
120 pParsePosition.setErrorIndex(offset);
121 return null;
122 }
123
124 offset = parseInt(pString, offset, digits);
125 if (digits.length() != 2)
126 {
127 pParsePosition.setErrorIndex(offset);
128 return null;
129 }
130 month = Integer.parseInt(digits.toString());
131
132 if (offset < length && pString.charAt(offset) == '-')
133 {
134 ++offset;
135 }
136 else
137 {
138 pParsePosition.setErrorIndex(offset);
139 return null;
140 }
141
142 offset = parseInt(pString, offset, digits);
143 if (digits.length() != 2)
144 {
145 pParsePosition.setErrorIndex(offset);
146 return null;
147 }
148 mday = Integer.parseInt(digits.toString());
149
150 if (parseTime)
151 {
152 if (offset < length && pString.charAt(offset) == 'T')
153 {
154 ++offset;
155 }
156 else
157 {
158 pParsePosition.setErrorIndex(offset);
159 return null;
160 }
161 }
162 }
163 else
164 {
165 year = month = mday = 0;
166 }
167
168 int hour, minute, second, millis;
169 if (parseTime)
170 {
171 offset = parseInt(pString, offset, digits);
172 if (digits.length() != 2)
173 {
174 pParsePosition.setErrorIndex(offset);
175 return null;
176 }
177 hour = Integer.parseInt(digits.toString());
178
179 if (offset < length && pString.charAt(offset) == ':')
180 {
181 ++offset;
182 }
183 else
184 {
185 pParsePosition.setErrorIndex(offset);
186 return null;
187 }
188
189 offset = parseInt(pString, offset, digits);
190 if (digits.length() != 2)
191 {
192 pParsePosition.setErrorIndex(offset);
193 return null;
194 }
195 minute = Integer.parseInt(digits.toString());
196
197 if (offset < length && pString.charAt(offset) == ':')
198 {
199 ++offset;
200 }
201 else
202 {
203 pParsePosition.setErrorIndex(offset);
204 return null;
205 }
206
207 offset = parseInt(pString, offset, digits);
208 if (digits.length() != 2)
209 {
210 pParsePosition.setErrorIndex(offset);
211 return null;
212 }
213 second = Integer.parseInt(digits.toString());
214
215 if (offset < length && pString.charAt(offset) == '.')
216 {
217 ++offset;
218 offset = parseInt(pString, offset, digits);
219 if (digits.length() > 0)
220 {
221 millis = Integer.parseInt(digits.toString());
222 }
223 else
224 {
225 millis = 0;
226 }
227 }
228 else
229 {
230 millis = 0;
231 }
232 }
233 else
234 {
235 hour = minute = second = millis = 0;
236 }
237
238 digits.setLength(0);
239 digits.append("GMT");
240 if (offset < length)
241 {
242 char c = pString.charAt(offset);
243 if (c == 'Z')
244 {
245
246 ++offset;
247 }
248 else if (c == '+' || c == '-')
249 {
250 digits.append(c);
251 ++offset;
252 for (int i = 0; i < 5; i++)
253 {
254 if (offset >= length)
255 {
256 pParsePosition.setErrorIndex(offset);
257 return null;
258 }
259 c = pString.charAt(offset);
260 if ((i != 2 && Character.isDigit(c)) || (i == 2 && c == ':'))
261 {
262 digits.append(c);
263 }
264 else
265 {
266 pParsePosition.setErrorIndex(offset);
267 return null;
268 }
269 ++offset;
270 }
271 }
272 }
273
274 Calendar cal = Calendar.getInstance(TimeZone.getTimeZone(digits.toString()));
275 cal.set(isMinus ? -year : year, parseDate ? month - 1 : month, mday, hour, minute, second);
276 cal.set(Calendar.MILLISECOND, millis);
277 pParsePosition.setIndex(offset);
278 return cal;
279 }
280
281 private void append(StringBuffer pBuffer, int pNum, int pMinLen)
282 {
283 String s = Integer.toString(pNum);
284 for (int i = s.length(); i < pMinLen; i++)
285 {
286 pBuffer.append('0');
287 }
288 pBuffer.append(s);
289 }
290
291 public StringBuffer format(Object pCalendar, StringBuffer pBuffer, FieldPosition pPos)
292 {
293 if (pCalendar == null)
294 {
295 throw new NullPointerException("The Calendar argument must not be null.");
296 }
297 if (pBuffer == null)
298 {
299 throw new NullPointerException("The StringBuffer argument must not be null.");
300 }
301 if (pPos == null)
302 {
303 throw new NullPointerException("The FieldPosition argument must not be null.");
304 }
305
306 Calendar cal = (Calendar) pCalendar;
307 if (parseDate)
308 {
309 int year = cal.get(Calendar.YEAR);
310 if (year < 0)
311 {
312 pBuffer.append('-');
313 year = -year;
314 }
315 append(pBuffer, year, 4);
316 pBuffer.append('-');
317 append(pBuffer, cal.get(Calendar.MONTH) + 1, 2);
318 pBuffer.append('-');
319 append(pBuffer, cal.get(Calendar.DAY_OF_MONTH), 2);
320 if (parseTime)
321 {
322 pBuffer.append('T');
323 }
324 }
325 if (parseTime)
326 {
327 append(pBuffer, cal.get(Calendar.HOUR_OF_DAY), 2);
328 pBuffer.append(':');
329 append(pBuffer, cal.get(Calendar.MINUTE), 2);
330 pBuffer.append(':');
331 append(pBuffer, cal.get(Calendar.SECOND), 2);
332 int millis = cal.get(Calendar.MILLISECOND);
333 if (millis > 0)
334 {
335 pBuffer.append('.');
336 append(pBuffer, millis, 3);
337 }
338 }
339 TimeZone tz = cal.getTimeZone();
340
341 int offset = cal.get(Calendar.ZONE_OFFSET);
342 if (tz.inDaylightTime(cal.getTime()))
343 {
344 offset += cal.get(Calendar.DST_OFFSET);
345 }
346 if (offset == 0)
347 {
348 pBuffer.append('Z');
349 }
350 else
351 {
352 if (offset < 0)
353 {
354 pBuffer.append('-');
355 offset = -offset;
356 }
357 else
358 {
359 pBuffer.append('+');
360 }
361 int minutes = offset / (60 * 1000);
362 int hours = minutes / 60;
363 minutes -= hours * 60;
364 append(pBuffer, hours, 2);
365 pBuffer.append(':');
366 append(pBuffer, minutes, 2);
367 }
368 return pBuffer;
369 }
370 }