View Javadoc

1   package org.codehaus.xfire.util;
2   
3   import java.text.SimpleDateFormat;
4   import java.util.Calendar;
5   import java.util.Date;
6   import java.util.GregorianCalendar;
7   import java.util.TimeZone;
8   
9   /***
10   * Helps reading and writing ISO8601 dates.
11   * <p>
12   * Contains code from Apache Axis.
13   * 
14   * @author <a href="mailto:dan@envoisolutions.com">Dan Diephouse </a>
15   */
16  public class DateUtils
17  {
18  	private static SimpleDateFormat dateFormatter = new SimpleDateFormat(
19  			"yyyy-MM-dd");
20  
21  	private static SimpleDateFormat dateTimeFormatter = new SimpleDateFormat(
22  			"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
23  
24      private static Calendar calendar = Calendar.getInstance();
25      
26  	static
27  	{
28  		dateTimeFormatter.setTimeZone(TimeZone.getTimeZone("GMT"));
29  	}
30  
31  	public static Date parseDate(String source)
32  	{
33  		Date result;
34  		boolean bc = false;
35  
36  		// validate fixed portion of format
37  		if (source != null)
38  		{
39  			if (source.charAt(0) == '+') source = source.substring(1);
40  
41  			if (source.charAt(0) == '-')
42  			{
43  				source = source.substring(1);
44  				bc = true;
45  			}
46  
47  			if (source.length() < 10) 
48                  throw new NumberFormatException("Invalid date format.");
49  
50  			if (source.charAt(4) != '-' || source.charAt(7) != '-')
51                   throw new NumberFormatException("Invalid date format.");
52  
53  		}
54  
55  		synchronized (calendar)
56  		{
57  			// convert what we have validated so far
58  			try
59  			{
60  				result = dateFormatter.parse(source == null ? null : (source.substring(0, 10)));
61  			}
62  			catch (Exception e)
63  			{
64  				throw new NumberFormatException(e.toString());
65  			}
66  
67  			// support dates before the Christian era
68  			if (bc)
69  			{
70  				calendar.setTime(result);
71  				calendar.set(Calendar.ERA, GregorianCalendar.BC);
72  				result = calendar.getTime();
73  			}
74  		}
75  
76  		return result;
77  	}
78  
79      public static String formatDate( Date date )
80      {
81          synchronized (dateFormatter) 
82          {
83              // Sun JDK bug http://developer.java.sun.com/developer/bugParade/bugs/4229798.html
84              return dateFormatter.format(date);
85          }   
86      }
87      
88      public static String formatDateTime( Date date )
89      {
90          synchronized (dateTimeFormatter) 
91          {
92              // Sun JDK bug http://developer.java.sun.com/developer/bugParade/bugs/4229798.html
93              return dateTimeFormatter.format(date);
94          }   
95      }
96      
97  	public static Date parseDateTime(String source)
98  	{
99  		Calendar calendar = Calendar.getInstance();
100 		Date date;
101 		boolean bc = false;
102 
103 		// validate fixed portion of format
104 		if (source != null)
105 		{
106 			if (source.charAt(0) == '+') source = source.substring(1);
107 
108 			if (source.charAt(0) == '-')
109 			{
110 				source = source.substring(1);
111 				bc = true;
112 			}
113 
114 			if (source.length() < 19) 
115                 throw new NumberFormatException("Invalid date format.");
116 
117 			if (source.charAt(4) != '-' || source.charAt(7) != '-'
118 					|| source.charAt(10) != 'T') 
119                 throw new NumberFormatException("Invalid date format.");
120 
121 			if (source.charAt(13) != ':' || source.charAt(16) != ':') 
122                 throw new NumberFormatException("Invalid date format.");
123 		}
124 
125 		// convert what we have validated so far
126 		try
127 		{
128 			synchronized (dateTimeFormatter)
129 			{
130 				date = dateTimeFormatter.parse(source == null ? null : (source.substring(0,19) + ".000Z"));
131 			}
132 		}
133 		catch (Exception e)
134 		{
135 			throw new NumberFormatException(e.toString());
136 		}
137 
138 		int pos = 19;
139 
140 		// parse optional milliseconds
141 		if (source != null)
142 		{
143 			if (pos < source.length() && source.charAt(pos) == '.')
144 			{
145 				int milliseconds = 0;
146 				int start = ++pos;
147 				while (pos < source.length()
148 						&& Character.isDigit(source.charAt(pos)))
149 					pos++;
150 
151 				String decimal = source.substring(start, pos);
152 				if (decimal.length() == 3)
153 				{
154 					milliseconds = Integer.parseInt(decimal);
155 				}
156 				else if (decimal.length() < 3)
157 				{
158 					milliseconds = Integer.parseInt((decimal + "000")
159 							.substring(0, 3));
160 				}
161 				else
162 				{
163 					milliseconds = Integer.parseInt(decimal.substring(0, 3));
164 					if (decimal.charAt(3) >= '5') ++milliseconds;
165 				}
166 
167 				// add milliseconds to the current date
168 				date.setTime(date.getTime() + milliseconds);
169 			}
170 
171 			// parse optional timezone
172 			if (pos + 5 < source.length()
173 					&& (source.charAt(pos) == '+' || (source.charAt(pos) == '-')))
174 			{
175 				if (!Character.isDigit(source.charAt(pos + 1))
176 						|| !Character.isDigit(source.charAt(pos + 2))
177 						|| source.charAt(pos + 3) != ':'
178 						|| !Character.isDigit(source.charAt(pos + 4))
179 						|| !Character.isDigit(source.charAt(pos + 5))) 
180                     throw new NumberFormatException("Invalid date format. Bad Timezone.");
181 
182 				int hours = (source.charAt(pos + 1) - '0') * 10
183 						+ source.charAt(pos + 2) - '0';
184 				int mins = (source.charAt(pos + 4) - '0') * 10
185 						+ source.charAt(pos + 5) - '0';
186 				int milliseconds = (hours * 60 + mins) * 60 * 1000;
187 
188 				// subtract milliseconds from current date to obtain GMT
189 				if (source.charAt(pos) == '+') milliseconds = -milliseconds;
190 				date.setTime(date.getTime() + milliseconds);
191 				pos += 6;
192 			}
193 
194 			if (pos < source.length() && source.charAt(pos) == 'Z')
195 			{
196 				pos++;
197 				calendar.setTimeZone(TimeZone.getTimeZone("GMT"));
198 			}
199 
200 			if (pos < source.length()) 
201                  throw new NumberFormatException("Invalid date format.");
202 		}
203 
204 		calendar.setTime(date);
205 
206 		// support dates before the Christian era
207 		if (bc)
208 		{
209 			calendar.set(Calendar.ERA, GregorianCalendar.BC);
210 		}
211 
212 		return date;
213 	}
214 }