mirror of
https://github.com/Eaglercraft-Archive/Eaglercraftx-1.8.8-src.git
synced 2025-06-28 10:58:15 -05:00
Update #0 - First Release
This commit is contained in:
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.commons.lang3.time;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Helps use {@link Calendar}s.
|
||||
*
|
||||
* @since 3.10
|
||||
*/
|
||||
public class CalendarUtils {
|
||||
|
||||
/**
|
||||
* The singleton instance for {@link Calendar#getInstance()}.
|
||||
*/
|
||||
public static final CalendarUtils INSTANCE = new CalendarUtils(Calendar.getInstance());
|
||||
|
||||
private final Calendar calendar;
|
||||
|
||||
/**
|
||||
* Creates an instance for the given Calendar.
|
||||
*
|
||||
* @param calendar A Calendar.
|
||||
*/
|
||||
public CalendarUtils(final Calendar calendar) {
|
||||
this.calendar = Objects.requireNonNull(calendar, "calendar");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current day of month.
|
||||
*
|
||||
* @return the current day of month.
|
||||
*/
|
||||
public int getDayOfMonth() {
|
||||
return calendar.get(Calendar.DAY_OF_MONTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current month.
|
||||
*
|
||||
* @return the current month.
|
||||
*/
|
||||
public int getMonth() {
|
||||
return calendar.get(Calendar.MONTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current year.
|
||||
*
|
||||
* @return the current year.
|
||||
*/
|
||||
public int getYear() {
|
||||
return calendar.get(Calendar.YEAR);
|
||||
}
|
||||
}
|
@ -0,0 +1,449 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.commons.lang3.time;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Date and time formatting utilities and constants.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Formatting is performed using the thread-safe
|
||||
* {@link org.apache.commons.lang3.time.FastDateFormat} class.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Note that the JDK has a bug wherein calling Calendar.get(int) will override
|
||||
* any previously called Calendar.clear() calls. See LANG-755.
|
||||
* </p>
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public class DateFormatUtils {
|
||||
|
||||
/**
|
||||
* The UTC time zone (often referred to as GMT). This is private as it is
|
||||
* mutable.
|
||||
*/
|
||||
private static final TimeZone UTC_TIME_ZONE = FastTimeZone.getGmtTimeZone();
|
||||
|
||||
/**
|
||||
* ISO 8601 formatter for date-time without time zone.
|
||||
*
|
||||
* <p>
|
||||
* The format used is {@code yyyy-MM-dd'T'HH:mm:ss}. This format uses the
|
||||
* default TimeZone in effect at the time of loading DateFormatUtils class.
|
||||
* </p>
|
||||
*
|
||||
* @since 3.5
|
||||
*/
|
||||
public static final FastDateFormat ISO_8601_EXTENDED_DATETIME_FORMAT = FastDateFormat
|
||||
.getInstance("yyyy-MM-dd'T'HH:mm:ss");
|
||||
|
||||
/**
|
||||
* @deprecated - as of 4.0, ISO_DATETIME_FORMAT will be replaced by
|
||||
* ISO_8601_EXTENDED_DATETIME_FORMAT.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final FastDateFormat ISO_DATETIME_FORMAT = ISO_8601_EXTENDED_DATETIME_FORMAT;
|
||||
|
||||
/**
|
||||
* ISO 8601 formatter for date-time with time zone.
|
||||
*
|
||||
* <p>
|
||||
* The format used is {@code yyyy-MM-dd'T'HH:mm:ssZZ}. This format uses the
|
||||
* default TimeZone in effect at the time of loading DateFormatUtils class.
|
||||
* </p>
|
||||
*
|
||||
* @since 3.5
|
||||
*/
|
||||
public static final FastDateFormat ISO_8601_EXTENDED_DATETIME_TIME_ZONE_FORMAT = FastDateFormat
|
||||
.getInstance("yyyy-MM-dd'T'HH:mm:ssZZ");
|
||||
|
||||
/**
|
||||
* @deprecated - as of 4.0, ISO_DATETIME_TIME_ZONE_FORMAT will be replaced by
|
||||
* ISO_8601_EXTENDED_DATETIME_TIME_ZONE_FORMAT.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final FastDateFormat ISO_DATETIME_TIME_ZONE_FORMAT = ISO_8601_EXTENDED_DATETIME_TIME_ZONE_FORMAT;
|
||||
|
||||
/**
|
||||
* ISO 8601 formatter for date without time zone.
|
||||
*
|
||||
* <p>
|
||||
* The format used is {@code yyyy-MM-dd}. This format uses the default TimeZone
|
||||
* in effect at the time of loading DateFormatUtils class.
|
||||
* </p>
|
||||
*
|
||||
* @since 3.5
|
||||
*/
|
||||
public static final FastDateFormat ISO_8601_EXTENDED_DATE_FORMAT = FastDateFormat.getInstance("yyyy-MM-dd");
|
||||
|
||||
/**
|
||||
* @deprecated - as of 4.0, ISO_DATE_FORMAT will be replaced by
|
||||
* ISO_8601_EXTENDED_DATE_FORMAT.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final FastDateFormat ISO_DATE_FORMAT = ISO_8601_EXTENDED_DATE_FORMAT;
|
||||
|
||||
/**
|
||||
* ISO 8601-like formatter for date with time zone.
|
||||
*
|
||||
* <p>
|
||||
* The format used is {@code yyyy-MM-ddZZ}. This pattern does not comply with
|
||||
* the formal ISO 8601 specification as the standard does not allow a time zone
|
||||
* without a time. This format uses the default TimeZone in effect at the time
|
||||
* of loading DateFormatUtils class.
|
||||
* </p>
|
||||
*
|
||||
* @deprecated - as of 4.0, ISO_DATE_TIME_ZONE_FORMAT will be removed.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final FastDateFormat ISO_DATE_TIME_ZONE_FORMAT = FastDateFormat.getInstance("yyyy-MM-ddZZ");
|
||||
|
||||
/**
|
||||
* Non-compliant formatter for time without time zone (ISO 8601 does not prefix
|
||||
* 'T' for standalone time value).
|
||||
*
|
||||
* <p>
|
||||
* The format used is {@code 'T'HH:mm:ss}. This format uses the default TimeZone
|
||||
* in effect at the time of loading DateFormatUtils class.
|
||||
* </p>
|
||||
*
|
||||
* @deprecated - as of 4.0, ISO_TIME_FORMAT will be removed.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final FastDateFormat ISO_TIME_FORMAT = FastDateFormat.getInstance("'T'HH:mm:ss");
|
||||
|
||||
/**
|
||||
* Non-compliant formatter for time with time zone (ISO 8601 does not prefix 'T'
|
||||
* for standalone time value).
|
||||
*
|
||||
* <p>
|
||||
* The format used is {@code 'T'HH:mm:ssZZ}. This format uses the default
|
||||
* TimeZone in effect at the time of loading DateFormatUtils class.
|
||||
* </p>
|
||||
*
|
||||
* @deprecated - as of 4.0, ISO_TIME_TIME_ZONE_FORMAT will be removed.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final FastDateFormat ISO_TIME_TIME_ZONE_FORMAT = FastDateFormat.getInstance("'T'HH:mm:ssZZ");
|
||||
|
||||
/**
|
||||
* ISO 8601 formatter for time without time zone.
|
||||
*
|
||||
* <p>
|
||||
* The format used is {@code HH:mm:ss}. This format uses the default TimeZone in
|
||||
* effect at the time of loading DateFormatUtils class.
|
||||
* </p>
|
||||
*
|
||||
* @since 3.5
|
||||
*/
|
||||
public static final FastDateFormat ISO_8601_EXTENDED_TIME_FORMAT = FastDateFormat.getInstance("HH:mm:ss");
|
||||
|
||||
/**
|
||||
* @deprecated - as of 4.0, ISO_TIME_NO_T_FORMAT will be replaced by
|
||||
* ISO_8601_EXTENDED_TIME_FORMAT.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final FastDateFormat ISO_TIME_NO_T_FORMAT = ISO_8601_EXTENDED_TIME_FORMAT;
|
||||
|
||||
/**
|
||||
* ISO 8601 formatter for time with time zone.
|
||||
*
|
||||
* <p>
|
||||
* The format used is {@code HH:mm:ssZZ}. This format uses the default TimeZone
|
||||
* in effect at the time of loading DateFormatUtils class.
|
||||
* </p>
|
||||
*
|
||||
* @since 3.5
|
||||
*/
|
||||
public static final FastDateFormat ISO_8601_EXTENDED_TIME_TIME_ZONE_FORMAT = FastDateFormat
|
||||
.getInstance("HH:mm:ssZZ");
|
||||
|
||||
/**
|
||||
* @deprecated - as of 4.0, ISO_TIME_NO_T_TIME_ZONE_FORMAT will be replaced by
|
||||
* ISO_8601_EXTENDED_TIME_TIME_ZONE_FORMAT.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final FastDateFormat ISO_TIME_NO_T_TIME_ZONE_FORMAT = ISO_8601_EXTENDED_TIME_TIME_ZONE_FORMAT;
|
||||
|
||||
/**
|
||||
* SMTP (and probably other) date headers.
|
||||
*
|
||||
* <p>
|
||||
* The format used is {@code EEE, dd MMM yyyy HH:mm:ss Z} in US locale. This
|
||||
* format uses the default TimeZone in effect at the time of loading
|
||||
* DateFormatUtils class.
|
||||
* </p>
|
||||
*/
|
||||
public static final FastDateFormat SMTP_DATETIME_FORMAT = FastDateFormat.getInstance("EEE, dd MMM yyyy HH:mm:ss Z",
|
||||
Locale.US);
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* <p>
|
||||
* DateFormatUtils instances should NOT be constructed in standard programming.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This constructor is public to permit tools that require a JavaBean instance
|
||||
* to operate.
|
||||
* </p>
|
||||
*/
|
||||
public DateFormatUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats a date/time into a specific pattern using the UTC time zone.
|
||||
* </p>
|
||||
*
|
||||
* @param millis the date to format expressed in milliseconds
|
||||
* @param pattern the pattern to use to format the date, not null
|
||||
* @return the formatted date
|
||||
*/
|
||||
public static String formatUTC(final long millis, final String pattern) {
|
||||
return format(new Date(millis), pattern, UTC_TIME_ZONE, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats a date/time into a specific pattern using the UTC time zone.
|
||||
* </p>
|
||||
*
|
||||
* @param date the date to format, not null
|
||||
* @param pattern the pattern to use to format the date, not null
|
||||
* @return the formatted date
|
||||
*/
|
||||
public static String formatUTC(final Date date, final String pattern) {
|
||||
return format(date, pattern, UTC_TIME_ZONE, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats a date/time into a specific pattern using the UTC time zone.
|
||||
* </p>
|
||||
*
|
||||
* @param millis the date to format expressed in milliseconds
|
||||
* @param pattern the pattern to use to format the date, not null
|
||||
* @param locale the locale to use, may be {@code null}
|
||||
* @return the formatted date
|
||||
*/
|
||||
public static String formatUTC(final long millis, final String pattern, final Locale locale) {
|
||||
return format(new Date(millis), pattern, UTC_TIME_ZONE, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats a date/time into a specific pattern using the UTC time zone.
|
||||
* </p>
|
||||
*
|
||||
* @param date the date to format, not null
|
||||
* @param pattern the pattern to use to format the date, not null
|
||||
* @param locale the locale to use, may be {@code null}
|
||||
* @return the formatted date
|
||||
*/
|
||||
public static String formatUTC(final Date date, final String pattern, final Locale locale) {
|
||||
return format(date, pattern, UTC_TIME_ZONE, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats a date/time into a specific pattern.
|
||||
* </p>
|
||||
*
|
||||
* @param millis the date to format expressed in milliseconds
|
||||
* @param pattern the pattern to use to format the date, not null
|
||||
* @return the formatted date
|
||||
*/
|
||||
public static String format(final long millis, final String pattern) {
|
||||
return format(new Date(millis), pattern, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats a date/time into a specific pattern.
|
||||
* </p>
|
||||
*
|
||||
* @param date the date to format, not null
|
||||
* @param pattern the pattern to use to format the date, not null
|
||||
* @return the formatted date
|
||||
*/
|
||||
public static String format(final Date date, final String pattern) {
|
||||
return format(date, pattern, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats a calendar into a specific pattern.
|
||||
* </p>
|
||||
*
|
||||
* @param calendar the calendar to format, not null
|
||||
* @param pattern the pattern to use to format the calendar, not null
|
||||
* @return the formatted calendar
|
||||
* @see FastDateFormat#format(Calendar)
|
||||
* @since 2.4
|
||||
*/
|
||||
public static String format(final Calendar calendar, final String pattern) {
|
||||
return format(calendar, pattern, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats a date/time into a specific pattern in a time zone.
|
||||
* </p>
|
||||
*
|
||||
* @param millis the time expressed in milliseconds
|
||||
* @param pattern the pattern to use to format the date, not null
|
||||
* @param timeZone the time zone to use, may be {@code null}
|
||||
* @return the formatted date
|
||||
*/
|
||||
public static String format(final long millis, final String pattern, final TimeZone timeZone) {
|
||||
return format(new Date(millis), pattern, timeZone, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats a date/time into a specific pattern in a time zone.
|
||||
* </p>
|
||||
*
|
||||
* @param date the date to format, not null
|
||||
* @param pattern the pattern to use to format the date, not null
|
||||
* @param timeZone the time zone to use, may be {@code null}
|
||||
* @return the formatted date
|
||||
*/
|
||||
public static String format(final Date date, final String pattern, final TimeZone timeZone) {
|
||||
return format(date, pattern, timeZone, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats a calendar into a specific pattern in a time zone.
|
||||
* </p>
|
||||
*
|
||||
* @param calendar the calendar to format, not null
|
||||
* @param pattern the pattern to use to format the calendar, not null
|
||||
* @param timeZone the time zone to use, may be {@code null}
|
||||
* @return the formatted calendar
|
||||
* @see FastDateFormat#format(Calendar)
|
||||
* @since 2.4
|
||||
*/
|
||||
public static String format(final Calendar calendar, final String pattern, final TimeZone timeZone) {
|
||||
return format(calendar, pattern, timeZone, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats a date/time into a specific pattern in a locale.
|
||||
* </p>
|
||||
*
|
||||
* @param millis the date to format expressed in milliseconds
|
||||
* @param pattern the pattern to use to format the date, not null
|
||||
* @param locale the locale to use, may be {@code null}
|
||||
* @return the formatted date
|
||||
*/
|
||||
public static String format(final long millis, final String pattern, final Locale locale) {
|
||||
return format(new Date(millis), pattern, null, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats a date/time into a specific pattern in a locale.
|
||||
* </p>
|
||||
*
|
||||
* @param date the date to format, not null
|
||||
* @param pattern the pattern to use to format the date, not null
|
||||
* @param locale the locale to use, may be {@code null}
|
||||
* @return the formatted date
|
||||
*/
|
||||
public static String format(final Date date, final String pattern, final Locale locale) {
|
||||
return format(date, pattern, null, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats a calendar into a specific pattern in a locale.
|
||||
* </p>
|
||||
*
|
||||
* @param calendar the calendar to format, not null
|
||||
* @param pattern the pattern to use to format the calendar, not null
|
||||
* @param locale the locale to use, may be {@code null}
|
||||
* @return the formatted calendar
|
||||
* @see FastDateFormat#format(Calendar)
|
||||
* @since 2.4
|
||||
*/
|
||||
public static String format(final Calendar calendar, final String pattern, final Locale locale) {
|
||||
return format(calendar, pattern, null, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats a date/time into a specific pattern in a time zone and locale.
|
||||
* </p>
|
||||
*
|
||||
* @param millis the date to format expressed in milliseconds
|
||||
* @param pattern the pattern to use to format the date, not null
|
||||
* @param timeZone the time zone to use, may be {@code null}
|
||||
* @param locale the locale to use, may be {@code null}
|
||||
* @return the formatted date
|
||||
*/
|
||||
public static String format(final long millis, final String pattern, final TimeZone timeZone, final Locale locale) {
|
||||
return format(new Date(millis), pattern, timeZone, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats a date/time into a specific pattern in a time zone and locale.
|
||||
* </p>
|
||||
*
|
||||
* @param date the date to format, not null
|
||||
* @param pattern the pattern to use to format the date, not null, not null
|
||||
* @param timeZone the time zone to use, may be {@code null}
|
||||
* @param locale the locale to use, may be {@code null}
|
||||
* @return the formatted date
|
||||
*/
|
||||
public static String format(final Date date, final String pattern, final TimeZone timeZone, final Locale locale) {
|
||||
final FastDateFormat df = FastDateFormat.getInstance(pattern, timeZone, locale);
|
||||
return df.format(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats a calendar into a specific pattern in a time zone and locale.
|
||||
* </p>
|
||||
*
|
||||
* @param calendar the calendar to format, not null
|
||||
* @param pattern the pattern to use to format the calendar, not null
|
||||
* @param timeZone the time zone to use, may be {@code null}
|
||||
* @param locale the locale to use, may be {@code null}
|
||||
* @return the formatted calendar
|
||||
* @see FastDateFormat#format(Calendar)
|
||||
* @since 2.4
|
||||
*/
|
||||
public static String format(final Calendar calendar, final String pattern, final TimeZone timeZone,
|
||||
final Locale locale) {
|
||||
final FastDateFormat df = FastDateFormat.getInstance(pattern, timeZone, locale);
|
||||
return df.format(calendar);
|
||||
}
|
||||
|
||||
}
|
139
sources/main/java/org/apache/commons/lang3/time/DateParser.java
Normal file
139
sources/main/java/org/apache/commons/lang3/time/DateParser.java
Normal file
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.commons.lang3.time;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.ParsePosition;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* DateParser is the "missing" interface for the parsing methods of
|
||||
* {@link java.text.DateFormat}. You can obtain an object implementing this
|
||||
* interface by using one of the FastDateFormat factory methods.
|
||||
* <p>
|
||||
* Warning: Since binary compatible methods may be added to this interface in
|
||||
* any release, developers are not expected to implement this interface.
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
public interface DateParser {
|
||||
|
||||
/**
|
||||
* Equivalent to DateFormat.parse(String).
|
||||
*
|
||||
* See {@link java.text.DateFormat#parse(String)} for more information.
|
||||
*
|
||||
* @param source A {@code String} whose beginning should be parsed.
|
||||
* @return A {@code Date} parsed from the string
|
||||
* @throws ParseException if the beginning of the specified string cannot be
|
||||
* parsed.
|
||||
*/
|
||||
Date parse(String source) throws ParseException;
|
||||
|
||||
/**
|
||||
* Equivalent to DateFormat.parse(String, ParsePosition).
|
||||
*
|
||||
* See {@link java.text.DateFormat#parse(String, ParsePosition)} for more
|
||||
* information.
|
||||
*
|
||||
* @param source A {@code String}, part of which should be parsed.
|
||||
* @param pos A {@code ParsePosition} object with index and error index
|
||||
* information as described above.
|
||||
* @return A {@code Date} parsed from the string. In case of error, returns
|
||||
* null.
|
||||
* @throws NullPointerException if text or pos is null.
|
||||
*/
|
||||
Date parse(String source, ParsePosition pos);
|
||||
|
||||
/**
|
||||
* Parses a formatted date string according to the format. Updates the Calendar
|
||||
* with parsed fields. Upon success, the ParsePosition index is updated to
|
||||
* indicate how much of the source text was consumed. Not all source text needs
|
||||
* to be consumed. Upon parse failure, ParsePosition error index is updated to
|
||||
* the offset of the source text which does not match the supplied format.
|
||||
*
|
||||
* @param source The text to parse.
|
||||
* @param pos On input, the position in the source to start parsing, on
|
||||
* output, updated position.
|
||||
* @param calendar The calendar into which to set parsed fields.
|
||||
* @return true, if source has been parsed (pos parsePosition is updated);
|
||||
* otherwise false (and pos errorIndex is updated)
|
||||
* @throws IllegalArgumentException when Calendar has been set to be not
|
||||
* lenient, and a parsed field is out of range.
|
||||
*
|
||||
* @since 3.5
|
||||
*/
|
||||
boolean parse(String source, ParsePosition pos, Calendar calendar);
|
||||
|
||||
// Accessors
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* <p>
|
||||
* Gets the pattern used by this parser.
|
||||
* </p>
|
||||
*
|
||||
* @return the pattern, {@link java.text.SimpleDateFormat} compatible
|
||||
*/
|
||||
String getPattern();
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Gets the time zone used by this parser.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The default {@link TimeZone} used to create a {@link Date} when the
|
||||
* {@link TimeZone} is not specified by the format pattern.
|
||||
* </p>
|
||||
*
|
||||
* @return the time zone
|
||||
*/
|
||||
TimeZone getTimeZone();
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Gets the locale used by this parser.
|
||||
* </p>
|
||||
*
|
||||
* @return the locale
|
||||
*/
|
||||
Locale getLocale();
|
||||
|
||||
/**
|
||||
* Parses text from a string to produce a Date.
|
||||
*
|
||||
* @param source A {@code String} whose beginning should be parsed.
|
||||
* @return a {@code java.util.Date} object
|
||||
* @throws ParseException if the beginning of the specified string cannot be
|
||||
* parsed.
|
||||
* @see java.text.DateFormat#parseObject(String)
|
||||
*/
|
||||
Object parseObject(String source) throws ParseException;
|
||||
|
||||
/**
|
||||
* Parses a date/time string according to the given parse position.
|
||||
*
|
||||
* @param source A {@code String} whose beginning should be parsed.
|
||||
* @param pos the parse position
|
||||
* @return a {@code java.util.Date} object
|
||||
* @see java.text.DateFormat#parseObject(String, ParsePosition)
|
||||
*/
|
||||
Object parseObject(String source, ParsePosition pos);
|
||||
}
|
207
sources/main/java/org/apache/commons/lang3/time/DatePrinter.java
Normal file
207
sources/main/java/org/apache/commons/lang3/time/DatePrinter.java
Normal file
@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.commons.lang3.time;
|
||||
|
||||
import java.text.FieldPosition;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* DatePrinter is the "missing" interface for the format methods of
|
||||
* {@link java.text.DateFormat}. You can obtain an object implementing this
|
||||
* interface by using one of the FastDateFormat factory methods.
|
||||
* <p>
|
||||
* Warning: Since binary compatible methods may be added to this interface in
|
||||
* any release, developers are not expected to implement this interface.
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
public interface DatePrinter {
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats a millisecond {@code long} value.
|
||||
* </p>
|
||||
*
|
||||
* @param millis the millisecond value to format
|
||||
* @return the formatted string
|
||||
* @since 2.1
|
||||
*/
|
||||
String format(long millis);
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats a {@code Date} object using a {@code GregorianCalendar}.
|
||||
* </p>
|
||||
*
|
||||
* @param date the date to format
|
||||
* @return the formatted string
|
||||
*/
|
||||
String format(Date date);
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats a {@code Calendar} object.
|
||||
* </p>
|
||||
* The TimeZone set on the Calendar is only used to adjust the time offset. The
|
||||
* TimeZone specified during the construction of the Parser will determine the
|
||||
* TimeZone used in the formatted string.
|
||||
*
|
||||
* @param calendar the calendar to format.
|
||||
* @return the formatted string
|
||||
*/
|
||||
String format(Calendar calendar);
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats a millisecond {@code long} value into the supplied
|
||||
* {@code StringBuffer}.
|
||||
* </p>
|
||||
*
|
||||
* @param millis the millisecond value to format
|
||||
* @param buf the buffer to format into
|
||||
* @return the specified string buffer
|
||||
* @deprecated Use {{@link #format(long, Appendable)}.
|
||||
*/
|
||||
@Deprecated
|
||||
StringBuffer format(long millis, StringBuffer buf);
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats a {@code Date} object into the supplied {@code StringBuffer} using a
|
||||
* {@code GregorianCalendar}.
|
||||
* </p>
|
||||
*
|
||||
* @param date the date to format
|
||||
* @param buf the buffer to format into
|
||||
* @return the specified string buffer
|
||||
* @deprecated Use {{@link #format(Date, Appendable)}.
|
||||
*/
|
||||
@Deprecated
|
||||
StringBuffer format(Date date, StringBuffer buf);
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats a {@code Calendar} object into the supplied {@code StringBuffer}.
|
||||
* </p>
|
||||
* The TimeZone set on the Calendar is only used to adjust the time offset. The
|
||||
* TimeZone specified during the construction of the Parser will determine the
|
||||
* TimeZone used in the formatted string.
|
||||
*
|
||||
* @param calendar the calendar to format
|
||||
* @param buf the buffer to format into
|
||||
* @return the specified string buffer
|
||||
* @deprecated Use {{@link #format(Calendar, Appendable)}.
|
||||
*/
|
||||
@Deprecated
|
||||
StringBuffer format(Calendar calendar, StringBuffer buf);
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats a millisecond {@code long} value into the supplied
|
||||
* {@code Appendable}.
|
||||
* </p>
|
||||
*
|
||||
* @param millis the millisecond value to format
|
||||
* @param buf the buffer to format into
|
||||
* @param <B> the Appendable class type, usually StringBuilder or
|
||||
* StringBuffer.
|
||||
* @return the specified string buffer
|
||||
* @since 3.5
|
||||
*/
|
||||
<B extends Appendable> B format(long millis, B buf);
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats a {@code Date} object into the supplied {@code Appendable} using a
|
||||
* {@code GregorianCalendar}.
|
||||
* </p>
|
||||
*
|
||||
* @param date the date to format
|
||||
* @param buf the buffer to format into
|
||||
* @param <B> the Appendable class type, usually StringBuilder or StringBuffer.
|
||||
* @return the specified string buffer
|
||||
* @since 3.5
|
||||
*/
|
||||
<B extends Appendable> B format(Date date, B buf);
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats a {@code Calendar} object into the supplied {@code Appendable}.
|
||||
* </p>
|
||||
* The TimeZone set on the Calendar is only used to adjust the time offset. The
|
||||
* TimeZone specified during the construction of the Parser will determine the
|
||||
* TimeZone used in the formatted string.
|
||||
*
|
||||
* @param calendar the calendar to format
|
||||
* @param buf the buffer to format into
|
||||
* @param <B> the Appendable class type, usually StringBuilder or
|
||||
* StringBuffer.
|
||||
* @return the specified string buffer
|
||||
* @since 3.5
|
||||
*/
|
||||
<B extends Appendable> B format(Calendar calendar, B buf);
|
||||
|
||||
// Accessors
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* <p>
|
||||
* Gets the pattern used by this printer.
|
||||
* </p>
|
||||
*
|
||||
* @return the pattern, {@link java.text.SimpleDateFormat} compatible
|
||||
*/
|
||||
String getPattern();
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Gets the time zone used by this printer.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This zone is always used for {@code Date} printing.
|
||||
* </p>
|
||||
*
|
||||
* @return the time zone
|
||||
*/
|
||||
TimeZone getTimeZone();
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Gets the locale used by this printer.
|
||||
* </p>
|
||||
*
|
||||
* @return the locale
|
||||
*/
|
||||
Locale getLocale();
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats a {@code Date}, {@code Calendar} or {@code Long} (milliseconds)
|
||||
* object.
|
||||
* </p>
|
||||
*
|
||||
* @param obj the object to format
|
||||
* @param toAppendTo the buffer to append to
|
||||
* @param pos the position - ignored
|
||||
* @return the buffer passed in
|
||||
* @see java.text.DateFormat#format(Object, StringBuffer, FieldPosition)
|
||||
*/
|
||||
StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos);
|
||||
}
|
2025
sources/main/java/org/apache/commons/lang3/time/DateUtils.java
Normal file
2025
sources/main/java/org/apache/commons/lang3/time/DateUtils.java
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,765 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.commons.lang3.time;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Duration formatting utilities and constants. The following table describes
|
||||
* the tokens used in the pattern language for formatting.
|
||||
* </p>
|
||||
* <table border="1">
|
||||
* <caption>Pattern Tokens</caption>
|
||||
* <tr>
|
||||
* <th>character</th>
|
||||
* <th>duration element</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>y</td>
|
||||
* <td>years</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>M</td>
|
||||
* <td>months</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>d</td>
|
||||
* <td>days</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>H</td>
|
||||
* <td>hours</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>m</td>
|
||||
* <td>minutes</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>s</td>
|
||||
* <td>seconds</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>S</td>
|
||||
* <td>milliseconds</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>'text'</td>
|
||||
* <td>arbitrary text content</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
* <b>Note: It's not currently possible to include a single-quote in a
|
||||
* format.</b> <br>
|
||||
* Token values are printed using decimal digits. A token character can be
|
||||
* repeated to ensure that the field occupies a certain minimum size. Values
|
||||
* will be left-padded with 0 unless padding is disabled in the method
|
||||
* invocation.
|
||||
*
|
||||
* @since 2.1
|
||||
*/
|
||||
public class DurationFormatUtils {
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* DurationFormatUtils instances should NOT be constructed in standard
|
||||
* programming.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This constructor is public to permit tools that require a JavaBean instance
|
||||
* to operate.
|
||||
* </p>
|
||||
*/
|
||||
public DurationFormatUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Pattern used with {@code FastDateFormat} and {@code SimpleDateFormat} for the
|
||||
* ISO 8601 period format used in durations.
|
||||
* </p>
|
||||
*
|
||||
* @see org.apache.commons.lang3.time.FastDateFormat
|
||||
* @see java.text.SimpleDateFormat
|
||||
*/
|
||||
public static final String ISO_EXTENDED_FORMAT_PATTERN = "'P'yyyy'Y'M'M'd'DT'H'H'm'M's.SSS'S'";
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* <p>
|
||||
* Formats the time gap as a string.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The format used is ISO 8601-like: {@code HH:mm:ss.SSS}.
|
||||
* </p>
|
||||
*
|
||||
* @param durationMillis the duration to format
|
||||
* @return the formatted duration, not null
|
||||
* @throws java.lang.IllegalArgumentException if durationMillis is negative
|
||||
*/
|
||||
public static String formatDurationHMS(final long durationMillis) {
|
||||
return formatDuration(durationMillis, "HH:mm:ss.SSS");
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats the time gap as a string.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The format used is the ISO 8601 period format.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This method formats durations using the days and lower fields of the ISO
|
||||
* format pattern, such as P7D6TH5M4.321S.
|
||||
* </p>
|
||||
*
|
||||
* @param durationMillis the duration to format
|
||||
* @return the formatted duration, not null
|
||||
* @throws java.lang.IllegalArgumentException if durationMillis is negative
|
||||
*/
|
||||
public static String formatDurationISO(final long durationMillis) {
|
||||
return formatDuration(durationMillis, ISO_EXTENDED_FORMAT_PATTERN, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats the time gap as a string, using the specified format, and padding
|
||||
* with zeros.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This method formats durations using the days and lower fields of the format
|
||||
* pattern. Months and larger are not used.
|
||||
* </p>
|
||||
*
|
||||
* @param durationMillis the duration to format
|
||||
* @param format the way in which to format the duration, not null
|
||||
* @return the formatted duration, not null
|
||||
* @throws java.lang.IllegalArgumentException if durationMillis is negative
|
||||
*/
|
||||
public static String formatDuration(final long durationMillis, final String format) {
|
||||
return formatDuration(durationMillis, format, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats the time gap as a string, using the specified format. Padding the
|
||||
* left hand side of numbers with zeroes is optional.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This method formats durations using the days and lower fields of the format
|
||||
* pattern. Months and larger are not used.
|
||||
* </p>
|
||||
*
|
||||
* @param durationMillis the duration to format
|
||||
* @param format the way in which to format the duration, not null
|
||||
* @param padWithZeros whether to pad the left hand side of numbers with 0's
|
||||
* @return the formatted duration, not null
|
||||
* @throws java.lang.IllegalArgumentException if durationMillis is negative
|
||||
*/
|
||||
public static String formatDuration(final long durationMillis, final String format, final boolean padWithZeros) {
|
||||
Validate.inclusiveBetween(0, Long.MAX_VALUE, durationMillis, "durationMillis must not be negative");
|
||||
|
||||
final Token[] tokens = lexx(format);
|
||||
|
||||
long days = 0;
|
||||
long hours = 0;
|
||||
long minutes = 0;
|
||||
long seconds = 0;
|
||||
long milliseconds = durationMillis;
|
||||
|
||||
if (Token.containsTokenWithValue(tokens, d)) {
|
||||
days = milliseconds / DateUtils.MILLIS_PER_DAY;
|
||||
milliseconds = milliseconds - (days * DateUtils.MILLIS_PER_DAY);
|
||||
}
|
||||
if (Token.containsTokenWithValue(tokens, H)) {
|
||||
hours = milliseconds / DateUtils.MILLIS_PER_HOUR;
|
||||
milliseconds = milliseconds - (hours * DateUtils.MILLIS_PER_HOUR);
|
||||
}
|
||||
if (Token.containsTokenWithValue(tokens, m)) {
|
||||
minutes = milliseconds / DateUtils.MILLIS_PER_MINUTE;
|
||||
milliseconds = milliseconds - (minutes * DateUtils.MILLIS_PER_MINUTE);
|
||||
}
|
||||
if (Token.containsTokenWithValue(tokens, s)) {
|
||||
seconds = milliseconds / DateUtils.MILLIS_PER_SECOND;
|
||||
milliseconds = milliseconds - (seconds * DateUtils.MILLIS_PER_SECOND);
|
||||
}
|
||||
|
||||
return format(tokens, 0, 0, days, hours, minutes, seconds, milliseconds, padWithZeros);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats an elapsed time into a pluralization correct string.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This method formats durations using the days and lower fields of the format
|
||||
* pattern. Months and larger are not used.
|
||||
* </p>
|
||||
*
|
||||
* @param durationMillis the elapsed time to report in
|
||||
* milliseconds
|
||||
* @param suppressLeadingZeroElements suppresses leading 0 elements
|
||||
* @param suppressTrailingZeroElements suppresses trailing 0 elements
|
||||
* @return the formatted text in days/hours/minutes/seconds, not null
|
||||
* @throws java.lang.IllegalArgumentException if durationMillis is negative
|
||||
*/
|
||||
public static String formatDurationWords(final long durationMillis, final boolean suppressLeadingZeroElements,
|
||||
final boolean suppressTrailingZeroElements) {
|
||||
|
||||
// This method is generally replaceable by the format method, but
|
||||
// there are a series of tweaks and special cases that require
|
||||
// trickery to replicate.
|
||||
String duration = formatDuration(durationMillis, "d' days 'H' hours 'm' minutes 's' seconds'");
|
||||
if (suppressLeadingZeroElements) {
|
||||
// this is a temporary marker on the front. Like ^ in regexp.
|
||||
duration = " " + duration;
|
||||
String tmp = StringUtils.replaceOnce(duration, " 0 days", StringUtils.EMPTY);
|
||||
if (tmp.length() != duration.length()) {
|
||||
duration = tmp;
|
||||
tmp = StringUtils.replaceOnce(duration, " 0 hours", StringUtils.EMPTY);
|
||||
if (tmp.length() != duration.length()) {
|
||||
duration = tmp;
|
||||
tmp = StringUtils.replaceOnce(duration, " 0 minutes", StringUtils.EMPTY);
|
||||
duration = tmp;
|
||||
if (tmp.length() != duration.length()) {
|
||||
duration = StringUtils.replaceOnce(tmp, " 0 seconds", StringUtils.EMPTY);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!duration.isEmpty()) {
|
||||
// strip the space off again
|
||||
duration = duration.substring(1);
|
||||
}
|
||||
}
|
||||
if (suppressTrailingZeroElements) {
|
||||
String tmp = StringUtils.replaceOnce(duration, " 0 seconds", StringUtils.EMPTY);
|
||||
if (tmp.length() != duration.length()) {
|
||||
duration = tmp;
|
||||
tmp = StringUtils.replaceOnce(duration, " 0 minutes", StringUtils.EMPTY);
|
||||
if (tmp.length() != duration.length()) {
|
||||
duration = tmp;
|
||||
tmp = StringUtils.replaceOnce(duration, " 0 hours", StringUtils.EMPTY);
|
||||
if (tmp.length() != duration.length()) {
|
||||
duration = StringUtils.replaceOnce(tmp, " 0 days", StringUtils.EMPTY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// handle plurals
|
||||
duration = " " + duration;
|
||||
duration = StringUtils.replaceOnce(duration, " 1 seconds", " 1 second");
|
||||
duration = StringUtils.replaceOnce(duration, " 1 minutes", " 1 minute");
|
||||
duration = StringUtils.replaceOnce(duration, " 1 hours", " 1 hour");
|
||||
duration = StringUtils.replaceOnce(duration, " 1 days", " 1 day");
|
||||
return duration.trim();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* <p>
|
||||
* Formats the time gap as a string.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The format used is the ISO 8601 period format.
|
||||
* </p>
|
||||
*
|
||||
* @param startMillis the start of the duration to format
|
||||
* @param endMillis the end of the duration to format
|
||||
* @return the formatted duration, not null
|
||||
* @throws java.lang.IllegalArgumentException if startMillis is greater than
|
||||
* endMillis
|
||||
*/
|
||||
public static String formatPeriodISO(final long startMillis, final long endMillis) {
|
||||
return formatPeriod(startMillis, endMillis, ISO_EXTENDED_FORMAT_PATTERN, false, TimeZone.getDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats the time gap as a string, using the specified format. Padding the
|
||||
* left hand side of numbers with zeroes is optional.
|
||||
*
|
||||
* @param startMillis the start of the duration
|
||||
* @param endMillis the end of the duration
|
||||
* @param format the way in which to format the duration, not null
|
||||
* @return the formatted duration, not null
|
||||
* @throws java.lang.IllegalArgumentException if startMillis is greater than
|
||||
* endMillis
|
||||
*/
|
||||
public static String formatPeriod(final long startMillis, final long endMillis, final String format) {
|
||||
return formatPeriod(startMillis, endMillis, format, true, TimeZone.getDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats the time gap as a string, using the specified format. Padding the
|
||||
* left hand side of numbers with zeroes is optional and the time zone may be
|
||||
* specified.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* When calculating the difference between months/days, it chooses to calculate
|
||||
* months first. So when working out the number of months and days between
|
||||
* January 15th and March 10th, it choose 1 month and 23 days gained by choosing
|
||||
* January->February = 1 month and then calculating days forwards, and not
|
||||
* the 1 month and 26 days gained by choosing March -> February = 1 month and
|
||||
* then calculating days backwards.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* For more control, the <a href="http://joda-time.sf.net/">Joda-Time</a>
|
||||
* library is recommended.
|
||||
* </p>
|
||||
*
|
||||
* @param startMillis the start of the duration
|
||||
* @param endMillis the end of the duration
|
||||
* @param format the way in which to format the duration, not null
|
||||
* @param padWithZeros whether to pad the left hand side of numbers with 0's
|
||||
* @param timezone the millis are defined in
|
||||
* @return the formatted duration, not null
|
||||
* @throws java.lang.IllegalArgumentException if startMillis is greater than
|
||||
* endMillis
|
||||
*/
|
||||
public static String formatPeriod(final long startMillis, final long endMillis, final String format,
|
||||
final boolean padWithZeros, final TimeZone timezone) {
|
||||
Validate.isTrue(startMillis <= endMillis, "startMillis must not be greater than endMillis");
|
||||
|
||||
// Used to optimise for differences under 28 days and
|
||||
// called formatDuration(millis, format); however this did not work
|
||||
// over leap years.
|
||||
// TODO: Compare performance to see if anything was lost by
|
||||
// losing this optimisation.
|
||||
|
||||
final Token[] tokens = lexx(format);
|
||||
|
||||
// time zones get funky around 0, so normalizing everything to GMT
|
||||
// stops the hours being off
|
||||
final Calendar start = Calendar.getInstance(timezone);
|
||||
start.setTime(new Date(startMillis));
|
||||
final Calendar end = Calendar.getInstance(timezone);
|
||||
end.setTime(new Date(endMillis));
|
||||
|
||||
// initial estimates
|
||||
int milliseconds = end.get(Calendar.MILLISECOND) - start.get(Calendar.MILLISECOND);
|
||||
int seconds = end.get(Calendar.SECOND) - start.get(Calendar.SECOND);
|
||||
int minutes = end.get(Calendar.MINUTE) - start.get(Calendar.MINUTE);
|
||||
int hours = end.get(Calendar.HOUR_OF_DAY) - start.get(Calendar.HOUR_OF_DAY);
|
||||
int days = end.get(Calendar.DAY_OF_MONTH) - start.get(Calendar.DAY_OF_MONTH);
|
||||
int months = end.get(Calendar.MONTH) - start.get(Calendar.MONTH);
|
||||
int years = end.get(Calendar.YEAR) - start.get(Calendar.YEAR);
|
||||
|
||||
// each initial estimate is adjusted in case it is under 0
|
||||
while (milliseconds < 0) {
|
||||
milliseconds += 1000;
|
||||
seconds -= 1;
|
||||
}
|
||||
while (seconds < 0) {
|
||||
seconds += 60;
|
||||
minutes -= 1;
|
||||
}
|
||||
while (minutes < 0) {
|
||||
minutes += 60;
|
||||
hours -= 1;
|
||||
}
|
||||
while (hours < 0) {
|
||||
hours += 24;
|
||||
days -= 1;
|
||||
}
|
||||
|
||||
if (Token.containsTokenWithValue(tokens, M)) {
|
||||
while (days < 0) {
|
||||
days += start.getActualMaximum(Calendar.DAY_OF_MONTH);
|
||||
months -= 1;
|
||||
start.add(Calendar.MONTH, 1);
|
||||
}
|
||||
|
||||
while (months < 0) {
|
||||
months += 12;
|
||||
years -= 1;
|
||||
}
|
||||
|
||||
if (!Token.containsTokenWithValue(tokens, y) && years != 0) {
|
||||
while (years != 0) {
|
||||
months += 12 * years;
|
||||
years = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// there are no M's in the format string
|
||||
|
||||
if (!Token.containsTokenWithValue(tokens, y)) {
|
||||
int target = end.get(Calendar.YEAR);
|
||||
if (months < 0) {
|
||||
// target is end-year -1
|
||||
target -= 1;
|
||||
}
|
||||
|
||||
while (start.get(Calendar.YEAR) != target) {
|
||||
days += start.getActualMaximum(Calendar.DAY_OF_YEAR) - start.get(Calendar.DAY_OF_YEAR);
|
||||
|
||||
// Not sure I grok why this is needed, but the brutal tests show it is
|
||||
if (start instanceof GregorianCalendar && start.get(Calendar.MONTH) == Calendar.FEBRUARY
|
||||
&& start.get(Calendar.DAY_OF_MONTH) == 29) {
|
||||
days += 1;
|
||||
}
|
||||
|
||||
start.add(Calendar.YEAR, 1);
|
||||
|
||||
days += start.get(Calendar.DAY_OF_YEAR);
|
||||
}
|
||||
|
||||
years = 0;
|
||||
}
|
||||
|
||||
while (start.get(Calendar.MONTH) != end.get(Calendar.MONTH)) {
|
||||
days += start.getActualMaximum(Calendar.DAY_OF_MONTH);
|
||||
start.add(Calendar.MONTH, 1);
|
||||
}
|
||||
|
||||
months = 0;
|
||||
|
||||
while (days < 0) {
|
||||
days += start.getActualMaximum(Calendar.DAY_OF_MONTH);
|
||||
months -= 1;
|
||||
start.add(Calendar.MONTH, 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// The rest of this code adds in values that
|
||||
// aren't requested. This allows the user to ask for the
|
||||
// number of months and get the real count and not just 0->11.
|
||||
|
||||
if (!Token.containsTokenWithValue(tokens, d)) {
|
||||
hours += 24 * days;
|
||||
days = 0;
|
||||
}
|
||||
if (!Token.containsTokenWithValue(tokens, H)) {
|
||||
minutes += 60 * hours;
|
||||
hours = 0;
|
||||
}
|
||||
if (!Token.containsTokenWithValue(tokens, m)) {
|
||||
seconds += 60 * minutes;
|
||||
minutes = 0;
|
||||
}
|
||||
if (!Token.containsTokenWithValue(tokens, s)) {
|
||||
milliseconds += 1000 * seconds;
|
||||
seconds = 0;
|
||||
}
|
||||
|
||||
return format(tokens, years, months, days, hours, minutes, seconds, milliseconds, padWithZeros);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* <p>
|
||||
* The internal method to do the formatting.
|
||||
* </p>
|
||||
*
|
||||
* @param tokens the tokens
|
||||
* @param years the number of years
|
||||
* @param months the number of months
|
||||
* @param days the number of days
|
||||
* @param hours the number of hours
|
||||
* @param minutes the number of minutes
|
||||
* @param seconds the number of seconds
|
||||
* @param milliseconds the number of millis
|
||||
* @param padWithZeros whether to pad
|
||||
* @return the formatted string
|
||||
*/
|
||||
static String format(final Token[] tokens, final long years, final long months, final long days, final long hours,
|
||||
final long minutes, final long seconds, final long milliseconds, final boolean padWithZeros) {
|
||||
final StringBuilder buffer = new StringBuilder();
|
||||
boolean lastOutputSeconds = false;
|
||||
for (final Token token : tokens) {
|
||||
final Object value = token.getValue();
|
||||
final int count = token.getCount();
|
||||
if (value instanceof StringBuilder) {
|
||||
buffer.append(value.toString());
|
||||
} else if (value.equals(y)) {
|
||||
buffer.append(paddedValue(years, padWithZeros, count));
|
||||
lastOutputSeconds = false;
|
||||
} else if (value.equals(M)) {
|
||||
buffer.append(paddedValue(months, padWithZeros, count));
|
||||
lastOutputSeconds = false;
|
||||
} else if (value.equals(d)) {
|
||||
buffer.append(paddedValue(days, padWithZeros, count));
|
||||
lastOutputSeconds = false;
|
||||
} else if (value.equals(H)) {
|
||||
buffer.append(paddedValue(hours, padWithZeros, count));
|
||||
lastOutputSeconds = false;
|
||||
} else if (value.equals(m)) {
|
||||
buffer.append(paddedValue(minutes, padWithZeros, count));
|
||||
lastOutputSeconds = false;
|
||||
} else if (value.equals(s)) {
|
||||
buffer.append(paddedValue(seconds, padWithZeros, count));
|
||||
lastOutputSeconds = true;
|
||||
} else if (value.equals(S)) {
|
||||
if (lastOutputSeconds) {
|
||||
// ensure at least 3 digits are displayed even if padding is not selected
|
||||
final int width = padWithZeros ? Math.max(3, count) : 3;
|
||||
buffer.append(paddedValue(milliseconds, true, width));
|
||||
} else {
|
||||
buffer.append(paddedValue(milliseconds, padWithZeros, count));
|
||||
}
|
||||
lastOutputSeconds = false;
|
||||
}
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Converts a {@code long} to a {@code String} with optional zero padding.
|
||||
* </p>
|
||||
*
|
||||
* @param value the value to convert
|
||||
* @param padWithZeros whether to pad with zeroes
|
||||
* @param count the size to pad to (ignored if {@code padWithZeros} is
|
||||
* false)
|
||||
* @return the string result
|
||||
*/
|
||||
private static String paddedValue(final long value, final boolean padWithZeros, final int count) {
|
||||
final String longString = Long.toString(value);
|
||||
return padWithZeros ? StringUtils.leftPad(longString, count, '0') : longString;
|
||||
}
|
||||
|
||||
static final String y = "y";
|
||||
static final String M = "M";
|
||||
static final String d = "d";
|
||||
static final String H = "H";
|
||||
static final String m = "m";
|
||||
static final String s = "s";
|
||||
static final String S = "S";
|
||||
|
||||
/**
|
||||
* Parses a classic date format string into Tokens
|
||||
*
|
||||
* @param format the format to parse, not null
|
||||
* @return array of Token[]
|
||||
*/
|
||||
static Token[] lexx(final String format) {
|
||||
final ArrayList<Token> list = new ArrayList<>(format.length());
|
||||
|
||||
boolean inLiteral = false;
|
||||
// Although the buffer is stored in a Token, the Tokens are only
|
||||
// used internally, so cannot be accessed by other threads
|
||||
StringBuilder buffer = null;
|
||||
Token previous = null;
|
||||
for (int i = 0; i < format.length(); i++) {
|
||||
final char ch = format.charAt(i);
|
||||
if (inLiteral && ch != '\'') {
|
||||
buffer.append(ch); // buffer can't be null if inLiteral is true
|
||||
continue;
|
||||
}
|
||||
String value = null;
|
||||
switch (ch) {
|
||||
// TODO: Need to handle escaping of '
|
||||
case '\'':
|
||||
if (inLiteral) {
|
||||
buffer = null;
|
||||
inLiteral = false;
|
||||
} else {
|
||||
buffer = new StringBuilder();
|
||||
list.add(new Token(buffer));
|
||||
inLiteral = true;
|
||||
}
|
||||
break;
|
||||
case 'y':
|
||||
value = y;
|
||||
break;
|
||||
case 'M':
|
||||
value = M;
|
||||
break;
|
||||
case 'd':
|
||||
value = d;
|
||||
break;
|
||||
case 'H':
|
||||
value = H;
|
||||
break;
|
||||
case 'm':
|
||||
value = m;
|
||||
break;
|
||||
case 's':
|
||||
value = s;
|
||||
break;
|
||||
case 'S':
|
||||
value = S;
|
||||
break;
|
||||
default:
|
||||
if (buffer == null) {
|
||||
buffer = new StringBuilder();
|
||||
list.add(new Token(buffer));
|
||||
}
|
||||
buffer.append(ch);
|
||||
}
|
||||
|
||||
if (value != null) {
|
||||
if (previous != null && previous.getValue().equals(value)) {
|
||||
previous.increment();
|
||||
} else {
|
||||
final Token token = new Token(value);
|
||||
list.add(token);
|
||||
previous = token;
|
||||
}
|
||||
buffer = null;
|
||||
}
|
||||
}
|
||||
if (inLiteral) { // i.e. we have not found the end of the literal
|
||||
throw new IllegalArgumentException("Unmatched quote in format: " + format);
|
||||
}
|
||||
return list.toArray(Token.EMPTY_ARRAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Element that is parsed from the format pattern.
|
||||
*/
|
||||
static class Token {
|
||||
|
||||
/** Empty array. */
|
||||
private static final Token[] EMPTY_ARRAY = new Token[0];
|
||||
|
||||
/**
|
||||
* Helper method to determine if a set of tokens contain a value
|
||||
*
|
||||
* @param tokens set to look in
|
||||
* @param value to look for
|
||||
* @return boolean {@code true} if contained
|
||||
*/
|
||||
static boolean containsTokenWithValue(final Token[] tokens, final Object value) {
|
||||
for (final Token token : tokens) {
|
||||
if (token.getValue() == value) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private final Object value;
|
||||
private int count;
|
||||
|
||||
/**
|
||||
* Wraps a token around a value. A value would be something like a 'Y'.
|
||||
*
|
||||
* @param value to wrap
|
||||
*/
|
||||
Token(final Object value) {
|
||||
this.value = value;
|
||||
this.count = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a token around a repeated number of a value, for example it would store
|
||||
* 'yyyy' as a value for y and a count of 4.
|
||||
*
|
||||
* @param value to wrap
|
||||
* @param count to wrap
|
||||
*/
|
||||
Token(final Object value, final int count) {
|
||||
this.value = value;
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds another one of the value
|
||||
*/
|
||||
void increment() {
|
||||
count++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current number of values represented
|
||||
*
|
||||
* @return int number of values represented
|
||||
*/
|
||||
int getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the particular value this token represents.
|
||||
*
|
||||
* @return Object value
|
||||
*/
|
||||
Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Supports equality of this Token to another Token.
|
||||
*
|
||||
* @param obj2 Object to consider equality of
|
||||
* @return boolean {@code true} if equal
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj2) {
|
||||
if (obj2 instanceof Token) {
|
||||
final Token tok2 = (Token) obj2;
|
||||
if (this.value.getClass() != tok2.value.getClass()) {
|
||||
return false;
|
||||
}
|
||||
if (this.count != tok2.count) {
|
||||
return false;
|
||||
}
|
||||
if (this.value instanceof StringBuilder) {
|
||||
return this.value.toString().equals(tok2.value.toString());
|
||||
} else if (this.value instanceof Number) {
|
||||
return this.value.equals(tok2.value);
|
||||
} else {
|
||||
return this.value == tok2.value;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hash code for the token equal to the hash code for the token's
|
||||
* value. Thus 'TT' and 'TTTT' will have the same hash code.
|
||||
*
|
||||
* @return The hash code for the token
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.value.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents this token as a String.
|
||||
*
|
||||
* @return String representation of the token
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return StringUtils.repeat(this.value.toString(), this.count);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.commons.lang3.time;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.Range;
|
||||
import org.apache.commons.lang3.function.FailableBiConsumer;
|
||||
import org.apache.commons.lang3.math.NumberUtils;
|
||||
|
||||
/**
|
||||
* Utilities for {@link Duration}.
|
||||
*
|
||||
* @since 3.12.0
|
||||
*/
|
||||
public class DurationUtils {
|
||||
|
||||
/**
|
||||
* An Integer Range that accepts Longs.
|
||||
*/
|
||||
static final Range<Long> LONG_TO_INT_RANGE = Range.between(NumberUtils.LONG_INT_MIN_VALUE,
|
||||
NumberUtils.LONG_INT_MAX_VALUE);
|
||||
|
||||
/**
|
||||
* Accepts the function with the duration as a long milliseconds and int
|
||||
* nanoseconds.
|
||||
*
|
||||
* @param <T> The function exception.
|
||||
* @param consumer Accepting function.
|
||||
* @param duration The duration to pick apart.
|
||||
* @throws T See the function signature.
|
||||
*/
|
||||
public static <T extends Throwable> void accept(final FailableBiConsumer<Long, Integer, T> consumer,
|
||||
final Duration duration) throws T {
|
||||
if (consumer != null && duration != null) {
|
||||
consumer.accept(duration.toMillis(), getNanosOfMiili(duration));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the nanosecond part of a Duration converted to milliseconds.
|
||||
* <p>
|
||||
* Handy when calling an API that takes a long of milliseconds and an int of
|
||||
* nanoseconds. For example, {@link Object#wait(long, int)} and
|
||||
* {@link Thread#sleep(long, int)}.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that is this different from {@link Duration#getNano()} because a
|
||||
* duration are seconds and nanoseconds.
|
||||
* </p>
|
||||
*
|
||||
* @param duration The duration to query.
|
||||
* @return nanoseconds between 0 and 999,999.
|
||||
*/
|
||||
public static int getNanosOfMiili(final Duration duration) {
|
||||
return duration.getNano() % 1_000_000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether the given Duration is positive (>0).
|
||||
*
|
||||
* @param duration the value to test
|
||||
* @return whether the given Duration is positive (>0).
|
||||
*/
|
||||
public static boolean isPositive(final Duration duration) {
|
||||
return !duration.isNegative() && !duration.isZero();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a {@link TimeUnit} to a {@link ChronoUnit}.
|
||||
*
|
||||
* @param timeUnit A non-null TimeUnit.
|
||||
* @return The corresponding ChronoUnit.
|
||||
*/
|
||||
static ChronoUnit toChronoUnit(final TimeUnit timeUnit) {
|
||||
// TODO when using Java >= 9: Use TimeUnit.toChronoUnit().
|
||||
switch (Objects.requireNonNull(timeUnit)) {
|
||||
case NANOSECONDS:
|
||||
return ChronoUnit.NANOS;
|
||||
case MICROSECONDS:
|
||||
return ChronoUnit.MICROS;
|
||||
case MILLISECONDS:
|
||||
return ChronoUnit.MILLIS;
|
||||
case SECONDS:
|
||||
return ChronoUnit.SECONDS;
|
||||
case MINUTES:
|
||||
return ChronoUnit.MINUTES;
|
||||
case HOURS:
|
||||
return ChronoUnit.HOURS;
|
||||
case DAYS:
|
||||
return ChronoUnit.DAYS;
|
||||
default:
|
||||
throw new IllegalArgumentException(timeUnit.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an amount and TimeUnit into a Duration.
|
||||
*
|
||||
* @param amount the amount of the duration, measured in terms of the unit,
|
||||
* positive or negative
|
||||
* @param timeUnit the unit that the duration is measured in, must have an exact
|
||||
* duration, not null
|
||||
* @return a Duration.
|
||||
*/
|
||||
public static Duration toDuration(final long amount, final TimeUnit timeUnit) {
|
||||
return Duration.of(amount, toChronoUnit(timeUnit));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Duration to milliseconds bound to an int (instead of a long).
|
||||
* <p>
|
||||
* Handy for low-level APIs that take millisecond timeouts in ints rather than
|
||||
* longs.
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>If the duration milliseconds are greater than {@link Integer#MAX_VALUE},
|
||||
* then return {@link Integer#MAX_VALUE}.</li>
|
||||
* <li>If the duration milliseconds are lesser than {@link Integer#MIN_VALUE},
|
||||
* then return {@link Integer#MIN_VALUE}.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param duration The duration to convert, not null.
|
||||
* @return int milliseconds.
|
||||
*/
|
||||
public static int toMillisInt(final Duration duration) {
|
||||
Objects.requireNonNull(duration, "duration");
|
||||
// intValue() does not do a narrowing conversion here
|
||||
return LONG_TO_INT_RANGE.fit(Long.valueOf(duration.toMillis())).intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given non-null value or {@link Duration#ZERO} if null.
|
||||
*
|
||||
* @param duration The duration to test.
|
||||
* @return The given duration or {@link Duration#ZERO}.
|
||||
*/
|
||||
public static Duration zeroIfNull(final Duration duration) {
|
||||
return ObjectUtils.defaultIfNull(duration, Duration.ZERO);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,757 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.commons.lang3.time;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.FieldPosition;
|
||||
import java.text.Format;
|
||||
import java.text.ParseException;
|
||||
import java.text.ParsePosition;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* FastDateFormat is a fast and thread-safe version of
|
||||
* {@link java.text.SimpleDateFormat}.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* To obtain an instance of FastDateFormat, use one of the static factory
|
||||
* methods: {@link #getInstance(String, TimeZone, Locale)},
|
||||
* {@link #getDateInstance(int, TimeZone, Locale)},
|
||||
* {@link #getTimeInstance(int, TimeZone, Locale)}, or
|
||||
* {@link #getDateTimeInstance(int, int, TimeZone, Locale)}
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Since FastDateFormat is thread safe, you can use a static member instance:
|
||||
* </p>
|
||||
* <code>
|
||||
* private static final FastDateFormat DATE_FORMATTER = FastDateFormat.getDateTimeInstance(FastDateFormat.LONG, FastDateFormat.SHORT);
|
||||
* </code>
|
||||
*
|
||||
* <p>
|
||||
* This class can be used as a direct replacement to {@code SimpleDateFormat} in
|
||||
* most formatting and parsing situations. This class is especially useful in
|
||||
* multi-threaded server environments. {@code SimpleDateFormat} is not
|
||||
* thread-safe in any JDK version, nor will it be as Sun have closed the
|
||||
* bug/RFE.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* All patterns are compatible with SimpleDateFormat (except time zones and some
|
||||
* year patterns - see below).
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Since 3.2, FastDateFormat supports parsing as well as printing.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Java 1.4 introduced a new pattern letter, {@code 'Z'}, to represent time
|
||||
* zones in RFC822 format (eg. {@code +0800} or {@code -1100}). This pattern
|
||||
* letter can be used here (on all JDK versions).
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* In addition, the pattern {@code 'ZZ'} has been made to represent ISO 8601
|
||||
* extended format time zones (eg. {@code +08:00} or {@code -11:00}). This
|
||||
* introduces a minor incompatibility with Java 1.4, but at a gain of useful
|
||||
* functionality.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Javadoc cites for the year pattern: <i>For formatting, if the number of
|
||||
* pattern letters is 2, the year is truncated to 2 digits; otherwise it is
|
||||
* interpreted as a number.</i> Starting with Java 1.7 a pattern of 'Y' or 'YYY'
|
||||
* will be formatted as '2003', while it was '03' in former Java versions.
|
||||
* FastDateFormat implements the behavior of Java 7.
|
||||
* </p>
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public class FastDateFormat extends Format implements DateParser, DatePrinter {
|
||||
|
||||
/**
|
||||
* Required for serialization support.
|
||||
*
|
||||
* @see java.io.Serializable
|
||||
*/
|
||||
private static final long serialVersionUID = 2L;
|
||||
|
||||
/**
|
||||
* FULL locale dependent date or time style.
|
||||
*/
|
||||
|
||||
public static final int FULL = DateFormat.FULL;
|
||||
|
||||
/**
|
||||
* LONG locale dependent date or time style.
|
||||
*/
|
||||
public static final int LONG = DateFormat.LONG;
|
||||
|
||||
/**
|
||||
* MEDIUM locale dependent date or time style.
|
||||
*/
|
||||
public static final int MEDIUM = DateFormat.MEDIUM;
|
||||
|
||||
/**
|
||||
* SHORT locale dependent date or time style.
|
||||
*/
|
||||
public static final int SHORT = DateFormat.SHORT;
|
||||
|
||||
private static final FormatCache<FastDateFormat> cache = new FormatCache<FastDateFormat>() {
|
||||
@Override
|
||||
protected FastDateFormat createInstance(final String pattern, final TimeZone timeZone, final Locale locale) {
|
||||
return new FastDateFormat(pattern, timeZone, locale);
|
||||
}
|
||||
};
|
||||
|
||||
private final FastDatePrinter printer;
|
||||
private final FastDateParser parser;
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* <p>
|
||||
* Gets a formatter instance using the default pattern in the default locale.
|
||||
* </p>
|
||||
*
|
||||
* @return a date/time formatter
|
||||
*/
|
||||
public static FastDateFormat getInstance() {
|
||||
return cache.getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Gets a formatter instance using the specified pattern in the default locale.
|
||||
* </p>
|
||||
*
|
||||
* @param pattern {@link java.text.SimpleDateFormat} compatible pattern
|
||||
* @return a pattern based date/time formatter
|
||||
* @throws IllegalArgumentException if pattern is invalid
|
||||
*/
|
||||
public static FastDateFormat getInstance(final String pattern) {
|
||||
return cache.getInstance(pattern, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Gets a formatter instance using the specified pattern and time zone.
|
||||
* </p>
|
||||
*
|
||||
* @param pattern {@link java.text.SimpleDateFormat} compatible pattern
|
||||
* @param timeZone optional time zone, overrides time zone of formatted date
|
||||
* @return a pattern based date/time formatter
|
||||
* @throws IllegalArgumentException if pattern is invalid
|
||||
*/
|
||||
public static FastDateFormat getInstance(final String pattern, final TimeZone timeZone) {
|
||||
return cache.getInstance(pattern, timeZone, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Gets a formatter instance using the specified pattern and locale.
|
||||
* </p>
|
||||
*
|
||||
* @param pattern {@link java.text.SimpleDateFormat} compatible pattern
|
||||
* @param locale optional locale, overrides system locale
|
||||
* @return a pattern based date/time formatter
|
||||
* @throws IllegalArgumentException if pattern is invalid
|
||||
*/
|
||||
public static FastDateFormat getInstance(final String pattern, final Locale locale) {
|
||||
return cache.getInstance(pattern, null, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Gets a formatter instance using the specified pattern, time zone and locale.
|
||||
* </p>
|
||||
*
|
||||
* @param pattern {@link java.text.SimpleDateFormat} compatible pattern
|
||||
* @param timeZone optional time zone, overrides time zone of formatted date
|
||||
* @param locale optional locale, overrides system locale
|
||||
* @return a pattern based date/time formatter
|
||||
* @throws IllegalArgumentException if pattern is invalid or {@code null}
|
||||
*/
|
||||
public static FastDateFormat getInstance(final String pattern, final TimeZone timeZone, final Locale locale) {
|
||||
return cache.getInstance(pattern, timeZone, locale);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* <p>
|
||||
* Gets a date formatter instance using the specified style in the default time
|
||||
* zone and locale.
|
||||
* </p>
|
||||
*
|
||||
* @param style date style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @return a localized standard date formatter
|
||||
* @throws IllegalArgumentException if the Locale has no date pattern defined
|
||||
* @since 2.1
|
||||
*/
|
||||
public static FastDateFormat getDateInstance(final int style) {
|
||||
return cache.getDateInstance(style, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Gets a date formatter instance using the specified style and locale in the
|
||||
* default time zone.
|
||||
* </p>
|
||||
*
|
||||
* @param style date style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @param locale optional locale, overrides system locale
|
||||
* @return a localized standard date formatter
|
||||
* @throws IllegalArgumentException if the Locale has no date pattern defined
|
||||
* @since 2.1
|
||||
*/
|
||||
public static FastDateFormat getDateInstance(final int style, final Locale locale) {
|
||||
return cache.getDateInstance(style, null, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Gets a date formatter instance using the specified style and time zone in the
|
||||
* default locale.
|
||||
* </p>
|
||||
*
|
||||
* @param style date style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @param timeZone optional time zone, overrides time zone of formatted date
|
||||
* @return a localized standard date formatter
|
||||
* @throws IllegalArgumentException if the Locale has no date pattern defined
|
||||
* @since 2.1
|
||||
*/
|
||||
public static FastDateFormat getDateInstance(final int style, final TimeZone timeZone) {
|
||||
return cache.getDateInstance(style, timeZone, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Gets a date formatter instance using the specified style, time zone and
|
||||
* locale.
|
||||
* </p>
|
||||
*
|
||||
* @param style date style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @param timeZone optional time zone, overrides time zone of formatted date
|
||||
* @param locale optional locale, overrides system locale
|
||||
* @return a localized standard date formatter
|
||||
* @throws IllegalArgumentException if the Locale has no date pattern defined
|
||||
*/
|
||||
public static FastDateFormat getDateInstance(final int style, final TimeZone timeZone, final Locale locale) {
|
||||
return cache.getDateInstance(style, timeZone, locale);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* <p>
|
||||
* Gets a time formatter instance using the specified style in the default time
|
||||
* zone and locale.
|
||||
* </p>
|
||||
*
|
||||
* @param style time style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @return a localized standard time formatter
|
||||
* @throws IllegalArgumentException if the Locale has no time pattern defined
|
||||
* @since 2.1
|
||||
*/
|
||||
public static FastDateFormat getTimeInstance(final int style) {
|
||||
return cache.getTimeInstance(style, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Gets a time formatter instance using the specified style and locale in the
|
||||
* default time zone.
|
||||
* </p>
|
||||
*
|
||||
* @param style time style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @param locale optional locale, overrides system locale
|
||||
* @return a localized standard time formatter
|
||||
* @throws IllegalArgumentException if the Locale has no time pattern defined
|
||||
* @since 2.1
|
||||
*/
|
||||
public static FastDateFormat getTimeInstance(final int style, final Locale locale) {
|
||||
return cache.getTimeInstance(style, null, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Gets a time formatter instance using the specified style and time zone in the
|
||||
* default locale.
|
||||
* </p>
|
||||
*
|
||||
* @param style time style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @param timeZone optional time zone, overrides time zone of formatted time
|
||||
* @return a localized standard time formatter
|
||||
* @throws IllegalArgumentException if the Locale has no time pattern defined
|
||||
* @since 2.1
|
||||
*/
|
||||
public static FastDateFormat getTimeInstance(final int style, final TimeZone timeZone) {
|
||||
return cache.getTimeInstance(style, timeZone, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Gets a time formatter instance using the specified style, time zone and
|
||||
* locale.
|
||||
* </p>
|
||||
*
|
||||
* @param style time style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @param timeZone optional time zone, overrides time zone of formatted time
|
||||
* @param locale optional locale, overrides system locale
|
||||
* @return a localized standard time formatter
|
||||
* @throws IllegalArgumentException if the Locale has no time pattern defined
|
||||
*/
|
||||
public static FastDateFormat getTimeInstance(final int style, final TimeZone timeZone, final Locale locale) {
|
||||
return cache.getTimeInstance(style, timeZone, locale);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* <p>
|
||||
* Gets a date/time formatter instance using the specified style in the default
|
||||
* time zone and locale.
|
||||
* </p>
|
||||
*
|
||||
* @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @return a localized standard date/time formatter
|
||||
* @throws IllegalArgumentException if the Locale has no date/time pattern
|
||||
* defined
|
||||
* @since 2.1
|
||||
*/
|
||||
public static FastDateFormat getDateTimeInstance(final int dateStyle, final int timeStyle) {
|
||||
return cache.getDateTimeInstance(dateStyle, timeStyle, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Gets a date/time formatter instance using the specified style and locale in
|
||||
* the default time zone.
|
||||
* </p>
|
||||
*
|
||||
* @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @param locale optional locale, overrides system locale
|
||||
* @return a localized standard date/time formatter
|
||||
* @throws IllegalArgumentException if the Locale has no date/time pattern
|
||||
* defined
|
||||
* @since 2.1
|
||||
*/
|
||||
public static FastDateFormat getDateTimeInstance(final int dateStyle, final int timeStyle, final Locale locale) {
|
||||
return cache.getDateTimeInstance(dateStyle, timeStyle, null, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Gets a date/time formatter instance using the specified style and time zone
|
||||
* in the default locale.
|
||||
* </p>
|
||||
*
|
||||
* @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @param timeZone optional time zone, overrides time zone of formatted date
|
||||
* @return a localized standard date/time formatter
|
||||
* @throws IllegalArgumentException if the Locale has no date/time pattern
|
||||
* defined
|
||||
* @since 2.1
|
||||
*/
|
||||
public static FastDateFormat getDateTimeInstance(final int dateStyle, final int timeStyle,
|
||||
final TimeZone timeZone) {
|
||||
return getDateTimeInstance(dateStyle, timeStyle, timeZone, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Gets a date/time formatter instance using the specified style, time zone and
|
||||
* locale.
|
||||
* </p>
|
||||
*
|
||||
* @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @param timeZone optional time zone, overrides time zone of formatted date
|
||||
* @param locale optional locale, overrides system locale
|
||||
* @return a localized standard date/time formatter
|
||||
* @throws IllegalArgumentException if the Locale has no date/time pattern
|
||||
* defined
|
||||
*/
|
||||
public static FastDateFormat getDateTimeInstance(final int dateStyle, final int timeStyle, final TimeZone timeZone,
|
||||
final Locale locale) {
|
||||
return cache.getDateTimeInstance(dateStyle, timeStyle, timeZone, locale);
|
||||
}
|
||||
|
||||
// Constructor
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* <p>
|
||||
* Constructs a new FastDateFormat.
|
||||
* </p>
|
||||
*
|
||||
* @param pattern {@link java.text.SimpleDateFormat} compatible pattern
|
||||
* @param timeZone non-null time zone to use
|
||||
* @param locale non-null locale to use
|
||||
* @throws NullPointerException if pattern, timeZone, or locale is null.
|
||||
*/
|
||||
protected FastDateFormat(final String pattern, final TimeZone timeZone, final Locale locale) {
|
||||
this(pattern, timeZone, locale, null);
|
||||
}
|
||||
|
||||
// Constructor
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* <p>
|
||||
* Constructs a new FastDateFormat.
|
||||
* </p>
|
||||
*
|
||||
* @param pattern {@link java.text.SimpleDateFormat} compatible pattern
|
||||
* @param timeZone non-null time zone to use
|
||||
* @param locale non-null locale to use
|
||||
* @param centuryStart The start of the 100 year period to use as the "default
|
||||
* century" for 2 digit year parsing. If centuryStart is
|
||||
* null, defaults to now - 80 years
|
||||
* @throws NullPointerException if pattern, timeZone, or locale is null.
|
||||
*/
|
||||
protected FastDateFormat(final String pattern, final TimeZone timeZone, final Locale locale,
|
||||
final Date centuryStart) {
|
||||
printer = new FastDatePrinter(pattern, timeZone, locale);
|
||||
parser = new FastDateParser(pattern, timeZone, locale, centuryStart);
|
||||
}
|
||||
|
||||
// Format methods
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* <p>
|
||||
* Formats a {@code Date}, {@code Calendar} or {@code Long} (milliseconds)
|
||||
* object.
|
||||
* </p>
|
||||
* This method is an implementation of
|
||||
* {@link Format#format(Object, StringBuffer, FieldPosition)}
|
||||
*
|
||||
* @param obj the object to format
|
||||
* @param toAppendTo the buffer to append to
|
||||
* @param pos the position - ignored
|
||||
* @return the buffer passed in
|
||||
*/
|
||||
@Override
|
||||
public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) {
|
||||
return toAppendTo.append(printer.format(obj));
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats a millisecond {@code long} value.
|
||||
* </p>
|
||||
*
|
||||
* @param millis the millisecond value to format
|
||||
* @return the formatted string
|
||||
* @since 2.1
|
||||
*/
|
||||
@Override
|
||||
public String format(final long millis) {
|
||||
return printer.format(millis);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats a {@code Date} object using a {@code GregorianCalendar}.
|
||||
* </p>
|
||||
*
|
||||
* @param date the date to format
|
||||
* @return the formatted string
|
||||
*/
|
||||
@Override
|
||||
public String format(final Date date) {
|
||||
return printer.format(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats a {@code Calendar} object.
|
||||
* </p>
|
||||
*
|
||||
* @param calendar the calendar to format
|
||||
* @return the formatted string
|
||||
*/
|
||||
@Override
|
||||
public String format(final Calendar calendar) {
|
||||
return printer.format(calendar);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats a millisecond {@code long} value into the supplied
|
||||
* {@code StringBuffer}.
|
||||
* </p>
|
||||
*
|
||||
* @param millis the millisecond value to format
|
||||
* @param buf the buffer to format into
|
||||
* @return the specified string buffer
|
||||
* @since 2.1
|
||||
* @deprecated Use {{@link #format(long, Appendable)}.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public StringBuffer format(final long millis, final StringBuffer buf) {
|
||||
return printer.format(millis, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats a {@code Date} object into the supplied {@code StringBuffer} using a
|
||||
* {@code GregorianCalendar}.
|
||||
* </p>
|
||||
*
|
||||
* @param date the date to format
|
||||
* @param buf the buffer to format into
|
||||
* @return the specified string buffer
|
||||
* @deprecated Use {{@link #format(Date, Appendable)}.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public StringBuffer format(final Date date, final StringBuffer buf) {
|
||||
return printer.format(date, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats a {@code Calendar} object into the supplied {@code StringBuffer}.
|
||||
* </p>
|
||||
*
|
||||
* @param calendar the calendar to format
|
||||
* @param buf the buffer to format into
|
||||
* @return the specified string buffer
|
||||
* @deprecated Use {{@link #format(Calendar, Appendable)}.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public StringBuffer format(final Calendar calendar, final StringBuffer buf) {
|
||||
return printer.format(calendar, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats a millisecond {@code long} value into the supplied
|
||||
* {@code StringBuffer}.
|
||||
* </p>
|
||||
*
|
||||
* @param millis the millisecond value to format
|
||||
* @param buf the buffer to format into
|
||||
* @return the specified string buffer
|
||||
* @since 3.5
|
||||
*/
|
||||
@Override
|
||||
public <B extends Appendable> B format(final long millis, final B buf) {
|
||||
return printer.format(millis, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats a {@code Date} object into the supplied {@code StringBuffer} using a
|
||||
* {@code GregorianCalendar}.
|
||||
* </p>
|
||||
*
|
||||
* @param date the date to format
|
||||
* @param buf the buffer to format into
|
||||
* @return the specified string buffer
|
||||
* @since 3.5
|
||||
*/
|
||||
@Override
|
||||
public <B extends Appendable> B format(final Date date, final B buf) {
|
||||
return printer.format(date, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Formats a {@code Calendar} object into the supplied {@code StringBuffer}.
|
||||
* </p>
|
||||
*
|
||||
* @param calendar the calendar to format
|
||||
* @param buf the buffer to format into
|
||||
* @return the specified string buffer
|
||||
* @since 3.5
|
||||
*/
|
||||
@Override
|
||||
public <B extends Appendable> B format(final Calendar calendar, final B buf) {
|
||||
return printer.format(calendar, buf);
|
||||
}
|
||||
|
||||
// Parsing
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see DateParser#parse(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public Date parse(final String source) throws ParseException {
|
||||
return parser.parse(source);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see DateParser#parse(java.lang.String, java.text.ParsePosition)
|
||||
*/
|
||||
@Override
|
||||
public Date parse(final String source, final ParsePosition pos) {
|
||||
return parser.parse(source, pos);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.apache.commons.lang3.time.DateParser#parse(java.lang.String,
|
||||
* java.text.ParsePosition, java.util.Calendar)
|
||||
*/
|
||||
@Override
|
||||
public boolean parse(final String source, final ParsePosition pos, final Calendar calendar) {
|
||||
return parser.parse(source, pos, calendar);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see java.text.Format#parseObject(java.lang.String, java.text.ParsePosition)
|
||||
*/
|
||||
@Override
|
||||
public Object parseObject(final String source, final ParsePosition pos) {
|
||||
return parser.parseObject(source, pos);
|
||||
}
|
||||
|
||||
// Accessors
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* <p>
|
||||
* Gets the pattern used by this formatter.
|
||||
* </p>
|
||||
*
|
||||
* @return the pattern, {@link java.text.SimpleDateFormat} compatible
|
||||
*/
|
||||
@Override
|
||||
public String getPattern() {
|
||||
return printer.getPattern();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Gets the time zone used by this formatter.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This zone is always used for {@code Date} formatting.
|
||||
* </p>
|
||||
*
|
||||
* @return the time zone
|
||||
*/
|
||||
@Override
|
||||
public TimeZone getTimeZone() {
|
||||
return printer.getTimeZone();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Gets the locale used by this formatter.
|
||||
* </p>
|
||||
*
|
||||
* @return the locale
|
||||
*/
|
||||
@Override
|
||||
public Locale getLocale() {
|
||||
return printer.getLocale();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Gets an estimate for the maximum string length that the formatter will
|
||||
* produce.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The actual formatted length will almost always be less than or equal to this
|
||||
* amount.
|
||||
* </p>
|
||||
*
|
||||
* @return the maximum formatted length
|
||||
*/
|
||||
public int getMaxLengthEstimate() {
|
||||
return printer.getMaxLengthEstimate();
|
||||
}
|
||||
|
||||
// Basics
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* <p>
|
||||
* Compares two objects for equality.
|
||||
* </p>
|
||||
*
|
||||
* @param obj the object to compare to
|
||||
* @return {@code true} if equal
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (!(obj instanceof FastDateFormat)) {
|
||||
return false;
|
||||
}
|
||||
final FastDateFormat other = (FastDateFormat) obj;
|
||||
// no need to check parser, as it has same invariants as printer
|
||||
return printer.equals(other.printer);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Returns a hash code compatible with equals.
|
||||
* </p>
|
||||
*
|
||||
* @return a hash code compatible with equals
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return printer.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Gets a debugging string version of this formatter.
|
||||
* </p>
|
||||
*
|
||||
* @return a debugging string
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "FastDateFormat[" + printer.getPattern() + "," + printer.getLocale() + ","
|
||||
+ printer.getTimeZone().getID() + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Performs the formatting by applying the rules to the specified calendar.
|
||||
* </p>
|
||||
*
|
||||
* @param calendar the calendar to format
|
||||
* @param buf the buffer to format into
|
||||
* @return the specified string buffer
|
||||
* @deprecated Use {@link #format(Calendar, Appendable)}
|
||||
*/
|
||||
@Deprecated
|
||||
protected StringBuffer applyRules(final Calendar calendar, final StringBuffer buf) {
|
||||
return printer.applyRules(calendar, buf);
|
||||
}
|
||||
}
|
1122
sources/main/java/org/apache/commons/lang3/time/FastDateParser.java
Normal file
1122
sources/main/java/org/apache/commons/lang3/time/FastDateParser.java
Normal file
File diff suppressed because it is too large
Load Diff
1697
sources/main/java/org/apache/commons/lang3/time/FastDatePrinter.java
Normal file
1697
sources/main/java/org/apache/commons/lang3/time/FastDatePrinter.java
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.commons.lang3.time;
|
||||
|
||||
import java.util.TimeZone;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Faster methods to produce custom time zones.
|
||||
*
|
||||
* @since 3.7
|
||||
*/
|
||||
public class FastTimeZone {
|
||||
|
||||
private static final Pattern GMT_PATTERN = Pattern.compile("^(?:(?i)GMT)?([+-])?(\\d\\d?)?(:?(\\d\\d?))?$");
|
||||
|
||||
private static final TimeZone GREENWICH = new GmtTimeZone(false, 0, 0);
|
||||
|
||||
/**
|
||||
* Gets the GMT TimeZone.
|
||||
*
|
||||
* @return A TimeZone with a raw offset of zero.
|
||||
*/
|
||||
public static TimeZone getGmtTimeZone() {
|
||||
return GREENWICH;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a TimeZone with GMT offsets. A GMT offset must be either 'Z', or 'UTC',
|
||||
* or match <em>(GMT)? hh?(:?mm?)?</em>, where h and m are digits representing
|
||||
* hours and minutes.
|
||||
*
|
||||
* @param pattern The GMT offset
|
||||
* @return A TimeZone with offset from GMT or null, if pattern does not match.
|
||||
*/
|
||||
public static TimeZone getGmtTimeZone(final String pattern) {
|
||||
if ("Z".equals(pattern) || "UTC".equals(pattern)) {
|
||||
return GREENWICH;
|
||||
}
|
||||
|
||||
final Matcher m = GMT_PATTERN.matcher(pattern);
|
||||
if (m.matches()) {
|
||||
final int hours = parseInt(m.group(2));
|
||||
final int minutes = parseInt(m.group(4));
|
||||
if (hours == 0 && minutes == 0) {
|
||||
return GREENWICH;
|
||||
}
|
||||
return new GmtTimeZone(parseSign(m.group(1)), hours, minutes);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a TimeZone, looking first for GMT custom ids, then falling back to Olson
|
||||
* ids. A GMT custom id can be 'Z', or 'UTC', or has an optional prefix of GMT,
|
||||
* followed by sign, hours digit(s), optional colon(':'), and optional minutes
|
||||
* digits. i.e. <em>[GMT] (+|-) Hours [[:] Minutes]</em>
|
||||
*
|
||||
* @param id A GMT custom id (or Olson id
|
||||
* @return A time zone
|
||||
*/
|
||||
public static TimeZone getTimeZone(final String id) {
|
||||
final TimeZone tz = getGmtTimeZone(id);
|
||||
if (tz != null) {
|
||||
return tz;
|
||||
}
|
||||
return TimeZone.getTimeZone(id);
|
||||
}
|
||||
|
||||
private static int parseInt(final String group) {
|
||||
return group != null ? Integer.parseInt(group) : 0;
|
||||
}
|
||||
|
||||
private static boolean parseSign(final String group) {
|
||||
return group != null && group.charAt(0) == '-';
|
||||
}
|
||||
|
||||
// do not instantiate
|
||||
private FastTimeZone() {
|
||||
}
|
||||
|
||||
}
|
270
sources/main/java/org/apache/commons/lang3/time/FormatCache.java
Normal file
270
sources/main/java/org/apache/commons/lang3/time/FormatCache.java
Normal file
@ -0,0 +1,270 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.commons.lang3.time;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.Format;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.apache.commons.lang3.LocaleUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
/**
|
||||
* FormatCache is a cache and factory for {@link Format}s.
|
||||
*
|
||||
* @since 3.0
|
||||
*/
|
||||
// TODO: Before making public move from getDateTimeInstance(Integer, ...) to int; or some other approach.
|
||||
abstract class FormatCache<F extends Format> {
|
||||
|
||||
/**
|
||||
* No date or no time. Used in same parameters as DateFormat.SHORT or
|
||||
* DateFormat.LONG
|
||||
*/
|
||||
static final int NONE = -1;
|
||||
|
||||
private final Map<ArrayKey, F> cInstanceCache = new HashMap<>(7);
|
||||
|
||||
private static final Map<ArrayKey, String> cDateTimeInstanceCache = new HashMap<>(7);
|
||||
|
||||
/**
|
||||
* Gets a formatter instance using the default pattern in the default time zone
|
||||
* and locale.
|
||||
*
|
||||
* @return a date/time formatter
|
||||
*/
|
||||
public F getInstance() {
|
||||
return getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, TimeZone.getDefault(), Locale.getDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a formatter instance using the specified pattern, time zone and locale.
|
||||
*
|
||||
* @param pattern {@link java.text.SimpleDateFormat} compatible pattern,
|
||||
* non-null
|
||||
* @param timeZone the time zone, null means use the default TimeZone
|
||||
* @param locale the locale, null means use the default Locale
|
||||
* @return a pattern based date/time formatter
|
||||
* @throws NullPointerException if pattern is {@code null}
|
||||
* @throws IllegalArgumentException if pattern is invalid
|
||||
*/
|
||||
public F getInstance(final String pattern, TimeZone timeZone, Locale locale) {
|
||||
Validate.notNull(pattern, "pattern");
|
||||
if (timeZone == null) {
|
||||
timeZone = TimeZone.getDefault();
|
||||
}
|
||||
locale = LocaleUtils.toLocale(locale);
|
||||
final ArrayKey key = new ArrayKey(pattern, timeZone, locale);
|
||||
F format = cInstanceCache.get(key);
|
||||
if (format == null) {
|
||||
format = createInstance(pattern, timeZone, locale);
|
||||
final F previousValue = cInstanceCache.putIfAbsent(key, format);
|
||||
if (previousValue != null) {
|
||||
// another thread snuck in and did the same work
|
||||
// we should return the instance that is in ConcurrentMap
|
||||
format = previousValue;
|
||||
}
|
||||
}
|
||||
return format;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a format instance using the specified pattern, time zone and locale.
|
||||
*
|
||||
* @param pattern {@link java.text.SimpleDateFormat} compatible pattern, this
|
||||
* will not be null.
|
||||
* @param timeZone time zone, this will not be null.
|
||||
* @param locale locale, this will not be null.
|
||||
* @return a pattern based date/time formatter
|
||||
* @throws IllegalArgumentException if pattern is invalid or {@code null}
|
||||
*/
|
||||
protected abstract F createInstance(String pattern, TimeZone timeZone, Locale locale);
|
||||
|
||||
/**
|
||||
* Gets a date/time formatter instance using the specified style, time zone and
|
||||
* locale.
|
||||
*
|
||||
* @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT, null indicates no
|
||||
* date in format
|
||||
* @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT, null indicates no
|
||||
* time in format
|
||||
* @param timeZone optional time zone, overrides time zone of formatted date,
|
||||
* null means use default Locale
|
||||
* @param locale optional locale, overrides system locale
|
||||
* @return a localized standard date/time formatter
|
||||
* @throws IllegalArgumentException if the Locale has no date/time pattern
|
||||
* defined
|
||||
*/
|
||||
// This must remain private, see LANG-884
|
||||
private F getDateTimeInstance(final Integer dateStyle, final Integer timeStyle, final TimeZone timeZone,
|
||||
Locale locale) {
|
||||
locale = LocaleUtils.toLocale(locale);
|
||||
final String pattern = getPatternForStyle(dateStyle, timeStyle, locale);
|
||||
return getInstance(pattern, timeZone, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a date/time formatter instance using the specified style, time zone and
|
||||
* locale.
|
||||
*
|
||||
* @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @param timeZone optional time zone, overrides time zone of formatted date,
|
||||
* null means use default Locale
|
||||
* @param locale optional locale, overrides system locale
|
||||
* @return a localized standard date/time formatter
|
||||
* @throws IllegalArgumentException if the Locale has no date/time pattern
|
||||
* defined
|
||||
*/
|
||||
// package protected, for access from FastDateFormat; do not make public or
|
||||
// protected
|
||||
F getDateTimeInstance(final int dateStyle, final int timeStyle, final TimeZone timeZone, final Locale locale) {
|
||||
return getDateTimeInstance(Integer.valueOf(dateStyle), Integer.valueOf(timeStyle), timeZone, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a date formatter instance using the specified style, time zone and
|
||||
* locale.
|
||||
*
|
||||
* @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @param timeZone optional time zone, overrides time zone of formatted date,
|
||||
* null means use default Locale
|
||||
* @param locale optional locale, overrides system locale
|
||||
* @return a localized standard date/time formatter
|
||||
* @throws IllegalArgumentException if the Locale has no date/time pattern
|
||||
* defined
|
||||
*/
|
||||
// package protected, for access from FastDateFormat; do not make public or
|
||||
// protected
|
||||
F getDateInstance(final int dateStyle, final TimeZone timeZone, final Locale locale) {
|
||||
return getDateTimeInstance(Integer.valueOf(dateStyle), null, timeZone, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a time formatter instance using the specified style, time zone and
|
||||
* locale.
|
||||
*
|
||||
* @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @param timeZone optional time zone, overrides time zone of formatted date,
|
||||
* null means use default Locale
|
||||
* @param locale optional locale, overrides system locale
|
||||
* @return a localized standard date/time formatter
|
||||
* @throws IllegalArgumentException if the Locale has no date/time pattern
|
||||
* defined
|
||||
*/
|
||||
// package protected, for access from FastDateFormat; do not make public or
|
||||
// protected
|
||||
F getTimeInstance(final int timeStyle, final TimeZone timeZone, final Locale locale) {
|
||||
return getDateTimeInstance(null, Integer.valueOf(timeStyle), timeZone, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a date/time format for the specified styles and locale.
|
||||
*
|
||||
* @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT, null indicates no
|
||||
* date in format
|
||||
* @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT, null indicates no
|
||||
* time in format
|
||||
* @param locale The non-null locale of the desired format
|
||||
* @return a localized standard date/time format
|
||||
* @throws IllegalArgumentException if the Locale has no date/time pattern
|
||||
* defined
|
||||
*/
|
||||
// package protected, for access from test code; do not make public or protected
|
||||
static String getPatternForStyle(final Integer dateStyle, final Integer timeStyle, final Locale locale) {
|
||||
final Locale safeLocale = LocaleUtils.toLocale(locale);
|
||||
final ArrayKey key = new ArrayKey(dateStyle, timeStyle, safeLocale);
|
||||
|
||||
String pattern = cDateTimeInstanceCache.get(key);
|
||||
if (pattern == null) {
|
||||
try {
|
||||
final DateFormat formatter;
|
||||
if (dateStyle == null) {
|
||||
formatter = DateFormat.getTimeInstance(timeStyle.intValue(), safeLocale);
|
||||
} else if (timeStyle == null) {
|
||||
formatter = DateFormat.getDateInstance(dateStyle.intValue(), safeLocale);
|
||||
} else {
|
||||
formatter = DateFormat.getDateTimeInstance(dateStyle.intValue(), timeStyle.intValue(), safeLocale);
|
||||
}
|
||||
pattern = ((SimpleDateFormat) formatter).toPattern();
|
||||
final String previous = cDateTimeInstanceCache.putIfAbsent(key, pattern);
|
||||
if (previous != null) {
|
||||
// even though it doesn't matter if another thread put the pattern
|
||||
// it's still good practice to return the String instance that is
|
||||
// actually in the ConcurrentMap
|
||||
pattern = previous;
|
||||
}
|
||||
} catch (final ClassCastException ex) {
|
||||
throw new IllegalArgumentException("No date time pattern for locale: " + safeLocale);
|
||||
}
|
||||
}
|
||||
return pattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class to hold multi-part Map keys as arrays.
|
||||
*/
|
||||
private static final class ArrayKey {
|
||||
|
||||
private static int computeHashCode(final Object[] keys) {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + Arrays.hashCode(keys);
|
||||
return result;
|
||||
}
|
||||
|
||||
private final Object[] keys;
|
||||
private final int hashCode;
|
||||
|
||||
/**
|
||||
* Constructs an instance of {@code MultipartKey} to hold the specified objects.
|
||||
*
|
||||
* @param keys the set of objects that make up the key. Each key may be null.
|
||||
*/
|
||||
ArrayKey(final Object... keys) {
|
||||
this.keys = keys;
|
||||
this.hashCode = computeHashCode(keys);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final ArrayKey other = (ArrayKey) obj;
|
||||
return Arrays.deepEquals(keys, other.keys);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
105
sources/main/java/org/apache/commons/lang3/time/GmtTimeZone.java
Normal file
105
sources/main/java/org/apache/commons/lang3/time/GmtTimeZone.java
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.commons.lang3.time;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* Custom time zone that contains offset from GMT.
|
||||
*
|
||||
* @since 3.7
|
||||
*/
|
||||
class GmtTimeZone extends TimeZone {
|
||||
|
||||
private static final int MILLISECONDS_PER_MINUTE = 60 * 1000;
|
||||
private static final int MINUTES_PER_HOUR = 60;
|
||||
private static final int HOURS_PER_DAY = 24;
|
||||
|
||||
// Serializable!
|
||||
static final long serialVersionUID = 1L;
|
||||
|
||||
private final int offset;
|
||||
private final String zoneId;
|
||||
|
||||
GmtTimeZone(final boolean negate, final int hours, final int minutes) {
|
||||
if (hours >= HOURS_PER_DAY) {
|
||||
throw new IllegalArgumentException(hours + " hours out of range");
|
||||
}
|
||||
if (minutes >= MINUTES_PER_HOUR) {
|
||||
throw new IllegalArgumentException(minutes + " minutes out of range");
|
||||
}
|
||||
final int milliseconds = (minutes + (hours * MINUTES_PER_HOUR)) * MILLISECONDS_PER_MINUTE;
|
||||
offset = negate ? -milliseconds : milliseconds;
|
||||
zoneId = twoDigits(twoDigits(new StringBuilder(9).append("GMT").append(negate ? '-' : '+'), hours).append(':'),
|
||||
minutes).toString();
|
||||
|
||||
}
|
||||
|
||||
private static StringBuilder twoDigits(final StringBuilder sb, final int n) {
|
||||
return sb.append((char) ('0' + (n / 10))).append((char) ('0' + (n % 10)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOffset(final int era, final int year, final int month, final int day, final int dayOfWeek,
|
||||
final int milliseconds) {
|
||||
return offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRawOffset(final int offsetMillis) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRawOffset() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getID() {
|
||||
return zoneId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useDaylightTime() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inDaylightTime(final Date date) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[GmtTimeZone id=\"" + zoneId + "\",offset=" + offset + ']';
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object other) {
|
||||
if (!(other instanceof GmtTimeZone)) {
|
||||
return false;
|
||||
}
|
||||
return zoneId == ((GmtTimeZone) other).zoneId;
|
||||
}
|
||||
}
|
650
sources/main/java/org/apache/commons/lang3/time/StopWatch.java
Normal file
650
sources/main/java/org/apache/commons/lang3/time/StopWatch.java
Normal file
@ -0,0 +1,650 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.commons.lang3.time;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* {@code StopWatch} provides a convenient API for timings.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* To start the watch, call {@link #start()} or
|
||||
* {@link StopWatch#createStarted()}. At this point you can:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>{@link #split()} the watch to get the time whilst the watch continues in
|
||||
* the background. {@link #unsplit()} will remove the effect of the split. At
|
||||
* this point, these three options are available again.</li>
|
||||
* <li>{@link #suspend()} the watch to pause it. {@link #resume()} allows the
|
||||
* watch to continue. Any time between the suspend and resume will not be
|
||||
* counted in the total. At this point, these three options are available
|
||||
* again.</li>
|
||||
* <li>{@link #stop()} the watch to complete the timing session.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* It is intended that the output methods {@link #toString()} and
|
||||
* {@link #getTime()} should only be called after stop, split or suspend,
|
||||
* however a suitable result will be returned at other points.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* NOTE: As from v2.1, the methods protect against inappropriate calls. Thus you
|
||||
* cannot now call stop before start, resume before suspend or unsplit before
|
||||
* split.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* 1. split(), suspend(), or stop() cannot be invoked twice<br>
|
||||
* 2. unsplit() may only be called if the watch has been split()<br>
|
||||
* 3. resume() may only be called if the watch has been suspend()<br>
|
||||
* 4. start() cannot be called twice without calling reset()
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This class is not thread-safe
|
||||
* </p>
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public class StopWatch {
|
||||
|
||||
/**
|
||||
* Enumeration type which indicates the split status of stopwatch.
|
||||
*/
|
||||
private enum SplitState {
|
||||
SPLIT, UNSPLIT
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumeration type which indicates the status of stopwatch.
|
||||
*/
|
||||
private enum State {
|
||||
|
||||
RUNNING {
|
||||
@Override
|
||||
boolean isStarted() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isStopped() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isSuspended() {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
STOPPED {
|
||||
@Override
|
||||
boolean isStarted() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isStopped() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isSuspended() {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
SUSPENDED {
|
||||
@Override
|
||||
boolean isStarted() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isStopped() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isSuspended() {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
UNSTARTED {
|
||||
@Override
|
||||
boolean isStarted() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isStopped() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isSuspended() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Returns whether the StopWatch is started. A suspended StopWatch is also
|
||||
* started watch.
|
||||
* </p>
|
||||
*
|
||||
* @return boolean If the StopWatch is started.
|
||||
*/
|
||||
abstract boolean isStarted();
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Returns whether the StopWatch is stopped. The stopwatch which's not yet
|
||||
* started and explicitly stopped stopwatch is considered as stopped.
|
||||
* </p>
|
||||
*
|
||||
* @return boolean If the StopWatch is stopped.
|
||||
*/
|
||||
abstract boolean isStopped();
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Returns whether the StopWatch is suspended.
|
||||
* </p>
|
||||
*
|
||||
* @return boolean If the StopWatch is suspended.
|
||||
*/
|
||||
abstract boolean isSuspended();
|
||||
}
|
||||
|
||||
private static final long NANO_2_MILLIS = 1000000L;
|
||||
|
||||
/**
|
||||
* Creates a stopwatch for convenience.
|
||||
*
|
||||
* @return StopWatch a stopwatch.
|
||||
*
|
||||
* @since 3.10
|
||||
*/
|
||||
public static StopWatch create() {
|
||||
return new StopWatch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a started stopwatch for convenience.
|
||||
*
|
||||
* @return StopWatch a stopwatch that's already been started.
|
||||
*
|
||||
* @since 3.5
|
||||
*/
|
||||
public static StopWatch createStarted() {
|
||||
final StopWatch sw = new StopWatch();
|
||||
sw.start();
|
||||
return sw;
|
||||
}
|
||||
|
||||
/**
|
||||
* A message for string presentation.
|
||||
*
|
||||
* @since 3.10
|
||||
*/
|
||||
private final String message;
|
||||
|
||||
/**
|
||||
* The current running state of the StopWatch.
|
||||
*/
|
||||
private State runningState = State.UNSTARTED;
|
||||
|
||||
/**
|
||||
* Whether the stopwatch has a split time recorded.
|
||||
*/
|
||||
private SplitState splitState = SplitState.UNSPLIT;
|
||||
|
||||
/**
|
||||
* The start time in nanoseconds.
|
||||
*/
|
||||
private long startTimeNanos;
|
||||
|
||||
/**
|
||||
* The start time in milliseconds - nanoTime is only for elapsed time so we need
|
||||
* to also store the currentTimeMillis to maintain the old getStartTime API.
|
||||
*/
|
||||
private long startTimeMillis;
|
||||
|
||||
/**
|
||||
* The end time in milliseconds - nanoTime is only for elapsed time so we need
|
||||
* to also store the currentTimeMillis to maintain the old getStartTime API.
|
||||
*/
|
||||
private long stopTimeMillis;
|
||||
|
||||
/**
|
||||
* The stop time in nanoseconds.
|
||||
*/
|
||||
private long stopTimeNanos;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Constructor.
|
||||
* </p>
|
||||
*/
|
||||
public StopWatch() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Constructor.
|
||||
* </p>
|
||||
*
|
||||
* @param message A message for string presentation.
|
||||
* @since 3.10
|
||||
*/
|
||||
public StopWatch(final String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time formatted by {@link DurationFormatUtils#formatDurationHMS}.
|
||||
*
|
||||
* @return the time formatted by {@link DurationFormatUtils#formatDurationHMS}.
|
||||
* @since 3.10
|
||||
*/
|
||||
public String formatSplitTime() {
|
||||
return DurationFormatUtils.formatDurationHMS(getSplitTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the split time formatted by
|
||||
* {@link DurationFormatUtils#formatDurationHMS}.
|
||||
*
|
||||
* @return the split time formatted by
|
||||
* {@link DurationFormatUtils#formatDurationHMS}.
|
||||
* @since 3.10
|
||||
*/
|
||||
public String formatTime() {
|
||||
return DurationFormatUtils.formatDurationHMS(getTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the message for string presentation.
|
||||
*
|
||||
* @return the message for string presentation.
|
||||
* @since 3.10
|
||||
*/
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Gets the <em>elapsed</em> time in nanoseconds.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This is either the time between the start and the moment this method is
|
||||
* called, or the amount of time between start and stop.
|
||||
* </p>
|
||||
*
|
||||
* @return the <em>elapsed</em> time in nanoseconds.
|
||||
* @see System#nanoTime()
|
||||
* @since 3.0
|
||||
*/
|
||||
public long getNanoTime() {
|
||||
if (this.runningState == State.STOPPED || this.runningState == State.SUSPENDED) {
|
||||
return this.stopTimeNanos - this.startTimeNanos;
|
||||
} else if (this.runningState == State.UNSTARTED) {
|
||||
return 0;
|
||||
} else if (this.runningState == State.RUNNING) {
|
||||
return System.nanoTime() - this.startTimeNanos;
|
||||
}
|
||||
throw new IllegalStateException("Illegal running state has occurred.");
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Gets the split time in nanoseconds.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This is the time between start and latest split.
|
||||
* </p>
|
||||
*
|
||||
* @return the split time in nanoseconds
|
||||
*
|
||||
* @throws IllegalStateException if the StopWatch has not yet been split.
|
||||
* @since 3.0
|
||||
*/
|
||||
public long getSplitNanoTime() {
|
||||
if (this.splitState != SplitState.SPLIT) {
|
||||
throw new IllegalStateException("Stopwatch must be split to get the split time.");
|
||||
}
|
||||
return this.stopTimeNanos - this.startTimeNanos;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Gets the split time on the stopwatch.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This is the time between start and latest split.
|
||||
* </p>
|
||||
*
|
||||
* @return the split time in milliseconds
|
||||
*
|
||||
* @throws IllegalStateException if the StopWatch has not yet been split.
|
||||
* @since 2.1
|
||||
*/
|
||||
public long getSplitTime() {
|
||||
return getSplitNanoTime() / NANO_2_MILLIS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the time this stopwatch was started in milliseconds, between the current
|
||||
* time and midnight, January 1, 1970 UTC.
|
||||
*
|
||||
* @return the time this stopwatch was started in milliseconds, between the
|
||||
* current time and midnight, January 1, 1970 UTC.
|
||||
* @throws IllegalStateException if this StopWatch has not been started
|
||||
* @since 2.4
|
||||
*/
|
||||
public long getStartTime() {
|
||||
if (this.runningState == State.UNSTARTED) {
|
||||
throw new IllegalStateException("Stopwatch has not been started");
|
||||
}
|
||||
// System.nanoTime is for elapsed time
|
||||
return this.startTimeMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the time this stopwatch was stopped in milliseconds, between the current
|
||||
* time and midnight, January 1, 1970 UTC.
|
||||
*
|
||||
* @return the time this stopwatch was started in milliseconds, between the
|
||||
* current time and midnight, January 1, 1970 UTC.
|
||||
* @throws IllegalStateException if this StopWatch has not been started
|
||||
* @since 3.12.0
|
||||
*/
|
||||
public long getStopTime() {
|
||||
if (this.runningState == State.UNSTARTED) {
|
||||
throw new IllegalStateException("Stopwatch has not been started");
|
||||
}
|
||||
// System.nanoTime is for elapsed time
|
||||
return this.stopTimeMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Gets the time on the stopwatch.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This is either the time between the start and the moment this method is
|
||||
* called, or the amount of time between start and stop.
|
||||
* </p>
|
||||
*
|
||||
* @return the time in milliseconds
|
||||
*/
|
||||
public long getTime() {
|
||||
return getNanoTime() / NANO_2_MILLIS;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Gets the time in the specified TimeUnit.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This is either the time between the start and the moment this method is
|
||||
* called, or the amount of time between start and stop. The resulting time will
|
||||
* be expressed in the desired TimeUnit with any remainder rounded down. For
|
||||
* example, if the specified unit is {@code TimeUnit.HOURS} and the stopwatch
|
||||
* time is 59 minutes, then the result returned will be {@code 0}.
|
||||
* </p>
|
||||
*
|
||||
* @param timeUnit the unit of time, not null
|
||||
* @return the time in the specified TimeUnit, rounded down
|
||||
* @since 3.5
|
||||
*/
|
||||
public long getTime(final TimeUnit timeUnit) {
|
||||
return timeUnit.convert(getNanoTime(), TimeUnit.NANOSECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Returns whether the StopWatch is started. A suspended StopWatch is also
|
||||
* started watch.
|
||||
* </p>
|
||||
*
|
||||
* @return boolean If the StopWatch is started.
|
||||
* @since 3.2
|
||||
*/
|
||||
public boolean isStarted() {
|
||||
return runningState.isStarted();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Returns whether StopWatch is stopped. The stopwatch which's not yet started
|
||||
* and explicitly stopped stopwatch is considered as stopped.
|
||||
* </p>
|
||||
*
|
||||
* @return boolean If the StopWatch is stopped.
|
||||
* @since 3.2
|
||||
*/
|
||||
public boolean isStopped() {
|
||||
return runningState.isStopped();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Returns whether the StopWatch is suspended.
|
||||
* </p>
|
||||
*
|
||||
* @return boolean If the StopWatch is suspended.
|
||||
* @since 3.2
|
||||
*/
|
||||
public boolean isSuspended() {
|
||||
return runningState.isSuspended();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Resets the stopwatch. Stops it if need be.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This method clears the internal values to allow the object to be reused.
|
||||
* </p>
|
||||
*/
|
||||
public void reset() {
|
||||
this.runningState = State.UNSTARTED;
|
||||
this.splitState = SplitState.UNSPLIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Resumes the stopwatch after a suspend.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This method resumes the watch after it was suspended. The watch will not
|
||||
* include time between the suspend and resume calls in the total time.
|
||||
* </p>
|
||||
*
|
||||
* @throws IllegalStateException if the StopWatch has not been suspended.
|
||||
*/
|
||||
public void resume() {
|
||||
if (this.runningState != State.SUSPENDED) {
|
||||
throw new IllegalStateException("Stopwatch must be suspended to resume. ");
|
||||
}
|
||||
this.startTimeNanos += System.nanoTime() - this.stopTimeNanos;
|
||||
this.runningState = State.RUNNING;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Splits the time.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This method sets the stop time of the watch to allow a time to be extracted.
|
||||
* The start time is unaffected, enabling {@link #unsplit()} to continue the
|
||||
* timing from the original start point.
|
||||
* </p>
|
||||
*
|
||||
* @throws IllegalStateException if the StopWatch is not running.
|
||||
*/
|
||||
public void split() {
|
||||
if (this.runningState != State.RUNNING) {
|
||||
throw new IllegalStateException("Stopwatch is not running. ");
|
||||
}
|
||||
this.stopTimeNanos = System.nanoTime();
|
||||
this.splitState = SplitState.SPLIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Starts the stopwatch.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This method starts a new timing session, clearing any previous values.
|
||||
* </p>
|
||||
*
|
||||
* @throws IllegalStateException if the StopWatch is already running.
|
||||
*/
|
||||
public void start() {
|
||||
if (this.runningState == State.STOPPED) {
|
||||
throw new IllegalStateException("Stopwatch must be reset before being restarted. ");
|
||||
}
|
||||
if (this.runningState != State.UNSTARTED) {
|
||||
throw new IllegalStateException("Stopwatch already started. ");
|
||||
}
|
||||
this.startTimeNanos = System.nanoTime();
|
||||
this.startTimeMillis = System.currentTimeMillis();
|
||||
this.runningState = State.RUNNING;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Stops the stopwatch.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This method ends a new timing session, allowing the time to be retrieved.
|
||||
* </p>
|
||||
*
|
||||
* @throws IllegalStateException if the StopWatch is not running.
|
||||
*/
|
||||
public void stop() {
|
||||
if (this.runningState != State.RUNNING && this.runningState != State.SUSPENDED) {
|
||||
throw new IllegalStateException("Stopwatch is not running. ");
|
||||
}
|
||||
if (this.runningState == State.RUNNING) {
|
||||
this.stopTimeNanos = System.nanoTime();
|
||||
this.stopTimeMillis = System.currentTimeMillis();
|
||||
}
|
||||
this.runningState = State.STOPPED;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Suspends the stopwatch for later resumption.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This method suspends the watch until it is resumed. The watch will not
|
||||
* include time between the suspend and resume calls in the total time.
|
||||
* </p>
|
||||
*
|
||||
* @throws IllegalStateException if the StopWatch is not currently running.
|
||||
*/
|
||||
public void suspend() {
|
||||
if (this.runningState != State.RUNNING) {
|
||||
throw new IllegalStateException("Stopwatch must be running to suspend. ");
|
||||
}
|
||||
this.stopTimeNanos = System.nanoTime();
|
||||
this.stopTimeMillis = System.currentTimeMillis();
|
||||
this.runningState = State.SUSPENDED;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Gets a summary of the split time that the stopwatch recorded as a string.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The format used is ISO 8601-like, [<i>message</i>
|
||||
* ]<i>hours</i>:<i>minutes</i>:<i>seconds</i>.<i>milliseconds</i>.
|
||||
* </p>
|
||||
*
|
||||
* @return the split time as a String
|
||||
* @since 2.1
|
||||
* @since 3.10 Returns the prefix {@code "message "} if the message is set.
|
||||
*/
|
||||
public String toSplitString() {
|
||||
final String msgStr = Objects.toString(message, StringUtils.EMPTY);
|
||||
final String formattedTime = formatSplitTime();
|
||||
return msgStr.isEmpty() ? formattedTime : msgStr + StringUtils.SPACE + formattedTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Gets a summary of the time that the stopwatch recorded as a string.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The format used is ISO 8601-like, [<i>message</i>
|
||||
* ]<i>hours</i>:<i>minutes</i>:<i>seconds</i>.<i>milliseconds</i>.
|
||||
* </p>
|
||||
*
|
||||
* @return the time as a String
|
||||
* @since 3.10 Returns the prefix {@code "message "} if the message is set.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
final String msgStr = Objects.toString(message, StringUtils.EMPTY);
|
||||
final String formattedTime = formatTime();
|
||||
return msgStr.isEmpty() ? formattedTime : msgStr + StringUtils.SPACE + formattedTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Removes a split.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This method clears the stop time. The start time is unaffected, enabling
|
||||
* timing from the original start point to continue.
|
||||
* </p>
|
||||
*
|
||||
* @throws IllegalStateException if the StopWatch has not been split.
|
||||
*/
|
||||
public void unsplit() {
|
||||
if (this.splitState != SplitState.SPLIT) {
|
||||
throw new IllegalStateException("Stopwatch has not been split. ");
|
||||
}
|
||||
this.splitState = SplitState.UNSPLIT;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.commons.lang3.time;
|
||||
|
||||
/**
|
||||
* Helps to deal with {@link java.util.TimeZone}s.
|
||||
*
|
||||
* @since 3.7
|
||||
*/
|
||||
public class TimeZones {
|
||||
|
||||
// do not instantiate
|
||||
private TimeZones() {
|
||||
}
|
||||
|
||||
/**
|
||||
* A public version of {@link java.util.TimeZone}'s package private
|
||||
* {@code GMT_ID} field.
|
||||
*/
|
||||
public static final String GMT_ID = "GMT";
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/**
|
||||
* <p>
|
||||
* Provides classes and methods to work with dates and durations. These classes
|
||||
* are immutable (and therefore thread-safe) apart from
|
||||
* {@link org.apache.commons.lang3.time.StopWatch}.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The time package contains some basic utilities for manipulating time (a
|
||||
* delorean, police box and grandfather clock?). These include a
|
||||
* {@link org.apache.commons.lang3.time.StopWatch} for simple performance
|
||||
* measurements and an optimised
|
||||
* {@link org.apache.commons.lang3.time.FastDateFormat} class.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* New in Lang 2.1 is the
|
||||
* {@link org.apache.commons.lang3.time.DurationFormatUtils} class, which
|
||||
* provides various methods for formatting durations.
|
||||
* </p>
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
package org.apache.commons.lang3.time;
|
Reference in New Issue
Block a user