1 /*
2 * $HeadURL: https://svn.apache.org/repos/asf/jakarta/httpcomponents/httpcore/tags/4.0-alpha2/src/java/org/apache/http/util/DateUtils.java $
3 * $Revision: 376458 $
4 * $Date: 2006-02-09 23:22:06 +0100 (Thu, 09 Feb 2006) $
5 *
6 * ====================================================================
7 *
8 * Copyright 1999-2006 The Apache Software Foundation
9 *
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21 * ====================================================================
22 *
23 * This software consists of voluntary contributions made by many
24 * individuals on behalf of the Apache Software Foundation. For more
25 * information on the Apache Software Foundation, please see
26 * <http://www.apache.org/>.
27 *
28 */
29
30 package org.apache.http.util;
31
32 import java.text.ParseException;
33 import java.text.SimpleDateFormat;
34 import java.util.Calendar;
35 import java.util.Date;
36 import java.util.Locale;
37 import java.util.TimeZone;
38
39 /**
40 * A utility class for parsing and formatting HTTP dates as used in cookies and
41 * other headers. This class handles dates as defined by RFC 2616 section
42 * 3.3.1 as well as some other common non-standard formats.
43 *
44 * @author Christopher Brown
45 * @author Michael Becke
46 */
47 public class DateUtils {
48
49 /**
50 * Date format pattern used to parse HTTP date headers in RFC 1123 format.
51 */
52 public static final String PATTERN_RFC1123 = "EEE, dd MMM yyyy HH:mm:ss zzz";
53
54 /**
55 * Date format pattern used to parse HTTP date headers in RFC 1036 format.
56 */
57 public static final String PATTERN_RFC1036 = "EEEE, dd-MMM-yy HH:mm:ss zzz";
58
59 /**
60 * Date format pattern used to parse HTTP date headers in ANSI C
61 * <code>asctime()</code> format.
62 */
63 public static final String PATTERN_ASCTIME = "EEE MMM d HH:mm:ss yyyy";
64
65 private static final String[] DEFAULT_PATTERNS = new String[] {
66 PATTERN_ASCTIME,
67 PATTERN_RFC1036,
68 PATTERN_RFC1123 };
69
70 private static final Date DEFAULT_TWO_DIGIT_YEAR_START;
71
72 public static final TimeZone GMT = TimeZone.getTimeZone("GMT");
73
74 static {
75 Calendar calendar = Calendar.getInstance();
76 calendar.setTimeZone(GMT);
77 calendar.set(2000, Calendar.JANUARY, 1, 0, 0, 0);
78 calendar.set(Calendar.MILLISECOND, 0);
79 DEFAULT_TWO_DIGIT_YEAR_START = calendar.getTime();
80 }
81
82 /**
83 * Parses a date value. The formats used for parsing the date value are retrieved from
84 * the default http params.
85 *
86 * @param dateValue the date value to parse
87 *
88 * @return the parsed date
89 *
90 * @throws DateParseException if the value could not be parsed using any of the
91 * supported date formats
92 */
93 public static Date parseDate(String dateValue) throws DateParseException {
94 return parseDate(dateValue, null, null);
95 }
96
97 /**
98 * Parses the date value using the given date formats.
99 *
100 * @param dateValue the date value to parse
101 * @param dateFormats the date formats to use
102 *
103 * @return the parsed date
104 *
105 * @throws DateParseException if none of the dataFormats could parse the dateValue
106 */
107 public static Date parseDate(final String dateValue, String[] dateFormats)
108 throws DateParseException {
109 return parseDate(dateValue, dateFormats, null);
110 }
111
112 /**
113 * Parses the date value using the given date formats.
114 *
115 * @param dateValue the date value to parse
116 * @param dateFormats the date formats to use
117 * @param startDate During parsing, two digit years will be placed in the range
118 * <code>startDate</code> to <code>startDate + 100 years</code>. This value may
119 * be <code>null</code>. When <code>null</code> is given as a parameter, year
120 * <code>2000</code> will be used.
121 *
122 * @return the parsed date
123 *
124 * @throws DateParseException if none of the dataFormats could parse the dateValue
125 */
126 public static Date parseDate(
127 String dateValue,
128 String[] dateFormats,
129 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
144 && dateValue.startsWith("'")
145 && dateValue.endsWith("'")
146 ) {
147 dateValue = dateValue.substring (1, dateValue.length() - 1);
148 }
149
150 SimpleDateFormat dateParser = null;
151 for (int i = 0; i < dateFormats.length; i++) {
152 if (dateParser == null) {
153 dateParser = new SimpleDateFormat(dateFormats[i], Locale.US);
154 dateParser.setTimeZone(TimeZone.getTimeZone("GMT"));
155 dateParser.set2DigitYearStart(startDate);
156 } else {
157 dateParser.applyPattern(dateFormats[i]);
158 }
159 try {
160 return dateParser.parse(dateValue);
161 } catch (ParseException pe) {
162 // ignore this exception, we will try the next format
163 }
164 }
165
166 // we were unable to parse the date
167 throw new DateParseException("Unable to parse the date " + dateValue);
168 }
169
170 /**
171 * Formats the given date according to the RFC 1123 pattern.
172 *
173 * @param date The date to format.
174 * @return An RFC 1123 formatted date string.
175 *
176 * @see #PATTERN_RFC1123
177 */
178 public static String formatDate(Date date) {
179 return formatDate(date, PATTERN_RFC1123);
180 }
181
182 /**
183 * Formats the given date according to the specified pattern. The pattern
184 * must conform to that used by the {@link SimpleDateFormat simple date
185 * format} class.
186 *
187 * @param date The date to format.
188 * @param pattern The pattern to use for formatting the date.
189 * @return A formatted date string.
190 *
191 * @throws IllegalArgumentException If the given date pattern is invalid.
192 *
193 * @see SimpleDateFormat
194 */
195 public static String formatDate(Date date, String pattern) {
196 if (date == null) throw new IllegalArgumentException("date is null");
197 if (pattern == null) throw new IllegalArgumentException("pattern is null");
198
199 SimpleDateFormat formatter = new SimpleDateFormat(pattern, Locale.US);
200 formatter.setTimeZone(GMT);
201 return formatter.format(date);
202 }
203
204 /** This class should not be instantiated. */
205 private DateUtils() {
206 }
207
208 }