1069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project/*
2069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/cookie/DateUtils.java $
3069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * $Revision: 677240 $
4069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * $Date: 2008-07-16 04:25:47 -0700 (Wed, 16 Jul 2008) $
5069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *
6069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * ====================================================================
7069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Licensed to the Apache Software Foundation (ASF) under one
8069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * or more contributor license agreements.  See the NOTICE file
9069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * distributed with this work for additional information
10069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * regarding copyright ownership.  The ASF licenses this file
11069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * to you under the Apache License, Version 2.0 (the
12069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * "License"); you may not use this file except in compliance
13069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * with the License.  You may obtain a copy of the License at
14069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *
15069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *   http://www.apache.org/licenses/LICENSE-2.0
16069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *
17069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Unless required by applicable law or agreed to in writing,
18069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * software distributed under the License is distributed on an
19069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * KIND, either express or implied.  See the License for the
21069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * specific language governing permissions and limitations
22069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * under the License.
23069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * ====================================================================
24069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *
25069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * This software consists of voluntary contributions made by many
26069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * individuals on behalf of the Apache Software Foundation.  For more
27069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * information on the Apache Software Foundation, please see
28069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * <http://www.apache.org/>.
29069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *
30069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */
31069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
32069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectpackage org.apache.http.impl.cookie;
33069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
34069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport java.lang.ref.SoftReference;
35069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport java.text.ParseException;
36069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport java.text.SimpleDateFormat;
37069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport java.util.Calendar;
38069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport java.util.Date;
39069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport java.util.HashMap;
40069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport java.util.Locale;
41069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport java.util.Map;
42069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectimport java.util.TimeZone;
43069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
44069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project/**
45069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * A utility class for parsing and formatting HTTP dates as used in cookies and
46069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * other headers.  This class handles dates as defined by RFC 2616 section
47069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * 3.3.1 as well as some other common non-standard formats.
48069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project *
49069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @author Christopher Brown
50069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * @author Michael Becke
51069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */
52069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectpublic final class DateUtils {
53069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
54069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
55069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Date format pattern used to parse HTTP date headers in RFC 1123 format.
56069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
57069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public static final String PATTERN_RFC1123 = "EEE, dd MMM yyyy HH:mm:ss zzz";
58069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
59069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
60069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Date format pattern used to parse HTTP date headers in RFC 1036 format.
61069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
62069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public static final String PATTERN_RFC1036 = "EEEE, dd-MMM-yy HH:mm:ss zzz";
63069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
64069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
65069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Date format pattern used to parse HTTP date headers in ANSI C
66069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * <code>asctime()</code> format.
67069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
68069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public static final String PATTERN_ASCTIME = "EEE MMM d HH:mm:ss yyyy";
69069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
70069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    private static final String[] DEFAULT_PATTERNS = new String[] {
71069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    	PATTERN_RFC1036,
72069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    	PATTERN_RFC1123,
73069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        PATTERN_ASCTIME
74069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    };
75069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
76069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    private static final Date DEFAULT_TWO_DIGIT_YEAR_START;
77069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
78069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public static final TimeZone GMT = TimeZone.getTimeZone("GMT");
79069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
80069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    static {
81069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        Calendar calendar = Calendar.getInstance();
82069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        calendar.setTimeZone(GMT);
83069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        calendar.set(2000, Calendar.JANUARY, 1, 0, 0, 0);
84069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        calendar.set(Calendar.MILLISECOND, 0);
85069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        DEFAULT_TWO_DIGIT_YEAR_START = calendar.getTime();
86069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
87069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
88069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
89069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Parses a date value.  The formats used for parsing the date value are retrieved from
90069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * the default http params.
91069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
92069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param dateValue the date value to parse
93069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
94069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @return the parsed date
95069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
96069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @throws DateParseException if the value could not be parsed using any of the
97069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * supported date formats
98069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
99069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public static Date parseDate(String dateValue) throws DateParseException {
100069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return parseDate(dateValue, null, null);
101069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
102069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
103069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
104069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Parses the date value using the given date formats.
105069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
106069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param dateValue the date value to parse
107069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param dateFormats the date formats to use
108069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
109069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @return the parsed date
110069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
111069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @throws DateParseException if none of the dataFormats could parse the dateValue
112069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
113069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public static Date parseDate(final String dateValue, String[] dateFormats)
114069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        throws DateParseException {
115069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return parseDate(dateValue, dateFormats, null);
116069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
117069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
118069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
119069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Parses the date value using the given date formats.
120069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
121069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param dateValue the date value to parse
122069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param dateFormats the date formats to use
123069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param startDate During parsing, two digit years will be placed in the range
124069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * <code>startDate</code> to <code>startDate + 100 years</code>. This value may
125069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * be <code>null</code>. When <code>null</code> is given as a parameter, year
126069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * <code>2000</code> will be used.
127069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
128069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @return the parsed date
129069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
130069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @throws DateParseException if none of the dataFormats could parse the dateValue
131069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
132069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public static Date parseDate(
133069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        String dateValue,
134069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        String[] dateFormats,
135069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        Date startDate
136069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    ) throws DateParseException {
137069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
138069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (dateValue == null) {
139069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            throw new IllegalArgumentException("dateValue is null");
140069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
141069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (dateFormats == null) {
142069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            dateFormats = DEFAULT_PATTERNS;
143069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
144069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (startDate == null) {
145069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            startDate = DEFAULT_TWO_DIGIT_YEAR_START;
146069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
147069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        // trim single quotes around date if present
148069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        // see issue #5279
149069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (dateValue.length() > 1
150069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            && dateValue.startsWith("'")
151069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            && dateValue.endsWith("'")
152069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        ) {
153069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            dateValue = dateValue.substring (1, dateValue.length() - 1);
154069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
155069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
156069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        for (String dateFormat : dateFormats) {
157069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            SimpleDateFormat dateParser = DateFormatHolder.formatFor(dateFormat);
158069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            dateParser.set2DigitYearStart(startDate);
159069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
160069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            try {
161069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                return dateParser.parse(dateValue);
162069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            } catch (ParseException pe) {
163069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                // ignore this exception, we will try the next format
164069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            }
165069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
166069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
167069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        // we were unable to parse the date
168069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        throw new DateParseException("Unable to parse the date " + dateValue);
169069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
170069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
171069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
172069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Formats the given date according to the RFC 1123 pattern.
173069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
174069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param date The date to format.
175069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @return An RFC 1123 formatted date string.
176069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
177069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @see #PATTERN_RFC1123
178069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
179069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public static String formatDate(Date date) {
180069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return formatDate(date, PATTERN_RFC1123);
181069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
182069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
183069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
184069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * Formats the given date according to the specified pattern.  The pattern
185069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * must conform to that used by the {@link SimpleDateFormat simple date
186069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * format} class.
187069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
188069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param date The date to format.
189069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @param pattern The pattern to use for formatting the date.
190069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @return A formatted date string.
191069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
192069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @throws IllegalArgumentException If the given date pattern is invalid.
193069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
194069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @see SimpleDateFormat
195069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
196069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    public static String formatDate(Date date, String pattern) {
197069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (date == null) throw new IllegalArgumentException("date is null");
198069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        if (pattern == null) throw new IllegalArgumentException("pattern is null");
199069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
200069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        SimpleDateFormat formatter = DateFormatHolder.formatFor(pattern);
201069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        return formatter.format(date);
202069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
203069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
204069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /** This class should not be instantiated. */
205069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    private DateUtils() {
206069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
207069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
208069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    /**
209069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * A factory for {@link SimpleDateFormat}s. The instances are stored in a
210069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * threadlocal way because SimpleDateFormat is not threadsafe as noted in
211069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * {@link SimpleDateFormat its javadoc}.
212069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     *
213069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     * @author Daniel Mueller
214069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project     */
215069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    final static class DateFormatHolder {
216069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
217069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        private static final ThreadLocal<SoftReference<Map<String, SimpleDateFormat>>>
218069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            THREADLOCAL_FORMATS = new ThreadLocal<SoftReference<Map<String, SimpleDateFormat>>>() {
219069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
220069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            @Override
221069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            protected SoftReference<Map<String, SimpleDateFormat>> initialValue() {
222069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                return new SoftReference<Map<String, SimpleDateFormat>>(
223069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        new HashMap<String, SimpleDateFormat>());
224069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            }
225069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
226069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        };
227069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
228069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        /**
229069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project         * creates a {@link SimpleDateFormat} for the requested format string.
230069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project         *
231069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project         * @param pattern
232069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project         *            a non-<code>null</code> format String according to
233069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project         *            {@link SimpleDateFormat}. The format is not checked against
234069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project         *            <code>null</code> since all paths go through
235069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project         *            {@link DateUtils}.
236069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project         * @return the requested format. This simple dateformat should not be used
237069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project         *         to {@link SimpleDateFormat#applyPattern(String) apply} to a
238069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project         *         different pattern.
239069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project         */
240069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        public static SimpleDateFormat formatFor(String pattern) {
241069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            SoftReference<Map<String, SimpleDateFormat>> ref = THREADLOCAL_FORMATS.get();
242069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            Map<String, SimpleDateFormat> formats = ref.get();
243069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            if (formats == null) {
244069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                formats = new HashMap<String, SimpleDateFormat>();
245069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                THREADLOCAL_FORMATS.set(
246069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                        new SoftReference<Map<String, SimpleDateFormat>>(formats));
247069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            }
248069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
249069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            SimpleDateFormat format = formats.get(pattern);
250069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            if (format == null) {
251069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                format = new SimpleDateFormat(pattern, Locale.US);
252069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                format.setTimeZone(TimeZone.getTimeZone("GMT"));
253069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project                formats.put(pattern, format);
254069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            }
255069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
256069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project            return format;
257069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project        }
258069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
259069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project    }
260069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project
261069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project}
262