001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.lang3.time;
018
019import java.util.Calendar;
020import java.util.Date;
021import java.util.Locale;
022import java.util.TimeZone;
023
024/**
025 * Date and time formatting utilities and constants.
026 *
027 * <p>Formatting is performed using the thread-safe
028 * {@link org.apache.commons.lang3.time.FastDateFormat} class.</p>
029 *
030 * <p>Note that the JDK has a bug wherein calling Calendar.get(int) will
031 * override any previously called Calendar.clear() calls. See LANG-755.</p>
032 *
033 * <p>Note that when using capital YYYY instead of lowercase yyyy, the formatter
034 * will assume current year as week year is not supported. See {@link java.util.GregorianCalendar}
035 * Week Year section for an explanation on the difference between calendar and week years.</p>
036 *
037 * @since 2.0
038 */
039public class DateFormatUtils {
040
041    /**
042     * The UTC time zone (often referred to as GMT).
043     * This is private as it is mutable.
044     */
045    private static final TimeZone UTC_TIME_ZONE = FastTimeZone.getGmtTimeZone();
046
047    /**
048     * ISO 8601 formatter for date-time without time zone.
049     *
050     * <p>
051     * The format used is {@code yyyy-MM-dd'T'HH:mm:ss}. This format uses the
052     * default TimeZone in effect at the time of loading DateFormatUtils class.
053     * </p>
054     *
055     * @since 3.5
056     */
057    public static final FastDateFormat ISO_8601_EXTENDED_DATETIME_FORMAT
058            = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss");
059
060    /**
061     * @deprecated - as of 4.0, ISO_DATETIME_FORMAT will be replaced by ISO_8601_EXTENDED_DATETIME_FORMAT.
062     */
063    @Deprecated
064    public static final FastDateFormat ISO_DATETIME_FORMAT = ISO_8601_EXTENDED_DATETIME_FORMAT;
065
066    /**
067     * ISO 8601 formatter for date-time with time zone.
068     *
069     * <p>
070     * The format used is {@code yyyy-MM-dd'T'HH:mm:ssZZ}. This format uses the
071     * default TimeZone in effect at the time of loading DateFormatUtils class.
072     * </p>
073     *
074     * @since 3.5
075     */
076    public static final FastDateFormat ISO_8601_EXTENDED_DATETIME_TIME_ZONE_FORMAT
077            = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ssZZ");
078
079    /**
080     * @deprecated - as of 4.0, ISO_DATETIME_TIME_ZONE_FORMAT will be replaced by ISO_8601_EXTENDED_DATETIME_TIME_ZONE_FORMAT.
081     */
082    @Deprecated
083    public static final FastDateFormat ISO_DATETIME_TIME_ZONE_FORMAT = ISO_8601_EXTENDED_DATETIME_TIME_ZONE_FORMAT;
084
085    /**
086     * ISO 8601 formatter for date without time zone.
087     *
088     * <p>
089     * The format used is {@code yyyy-MM-dd}. This format uses the
090     * default TimeZone in effect at the time of loading DateFormatUtils class.
091     * </p>
092     *
093     * @since 3.5
094     */
095    public static final FastDateFormat ISO_8601_EXTENDED_DATE_FORMAT
096            = FastDateFormat.getInstance("yyyy-MM-dd");
097
098    /**
099     * @deprecated - as of 4.0, ISO_DATE_FORMAT will be replaced by ISO_8601_EXTENDED_DATE_FORMAT.
100     */
101    @Deprecated
102    public static final FastDateFormat ISO_DATE_FORMAT = ISO_8601_EXTENDED_DATE_FORMAT;
103
104    /**
105     * ISO 8601-like formatter for date with time zone.
106     *
107     * <p>
108     * The format used is {@code yyyy-MM-ddZZ}. This pattern does not comply
109     * with the formal ISO 8601 specification as the standard does not allow
110     * a time zone  without a time. This format uses the default TimeZone in
111     * effect at the time of loading DateFormatUtils class.
112     * </p>
113     *
114     * @deprecated - as of 4.0, ISO_DATE_TIME_ZONE_FORMAT will be removed.
115     */
116    @Deprecated
117    public static final FastDateFormat ISO_DATE_TIME_ZONE_FORMAT
118            = FastDateFormat.getInstance("yyyy-MM-ddZZ");
119
120    /**
121     * Non-compliant formatter for time without time zone (ISO 8601 does not
122     * prefix 'T' for standalone time value).
123     *
124     * <p>
125     * The format used is {@code 'T'HH:mm:ss}. This format uses the default
126     * TimeZone in effect at the time of loading DateFormatUtils class.
127     * </p>
128     *
129     * @deprecated - as of 4.0, ISO_TIME_FORMAT will be removed.
130     */
131    @Deprecated
132    public static final FastDateFormat ISO_TIME_FORMAT
133            = FastDateFormat.getInstance("'T'HH:mm:ss");
134
135    /**
136     * Non-compliant formatter for time with time zone (ISO 8601 does not
137     * prefix 'T' for standalone time value).
138     *
139     * <p>
140     * The format used is {@code 'T'HH:mm:ssZZ}. This format uses the default
141     * TimeZone in effect at the time of loading DateFormatUtils class.
142     * </p>
143     *
144     * @deprecated - as of 4.0, ISO_TIME_TIME_ZONE_FORMAT will be removed.
145     */
146    @Deprecated
147    public static final FastDateFormat ISO_TIME_TIME_ZONE_FORMAT
148            = FastDateFormat.getInstance("'T'HH:mm:ssZZ");
149
150    /**
151     * ISO 8601 formatter for time without time zone.
152     *
153     * <p>
154     * The format used is {@code HH:mm:ss}. This format uses the default
155     * TimeZone in effect at the time of loading DateFormatUtils class.
156     * </p>
157     *
158     * @since 3.5
159     */
160    public static final FastDateFormat ISO_8601_EXTENDED_TIME_FORMAT
161            = FastDateFormat.getInstance("HH:mm:ss");
162
163    /**
164     * @deprecated - as of 4.0, ISO_TIME_NO_T_FORMAT will be replaced by ISO_8601_EXTENDED_TIME_FORMAT.
165     */
166    @Deprecated
167    public static final FastDateFormat ISO_TIME_NO_T_FORMAT = ISO_8601_EXTENDED_TIME_FORMAT;
168
169    /**
170     * ISO 8601 formatter for time with time zone.
171     *
172     * <p>
173     * The format used is {@code HH:mm:ssZZ}. This format uses the default
174     * TimeZone in effect at the time of loading DateFormatUtils class.
175     * </p>
176     *
177     * @since 3.5
178     */
179    public static final FastDateFormat ISO_8601_EXTENDED_TIME_TIME_ZONE_FORMAT
180            = FastDateFormat.getInstance("HH:mm:ssZZ");
181
182    /**
183     * @deprecated - as of 4.0, ISO_TIME_NO_T_TIME_ZONE_FORMAT will be replaced by ISO_8601_EXTENDED_TIME_TIME_ZONE_FORMAT.
184     */
185    @Deprecated
186    public static final FastDateFormat ISO_TIME_NO_T_TIME_ZONE_FORMAT = ISO_8601_EXTENDED_TIME_TIME_ZONE_FORMAT;
187
188    /**
189     * SMTP (and probably other) date headers.
190     *
191     * <p>
192     * The format used is {@code EEE, dd MMM yyyy HH:mm:ss Z} in US locale.
193     * This format uses the default TimeZone in effect at the time of loading
194     * DateFormatUtils class.
195     * </p>
196     */
197    public static final FastDateFormat SMTP_DATETIME_FORMAT
198            = FastDateFormat.getInstance("EEE, dd MMM yyyy HH:mm:ss Z", Locale.US);
199
200    /**
201     * Formats a calendar into a specific pattern. The TimeZone from the calendar
202     * will be used for formatting.
203     *
204     * @param calendar  the calendar to format, not null
205     * @param pattern  the pattern to use to format the calendar, not null
206     * @return the formatted calendar
207     * @see FastDateFormat#format(Calendar)
208     * @since 2.4
209     */
210    public static String format(final Calendar calendar, final String pattern) {
211        return format(calendar, pattern, getTimeZone(calendar), null);
212    }
213
214    /**
215     * Formats a calendar into a specific pattern in a locale. The TimeZone from the calendar
216     * will be used for formatting.
217     *
218     * @param calendar  the calendar to format, not null
219     * @param pattern  the pattern to use to format the calendar, not null
220     * @param locale  the locale to use, may be {@code null}
221     * @return the formatted calendar
222     * @see FastDateFormat#format(Calendar)
223     * @since 2.4
224     */
225    public static String format(final Calendar calendar, final String pattern, final Locale locale) {
226        return format(calendar, pattern, getTimeZone(calendar), locale);
227    }
228
229    /**
230     * Formats a calendar into a specific pattern in a time zone.
231     *
232     * @param calendar  the calendar to format, not null
233     * @param pattern  the pattern to use to format the calendar, not null
234     * @param timeZone  the time zone  to use, may be {@code null}
235     * @return the formatted calendar
236     * @see FastDateFormat#format(Calendar)
237     * @since 2.4
238     */
239    public static String format(final Calendar calendar, final String pattern, final TimeZone timeZone) {
240        return format(calendar, pattern, timeZone, null);
241    }
242
243    /**
244     * Formats a calendar into a specific pattern in a time zone and locale.
245     *
246     * @param calendar  the calendar to format, not null
247     * @param pattern  the pattern to use to format the calendar, not null
248     * @param timeZone  the time zone  to use, may be {@code null}
249     * @param locale  the locale to use, may be {@code null}
250     * @return the formatted calendar
251     * @see FastDateFormat#format(Calendar)
252     * @since 2.4
253     */
254    public static String format(final Calendar calendar, final String pattern, final TimeZone timeZone, final Locale locale) {
255        final FastDateFormat df = FastDateFormat.getInstance(pattern, timeZone, locale);
256        return df.format(calendar);
257    }
258
259    /**
260     * Formats a date/time into a specific pattern.
261     *
262     * @param date  the date to format, not null
263     * @param pattern  the pattern to use to format the date, not null
264     * @return the formatted date
265     */
266    public static String format(final Date date, final String pattern) {
267        return format(date, pattern, null, null);
268    }
269
270    /**
271     * Formats a date/time into a specific pattern in a locale.
272     *
273     * @param date  the date to format, not null
274     * @param pattern  the pattern to use to format the date, not null
275     * @param locale  the locale to use, may be {@code null}
276     * @return the formatted date
277     */
278    public static String format(final Date date, final String pattern, final Locale locale) {
279        return format(date, pattern, null, locale);
280    }
281
282    /**
283     * Formats a date/time into a specific pattern in a time zone.
284     *
285     * @param date  the date to format, not null
286     * @param pattern  the pattern to use to format the date, not null
287     * @param timeZone  the time zone  to use, may be {@code null}
288     * @return the formatted date
289     */
290    public static String format(final Date date, final String pattern, final TimeZone timeZone) {
291        return format(date, pattern, timeZone, null);
292    }
293
294    /**
295     * Formats a date/time into a specific pattern in a time zone and locale.
296     *
297     * @param date  the date to format, not null
298     * @param pattern  the pattern to use to format the date, not null, not null
299     * @param timeZone  the time zone  to use, may be {@code null}
300     * @param locale  the locale to use, may be {@code null}
301     * @return the formatted date
302     */
303    public static String format(final Date date, final String pattern, final TimeZone timeZone, final Locale locale) {
304        final FastDateFormat df = FastDateFormat.getInstance(pattern, timeZone, locale);
305        return df.format(date);
306    }
307
308    /**
309     * Formats a date/time into a specific pattern.
310     *
311     * @param millis  the date to format expressed in milliseconds
312     * @param pattern  the pattern to use to format the date, not null
313     * @return the formatted date
314     */
315    public static String format(final long millis, final String pattern) {
316        return format(new Date(millis), pattern, null, null);
317    }
318
319    /**
320     * Formats a date/time into a specific pattern in a locale.
321     *
322     * @param millis  the date to format expressed in milliseconds
323     * @param pattern  the pattern to use to format the date, not null
324     * @param locale  the locale to use, may be {@code null}
325     * @return the formatted date
326     */
327    public static String format(final long millis, final String pattern, final Locale locale) {
328        return format(new Date(millis), pattern, null, locale);
329    }
330
331    /**
332     * Formats a date/time into a specific pattern in a time zone.
333     *
334     * @param millis  the time expressed in milliseconds
335     * @param pattern  the pattern to use to format the date, not null
336     * @param timeZone  the time zone  to use, may be {@code null}
337     * @return the formatted date
338     */
339    public static String format(final long millis, final String pattern, final TimeZone timeZone) {
340        return format(new Date(millis), pattern, timeZone, null);
341    }
342
343    /**
344     * Formats a date/time into a specific pattern in a time zone and locale.
345     *
346     * @param millis  the date to format expressed in milliseconds
347     * @param pattern  the pattern to use to format the date, not null
348     * @param timeZone  the time zone  to use, may be {@code null}
349     * @param locale  the locale to use, may be {@code null}
350     * @return the formatted date
351     */
352    public static String format(final long millis, final String pattern, final TimeZone timeZone, final Locale locale) {
353        return format(new Date(millis), pattern, timeZone, locale);
354    }
355
356    /**
357     * Formats a date/time into a specific pattern using the UTC time zone.
358     *
359     * @param date  the date to format, not null
360     * @param pattern  the pattern to use to format the date, not null
361     * @return the formatted date
362     */
363    public static String formatUTC(final Date date, final String pattern) {
364        return format(date, pattern, UTC_TIME_ZONE, null);
365    }
366
367    /**
368     * Formats a date/time into a specific pattern using the UTC time zone.
369     *
370     * @param date  the date to format, not null
371     * @param pattern  the pattern to use to format the date, not null
372     * @param locale  the locale to use, may be {@code null}
373     * @return the formatted date
374     */
375    public static String formatUTC(final Date date, final String pattern, final Locale locale) {
376        return format(date, pattern, UTC_TIME_ZONE, locale);
377    }
378
379    /**
380     * Formats a date/time into a specific pattern using the UTC time zone.
381     *
382     * @param millis  the date to format expressed in milliseconds
383     * @param pattern  the pattern to use to format the date, not null
384     * @return the formatted date
385     */
386    public static String formatUTC(final long millis, final String pattern) {
387        return format(new Date(millis), pattern, UTC_TIME_ZONE, null);
388    }
389
390    /**
391     * Formats a date/time into a specific pattern using the UTC time zone.
392     *
393     * @param millis  the date to format expressed in milliseconds
394     * @param pattern  the pattern to use to format the date, not null
395     * @param locale  the locale to use, may be {@code null}
396     * @return the formatted date
397     */
398    public static String formatUTC(final long millis, final String pattern, final Locale locale) {
399        return format(new Date(millis), pattern, UTC_TIME_ZONE, locale);
400    }
401
402    private static TimeZone getTimeZone(final Calendar calendar) {
403        return calendar == null ? null : calendar.getTimeZone();
404    }
405
406    /**
407     * DateFormatUtils instances should NOT be constructed in standard programming.
408     *
409     * <p>This constructor is public to permit tools that require a JavaBean instance
410     * to operate.</p>
411     */
412    public DateFormatUtils() {
413    }
414
415}