Merge from the pain train
[official-gcc.git] / libjava / gnu / java / net / protocol / http / HTTPDateFormat.java
blob0137596aa746fae70c89dd29fc14938978a6ae0f
1 /* HTTPDateFormat.java --
2 Copyright (C) 2004 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package gnu.java.net.protocol.http;
41 import java.text.DateFormat;
42 import java.text.DecimalFormat;
43 import java.text.FieldPosition;
44 import java.text.NumberFormat;
45 import java.text.ParsePosition;
46 import java.util.Calendar;
47 import java.util.Date;
48 import java.util.GregorianCalendar;
49 import java.util.TimeZone;
51 /**
52 * HTTP date formatter and parser.
53 * Formats dates according to RFC 822 (updated by RFC 1123).
54 * Parses dates according to the above, <i>or</i> RFC 1036, <i>or</i> the
55 * ANSI C <code>asctime()</code> format.
57 * @author Chris Burdess (dog@gnu.org)
59 public class HTTPDateFormat
60 extends DateFormat
63 static final String[] DAYS_OF_WEEK = {
64 null, "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
67 static final String[] MONTHS = {
68 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
69 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
72 public HTTPDateFormat()
74 calendar = new GregorianCalendar(TimeZone.getTimeZone ("GMT"));
75 numberFormat = new DecimalFormat();
78 /**
79 * Appends the textual value for the specified field to the given string
80 * buffer. This method should be avoided, use <code>format(Date)</code>
81 * instead.
82 * @param date the Date object
83 * @param buf the buffer to append to
84 * @param field the current field position
85 * @return the modified buffer
87 public StringBuffer format(Date date, StringBuffer buf,
88 FieldPosition field)
90 calendar.clear();
91 calendar.setTime(date);
92 buf.setLength(0);
94 // Day of week
95 buf.append(DAYS_OF_WEEK[calendar.get(Calendar.DAY_OF_WEEK)]);
96 buf.append(',');
97 buf.append(' ');
99 // Day of month
100 int day = calendar.get(Calendar.DAY_OF_MONTH);
101 buf.append(Character.forDigit(day / 10, 10));
102 buf.append(Character.forDigit(day % 10, 10));
103 buf.append(' ');
105 // Month
106 buf.append(MONTHS[calendar.get(Calendar.MONTH)]);
107 buf.append(' ');
109 // Year
110 int year = calendar.get(Calendar.YEAR);
111 if (year < 1000)
113 buf.append('0');
114 if (year < 100)
116 buf.append('0');
117 if (year < 10)
119 buf.append('0');
123 buf.append(Integer.toString(year));
124 buf.append(' ');
126 // Hour
127 int hour = calendar.get(Calendar.HOUR_OF_DAY);
128 buf.append(Character.forDigit(hour / 10, 10));
129 buf.append(Character.forDigit(hour % 10, 10));
130 buf.append(':');
132 // Minute
133 int minute = calendar.get(Calendar.MINUTE);
134 buf.append(Character.forDigit(minute / 10, 10));
135 buf.append(Character.forDigit(minute % 10, 10));
136 buf.append(':');
138 // Second
139 int second = calendar.get(Calendar.SECOND);
140 buf.append(Character.forDigit(second / 10, 10));
141 buf.append(Character.forDigit(second % 10, 10));
142 buf.append(' ');
144 // Timezone
145 // Get time offset in minutes
146 int zoneOffset =(calendar.get(Calendar.ZONE_OFFSET) +
147 calendar.get(Calendar.DST_OFFSET)) / 60000;
149 // Apply + or - appropriately
150 if (zoneOffset < 0)
152 zoneOffset = -zoneOffset;
153 buf.append('-');
155 else
157 buf.append('+');
160 // Set the 2 2-char fields as specified above
161 int tzhours = zoneOffset / 60;
162 buf.append(Character.forDigit(tzhours / 10, 10));
163 buf.append(Character.forDigit(tzhours % 10, 10));
164 int tzminutes = zoneOffset % 60;
165 buf.append(Character.forDigit(tzminutes / 10, 10));
166 buf.append(Character.forDigit(tzminutes % 10, 10));
168 field.setBeginIndex(0);
169 field.setEndIndex(buf.length());
170 return buf;
174 * Parses the given date in the current TimeZone.
175 * @param text the formatted date to be parsed
176 * @param pos the current parse position
178 public Date parse(String text, ParsePosition pos)
180 int date, month, year, hour, minute, second;
181 String monthText;
182 int start = 0, end = -1;
183 int len = text.length();
184 calendar.clear();
185 pos.setIndex(start);
188 // Advance to date
189 if (Character.isLetter(text.charAt(start)))
191 start = skipNonWhitespace(text, start);
193 // Determine mode
194 switch(start)
196 case 3:
197 // asctime
198 start = skipWhitespace(text, start);
199 pos.setIndex(start);
200 end = skipNonWhitespace(text, start + 1);
201 monthText = text.substring(start, end);
202 month = -1;
203 for (int i = 0; i < 12; i++)
205 if (MONTHS[i].equals(monthText))
207 month = i;
208 break;
211 if (month == -1)
213 pos.setErrorIndex(end);
214 return null;
216 // Advance to date
217 start = skipWhitespace(text, end + 1);
218 pos.setIndex(start);
219 end = skipNonWhitespace(text, start + 1);
220 date = Integer.parseInt(text.substring(start, end));
221 // Advance to hour
222 start = skipWhitespace(text, end + 1);
223 pos.setIndex(start);
224 end = skipTo(text, start + 1, ':');
225 hour = Integer.parseInt(text.substring(start, end));
226 // Advance to minute
227 start = end + 1;
228 pos.setIndex(start);
229 end = skipTo(text, start + 1, ':');
230 minute = Integer.parseInt(text.substring(start, end));
231 // Advance to second
232 start = end + 1;
233 pos.setIndex(start);
234 end = skipNonWhitespace(text, start + 1);
235 second = Integer.parseInt(text.substring(start, end));
236 // Advance to year
237 start = skipWhitespace(text, end + 1);
238 pos.setIndex(start);
239 end = skipNonWhitespace(text, start + 1);
240 year = Integer.parseInt(text.substring(start, end));
241 break;
242 case 0:
243 case 4:
244 // rfc822
245 start = skipWhitespace(text, start);
246 pos.setIndex(start);
247 end = skipNonWhitespace(text, start + 1);
248 date = Integer.parseInt(text.substring(start, end));
249 // Advance to month
250 start = skipWhitespace(text, end + 1);
251 pos.setIndex(start);
252 end = skipNonWhitespace(text, start + 1);
253 monthText = text.substring(start, end);
254 month = -1;
255 for (int i = 0; i < 12; i++)
257 if (MONTHS[i].equals(monthText))
259 month = i;
260 break;
263 if (month == -1)
265 pos.setErrorIndex(end);
266 return null;
268 // Advance to year
269 start = skipWhitespace(text, end + 1);
270 pos.setIndex(start);
271 end = skipNonWhitespace(text, start + 1);
272 year = Integer.parseInt(text.substring(start, end));
273 // Advance to hour
274 start = skipWhitespace(text, end + 1);
275 pos.setIndex(start);
276 end = skipTo(text, start + 1, ':');
277 hour = Integer.parseInt(text.substring(start, end));
278 // Advance to minute
279 start = end + 1;
280 pos.setIndex(start);
281 end = skipTo(text, start + 1, ':');
282 minute = Integer.parseInt(text.substring(start, end));
283 // Advance to second
284 start = end + 1;
285 pos.setIndex(start);
286 end = start + 1;
287 while (end < len && !Character.isWhitespace(text.charAt(end)))
289 end++;
291 second = Integer.parseInt(text.substring(start, end));
292 break;
293 default:
294 // rfc850(obsolete)
295 start = skipWhitespace(text, start);
296 pos.setIndex(start);
297 end = skipTo(text, start + 1, '-');
298 date = Integer.parseInt(text.substring(start, end));
299 // Advance to month
300 start = end + 1;
301 pos.setIndex(start);
302 end = skipTo(text, start + 1, '-');
303 monthText = text.substring(start, end);
304 month = -1;
305 for (int i = 0; i < 12; i++)
307 if (MONTHS[i].equals(monthText))
309 month = i;
310 break;
313 if (month == -1)
315 pos.setErrorIndex(end);
316 return null;
318 // Advance to year
319 start = end + 1;
320 pos.setIndex(start);
321 end = skipNonWhitespace(text, start + 1);
322 year = 1900 + Integer.parseInt(text.substring(start, end));
323 // Advance to hour
324 start = skipWhitespace(text, end + 1);
325 pos.setIndex(start);
326 end = skipTo(text, start + 1, ':');
327 hour = Integer.parseInt(text.substring(start, end));
328 // Advance to minute
329 start = end + 1;
330 pos.setIndex(start);
331 end = skipTo(text, start + 1, ':');
332 minute = Integer.parseInt(text.substring(start, end));
333 // Advance to second
334 start = end + 1;
335 pos.setIndex(start);
336 end = start + 1;
337 while (end < len && !Character.isWhitespace(text.charAt(end)))
339 end++;
341 second = Integer.parseInt(text.substring(start, end));
344 calendar.set(Calendar.YEAR, year);
345 calendar.set(Calendar.MONTH, month);
346 calendar.set(Calendar.DAY_OF_MONTH, date);
347 calendar.set(Calendar.HOUR, hour);
348 calendar.set(Calendar.MINUTE, minute);
349 calendar.set(Calendar.SECOND, second);
351 if (end != len)
353 // Timezone
354 start = skipWhitespace(text, end + 1);
355 end = start + 1;
356 while (end < len && !Character.isWhitespace(text.charAt(end)))
358 end++;
360 char pm = text.charAt(start);
361 if (Character.isLetter(pm))
363 TimeZone tz =
364 TimeZone.getTimeZone(text.substring(start, end));
365 calendar.set(Calendar.ZONE_OFFSET, tz.getRawOffset());
367 else
369 int zoneOffset = 0;
370 zoneOffset += 600 * Character.digit(text.charAt(++start), 10);
371 zoneOffset += 60 * Character.digit(text.charAt(++start), 10);
372 zoneOffset += 10 * Character.digit(text.charAt(++start), 10);
373 zoneOffset += Character.digit(text.charAt(++start), 10);
374 zoneOffset *= 60000; // minutes -> ms
375 if ('-' == pm)
377 zoneOffset = -zoneOffset;
379 calendar.set(Calendar.ZONE_OFFSET, zoneOffset);
382 pos.setIndex(end);
384 return calendar.getTime();
386 catch (NumberFormatException e)
388 pos.setErrorIndex(Math.max(start, end));
390 catch (StringIndexOutOfBoundsException e)
392 pos.setErrorIndex(Math.max(start, end));
394 return null;
397 private int skipWhitespace(String text, int pos)
399 while(Character.isWhitespace(text.charAt(pos)))
401 pos++;
403 return pos;
406 private int skipNonWhitespace(String text, int pos)
408 while(!Character.isWhitespace(text.charAt(pos)))
410 pos++;
412 return pos;
415 private int skipTo(String text, int pos, char c)
417 while(text.charAt(pos) != c)
419 pos++;
421 return pos;
425 * Don't allow setting the calendar.
427 public void setCalendar(Calendar newCalendar)
429 throw new UnsupportedOperationException();
433 * Don't allow setting the NumberFormat.
435 public void setNumberFormat(NumberFormat newNumberFormat)
437 throw new UnsupportedOperationException();