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)
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
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
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
;
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
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();
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>
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
,
91 calendar
.setTime(date
);
95 buf
.append(DAYS_OF_WEEK
[calendar
.get(Calendar
.DAY_OF_WEEK
)]);
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));
106 buf
.append(MONTHS
[calendar
.get(Calendar
.MONTH
)]);
110 int year
= calendar
.get(Calendar
.YEAR
);
123 buf
.append(Integer
.toString(year
));
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));
133 int minute
= calendar
.get(Calendar
.MINUTE
);
134 buf
.append(Character
.forDigit(minute
/ 10, 10));
135 buf
.append(Character
.forDigit(minute
% 10, 10));
139 int second
= calendar
.get(Calendar
.SECOND
);
140 buf
.append(Character
.forDigit(second
/ 10, 10));
141 buf
.append(Character
.forDigit(second
% 10, 10));
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
152 zoneOffset
= -zoneOffset
;
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());
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
;
182 int start
= 0, end
= -1;
183 int len
= text
.length();
189 if (Character
.isLetter(text
.charAt(start
)))
191 start
= skipNonWhitespace(text
, start
);
198 start
= skipWhitespace(text
, start
);
200 end
= skipNonWhitespace(text
, start
+ 1);
201 monthText
= text
.substring(start
, end
);
203 for (int i
= 0; i
< 12; i
++)
205 if (MONTHS
[i
].equals(monthText
))
213 pos
.setErrorIndex(end
);
217 start
= skipWhitespace(text
, end
+ 1);
219 end
= skipNonWhitespace(text
, start
+ 1);
220 date
= Integer
.parseInt(text
.substring(start
, end
));
222 start
= skipWhitespace(text
, end
+ 1);
224 end
= skipTo(text
, start
+ 1, ':');
225 hour
= Integer
.parseInt(text
.substring(start
, end
));
229 end
= skipTo(text
, start
+ 1, ':');
230 minute
= Integer
.parseInt(text
.substring(start
, end
));
234 end
= skipNonWhitespace(text
, start
+ 1);
235 second
= Integer
.parseInt(text
.substring(start
, end
));
237 start
= skipWhitespace(text
, end
+ 1);
239 end
= skipNonWhitespace(text
, start
+ 1);
240 year
= Integer
.parseInt(text
.substring(start
, end
));
245 start
= skipWhitespace(text
, start
);
247 end
= skipNonWhitespace(text
, start
+ 1);
248 date
= Integer
.parseInt(text
.substring(start
, end
));
250 start
= skipWhitespace(text
, end
+ 1);
252 end
= skipNonWhitespace(text
, start
+ 1);
253 monthText
= text
.substring(start
, end
);
255 for (int i
= 0; i
< 12; i
++)
257 if (MONTHS
[i
].equals(monthText
))
265 pos
.setErrorIndex(end
);
269 start
= skipWhitespace(text
, end
+ 1);
271 end
= skipNonWhitespace(text
, start
+ 1);
272 year
= Integer
.parseInt(text
.substring(start
, end
));
274 start
= skipWhitespace(text
, end
+ 1);
276 end
= skipTo(text
, start
+ 1, ':');
277 hour
= Integer
.parseInt(text
.substring(start
, end
));
281 end
= skipTo(text
, start
+ 1, ':');
282 minute
= Integer
.parseInt(text
.substring(start
, end
));
287 while (end
< len
&& !Character
.isWhitespace(text
.charAt(end
)))
291 second
= Integer
.parseInt(text
.substring(start
, end
));
295 start
= skipWhitespace(text
, start
);
297 end
= skipTo(text
, start
+ 1, '-');
298 date
= Integer
.parseInt(text
.substring(start
, end
));
302 end
= skipTo(text
, start
+ 1, '-');
303 monthText
= text
.substring(start
, end
);
305 for (int i
= 0; i
< 12; i
++)
307 if (MONTHS
[i
].equals(monthText
))
315 pos
.setErrorIndex(end
);
321 end
= skipNonWhitespace(text
, start
+ 1);
322 year
= 1900 + Integer
.parseInt(text
.substring(start
, end
));
324 start
= skipWhitespace(text
, end
+ 1);
326 end
= skipTo(text
, start
+ 1, ':');
327 hour
= Integer
.parseInt(text
.substring(start
, end
));
331 end
= skipTo(text
, start
+ 1, ':');
332 minute
= Integer
.parseInt(text
.substring(start
, end
));
337 while (end
< len
&& !Character
.isWhitespace(text
.charAt(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
);
354 start
= skipWhitespace(text
, end
+ 1);
356 while (end
< len
&& !Character
.isWhitespace(text
.charAt(end
)))
360 char pm
= text
.charAt(start
);
361 if (Character
.isLetter(pm
))
364 TimeZone
.getTimeZone(text
.substring(start
, end
));
365 calendar
.set(Calendar
.ZONE_OFFSET
, tz
.getRawOffset());
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
377 zoneOffset
= -zoneOffset
;
379 calendar
.set(Calendar
.ZONE_OFFSET
, zoneOffset
);
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
));
397 private int skipWhitespace(String text
, int pos
)
399 while(Character
.isWhitespace(text
.charAt(pos
)))
406 private int skipNonWhitespace(String text
, int pos
)
408 while(!Character
.isWhitespace(text
.charAt(pos
)))
415 private int skipTo(String text
, int pos
, char c
)
417 while(text
.charAt(pos
) != c
)
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();