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