View Javadoc

1   /*
2    * Copyright 2003, 2004  The Apache Software Foundation
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    * http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
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              // Sign
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                 // Ignore UTC, it is the default
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         // JDK 1.4: int offset = tz.getOffset(cal.getTimeInMillis());
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 }