001: /*
002: * Copyright 2005-2007 Noelios Consulting.
003: *
004: * The contents of this file are subject to the terms of the Common Development
005: * and Distribution License (the "License"). You may not use this file except in
006: * compliance with the License.
007: *
008: * You can obtain a copy of the license at
009: * http://www.opensource.org/licenses/cddl1.txt See the License for the specific
010: * language governing permissions and limitations under the License.
011: *
012: * When distributing Covered Code, include this CDDL HEADER in each file and
013: * include the License file at http://www.opensource.org/licenses/cddl1.txt If
014: * applicable, add the following below this CDDL HEADER, with the fields
015: * enclosed by brackets "[]" replaced with your own identifying information:
016: * Portions Copyright [yyyy] [name of copyright owner]
017: */
018:
019: package org.restlet.util;
020:
021: import java.text.ParseException;
022: import java.text.SimpleDateFormat;
023: import java.util.Arrays;
024: import java.util.Collections;
025: import java.util.Date;
026: import java.util.List;
027: import java.util.Locale;
028: import java.util.TimeZone;
029: import java.util.WeakHashMap;
030:
031: /**
032: * Date manipulation utilities.
033: *
034: * @author Jerome Louvel (contact@noelios.com)
035: * @author Piyush Purang (ppurang@gmail.com)
036: */
037: public final class DateUtils {
038: /** Preferred HTTP date format (RFC 1123). */
039: public static final List<String> FORMAT_RFC_1123 = unmodifiableList("EEE, dd MMM yyyy HH:mm:ss zzz");
040:
041: /** Obsoleted HTTP date format (RFC 1036). */
042: public static final List<String> FORMAT_RFC_1036 = unmodifiableList("EEEE, dd-MMM-yy HH:mm:ss zzz");
043:
044: /** Obsoleted HTTP date format (ANSI C asctime() format). */
045: public static final List<String> FORMAT_ASC_TIME = unmodifiableList("EEE MMM dd HH:mm:ss yyyy");
046:
047: /** W3C date format (RFC 3339). */
048: public static final List<String> FORMAT_RFC_3339 = unmodifiableList(
049: "yyyy-MM-dd'T'HH:mm:ssz", "yyyy-MM-dd'T'HH:mmz",
050: "yyyy-MM-dd", "yyyy-MM", "yyyy");
051:
052: /** Common date format (RFC 822). */
053: public static final List<String> FORMAT_RFC_822 = unmodifiableList(
054: "EEE, dd MMM yy HH:mm:ss z", "EEE, dd MMM yy HH:mm z",
055: "dd MMM yy HH:mm:ss z", "dd MMM yy HH:mm z");
056:
057: /** Remember the often used GMT time zone. */
058: private static final TimeZone TIMEZONE_GMT = TimeZone
059: .getTimeZone("GMT");
060:
061: /**
062: * Compares two date with a precision of one second.
063: *
064: * @param baseDate
065: * The base date
066: * @param afterDate
067: * The date supposed to be after.
068: * @return True if the afterDate is indeed after the baseDate.
069: */
070: public static boolean after(final Date baseDate,
071: final Date afterDate) {
072: if ((baseDate == null) || (afterDate == null)) {
073: throw new IllegalArgumentException(
074: "Can't compare the dates, at least one of them is null");
075: } else {
076: long baseTime = baseDate.getTime() / 1000;
077: long afterTime = afterDate.getTime() / 1000;
078: return baseTime < afterTime;
079: }
080: }
081:
082: /**
083: * Compares two date with a precision of one second.
084: *
085: * @param baseDate
086: * The base date
087: * @param beforeDate
088: * The date supposed to be before.
089: * @return True if the beforeDate is indeed before the baseDate.
090: */
091: public static boolean before(final Date baseDate,
092: final Date beforeDate) {
093: if ((baseDate == null) || (beforeDate == null)) {
094: throw new IllegalArgumentException(
095: "Can't compare the dates, at least one of them is null");
096: } else {
097: long baseTime = baseDate.getTime() / 1000;
098: long beforeTime = beforeDate.getTime() / 1000;
099: return beforeTime < baseTime;
100: }
101: }
102:
103: /**
104: * Compares two date with a precision of one second.
105: *
106: * @param baseDate
107: * The base date
108: * @param otherDate
109: * The other date supposed to be equals.
110: * @return True if both dates are equals.
111: */
112: public static boolean equals(final Date baseDate,
113: final Date otherDate) {
114: if ((baseDate == null) || (otherDate == null)) {
115: throw new IllegalArgumentException(
116: "Can't compare the dates, at least one of them is null");
117: } else {
118: long baseTime = baseDate.getTime() / 1000;
119: long otherTime = otherDate.getTime() / 1000;
120: return otherTime == baseTime;
121: }
122: }
123:
124: /**
125: * Formats a Date according to the first format in the array.
126: *
127: * @param date
128: * The date to format.
129: * @param format
130: * The date format to use.
131: * @return The formatted date.
132: */
133: public static String format(final Date date, final String format) {
134: if (date == null) {
135: throw new IllegalArgumentException("Date is null");
136: } else {
137: SimpleDateFormat formatter = new SimpleDateFormat(format,
138: Locale.US);
139: formatter.setTimeZone(TIMEZONE_GMT);
140: return formatter.format(date);
141: }
142: }
143:
144: /**
145: * Parses a formatted date into a Date object.
146: *
147: * @param date
148: * The date to parse.
149: * @param formats
150: * The date formats to use sorted by completeness.
151: * @return The parsed date.
152: */
153: public static Date parse(final String date,
154: final List<String> formats) {
155: Date result = null;
156:
157: if (date == null) {
158: throw new IllegalArgumentException("Date is null");
159: } else {
160: String format = null;
161: final int formatsSize = formats.size();
162: for (int i = 0; (result == null) && (i < formatsSize); i++) {
163: format = formats.get(i);
164: SimpleDateFormat parser = new SimpleDateFormat(format,
165: Locale.US);
166: parser.setTimeZone(TIMEZONE_GMT);
167:
168: try {
169: result = parser.parse(date);
170: } catch (ParseException e) {
171: // Ignores error as the next format may work better
172: }
173: }
174: }
175:
176: return result;
177: }
178:
179: /**
180: * Helper method to help initialize this class by providing unmodifiable
181: * lists based on arrays.
182: *
183: * @param <T>
184: * Any valid java object
185: * @param array
186: * to be convereted into an unmodifiable list
187: * @return unmodifiable list based on the provided array
188: */
189: private static <T> List<T> unmodifiableList(final T... array) {
190: return Collections.unmodifiableList(Arrays.asList(array));
191: }
192:
193: /**
194: * Returns an immutable version of a given date.
195: *
196: * @param date
197: * The modifiable date.
198: * @return An immutable version of a given date.
199: */
200: public static Date unmodifiable(Date date) {
201: return (date == null) ? null : ImmutableDate.valueOf(date);
202: }
203:
204: /**
205: * Private constructor to ensure that the class acts as a true utility class
206: * i.e. it isn't instatiable and extensible.
207: */
208: private DateUtils() {
209:
210: }
211:
212: /**
213: * Class acting as an immutable date class based on the
214: * {@link java.util.Date} class.
215: *
216: * Throws {@link UnsupportedOperationException} when muttable methopds are
217: * invoked.
218: *
219: * @author Piyush Purang (ppurang@gmail.com)
220: * @see java.util.Date
221: * @see <a
222: * href="http://discuss.fogcreek.com/joelonsoftware3/default.asp?cmd=show&ixPost=73959&ixReplies=24">Immutable
223: * Date</a>
224: */
225: private static final class ImmutableDate extends Date {
226: // TODO Are we serializable?
227: private static final long serialVersionUID = -5946186780670229206L;
228:
229: private static final transient WeakHashMap<Date, ImmutableDate> CACHE = new WeakHashMap<Date, ImmutableDate>();
230:
231: /**
232: * Returns an ImmutableDate object wrapping the given date.
233: *
234: * @param date
235: * object to be made immutable
236: * @return an immutable date object
237: */
238: public static ImmutableDate valueOf(Date date) {
239: if (!CACHE.containsKey(date)) {
240: CACHE.put(date, new ImmutableDate(date));
241: }
242: return CACHE.get(date);
243: }
244:
245: /** Delegate being wrapped */
246: private final Date delegate;
247:
248: /**
249: * Private constructor. A factory method is provided.
250: *
251: * @param date
252: * date to be made immutable
253: */
254: private ImmutableDate(Date date) {
255: this .delegate = (Date) date.clone();
256: }
257:
258: /** {@inheritDoc} */
259: @Override
260: public boolean after(Date when) {
261: return delegate.after(when);
262: }
263:
264: /** {@inheritDoc} */
265: @Override
266: public boolean before(Date when) {
267: return delegate.before(when);
268: }
269:
270: /** {@inheritDoc} */
271: @Override
272: public Object clone() {
273: throw new UnsupportedOperationException(
274: "ImmutableDate is immutable");
275: }
276:
277: /** {@inheritDoc} */
278: @Override
279: public int compareTo(Date anotherDate) {
280: return delegate.compareTo(anotherDate);
281: }
282:
283: /** {@inheritDoc} */
284: @Override
285: public boolean equals(Object obj) {
286: return delegate.equals(obj);
287: }
288:
289: /** {@inheritDoc} */
290: @Override
291: public long getTime() {
292: return delegate.getTime();
293: }
294:
295: /** {@inheritDoc} */
296: @Override
297: public int hashCode() {
298: return delegate.hashCode();
299: }
300:
301: /** {@inheritDoc} */
302: @Override
303: public String toString() {
304: return delegate.toString();
305: }
306: }
307:
308: }
|