001: /*
002: * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/util/DateUtil.java,v 1.2 2004/12/24 20:36:13 olegk Exp $
003: * $Revision: 480424 $
004: * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
005: *
006: * ====================================================================
007: *
008: * Licensed to the Apache Software Foundation (ASF) under one or more
009: * contributor license agreements. See the NOTICE file distributed with
010: * this work for additional information regarding copyright ownership.
011: * The ASF licenses this file to You under the Apache License, Version 2.0
012: * (the "License"); you may not use this file except in compliance with
013: * the License. You may obtain a copy of the License at
014: *
015: * http://www.apache.org/licenses/LICENSE-2.0
016: *
017: * Unless required by applicable law or agreed to in writing, software
018: * distributed under the License is distributed on an "AS IS" BASIS,
019: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
020: * See the License for the specific language governing permissions and
021: * limitations under the License.
022: * ====================================================================
023: *
024: * This software consists of voluntary contributions made by many
025: * individuals on behalf of the Apache Software Foundation. For more
026: * information on the Apache Software Foundation, please see
027: * <http://www.apache.org/>.
028: *
029: */
030:
031: package org.apache.commons.httpclient.util;
032:
033: import java.text.ParseException;
034: import java.text.SimpleDateFormat;
035: import java.util.Arrays;
036: import java.util.Calendar;
037: import java.util.Collection;
038: import java.util.Date;
039: import java.util.Iterator;
040: import java.util.Locale;
041: import java.util.TimeZone;
042:
043: /**
044: * A utility class for parsing and formatting HTTP dates as used in cookies and
045: * other headers. This class handles dates as defined by RFC 2616 section
046: * 3.3.1 as well as some other common non-standard formats.
047: *
048: * @author Christopher Brown
049: * @author Michael Becke
050: */
051: public class DateUtil {
052:
053: /**
054: * Date format pattern used to parse HTTP date headers in RFC 1123 format.
055: */
056: public static final String PATTERN_RFC1123 = "EEE, dd MMM yyyy HH:mm:ss zzz";
057:
058: /**
059: * Date format pattern used to parse HTTP date headers in RFC 1036 format.
060: */
061: public static final String PATTERN_RFC1036 = "EEEE, dd-MMM-yy HH:mm:ss zzz";
062:
063: /**
064: * Date format pattern used to parse HTTP date headers in ANSI C
065: * <code>asctime()</code> format.
066: */
067: public static final String PATTERN_ASCTIME = "EEE MMM d HH:mm:ss yyyy";
068:
069: private static final Collection DEFAULT_PATTERNS = Arrays
070: .asList(new String[] { PATTERN_ASCTIME, PATTERN_RFC1036,
071: PATTERN_RFC1123 });
072:
073: private static final Date DEFAULT_TWO_DIGIT_YEAR_START;
074:
075: static {
076: Calendar calendar = Calendar.getInstance();
077: calendar.set(2000, Calendar.JANUARY, 1, 0, 0);
078: DEFAULT_TWO_DIGIT_YEAR_START = calendar.getTime();
079: }
080:
081: private static final TimeZone GMT = TimeZone.getTimeZone("GMT");
082:
083: /**
084: * Parses a date value. The formats used for parsing the date value are retrieved from
085: * the default http params.
086: *
087: * @param dateValue the date value to parse
088: *
089: * @return the parsed date
090: *
091: * @throws DateParseException if the value could not be parsed using any of the
092: * supported date formats
093: */
094: public static Date parseDate(String dateValue)
095: throws DateParseException {
096: return parseDate(dateValue, null, null);
097: }
098:
099: /**
100: * Parses the date value using the given date formats.
101: *
102: * @param dateValue the date value to parse
103: * @param dateFormats the date formats to use
104: *
105: * @return the parsed date
106: *
107: * @throws DateParseException if none of the dataFormats could parse the dateValue
108: */
109: public static Date parseDate(String dateValue,
110: Collection dateFormats) throws DateParseException {
111: return parseDate(dateValue, dateFormats, null);
112: }
113:
114: /**
115: * Parses the date value using the given date formats.
116: *
117: * @param dateValue the date value to parse
118: * @param dateFormats the date formats to use
119: * @param startDate During parsing, two digit years will be placed in the range
120: * <code>startDate</code> to <code>startDate + 100 years</code>. This value may
121: * be <code>null</code>. When <code>null</code> is given as a parameter, year
122: * <code>2000</code> will be used.
123: *
124: * @return the parsed date
125: *
126: * @throws DateParseException if none of the dataFormats could parse the dateValue
127: */
128: public static Date parseDate(String dateValue,
129: Collection dateFormats, Date startDate)
130: throws DateParseException {
131:
132: if (dateValue == null) {
133: throw new IllegalArgumentException("dateValue is null");
134: }
135: if (dateFormats == null) {
136: dateFormats = DEFAULT_PATTERNS;
137: }
138: if (startDate == null) {
139: startDate = DEFAULT_TWO_DIGIT_YEAR_START;
140: }
141: // trim single quotes around date if present
142: // see issue #5279
143: if (dateValue.length() > 1 && dateValue.startsWith("'")
144: && dateValue.endsWith("'")) {
145: dateValue = dateValue.substring(1, dateValue.length() - 1);
146: }
147:
148: SimpleDateFormat dateParser = null;
149: Iterator formatIter = dateFormats.iterator();
150:
151: while (formatIter.hasNext()) {
152: String format = (String) formatIter.next();
153: if (dateParser == null) {
154: dateParser = new SimpleDateFormat(format, Locale.US);
155: dateParser.setTimeZone(TimeZone.getTimeZone("GMT"));
156: dateParser.set2DigitYearStart(startDate);
157: } else {
158: dateParser.applyPattern(format);
159: }
160: try {
161: return dateParser.parse(dateValue);
162: } catch (ParseException pe) {
163: // ignore this exception, we will try the next format
164: }
165: }
166:
167: // we were unable to parse the date
168: throw new DateParseException("Unable to parse the date "
169: + dateValue);
170: }
171:
172: /**
173: * Formats the given date according to the RFC 1123 pattern.
174: *
175: * @param date The date to format.
176: * @return An RFC 1123 formatted date string.
177: *
178: * @see #PATTERN_RFC1123
179: */
180: public static String formatDate(Date date) {
181: return formatDate(date, PATTERN_RFC1123);
182: }
183:
184: /**
185: * Formats the given date according to the specified pattern. The pattern
186: * must conform to that used by the {@link SimpleDateFormat simple date
187: * format} class.
188: *
189: * @param date The date to format.
190: * @param pattern The pattern to use for formatting the date.
191: * @return A formatted date string.
192: *
193: * @throws IllegalArgumentException If the given date pattern is invalid.
194: *
195: * @see SimpleDateFormat
196: */
197: public static String formatDate(Date date, String pattern) {
198: if (date == null)
199: throw new IllegalArgumentException("date is null");
200: if (pattern == null)
201: throw new IllegalArgumentException("pattern is null");
202:
203: SimpleDateFormat formatter = new SimpleDateFormat(pattern,
204: Locale.US);
205: formatter.setTimeZone(GMT);
206: return formatter.format(date);
207: }
208:
209: /** This class should not be instantiated. */
210: private DateUtil() {
211: }
212:
213: }
|