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     * DateFormatUtils instances should NOT be constructed in standard programming.
202     *
203     * <p>This constructor is public to permit tools that require a JavaBean instance
204     * to operate.</p>
205     */
206    public DateFormatUtils() {
207    }
208
209    /**
210     * Formats a calendar into a specific pattern. The TimeZone from the calendar
211     * will be used for formatting.
212     *
213     * @param calendar  the calendar to format, not null
214     * @param pattern  the pattern to use to format the calendar, not null
215     * @return the formatted calendar
216     * @see FastDateFormat#format(Calendar)
217     * @since 2.4
218     */
219    public static String format(final Calendar calendar, final String pattern) {
220        return format(calendar, pattern, getTimeZone(calendar), null);
221    }
222
223    /**
224     * Formats a calendar into a specific pattern in a locale. The TimeZone from the calendar
225     * will be used for formatting.
226     *
227     * @param calendar  the calendar to format, not null
228     * @param pattern  the pattern to use to format the calendar, not null
229     * @param locale  the locale to use, may be {@code null}
230     * @return the formatted calendar
231     * @see FastDateFormat#format(Calendar)
232     * @since 2.4
233     */
234    public static String format(final Calendar calendar, final String pattern, final Locale locale) {
235        return format(calendar, pattern, getTimeZone(calendar), locale);
236    }
237
238    /**
239     * Formats a calendar into a specific pattern in a time zone.
240     *
241     * @param calendar  the calendar to format, not null
242     * @param pattern  the pattern to use to format the calendar, not null
243     * @param timeZone  the time zone  to use, may be {@code null}
244     * @return the formatted calendar
245     * @see FastDateFormat#format(Calendar)
246     * @since 2.4
247     */
248    public static String format(final Calendar calendar, final String pattern, final TimeZone timeZone) {
249        return format(calendar, pattern, timeZone, null);
250    }
251
252    /**
253     * Formats a calendar into a specific pattern in a time zone and locale.
254     *
255     * @param calendar  the calendar to format, not null
256     * @param pattern  the pattern to use to format the calendar, not null
257     * @param timeZone  the time zone  to use, may be {@code null}
258     * @param locale  the locale to use, may be {@code null}
259     * @return the formatted calendar
260     * @see FastDateFormat#format(Calendar)
261     * @since 2.4
262     */
263    public static String format(final Calendar calendar, final String pattern, final TimeZone timeZone, final Locale locale) {
264        final FastDateFormat df = FastDateFormat.getInstance(pattern, timeZone, locale);
265        return df.format(calendar);
266    }
267
268    /**
269     * Formats a date/time into a specific pattern.
270     *
271     * @param date  the date to format, not null
272     * @param pattern  the pattern to use to format the date, not null
273     * @return the formatted date
274     */
275    public static String format(final Date date, final String pattern) {
276        return format(date, pattern, null, null);
277    }
278
279    /**
280     * Formats a date/time into a specific pattern in a locale.
281     *
282     * @param date  the date to format, not null
283     * @param pattern  the pattern to use to format the date, not null
284     * @param locale  the locale to use, may be {@code null}
285     * @return the formatted date
286     */
287    public static String format(final Date date, final String pattern, final Locale locale) {
288        return format(date, pattern, null, locale);
289    }
290
291    /**
292     * Formats a date/time into a specific pattern in a time zone.
293     *
294     * @param date  the date to format, not null
295     * @param pattern  the pattern to use to format the date, not null
296     * @param timeZone  the time zone  to use, may be {@code null}
297     * @return the formatted date
298     */
299    public static String format(final Date date, final String pattern, final TimeZone timeZone) {
300        return format(date, pattern, timeZone, null);
301    }
302
303    /**
304     * Formats a date/time into a specific pattern in a time zone and locale.
305     *
306     * @param date  the date to format, not null
307     * @param pattern  the pattern to use to format the date, not null, not null
308     * @param timeZone  the time zone  to use, may be {@code null}
309     * @param locale  the locale to use, may be {@code null}
310     * @return the formatted date
311     */
312    public static String format(final Date date, final String pattern, final TimeZone timeZone, final Locale locale) {
313        final FastDateFormat df = FastDateFormat.getInstance(pattern, timeZone, locale);
314        return df.format(date);
315    }
316
317    /**
318     * Formats a date/time into a specific pattern.
319     *
320     * @param millis  the date to format expressed in milliseconds
321     * @param pattern  the pattern to use to format the date, not null
322     * @return the formatted date
323     */
324    public static String format(final long millis, final String pattern) {
325        return format(new Date(millis), pattern, null, null);
326    }
327
328    /**
329     * Formats a date/time into a specific pattern in a locale.
330     *
331     * @param millis  the date to format expressed in milliseconds
332     * @param pattern  the pattern to use to format the date, not null
333     * @param locale  the locale to use, may be {@code null}
334     * @return the formatted date
335     */
336    public static String format(final long millis, final String pattern, final Locale locale) {
337        return format(new Date(millis), pattern, null, locale);
338    }
339
340    /**
341     * Formats a date/time into a specific pattern in a time zone.
342     *
343     * @param millis  the time expressed in milliseconds
344     * @param pattern  the pattern to use to format the date, not null
345     * @param timeZone  the time zone  to use, may be {@code null}
346     * @return the formatted date
347     */
348    public static String format(final long millis, final String pattern, final TimeZone timeZone) {
349        return format(new Date(millis), pattern, timeZone, null);
350    }
351
352    /**
353     * Formats a date/time into a specific pattern in a time zone and locale.
354     *
355     * @param millis  the date to format expressed in milliseconds
356     * @param pattern  the pattern to use to format the date, not null
357     * @param timeZone  the time zone  to use, may be {@code null}
358     * @param locale  the locale to use, may be {@code null}
359     * @return the formatted date
360     */
361    public static String format(final long millis, final String pattern, final TimeZone timeZone, final Locale locale) {
362        return format(new Date(millis), pattern, timeZone, locale);
363    }
364
365    /**
366     * Formats a date/time into a specific pattern using the UTC time zone.
367     *
368     * @param date  the date to format, not null
369     * @param pattern  the pattern to use to format the date, not null
370     * @return the formatted date
371     */
372    public static String formatUTC(final Date date, final String pattern) {
373        return format(date, pattern, UTC_TIME_ZONE, null);
374    }
375
376    /**
377     * Formats a date/time into a specific pattern using the UTC time zone.
378     *
379     * @param date  the date to format, not null
380     * @param pattern  the pattern to use to format the date, not null
381     * @param locale  the locale to use, may be {@code null}
382     * @return the formatted date
383     */
384    public static String formatUTC(final Date date, final String pattern, final Locale locale) {
385        return format(date, pattern, UTC_TIME_ZONE, locale);
386    }
387
388    /**
389     * Formats a date/time into a specific pattern using the UTC time zone.
390     *
391     * @param millis  the date to format expressed in milliseconds
392     * @param pattern  the pattern to use to format the date, not null
393     * @return the formatted date
394     */
395    public static String formatUTC(final long millis, final String pattern) {
396        return format(new Date(millis), pattern, UTC_TIME_ZONE, null);
397    }
398
399    /**
400     * Formats a date/time into a specific pattern using the UTC time zone.
401     *
402     * @param millis  the date to format expressed in milliseconds
403     * @param pattern  the pattern to use to format the date, not null
404     * @param locale  the locale to use, may be {@code null}
405     * @return the formatted date
406     */
407    public static String formatUTC(final long millis, final String pattern, final Locale locale) {
408        return format(new Date(millis), pattern, UTC_TIME_ZONE, locale);
409    }
410
411    private static TimeZone getTimeZone(final Calendar calendar) {
412        return calendar == null ? null : calendar.getTimeZone();
413    }
414
415}