    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>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     * @deprecated TODO Make private in 4.0.
    413     */
    414    @Deprecated
    415    public DateFormatUtils() {
    416        // empty
    417    }
    418
    419}