    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}