From 8bbc46b9514f49ebf4b9533688ca296046563ef9 Mon Sep 17 00:00:00 2001 From: Gerald Barker Date: Sat, 3 Sep 2011 15:07:13 +0100 Subject: Remove Commons time package as we are using our own implementation --- .../apache/commons/lang3/time/DateFormatUtils.java | 320 ---- src/org/apache/commons/lang3/time/DateUtils.java | 1831 -------------------- .../commons/lang3/time/DurationFormatUtils.java | 662 ------- .../apache/commons/lang3/time/FastDateFormat.java | 1519 ---------------- src/org/apache/commons/lang3/time/FormatCache.java | 202 --- src/org/apache/commons/lang3/time/StopWatch.java | 382 ---- 6 files changed, 4916 deletions(-) delete mode 100644 src/org/apache/commons/lang3/time/DateFormatUtils.java delete mode 100644 src/org/apache/commons/lang3/time/DateUtils.java delete mode 100644 src/org/apache/commons/lang3/time/DurationFormatUtils.java delete mode 100644 src/org/apache/commons/lang3/time/FastDateFormat.java delete mode 100644 src/org/apache/commons/lang3/time/FormatCache.java delete mode 100644 src/org/apache/commons/lang3/time/StopWatch.java (limited to 'src') diff --git a/src/org/apache/commons/lang3/time/DateFormatUtils.java b/src/org/apache/commons/lang3/time/DateFormatUtils.java deleted file mode 100644 index b3b6541..0000000 --- a/src/org/apache/commons/lang3/time/DateFormatUtils.java +++ /dev/null @@ -1,320 +0,0 @@ -/* - * 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; - -/** - *

Date and time formatting utilities and constants.

- * - *

Formatting is performed using the thread-safe - * {@link org.apache.commons.lang3.time.FastDateFormat} class.

- * - * @since 2.0 - * @version $Id: DateFormatUtils.java 1088899 2011-04-05 05:31:27Z bayard $ - */ -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 = TimeZone.getTimeZone("GMT"); - /** - * ISO8601 formatter for date-time without time zone. - * The format used is yyyy-MM-dd'T'HH:mm:ss. - */ - public static final FastDateFormat ISO_DATETIME_FORMAT - = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss"); - - /** - * ISO8601 formatter for date-time with time zone. - * The format used is yyyy-MM-dd'T'HH:mm:ssZZ. - */ - public static final FastDateFormat ISO_DATETIME_TIME_ZONE_FORMAT - = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ssZZ"); - - /** - * ISO8601 formatter for date without time zone. - * The format used is yyyy-MM-dd. - */ - public static final FastDateFormat ISO_DATE_FORMAT - = FastDateFormat.getInstance("yyyy-MM-dd"); - - /** - * ISO8601-like formatter for date with time zone. - * The format used is yyyy-MM-ddZZ. - * This pattern does not comply with the formal ISO8601 specification - * as the standard does not allow a time zone without a time. - */ - public static final FastDateFormat ISO_DATE_TIME_ZONE_FORMAT - = FastDateFormat.getInstance("yyyy-MM-ddZZ"); - - /** - * ISO8601 formatter for time without time zone. - * The format used is 'T'HH:mm:ss. - */ - public static final FastDateFormat ISO_TIME_FORMAT - = FastDateFormat.getInstance("'T'HH:mm:ss"); - - /** - * ISO8601 formatter for time with time zone. - * The format used is 'T'HH:mm:ssZZ. - */ - public static final FastDateFormat ISO_TIME_TIME_ZONE_FORMAT - = FastDateFormat.getInstance("'T'HH:mm:ssZZ"); - - /** - * ISO8601-like formatter for time without time zone. - * The format used is HH:mm:ss. - * This pattern does not comply with the formal ISO8601 specification - * as the standard requires the 'T' prefix for times. - */ - public static final FastDateFormat ISO_TIME_NO_T_FORMAT - = FastDateFormat.getInstance("HH:mm:ss"); - - /** - * ISO8601-like formatter for time with time zone. - * The format used is HH:mm:ssZZ. - * This pattern does not comply with the formal ISO8601 specification - * as the standard requires the 'T' prefix for times. - */ - public static final FastDateFormat ISO_TIME_NO_T_TIME_ZONE_FORMAT - = FastDateFormat.getInstance("HH:mm:ssZZ"); - - /** - * SMTP (and probably other) date headers. - * The format used is EEE, dd MMM yyyy HH:mm:ss Z in US locale. - */ - public static final FastDateFormat SMTP_DATETIME_FORMAT - = FastDateFormat.getInstance("EEE, dd MMM yyyy HH:mm:ss Z", Locale.US); - - //----------------------------------------------------------------------- - /** - *

DateFormatUtils instances should NOT be constructed in standard programming.

- * - *

This constructor is public to permit tools that require a JavaBean instance - * to operate.

- */ - public DateFormatUtils() { - super(); - } - - /** - *

Formats a date/time into a specific pattern using the UTC time zone.

- * - * @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(long millis, String pattern) { - return format(new Date(millis), pattern, UTC_TIME_ZONE, null); - } - - /** - *

Formats a date/time into a specific pattern using the UTC time zone.

- * - * @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(Date date, String pattern) { - return format(date, pattern, UTC_TIME_ZONE, null); - } - - /** - *

Formats a date/time into a specific pattern using the UTC time zone.

- * - * @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 null - * @return the formatted date - */ - public static String formatUTC(long millis, String pattern, Locale locale) { - return format(new Date(millis), pattern, UTC_TIME_ZONE, locale); - } - - /** - *

Formats a date/time into a specific pattern using the UTC time zone.

- * - * @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 null - * @return the formatted date - */ - public static String formatUTC(Date date, String pattern, Locale locale) { - return format(date, pattern, UTC_TIME_ZONE, locale); - } - - /** - *

Formats a date/time into a specific pattern.

- * - * @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(long millis, String pattern) { - return format(new Date(millis), pattern, null, null); - } - - /** - *

Formats a date/time into a specific pattern.

- * - * @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(Date date, String pattern) { - return format(date, pattern, null, null); - } - - /** - *

Formats a calendar into a specific pattern.

- * - * @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(Calendar calendar, String pattern) { - return format(calendar, pattern, null, null); - } - - /** - *

Formats a date/time into a specific pattern in a time zone.

- * - * @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 null - * @return the formatted date - */ - public static String format(long millis, String pattern, TimeZone timeZone) { - return format(new Date(millis), pattern, timeZone, null); - } - - /** - *

Formats a date/time into a specific pattern in a time zone.

- * - * @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 null - * @return the formatted date - */ - public static String format(Date date, String pattern, TimeZone timeZone) { - return format(date, pattern, timeZone, null); - } - - /** - *

Formats a calendar into a specific pattern in a time zone.

- * - * @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 null - * @return the formatted calendar - * @see FastDateFormat#format(Calendar) - * @since 2.4 - */ - public static String format(Calendar calendar, String pattern, TimeZone timeZone) { - return format(calendar, pattern, timeZone, null); - } - - /** - *

Formats a date/time into a specific pattern in a locale.

- * - * @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 null - * @return the formatted date - */ - public static String format(long millis, String pattern, Locale locale) { - return format(new Date(millis), pattern, null, locale); - } - - /** - *

Formats a date/time into a specific pattern in a locale.

- * - * @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 null - * @return the formatted date - */ - public static String format(Date date, String pattern, Locale locale) { - return format(date, pattern, null, locale); - } - - /** - *

Formats a calendar into a specific pattern in a locale.

- * - * @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 null - * @return the formatted calendar - * @see FastDateFormat#format(Calendar) - * @since 2.4 - */ - public static String format(Calendar calendar, String pattern, Locale locale) { - return format(calendar, pattern, null, locale); - } - - /** - *

Formats a date/time into a specific pattern in a time zone and locale.

- * - * @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 null - * @param locale the locale to use, may be null - * @return the formatted date - */ - public static String format(long millis, String pattern, TimeZone timeZone, Locale locale) { - return format(new Date(millis), pattern, timeZone, locale); - } - - /** - *

Formats a date/time into a specific pattern in a time zone and locale.

- * - * @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 null - * @param locale the locale to use, may be null - * @return the formatted date - */ - public static String format(Date date, String pattern, TimeZone timeZone, Locale locale) { - FastDateFormat df = FastDateFormat.getInstance(pattern, timeZone, locale); - return df.format(date); - } - - /** - *

Formats a calendar into a specific pattern in a time zone and locale.

- * - * @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 null - * @param locale the locale to use, may be null - * @return the formatted calendar - * @see FastDateFormat#format(Calendar) - * @since 2.4 - */ - public static String format(Calendar calendar, String pattern, TimeZone timeZone, Locale locale) { - FastDateFormat df = FastDateFormat.getInstance(pattern, timeZone, locale); - return df.format(calendar); - } - -} diff --git a/src/org/apache/commons/lang3/time/DateUtils.java b/src/org/apache/commons/lang3/time/DateUtils.java deleted file mode 100644 index 578d3a3..0000000 --- a/src/org/apache/commons/lang3/time/DateUtils.java +++ /dev/null @@ -1,1831 +0,0 @@ -/* - * 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.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; -import java.util.Iterator; -import java.util.NoSuchElementException; - -/** - *

A suite of utilities surrounding the use of the - * {@link java.util.Calendar} and {@link java.util.Date} object.

- * - *

DateUtils contains a lot of common methods considering manipulations - * of Dates or Calendars. Some methods require some extra explanation. - * The truncate, ceiling and round methods could be considered the Math.floor(), - * Math.ceil() or Math.round versions for dates - * This way date-fields will be ignored in bottom-up order. - * As a complement to these methods we've introduced some fragment-methods. - * With these methods the Date-fields will be ignored in top-down order. - * Since a date without a year is not a valid date, you have to decide in what - * kind of date-field you want your result, for instance milliseconds or days. - *

- * - * @since 2.0 - * @version $Id: DateUtils.java 1144992 2011-07-11 00:49:04Z ggregory $ - */ -public class DateUtils { - - /** - * Number of milliseconds in a standard second. - * @since 2.1 - */ - public static final long MILLIS_PER_SECOND = 1000; - /** - * Number of milliseconds in a standard minute. - * @since 2.1 - */ - public static final long MILLIS_PER_MINUTE = 60 * MILLIS_PER_SECOND; - /** - * Number of milliseconds in a standard hour. - * @since 2.1 - */ - public static final long MILLIS_PER_HOUR = 60 * MILLIS_PER_MINUTE; - /** - * Number of milliseconds in a standard day. - * @since 2.1 - */ - public static final long MILLIS_PER_DAY = 24 * MILLIS_PER_HOUR; - - /** - * This is half a month, so this represents whether a date is in the top - * or bottom half of the month. - */ - public static final int SEMI_MONTH = 1001; - - private static final int[][] fields = { - {Calendar.MILLISECOND}, - {Calendar.SECOND}, - {Calendar.MINUTE}, - {Calendar.HOUR_OF_DAY, Calendar.HOUR}, - {Calendar.DATE, Calendar.DAY_OF_MONTH, Calendar.AM_PM - /* Calendar.DAY_OF_YEAR, Calendar.DAY_OF_WEEK, Calendar.DAY_OF_WEEK_IN_MONTH */ - }, - {Calendar.MONTH, DateUtils.SEMI_MONTH}, - {Calendar.YEAR}, - {Calendar.ERA}}; - - /** - * A week range, starting on Sunday. - */ - public static final int RANGE_WEEK_SUNDAY = 1; - /** - * A week range, starting on Monday. - */ - public static final int RANGE_WEEK_MONDAY = 2; - /** - * A week range, starting on the day focused. - */ - public static final int RANGE_WEEK_RELATIVE = 3; - /** - * A week range, centered around the day focused. - */ - public static final int RANGE_WEEK_CENTER = 4; - /** - * A month range, the week starting on Sunday. - */ - public static final int RANGE_MONTH_SUNDAY = 5; - /** - * A month range, the week starting on Monday. - */ - public static final int RANGE_MONTH_MONDAY = 6; - - /** - * Constant marker for truncating. - * @since 3.0 - */ - private static final int MODIFY_TRUNCATE = 0; - /** - * Constant marker for rounding. - * @since 3.0 - */ - private static final int MODIFY_ROUND = 1; - /** - * Constant marker for ceiling. - * @since 3.0 - */ - private static final int MODIFY_CEILING = 2; - - /** - *

{@code DateUtils} instances should NOT be constructed in - * standard programming. Instead, the static methods on the class should - * be used, such as {@code DateUtils.parseDate(str);}.

- * - *

This constructor is public to permit tools that require a JavaBean - * instance to operate.

- */ - public DateUtils() { - super(); - } - - //----------------------------------------------------------------------- - /** - *

Checks if two date objects are on the same day ignoring time.

- * - *

28 Mar 2002 13:45 and 28 Mar 2002 06:01 would return true. - * 28 Mar 2002 13:45 and 12 Mar 2002 13:45 would return false. - *

- * - * @param date1 the first date, not altered, not null - * @param date2 the second date, not altered, not null - * @return true if they represent the same day - * @throws IllegalArgumentException if either date is null - * @since 2.1 - */ - public static boolean isSameDay(Date date1, Date date2) { - if (date1 == null || date2 == null) { - throw new IllegalArgumentException("The date must not be null"); - } - Calendar cal1 = Calendar.getInstance(); - cal1.setTime(date1); - Calendar cal2 = Calendar.getInstance(); - cal2.setTime(date2); - return isSameDay(cal1, cal2); - } - - /** - *

Checks if two calendar objects are on the same day ignoring time.

- * - *

28 Mar 2002 13:45 and 28 Mar 2002 06:01 would return true. - * 28 Mar 2002 13:45 and 12 Mar 2002 13:45 would return false. - *

- * - * @param cal1 the first calendar, not altered, not null - * @param cal2 the second calendar, not altered, not null - * @return true if they represent the same day - * @throws IllegalArgumentException if either calendar is null - * @since 2.1 - */ - public static boolean isSameDay(Calendar cal1, Calendar cal2) { - if (cal1 == null || cal2 == null) { - throw new IllegalArgumentException("The date must not be null"); - } - return (cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA) && - cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) && - cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR)); - } - - //----------------------------------------------------------------------- - /** - *

Checks if two date objects represent the same instant in time.

- * - *

This method compares the long millisecond time of the two objects.

- * - * @param date1 the first date, not altered, not null - * @param date2 the second date, not altered, not null - * @return true if they represent the same millisecond instant - * @throws IllegalArgumentException if either date is null - * @since 2.1 - */ - public static boolean isSameInstant(Date date1, Date date2) { - if (date1 == null || date2 == null) { - throw new IllegalArgumentException("The date must not be null"); - } - return date1.getTime() == date2.getTime(); - } - - /** - *

Checks if two calendar objects represent the same instant in time.

- * - *

This method compares the long millisecond time of the two objects.

- * - * @param cal1 the first calendar, not altered, not null - * @param cal2 the second calendar, not altered, not null - * @return true if they represent the same millisecond instant - * @throws IllegalArgumentException if either date is null - * @since 2.1 - */ - public static boolean isSameInstant(Calendar cal1, Calendar cal2) { - if (cal1 == null || cal2 == null) { - throw new IllegalArgumentException("The date must not be null"); - } - return cal1.getTime().getTime() == cal2.getTime().getTime(); - } - - //----------------------------------------------------------------------- - /** - *

Checks if two calendar objects represent the same local time.

- * - *

This method compares the values of the fields of the two objects. - * In addition, both calendars must be the same of the same type.

- * - * @param cal1 the first calendar, not altered, not null - * @param cal2 the second calendar, not altered, not null - * @return true if they represent the same millisecond instant - * @throws IllegalArgumentException if either date is null - * @since 2.1 - */ - public static boolean isSameLocalTime(Calendar cal1, Calendar cal2) { - if (cal1 == null || cal2 == null) { - throw new IllegalArgumentException("The date must not be null"); - } - return (cal1.get(Calendar.MILLISECOND) == cal2.get(Calendar.MILLISECOND) && - cal1.get(Calendar.SECOND) == cal2.get(Calendar.SECOND) && - cal1.get(Calendar.MINUTE) == cal2.get(Calendar.MINUTE) && - cal1.get(Calendar.HOUR_OF_DAY) == cal2.get(Calendar.HOUR_OF_DAY) && - cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR) && - cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) && - cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA) && - cal1.getClass() == cal2.getClass()); - } - - //----------------------------------------------------------------------- - /** - *

Parses a string representing a date by trying a variety of different parsers.

- * - *

The parse will try each parse pattern in turn. - * A parse is only deemed successful if it parses the whole of the input string. - * If no parse patterns match, a ParseException is thrown.

- * The parser will be lenient toward the parsed date. - * - * @param str the date to parse, not null - * @param parsePatterns the date format patterns to use, see SimpleDateFormat, not null - * @return the parsed date - * @throws IllegalArgumentException if the date string or pattern array is null - * @throws ParseException if none of the date patterns were suitable (or there were none) - */ - public static Date parseDate(String str, String... parsePatterns) throws ParseException { - return parseDateWithLeniency(str, parsePatterns, true); - } - - //----------------------------------------------------------------------- - /** - *

Parses a string representing a date by trying a variety of different parsers.

- * - *

The parse will try each parse pattern in turn. - * A parse is only deemed successful if it parses the whole of the input string. - * If no parse patterns match, a ParseException is thrown.

- * The parser parses strictly - it does not allow for dates such as "February 942, 1996". - * - * @param str the date to parse, not null - * @param parsePatterns the date format patterns to use, see SimpleDateFormat, not null - * @return the parsed date - * @throws IllegalArgumentException if the date string or pattern array is null - * @throws ParseException if none of the date patterns were suitable - * @since 2.5 - */ - public static Date parseDateStrictly(String str, String... parsePatterns) throws ParseException { - return parseDateWithLeniency(str, parsePatterns, false); - } - - /** - *

Parses a string representing a date by trying a variety of different parsers.

- * - *

The parse will try each parse pattern in turn. - * A parse is only deemed successful if it parses the whole of the input string. - * If no parse patterns match, a ParseException is thrown.

- * - * @param str the date to parse, not null - * @param parsePatterns the date format patterns to use, see SimpleDateFormat, not null - * @param lenient Specify whether or not date/time parsing is to be lenient. - * @return the parsed date - * @throws IllegalArgumentException if the date string or pattern array is null - * @throws ParseException if none of the date patterns were suitable - * @see java.util.Calender#isLenient() - */ - private static Date parseDateWithLeniency( - String str, String[] parsePatterns, boolean lenient) throws ParseException { - if (str == null || parsePatterns == null) { - throw new IllegalArgumentException("Date and Patterns must not be null"); - } - - SimpleDateFormat parser = new SimpleDateFormat(); - parser.setLenient(lenient); - ParsePosition pos = new ParsePosition(0); - for (String parsePattern : parsePatterns) { - - String pattern = parsePattern; - - // LANG-530 - need to make sure 'ZZ' output doesn't get passed to SimpleDateFormat - if (parsePattern.endsWith("ZZ")) { - pattern = pattern.substring(0, pattern.length() - 1); - } - - parser.applyPattern(pattern); - pos.setIndex(0); - - String str2 = str; - // LANG-530 - need to make sure 'ZZ' output doesn't hit SimpleDateFormat as it will ParseException - if (parsePattern.endsWith("ZZ")) { - str2 = str.replaceAll("([-+][0-9][0-9]):([0-9][0-9])$", "$1$2"); - } - - Date date = parser.parse(str2, pos); - if (date != null && pos.getIndex() == str2.length()) { - return date; - } - } - throw new ParseException("Unable to parse the date: " + str, -1); - } - - //----------------------------------------------------------------------- - /** - * Adds a number of years to a date returning a new object. - * The original {@code Date} is unchanged. - * - * @param date the date, not null - * @param amount the amount to add, may be negative - * @return the new {@code Date} with the amount added - * @throws IllegalArgumentException if the date is null - */ - public static Date addYears(Date date, int amount) { - return add(date, Calendar.YEAR, amount); - } - - //----------------------------------------------------------------------- - /** - * Adds a number of months to a date returning a new object. - * The original {@code Date} is unchanged. - * - * @param date the date, not null - * @param amount the amount to add, may be negative - * @return the new {@code Date} with the amount added - * @throws IllegalArgumentException if the date is null - */ - public static Date addMonths(Date date, int amount) { - return add(date, Calendar.MONTH, amount); - } - - //----------------------------------------------------------------------- - /** - * Adds a number of weeks to a date returning a new object. - * The original {@code Date} is unchanged. - * - * @param date the date, not null - * @param amount the amount to add, may be negative - * @return the new {@code Date} with the amount added - * @throws IllegalArgumentException if the date is null - */ - public static Date addWeeks(Date date, int amount) { - return add(date, Calendar.WEEK_OF_YEAR, amount); - } - - //----------------------------------------------------------------------- - /** - * Adds a number of days to a date returning a new object. - * The original {@code Date} is unchanged. - * - * @param date the date, not null - * @param amount the amount to add, may be negative - * @return the new {@code Date} with the amount added - * @throws IllegalArgumentException if the date is null - */ - public static Date addDays(Date date, int amount) { - return add(date, Calendar.DAY_OF_MONTH, amount); - } - - //----------------------------------------------------------------------- - /** - * Adds a number of hours to a date returning a new object. - * The original {@code Date} is unchanged. - * - * @param date the date, not null - * @param amount the amount to add, may be negative - * @return the new {@code Date} with the amount added - * @throws IllegalArgumentException if the date is null - */ - public static Date addHours(Date date, int amount) { - return add(date, Calendar.HOUR_OF_DAY, amount); - } - - //----------------------------------------------------------------------- - /** - * Adds a number of minutes to a date returning a new object. - * The original {@code Date} is unchanged. - * - * @param date the date, not null - * @param amount the amount to add, may be negative - * @return the new {@code Date} with the amount added - * @throws IllegalArgumentException if the date is null - */ - public static Date addMinutes(Date date, int amount) { - return add(date, Calendar.MINUTE, amount); - } - - //----------------------------------------------------------------------- - /** - * Adds a number of seconds to a date returning a new object. - * The original {@code Date} is unchanged. - * - * @param date the date, not null - * @param amount the amount to add, may be negative - * @return the new {@code Date} with the amount added - * @throws IllegalArgumentException if the date is null - */ - public static Date addSeconds(Date date, int amount) { - return add(date, Calendar.SECOND, amount); - } - - //----------------------------------------------------------------------- - /** - * Adds a number of milliseconds to a date returning a new object. - * The original {@code Date} is unchanged. - * - * @param date the date, not null - * @param amount the amount to add, may be negative - * @return the new {@code Date} with the amount added - * @throws IllegalArgumentException if the date is null - */ - public static Date addMilliseconds(Date date, int amount) { - return add(date, Calendar.MILLISECOND, amount); - } - - //----------------------------------------------------------------------- - /** - * Adds to a date returning a new object. - * The original {@code Date} is unchanged. - * - * @param date the date, not null - * @param calendarField the calendar field to add to - * @param amount the amount to add, may be negative - * @return the new {@code Date} with the amount added - * @throws IllegalArgumentException if the date is null - */ - private static Date add(Date date, int calendarField, int amount) { - if (date == null) { - throw new IllegalArgumentException("The date must not be null"); - } - Calendar c = Calendar.getInstance(); - c.setTime(date); - c.add(calendarField, amount); - return c.getTime(); - } - - //----------------------------------------------------------------------- - /** - * Sets the years field to a date returning a new object. - * The original {@code Date} is unchanged. - * - * @param date the date, not null - * @param amount the amount to set - * @return a new {@code Date} set with the specified value - * @throws IllegalArgumentException if the date is null - * @since 2.4 - */ - public static Date setYears(Date date, int amount) { - return set(date, Calendar.YEAR, amount); - } - - //----------------------------------------------------------------------- - /** - * Sets the months field to a date returning a new object. - * The original {@code Date} is unchanged. - * - * @param date the date, not null - * @param amount the amount to set - * @return a new {@code Date} set with the specified value - * @throws IllegalArgumentException if the date is null - * @since 2.4 - */ - public static Date setMonths(Date date, int amount) { - return set(date, Calendar.MONTH, amount); - } - - //----------------------------------------------------------------------- - /** - * Sets the day of month field to a date returning a new object. - * The original {@code Date} is unchanged. - * - * @param date the date, not null - * @param amount the amount to set - * @return a new {@code Date} set with the specified value - * @throws IllegalArgumentException if the date is null - * @since 2.4 - */ - public static Date setDays(Date date, int amount) { - return set(date, Calendar.DAY_OF_MONTH, amount); - } - - //----------------------------------------------------------------------- - /** - * Sets the hours field to a date returning a new object. Hours range - * from 0-23. - * The original {@code Date} is unchanged. - * - * @param date the date, not null - * @param amount the amount to set - * @return a new {@code Date} set with the specified value - * @throws IllegalArgumentException if the date is null - * @since 2.4 - */ - public static Date setHours(Date date, int amount) { - return set(date, Calendar.HOUR_OF_DAY, amount); - } - - //----------------------------------------------------------------------- - /** - * Sets the minute field to a date returning a new object. - * The original {@code Date} is unchanged. - * - * @param date the date, not null - * @param amount the amount to set - * @return a new {@code Date} set with the specified value - * @throws IllegalArgumentException if the date is null - * @since 2.4 - */ - public static Date setMinutes(Date date, int amount) { - return set(date, Calendar.MINUTE, amount); - } - - //----------------------------------------------------------------------- - /** - * Sets the seconds field to a date returning a new object. - * The original {@code Date} is unchanged. - * - * @param date the date, not null - * @param amount the amount to set - * @return a new {@code Date} set with the specified value - * @throws IllegalArgumentException if the date is null - * @since 2.4 - */ - public static Date setSeconds(Date date, int amount) { - return set(date, Calendar.SECOND, amount); - } - - //----------------------------------------------------------------------- - /** - * Sets the miliseconds field to a date returning a new object. - * The original {@code Date} is unchanged. - * - * @param date the date, not null - * @param amount the amount to set - * @return a new {@code Date} set with the specified value - * @throws IllegalArgumentException if the date is null - * @since 2.4 - */ - public static Date setMilliseconds(Date date, int amount) { - return set(date, Calendar.MILLISECOND, amount); - } - - //----------------------------------------------------------------------- - /** - * Sets the specified field to a date returning a new object. - * This does not use a lenient calendar. - * The original {@code Date} is unchanged. - * - * @param date the date, not null - * @param calendarField the {@code Calendar} field to set the amount to - * @param amount the amount to set - * @return a new {@code Date} set with the specified value - * @throws IllegalArgumentException if the date is null - * @since 2.4 - */ - private static Date set(Date date, int calendarField, int amount) { - if (date == null) { - throw new IllegalArgumentException("The date must not be null"); - } - // getInstance() returns a new object, so this method is thread safe. - Calendar c = Calendar.getInstance(); - c.setLenient(false); - c.setTime(date); - c.set(calendarField, amount); - return c.getTime(); - } - - //----------------------------------------------------------------------- - /** - * Convert a {@code Date} into a {@code Calendar}. - * - * @param date the date to convert to a Calendar - * @return the created Calendar - * @throws NullPointerException if null is passed in - * @since 3.0 - */ - public static Calendar toCalendar(Date date) { - Calendar c = Calendar.getInstance(); - c.setTime(date); - return c; - } - - //----------------------------------------------------------------------- - /** - *

Round this date, leaving the field specified as the most - * significant field.

- * - *

For example, if you had the datetime of 28 Mar 2002 - * 13:45:01.231, if this was passed with HOUR, it would return - * 28 Mar 2002 14:00:00.000. If this was passed with MONTH, it - * would return 1 April 2002 0:00:00.000.

- * - *

For a date in a timezone that handles the change to daylight - * saving time, rounding to Calendar.HOUR_OF_DAY will behave as follows. - * Suppose daylight saving time begins at 02:00 on March 30. Rounding a - * date that crosses this time would produce the following values: - *

- *

- * - * @param date the date to work with, not null - * @param field the field from {@code Calendar} or {@code SEMI_MONTH} - * @return the different rounded date, not null - * @throws ArithmeticException if the year is over 280 million - */ - public static Date round(Date date, int field) { - if (date == null) { - throw new IllegalArgumentException("The date must not be null"); - } - Calendar gval = Calendar.getInstance(); - gval.setTime(date); - modify(gval, field, MODIFY_ROUND); - return gval.getTime(); - } - - /** - *

Round this date, leaving the field specified as the most - * significant field.

- * - *

For example, if you had the datetime of 28 Mar 2002 - * 13:45:01.231, if this was passed with HOUR, it would return - * 28 Mar 2002 14:00:00.000. If this was passed with MONTH, it - * would return 1 April 2002 0:00:00.000.

- * - *

For a date in a timezone that handles the change to daylight - * saving time, rounding to Calendar.HOUR_OF_DAY will behave as follows. - * Suppose daylight saving time begins at 02:00 on March 30. Rounding a - * date that crosses this time would produce the following values: - *

- *

- * - * @param date the date to work with, not null - * @param field the field from {@code Calendar} or SEMI_MONTH - * @return the different rounded date, not null - * @throws IllegalArgumentException if the date is null - * @throws ArithmeticException if the year is over 280 million - */ - public static Calendar round(Calendar date, int field) { - if (date == null) { - throw new IllegalArgumentException("The date must not be null"); - } - Calendar rounded = (Calendar) date.clone(); - modify(rounded, field, MODIFY_ROUND); - return rounded; - } - - /** - *

Round this date, leaving the field specified as the most - * significant field.

- * - *

For example, if you had the datetime of 28 Mar 2002 - * 13:45:01.231, if this was passed with HOUR, it would return - * 28 Mar 2002 14:00:00.000. If this was passed with MONTH, it - * would return 1 April 2002 0:00:00.000.

- * - *

For a date in a timezone that handles the change to daylight - * saving time, rounding to Calendar.HOUR_OF_DAY will behave as follows. - * Suppose daylight saving time begins at 02:00 on March 30. Rounding a - * date that crosses this time would produce the following values: - *

- *

- * - * @param date the date to work with, either {@code Date} or {@code Calendar}, not null - * @param field the field from {@code Calendar} or SEMI_MONTH - * @return the different rounded date, not null - * @throws IllegalArgumentException if the date is null - * @throws ClassCastException if the object type is not a {@code Date} or {@code Calendar} - * @throws ArithmeticException if the year is over 280 million - */ - public static Date round(Object date, int field) { - if (date == null) { - throw new IllegalArgumentException("The date must not be null"); - } - if (date instanceof Date) { - return round((Date) date, field); - } else if (date instanceof Calendar) { - return round((Calendar) date, field).getTime(); - } else { - throw new ClassCastException("Could not round " + date); - } - } - - //----------------------------------------------------------------------- - /** - *

Truncate this date, leaving the field specified as the most - * significant field.

- * - *

For example, if you had the datetime of 28 Mar 2002 - * 13:45:01.231, if you passed with HOUR, it would return 28 Mar - * 2002 13:00:00.000. If this was passed with MONTH, it would - * return 1 Mar 2002 0:00:00.000.

- * - * @param date the date to work with, not null - * @param field the field from {@code Calendar} or SEMI_MONTH - * @return the different truncated date, not null - * @throws IllegalArgumentException if the date is null - * @throws ArithmeticException if the year is over 280 million - */ - public static Date truncate(Date date, int field) { - if (date == null) { - throw new IllegalArgumentException("The date must not be null"); - } - Calendar gval = Calendar.getInstance(); - gval.setTime(date); - modify(gval, field, MODIFY_TRUNCATE); - return gval.getTime(); - } - - /** - *

Truncate this date, leaving the field specified as the most - * significant field.

- * - *

For example, if you had the datetime of 28 Mar 2002 - * 13:45:01.231, if you passed with HOUR, it would return 28 Mar - * 2002 13:00:00.000. If this was passed with MONTH, it would - * return 1 Mar 2002 0:00:00.000.

- * - * @param date the date to work with, not null - * @param field the field from {@code Calendar} or SEMI_MONTH - * @return the different truncated date, not null - * @throws IllegalArgumentException if the date is null - * @throws ArithmeticException if the year is over 280 million - */ - public static Calendar truncate(Calendar date, int field) { - if (date == null) { - throw new IllegalArgumentException("The date must not be null"); - } - Calendar truncated = (Calendar) date.clone(); - modify(truncated, field, MODIFY_TRUNCATE); - return truncated; - } - - /** - *

Truncate this date, leaving the field specified as the most - * significant field.

- * - *

For example, if you had the datetime of 28 Mar 2002 - * 13:45:01.231, if you passed with HOUR, it would return 28 Mar - * 2002 13:00:00.000. If this was passed with MONTH, it would - * return 1 Mar 2002 0:00:00.000.

- * - * @param date the date to work with, either {@code Date} or {@code Calendar}, not null - * @param field the field from {@code Calendar} or SEMI_MONTH - * @return the different truncated date, not null - * @throws IllegalArgumentException if the date is null - * @throws ClassCastException if the object type is not a {@code Date} or {@code Calendar} - * @throws ArithmeticException if the year is over 280 million - */ - public static Date truncate(Object date, int field) { - if (date == null) { - throw new IllegalArgumentException("The date must not be null"); - } - if (date instanceof Date) { - return truncate((Date) date, field); - } else if (date instanceof Calendar) { - return truncate((Calendar) date, field).getTime(); - } else { - throw new ClassCastException("Could not truncate " + date); - } - } - - //----------------------------------------------------------------------- - /** - *

Ceil this date, leaving the field specified as the most - * significant field.

- * - *

For example, if you had the datetime of 28 Mar 2002 - * 13:45:01.231, if you passed with HOUR, it would return 28 Mar - * 2002 14:00:00.000. If this was passed with MONTH, it would - * return 1 Apr 2002 0:00:00.000.

- * - * @param date the date to work with, not null - * @param field the field from {@code Calendar} or SEMI_MONTH - * @return the different ceil date, not null - * @throws IllegalArgumentException if the date is null - * @throws ArithmeticException if the year is over 280 million - * @since 2.5 - */ - public static Date ceiling(Date date, int field) { - if (date == null) { - throw new IllegalArgumentException("The date must not be null"); - } - Calendar gval = Calendar.getInstance(); - gval.setTime(date); - modify(gval, field, MODIFY_CEILING); - return gval.getTime(); - } - - /** - *

Ceil this date, leaving the field specified as the most - * significant field.

- * - *

For example, if you had the datetime of 28 Mar 2002 - * 13:45:01.231, if you passed with HOUR, it would return 28 Mar - * 2002 13:00:00.000. If this was passed with MONTH, it would - * return 1 Mar 2002 0:00:00.000.

- * - * @param date the date to work with, not null - * @param field the field from {@code Calendar} or SEMI_MONTH - * @return the different ceil date, not null - * @throws IllegalArgumentException if the date is null - * @throws ArithmeticException if the year is over 280 million - * @since 2.5 - */ - public static Calendar ceiling(Calendar date, int field) { - if (date == null) { - throw new IllegalArgumentException("The date must not be null"); - } - Calendar ceiled = (Calendar) date.clone(); - modify(ceiled, field, MODIFY_CEILING); - return ceiled; - } - - /** - *

Ceil this date, leaving the field specified as the most - * significant field.

- * - *

For example, if you had the datetime of 28 Mar 2002 - * 13:45:01.231, if you passed with HOUR, it would return 28 Mar - * 2002 13:00:00.000. If this was passed with MONTH, it would - * return 1 Mar 2002 0:00:00.000.

- * - * @param date the date to work with, either {@code Date} or {@code Calendar}, not null - * @param field the field from {@code Calendar} or SEMI_MONTH - * @return the different ceil date, not null - * @throws IllegalArgumentException if the date is null - * @throws ClassCastException if the object type is not a {@code Date} or {@code Calendar} - * @throws ArithmeticException if the year is over 280 million - * @since 2.5 - */ - public static Date ceiling(Object date, int field) { - if (date == null) { - throw new IllegalArgumentException("The date must not be null"); - } - if (date instanceof Date) { - return ceiling((Date) date, field); - } else if (date instanceof Calendar) { - return ceiling((Calendar) date, field).getTime(); - } else { - throw new ClassCastException("Could not find ceiling of for type: " + date.getClass()); - } - } - - //----------------------------------------------------------------------- - /** - *

Internal calculation method.

- * - * @param val the calendar, not null - * @param field the field constant - * @param modType type to truncate, round or ceiling - * @throws ArithmeticException if the year is over 280 million - */ - private static void modify(Calendar val, int field, int modType) { - if (val.get(Calendar.YEAR) > 280000000) { - throw new ArithmeticException("Calendar value too large for accurate calculations"); - } - - if (field == Calendar.MILLISECOND) { - return; - } - - // ----------------- Fix for LANG-59 ---------------------- START --------------- - // see http://issues.apache.org/jira/browse/LANG-59 - // - // Manually truncate milliseconds, seconds and minutes, rather than using - // Calendar methods. - - Date date = val.getTime(); - long time = date.getTime(); - boolean done = false; - - // truncate milliseconds - int millisecs = val.get(Calendar.MILLISECOND); - if (MODIFY_TRUNCATE == modType || millisecs < 500) { - time = time - millisecs; - } - if (field == Calendar.SECOND) { - done = true; - } - - // truncate seconds - int seconds = val.get(Calendar.SECOND); - if (!done && (MODIFY_TRUNCATE == modType || seconds < 30)) { - time = time - (seconds * 1000L); - } - if (field == Calendar.MINUTE) { - done = true; - } - - // truncate minutes - int minutes = val.get(Calendar.MINUTE); - if (!done && (MODIFY_TRUNCATE == modType || minutes < 30)) { - time = time - (minutes * 60000L); - } - - // reset time - if (date.getTime() != time) { - date.setTime(time); - val.setTime(date); - } - // ----------------- Fix for LANG-59 ----------------------- END ---------------- - - boolean roundUp = false; - for (int[] aField : fields) { - for (int element : aField) { - if (element == field) { - //This is our field... we stop looping - if (modType == MODIFY_CEILING || (modType == MODIFY_ROUND && roundUp)) { - if (field == DateUtils.SEMI_MONTH) { - //This is a special case that's hard to generalize - //If the date is 1, we round up to 16, otherwise - // we subtract 15 days and add 1 month - if (val.get(Calendar.DATE) == 1) { - val.add(Calendar.DATE, 15); - } else { - val.add(Calendar.DATE, -15); - val.add(Calendar.MONTH, 1); - } -// ----------------- Fix for LANG-440 ---------------------- START --------------- - } else if (field == Calendar.AM_PM) { - // This is a special case - // If the time is 0, we round up to 12, otherwise - // we subtract 12 hours and add 1 day - if (val.get(Calendar.HOUR_OF_DAY) == 0) { - val.add(Calendar.HOUR_OF_DAY, 12); - } else { - val.add(Calendar.HOUR_OF_DAY, -12); - val.add(Calendar.DATE, 1); - } -// ----------------- Fix for LANG-440 ---------------------- END --------------- - } else { - //We need at add one to this field since the - // last number causes us to round up - val.add(aField[0], 1); - } - } - return; - } - } - //We have various fields that are not easy roundings - int offset = 0; - boolean offsetSet = false; - //These are special types of fields that require different rounding rules - switch (field) { - case DateUtils.SEMI_MONTH: - if (aField[0] == Calendar.DATE) { - //If we're going to drop the DATE field's value, - // we want to do this our own way. - //We need to subtrace 1 since the date has a minimum of 1 - offset = val.get(Calendar.DATE) - 1; - //If we're above 15 days adjustment, that means we're in the - // bottom half of the month and should stay accordingly. - if (offset >= 15) { - offset -= 15; - } - //Record whether we're in the top or bottom half of that range - roundUp = offset > 7; - offsetSet = true; - } - break; - case Calendar.AM_PM: - if (aField[0] == Calendar.HOUR_OF_DAY) { - //If we're going to drop the HOUR field's value, - // we want to do this our own way. - offset = val.get(Calendar.HOUR_OF_DAY); - if (offset >= 12) { - offset -= 12; - } - roundUp = offset >= 6; - offsetSet = true; - } - break; - } - if (!offsetSet) { - int min = val.getActualMinimum(aField[0]); - int max = val.getActualMaximum(aField[0]); - //Calculate the offset from the minimum allowed value - offset = val.get(aField[0]) - min; - //Set roundUp if this is more than half way between the minimum and maximum - roundUp = offset > ((max - min) / 2); - } - //We need to remove this field - if (offset != 0) { - val.set(aField[0], val.get(aField[0]) - offset); - } - } - throw new IllegalArgumentException("The field " + field + " is not supported"); - - } - - //----------------------------------------------------------------------- - /** - *

This constructs an Iterator over each day in a date - * range defined by a focus date and range style.

- * - *

For instance, passing Thursday, July 4, 2002 and a - * RANGE_MONTH_SUNDAY will return an Iterator - * that starts with Sunday, June 30, 2002 and ends with Saturday, August 3, - * 2002, returning a Calendar instance for each intermediate day.

- * - *

This method provides an iterator that returns Calendar objects. - * The days are progressed using {@link Calendar#add(int, int)}.

- * - * @param focus the date to work with, not null - * @param rangeStyle the style constant to use. Must be one of - * {@link DateUtils#RANGE_MONTH_SUNDAY}, - * {@link DateUtils#RANGE_MONTH_MONDAY}, - * {@link DateUtils#RANGE_WEEK_SUNDAY}, - * {@link DateUtils#RANGE_WEEK_MONDAY}, - * {@link DateUtils#RANGE_WEEK_RELATIVE}, - * {@link DateUtils#RANGE_WEEK_CENTER} - * @return the date iterator, not null, not null - * @throws IllegalArgumentException if the date is null - * @throws IllegalArgumentException if the rangeStyle is invalid - */ - public static Iterator iterator(Date focus, int rangeStyle) { - if (focus == null) { - throw new IllegalArgumentException("The date must not be null"); - } - Calendar gval = Calendar.getInstance(); - gval.setTime(focus); - return iterator(gval, rangeStyle); - } - - /** - *

This constructs an Iterator over each day in a date - * range defined by a focus date and range style.

- * - *

For instance, passing Thursday, July 4, 2002 and a - * RANGE_MONTH_SUNDAY will return an Iterator - * that starts with Sunday, June 30, 2002 and ends with Saturday, August 3, - * 2002, returning a Calendar instance for each intermediate day.

- * - *

This method provides an iterator that returns Calendar objects. - * The days are progressed using {@link Calendar#add(int, int)}.

- * - * @param focus the date to work with, not null - * @param rangeStyle the style constant to use. Must be one of - * {@link DateUtils#RANGE_MONTH_SUNDAY}, - * {@link DateUtils#RANGE_MONTH_MONDAY}, - * {@link DateUtils#RANGE_WEEK_SUNDAY}, - * {@link DateUtils#RANGE_WEEK_MONDAY}, - * {@link DateUtils#RANGE_WEEK_RELATIVE}, - * {@link DateUtils#RANGE_WEEK_CENTER} - * @return the date iterator, not null - * @throws IllegalArgumentException if the date is null - * @throws IllegalArgumentException if the rangeStyle is invalid - */ - public static Iterator iterator(Calendar focus, int rangeStyle) { - if (focus == null) { - throw new IllegalArgumentException("The date must not be null"); - } - Calendar start = null; - Calendar end = null; - int startCutoff = Calendar.SUNDAY; - int endCutoff = Calendar.SATURDAY; - switch (rangeStyle) { - case RANGE_MONTH_SUNDAY: - case RANGE_MONTH_MONDAY: - //Set start to the first of the month - start = truncate(focus, Calendar.MONTH); - //Set end to the last of the month - end = (Calendar) start.clone(); - end.add(Calendar.MONTH, 1); - end.add(Calendar.DATE, -1); - //Loop start back to the previous sunday or monday - if (rangeStyle == RANGE_MONTH_MONDAY) { - startCutoff = Calendar.MONDAY; - endCutoff = Calendar.SUNDAY; - } - break; - case RANGE_WEEK_SUNDAY: - case RANGE_WEEK_MONDAY: - case RANGE_WEEK_RELATIVE: - case RANGE_WEEK_CENTER: - //Set start and end to the current date - start = truncate(focus, Calendar.DATE); - end = truncate(focus, Calendar.DATE); - switch (rangeStyle) { - case RANGE_WEEK_SUNDAY: - //already set by default - break; - case RANGE_WEEK_MONDAY: - startCutoff = Calendar.MONDAY; - endCutoff = Calendar.SUNDAY; - break; - case RANGE_WEEK_RELATIVE: - startCutoff = focus.get(Calendar.DAY_OF_WEEK); - endCutoff = startCutoff - 1; - break; - case RANGE_WEEK_CENTER: - startCutoff = focus.get(Calendar.DAY_OF_WEEK) - 3; - endCutoff = focus.get(Calendar.DAY_OF_WEEK) + 3; - break; - } - break; - default: - throw new IllegalArgumentException("The range style " + rangeStyle + " is not valid."); - } - if (startCutoff < Calendar.SUNDAY) { - startCutoff += 7; - } - if (startCutoff > Calendar.SATURDAY) { - startCutoff -= 7; - } - if (endCutoff < Calendar.SUNDAY) { - endCutoff += 7; - } - if (endCutoff > Calendar.SATURDAY) { - endCutoff -= 7; - } - while (start.get(Calendar.DAY_OF_WEEK) != startCutoff) { - start.add(Calendar.DATE, -1); - } - while (end.get(Calendar.DAY_OF_WEEK) != endCutoff) { - end.add(Calendar.DATE, 1); - } - return new DateIterator(start, end); - } - - /** - *

This constructs an Iterator over each day in a date - * range defined by a focus date and range style.

- * - *

For instance, passing Thursday, July 4, 2002 and a - * RANGE_MONTH_SUNDAY will return an Iterator - * that starts with Sunday, June 30, 2002 and ends with Saturday, August 3, - * 2002, returning a Calendar instance for each intermediate day.

- * - * @param focus the date to work with, either {@code Date} or {@code Calendar}, not null - * @param rangeStyle the style constant to use. Must be one of the range - * styles listed for the {@link #iterator(Calendar, int)} method. - * @return the date iterator, not null - * @throws IllegalArgumentException if the date is null - * @throws ClassCastException if the object type is not a {@code Date} or {@code Calendar} - */ - public static Iterator iterator(Object focus, int rangeStyle) { - if (focus == null) { - throw new IllegalArgumentException("The date must not be null"); - } - if (focus instanceof Date) { - return iterator((Date) focus, rangeStyle); - } else if (focus instanceof Calendar) { - return iterator((Calendar) focus, rangeStyle); - } else { - throw new ClassCastException("Could not iterate based on " + focus); - } - } - - /** - *

Returns the number of milliseconds within the - * fragment. All datefields greater than the fragment will be ignored.

- * - *

Asking the milliseconds of any date will only return the number of milliseconds - * of the current second (resulting in a number between 0 and 999). This - * method will retrieve the number of milliseconds for any fragment. - * For example, if you want to calculate the number of milliseconds past today, - * your fragment is Calendar.DATE or Calendar.DAY_OF_YEAR. The result will - * be all milliseconds of the past hour(s), minutes(s) and second(s).

- * - *

Valid fragments are: Calendar.YEAR, Calendar.MONTH, both - * Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY, - * Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND - * A fragment less than or equal to a SECOND field will return 0.

- * - *

- *

    - *
  • January 1, 2008 7:15:10.538 with Calendar.SECOND as fragment will return 538
  • - *
  • January 6, 2008 7:15:10.538 with Calendar.SECOND as fragment will return 538
  • - *
  • January 6, 2008 7:15:10.538 with Calendar.MINUTE as fragment will return 10538 (10*1000 + 538)
  • - *
  • January 16, 2008 7:15:10.538 with Calendar.MILLISECOND as fragment will return 0 - * (a millisecond cannot be split in milliseconds)
  • - *
- *

- * - * @param date the date to work with, not null - * @param fragment the {@code Calendar} field part of date to calculate - * @return number of milliseconds within the fragment of date - * @throws IllegalArgumentException if the date is null or - * fragment is not supported - * @since 2.4 - */ - public static long getFragmentInMilliseconds(Date date, int fragment) { - return getFragment(date, fragment, Calendar.MILLISECOND); - } - - /** - *

Returns the number of seconds within the - * fragment. All datefields greater than the fragment will be ignored.

- * - *

Asking the seconds of any date will only return the number of seconds - * of the current minute (resulting in a number between 0 and 59). This - * method will retrieve the number of seconds for any fragment. - * For example, if you want to calculate the number of seconds past today, - * your fragment is Calendar.DATE or Calendar.DAY_OF_YEAR. The result will - * be all seconds of the past hour(s) and minutes(s).

- * - *

Valid fragments are: Calendar.YEAR, Calendar.MONTH, both - * Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY, - * Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND - * A fragment less than or equal to a SECOND field will return 0.

- * - *

- *

    - *
  • January 1, 2008 7:15:10.538 with Calendar.MINUTE as fragment will return 10 - * (equivalent to deprecated date.getSeconds())
  • - *
  • January 6, 2008 7:15:10.538 with Calendar.MINUTE as fragment will return 10 - * (equivalent to deprecated date.getSeconds())
  • - *
  • January 6, 2008 7:15:10.538 with Calendar.DAY_OF_YEAR as fragment will return 26110 - * (7*3600 + 15*60 + 10)
  • - *
  • January 16, 2008 7:15:10.538 with Calendar.MILLISECOND as fragment will return 0 - * (a millisecond cannot be split in seconds)
  • - *
- *

- * - * @param date the date to work with, not null - * @param fragment the {@code Calendar} field part of date to calculate - * @return number of seconds within the fragment of date - * @throws IllegalArgumentException if the date is null or - * fragment is not supported - * @since 2.4 - */ - public static long getFragmentInSeconds(Date date, int fragment) { - return getFragment(date, fragment, Calendar.SECOND); - } - - /** - *

Returns the number of minutes within the - * fragment. All datefields greater than the fragment will be ignored.

- * - *

Asking the minutes of any date will only return the number of minutes - * of the current hour (resulting in a number between 0 and 59). This - * method will retrieve the number of minutes for any fragment. - * For example, if you want to calculate the number of minutes past this month, - * your fragment is Calendar.MONTH. The result will be all minutes of the - * past day(s) and hour(s).

- * - *

Valid fragments are: Calendar.YEAR, Calendar.MONTH, both - * Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY, - * Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND - * A fragment less than or equal to a MINUTE field will return 0.

- * - *

- *

    - *
  • January 1, 2008 7:15:10.538 with Calendar.HOUR_OF_DAY as fragment will return 15 - * (equivalent to deprecated date.getMinutes())
  • - *
  • January 6, 2008 7:15:10.538 with Calendar.HOUR_OF_DAY as fragment will return 15 - * (equivalent to deprecated date.getMinutes())
  • - *
  • January 1, 2008 7:15:10.538 with Calendar.MONTH as fragment will return 15
  • - *
  • January 6, 2008 7:15:10.538 with Calendar.MONTH as fragment will return 435 (7*60 + 15)
  • - *
  • January 16, 2008 7:15:10.538 with Calendar.MILLISECOND as fragment will return 0 - * (a millisecond cannot be split in minutes)
  • - *
- *

- * - * @param date the date to work with, not null - * @param fragment the {@code Calendar} field part of date to calculate - * @return number of minutes within the fragment of date - * @throws IllegalArgumentException if the date is null or - * fragment is not supported - * @since 2.4 - */ - public static long getFragmentInMinutes(Date date, int fragment) { - return getFragment(date, fragment, Calendar.MINUTE); - } - - /** - *

Returns the number of hours within the - * fragment. All datefields greater than the fragment will be ignored.

- * - *

Asking the hours of any date will only return the number of hours - * of the current day (resulting in a number between 0 and 23). This - * method will retrieve the number of hours for any fragment. - * For example, if you want to calculate the number of hours past this month, - * your fragment is Calendar.MONTH. The result will be all hours of the - * past day(s).

- * - *

Valid fragments are: Calendar.YEAR, Calendar.MONTH, both - * Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY, - * Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND - * A fragment less than or equal to a HOUR field will return 0.

- * - *

- *

    - *
  • January 1, 2008 7:15:10.538 with Calendar.DAY_OF_YEAR as fragment will return 7 - * (equivalent to deprecated date.getHours())
  • - *
  • January 6, 2008 7:15:10.538 with Calendar.DAY_OF_YEAR as fragment will return 7 - * (equivalent to deprecated date.getHours())
  • - *
  • January 1, 2008 7:15:10.538 with Calendar.MONTH as fragment will return 7
  • - *
  • January 6, 2008 7:15:10.538 with Calendar.MONTH as fragment will return 127 (5*24 + 7)
  • - *
  • January 16, 2008 7:15:10.538 with Calendar.MILLISECOND as fragment will return 0 - * (a millisecond cannot be split in hours)
  • - *
- *

- * - * @param date the date to work with, not null - * @param fragment the {@code Calendar} field part of date to calculate - * @return number of hours within the fragment of date - * @throws IllegalArgumentException if the date is null or - * fragment is not supported - * @since 2.4 - */ - public static long getFragmentInHours(Date date, int fragment) { - return getFragment(date, fragment, Calendar.HOUR_OF_DAY); - } - - /** - *

Returns the number of days within the - * fragment. All datefields greater than the fragment will be ignored.

- * - *

Asking the days of any date will only return the number of days - * of the current month (resulting in a number between 1 and 31). This - * method will retrieve the number of days for any fragment. - * For example, if you want to calculate the number of days past this year, - * your fragment is Calendar.YEAR. The result will be all days of the - * past month(s).

- * - *

Valid fragments are: Calendar.YEAR, Calendar.MONTH, both - * Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY, - * Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND - * A fragment less than or equal to a DAY field will return 0.

- * - *

- *

    - *
  • January 28, 2008 with Calendar.MONTH as fragment will return 28 - * (equivalent to deprecated date.getDay())
  • - *
  • February 28, 2008 with Calendar.MONTH as fragment will return 28 - * (equivalent to deprecated date.getDay())
  • - *
  • January 28, 2008 with Calendar.YEAR as fragment will return 28
  • - *
  • February 28, 2008 with Calendar.YEAR as fragment will return 59
  • - *
  • January 28, 2008 with Calendar.MILLISECOND as fragment will return 0 - * (a millisecond cannot be split in days)
  • - *
- *

- * - * @param date the date to work with, not null - * @param fragment the {@code Calendar} field part of date to calculate - * @return number of days within the fragment of date - * @throws IllegalArgumentException if the date is null or - * fragment is not supported - * @since 2.4 - */ - public static long getFragmentInDays(Date date, int fragment) { - return getFragment(date, fragment, Calendar.DAY_OF_YEAR); - } - - /** - *

Returns the number of milliseconds within the - * fragment. All datefields greater than the fragment will be ignored.

- * - *

Asking the milliseconds of any date will only return the number of milliseconds - * of the current second (resulting in a number between 0 and 999). This - * method will retrieve the number of milliseconds for any fragment. - * For example, if you want to calculate the number of seconds past today, - * your fragment is Calendar.DATE or Calendar.DAY_OF_YEAR. The result will - * be all seconds of the past hour(s), minutes(s) and second(s).

- * - *

Valid fragments are: Calendar.YEAR, Calendar.MONTH, both - * Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY, - * Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND - * A fragment less than or equal to a MILLISECOND field will return 0.

- * - *

- *

    - *
  • January 1, 2008 7:15:10.538 with Calendar.SECOND as fragment will return 538 - * (equivalent to calendar.get(Calendar.MILLISECOND))
  • - *
  • January 6, 2008 7:15:10.538 with Calendar.SECOND as fragment will return 538 - * (equivalent to calendar.get(Calendar.MILLISECOND))
  • - *
  • January 6, 2008 7:15:10.538 with Calendar.MINUTE as fragment will return 10538 - * (10*1000 + 538)
  • - *
  • January 16, 2008 7:15:10.538 with Calendar.MILLISECOND as fragment will return 0 - * (a millisecond cannot be split in milliseconds)
  • - *
- *

- * - * @param calendar the calendar to work with, not null - * @param fragment the {@code Calendar} field part of calendar to calculate - * @return number of milliseconds within the fragment of date - * @throws IllegalArgumentException if the date is null or - * fragment is not supported - * @since 2.4 - */ - public static long getFragmentInMilliseconds(Calendar calendar, int fragment) { - return getFragment(calendar, fragment, Calendar.MILLISECOND); - } - /** - *

Returns the number of seconds within the - * fragment. All datefields greater than the fragment will be ignored.

- * - *

Asking the seconds of any date will only return the number of seconds - * of the current minute (resulting in a number between 0 and 59). This - * method will retrieve the number of seconds for any fragment. - * For example, if you want to calculate the number of seconds past today, - * your fragment is Calendar.DATE or Calendar.DAY_OF_YEAR. The result will - * be all seconds of the past hour(s) and minutes(s).

- * - *

Valid fragments are: Calendar.YEAR, Calendar.MONTH, both - * Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY, - * Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND - * A fragment less than or equal to a SECOND field will return 0.

- * - *

- *

    - *
  • January 1, 2008 7:15:10.538 with Calendar.MINUTE as fragment will return 10 - * (equivalent to calendar.get(Calendar.SECOND))
  • - *
  • January 6, 2008 7:15:10.538 with Calendar.MINUTE as fragment will return 10 - * (equivalent to calendar.get(Calendar.SECOND))
  • - *
  • January 6, 2008 7:15:10.538 with Calendar.DAY_OF_YEAR as fragment will return 26110 - * (7*3600 + 15*60 + 10)
  • - *
  • January 16, 2008 7:15:10.538 with Calendar.MILLISECOND as fragment will return 0 - * (a millisecond cannot be split in seconds)
  • - *
- *

- * - * @param calendar the calendar to work with, not null - * @param fragment the {@code Calendar} field part of calendar to calculate - * @return number of seconds within the fragment of date - * @throws IllegalArgumentException if the date is null or - * fragment is not supported - * @since 2.4 - */ - public static long getFragmentInSeconds(Calendar calendar, int fragment) { - return getFragment(calendar, fragment, Calendar.SECOND); - } - - /** - *

Returns the number of minutes within the - * fragment. All datefields greater than the fragment will be ignored.

- * - *

Asking the minutes of any date will only return the number of minutes - * of the current hour (resulting in a number between 0 and 59). This - * method will retrieve the number of minutes for any fragment. - * For example, if you want to calculate the number of minutes past this month, - * your fragment is Calendar.MONTH. The result will be all minutes of the - * past day(s) and hour(s).

- * - *

Valid fragments are: Calendar.YEAR, Calendar.MONTH, both - * Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY, - * Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND - * A fragment less than or equal to a MINUTE field will return 0.

- * - *

- *

    - *
  • January 1, 2008 7:15:10.538 with Calendar.HOUR_OF_DAY as fragment will return 15 - * (equivalent to calendar.get(Calendar.MINUTES))
  • - *
  • January 6, 2008 7:15:10.538 with Calendar.HOUR_OF_DAY as fragment will return 15 - * (equivalent to calendar.get(Calendar.MINUTES))
  • - *
  • January 1, 2008 7:15:10.538 with Calendar.MONTH as fragment will return 15
  • - *
  • January 6, 2008 7:15:10.538 with Calendar.MONTH as fragment will return 435 (7*60 + 15)
  • - *
  • January 16, 2008 7:15:10.538 with Calendar.MILLISECOND as fragment will return 0 - * (a millisecond cannot be split in minutes)
  • - *
- *

- * - * @param calendar the calendar to work with, not null - * @param fragment the {@code Calendar} field part of calendar to calculate - * @return number of minutes within the fragment of date - * @throws IllegalArgumentException if the date is null or - * fragment is not supported - * @since 2.4 - */ - public static long getFragmentInMinutes(Calendar calendar, int fragment) { - return getFragment(calendar, fragment, Calendar.MINUTE); - } - - /** - *

Returns the number of hours within the - * fragment. All datefields greater than the fragment will be ignored.

- * - *

Asking the hours of any date will only return the number of hours - * of the current day (resulting in a number between 0 and 23). This - * method will retrieve the number of hours for any fragment. - * For example, if you want to calculate the number of hours past this month, - * your fragment is Calendar.MONTH. The result will be all hours of the - * past day(s).

- * - *

Valid fragments are: Calendar.YEAR, Calendar.MONTH, both - * Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY, - * Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND - * A fragment less than or equal to a HOUR field will return 0.

- * - *

- *

    - *
  • January 1, 2008 7:15:10.538 with Calendar.DAY_OF_YEAR as fragment will return 7 - * (equivalent to calendar.get(Calendar.HOUR_OF_DAY))
  • - *
  • January 6, 2008 7:15:10.538 with Calendar.DAY_OF_YEAR as fragment will return 7 - * (equivalent to calendar.get(Calendar.HOUR_OF_DAY))
  • - *
  • January 1, 2008 7:15:10.538 with Calendar.MONTH as fragment will return 7
  • - *
  • January 6, 2008 7:15:10.538 with Calendar.MONTH as fragment will return 127 (5*24 + 7)
  • - *
  • January 16, 2008 7:15:10.538 with Calendar.MILLISECOND as fragment will return 0 - * (a millisecond cannot be split in hours)
  • - *
- *

- * - * @param calendar the calendar to work with, not null - * @param fragment the {@code Calendar} field part of calendar to calculate - * @return number of hours within the fragment of date - * @throws IllegalArgumentException if the date is null or - * fragment is not supported - * @since 2.4 - */ - public static long getFragmentInHours(Calendar calendar, int fragment) { - return getFragment(calendar, fragment, Calendar.HOUR_OF_DAY); - } - - /** - *

Returns the number of days within the - * fragment. All datefields greater than the fragment will be ignored.

- * - *

Asking the days of any date will only return the number of days - * of the current month (resulting in a number between 1 and 31). This - * method will retrieve the number of days for any fragment. - * For example, if you want to calculate the number of days past this year, - * your fragment is Calendar.YEAR. The result will be all days of the - * past month(s).

- * - *

Valid fragments are: Calendar.YEAR, Calendar.MONTH, both - * Calendar.DAY_OF_YEAR and Calendar.DATE, Calendar.HOUR_OF_DAY, - * Calendar.MINUTE, Calendar.SECOND and Calendar.MILLISECOND - * A fragment less than or equal to a DAY field will return 0.

- * - *

- *

    - *
  • January 28, 2008 with Calendar.MONTH as fragment will return 28 - * (equivalent to calendar.get(Calendar.DAY_OF_MONTH))
  • - *
  • February 28, 2008 with Calendar.MONTH as fragment will return 28 - * (equivalent to calendar.get(Calendar.DAY_OF_MONTH))
  • - *
  • January 28, 2008 with Calendar.YEAR as fragment will return 28 - * (equivalent to calendar.get(Calendar.DAY_OF_YEAR))
  • - *
  • February 28, 2008 with Calendar.YEAR as fragment will return 59 - * (equivalent to calendar.get(Calendar.DAY_OF_YEAR))
  • - *
  • January 28, 2008 with Calendar.MILLISECOND as fragment will return 0 - * (a millisecond cannot be split in days)
  • - *
- *

- * - * @param calendar the calendar to work with, not null - * @param fragment the {@code Calendar} field part of calendar to calculate - * @return number of days within the fragment of date - * @throws IllegalArgumentException if the date is null or - * fragment is not supported - * @since 2.4 - */ - public static long getFragmentInDays(Calendar calendar, int fragment) { - return getFragment(calendar, fragment, Calendar.DAY_OF_YEAR); - } - - /** - * Date-version for fragment-calculation in any unit - * - * @param date the date to work with, not null - * @param fragment the Calendar field part of date to calculate - * @param unit the {@code Calendar} field defining the unit - * @return number of units within the fragment of the date - * @throws IllegalArgumentException if the date is null or - * fragment is not supported - * @since 2.4 - */ - private static long getFragment(Date date, int fragment, int unit) { - if(date == null) { - throw new IllegalArgumentException("The date must not be null"); - } - Calendar calendar = Calendar.getInstance(); - calendar.setTime(date); - return getFragment(calendar, fragment, unit); - } - - /** - * Calendar-version for fragment-calculation in any unit - * - * @param calendar the calendar to work with, not null - * @param fragment the Calendar field part of calendar to calculate - * @param unit the {@code Calendar} field defining the unit - * @return number of units within the fragment of the calendar - * @throws IllegalArgumentException if the date is null or - * fragment is not supported - * @since 2.4 - */ - private static long getFragment(Calendar calendar, int fragment, int unit) { - if(calendar == null) { - throw new IllegalArgumentException("The date must not be null"); - } - long millisPerUnit = getMillisPerUnit(unit); - long result = 0; - - // Fragments bigger than a day require a breakdown to days - switch (fragment) { - case Calendar.YEAR: - result += (calendar.get(Calendar.DAY_OF_YEAR) * MILLIS_PER_DAY) / millisPerUnit; - break; - case Calendar.MONTH: - result += (calendar.get(Calendar.DAY_OF_MONTH) * MILLIS_PER_DAY) / millisPerUnit; - break; - } - - switch (fragment) { - // Number of days already calculated for these cases - case Calendar.YEAR: - case Calendar.MONTH: - - // The rest of the valid cases - case Calendar.DAY_OF_YEAR: - case Calendar.DATE: - result += (calendar.get(Calendar.HOUR_OF_DAY) * MILLIS_PER_HOUR) / millisPerUnit; - //$FALL-THROUGH$ - case Calendar.HOUR_OF_DAY: - result += (calendar.get(Calendar.MINUTE) * MILLIS_PER_MINUTE) / millisPerUnit; - //$FALL-THROUGH$ - case Calendar.MINUTE: - result += (calendar.get(Calendar.SECOND) * MILLIS_PER_SECOND) / millisPerUnit; - //$FALL-THROUGH$ - case Calendar.SECOND: - result += (calendar.get(Calendar.MILLISECOND) * 1) / millisPerUnit; - break; - case Calendar.MILLISECOND: break;//never useful - default: throw new IllegalArgumentException("The fragment " + fragment + " is not supported"); - } - return result; - } - - /** - * Determines if two calendars are equal up to no more than the specified - * most significant field. - * - * @param cal1 the first calendar, not null - * @param cal2 the second calendar, not null - * @param field the field from {@code Calendar} - * @return true if equal; otherwise false - * @throws IllegalArgumentException if any argument is null - * @see #truncate(Calendar, int) - * @see #truncatedEquals(Date, Date, int) - * @since 3.0 - */ - public static boolean truncatedEquals(Calendar cal1, Calendar cal2, int field) { - return truncatedCompareTo(cal1, cal2, field) == 0; - } - - /** - * Determines if two dates are equal up to no more than the specified - * most significant field. - * - * @param date1 the first date, not null - * @param date2 the second date, not null - * @param field the field from {@code Calendar} - * @return true if equal; otherwise false - * @throws IllegalArgumentException if any argument is null - * @see #truncate(Date, int) - * @see #truncatedEquals(Calendar, Calendar, int) - * @since 3.0 - */ - public static boolean truncatedEquals(Date date1, Date date2, int field) { - return truncatedCompareTo(date1, date2, field) == 0; - } - - /** - * Determines how two calendars compare up to no more than the specified - * most significant field. - * - * @param cal1 the first calendar, not null - * @param cal2 the second calendar, not null - * @param field the field from {@code Calendar} - * @return a negative integer, zero, or a positive integer as the first - * calendar is less than, equal to, or greater than the second. - * @throws IllegalArgumentException if any argument is null - * @see #truncate(Calendar, int) - * @see #truncatedCompareTo(Date, Date, int) - * @since 3.0 - */ - public static int truncatedCompareTo(Calendar cal1, Calendar cal2, int field) { - Calendar truncatedCal1 = truncate(cal1, field); - Calendar truncatedCal2 = truncate(cal2, field); - return truncatedCal1.compareTo(truncatedCal2); - } - - /** - * Determines how two dates compare up to no more than the specified - * most significant field. - * - * @param date1 the first date, not null - * @param date2 the second date, not null - * @param field the field from Calendar - * @return a negative integer, zero, or a positive integer as the first - * date is less than, equal to, or greater than the second. - * @throws IllegalArgumentException if any argument is null - * @see #truncate(Calendar, int) - * @see #truncatedCompareTo(Date, Date, int) - * @since 3.0 - */ - public static int truncatedCompareTo(Date date1, Date date2, int field) { - Date truncatedDate1 = truncate(date1, field); - Date truncatedDate2 = truncate(date2, field); - return truncatedDate1.compareTo(truncatedDate2); - } - - /** - * Returns the number of milliseconds of a {@code Calendar} field, if this is a constant value. - * This handles millisecond, second, minute, hour and day (even though days can very in length). - * - * @param unit a {@code Calendar} field constant which is a valid unit for a fragment - * @return the number of milliseconds in the field - * @throws IllegalArgumentException if date can't be represented in milliseconds - * @since 2.4 - */ - private static long getMillisPerUnit(int unit) { - long result = Long.MAX_VALUE; - switch (unit) { - case Calendar.DAY_OF_YEAR: - case Calendar.DATE: - result = MILLIS_PER_DAY; - break; - case Calendar.HOUR_OF_DAY: - result = MILLIS_PER_HOUR; - break; - case Calendar.MINUTE: - result = MILLIS_PER_MINUTE; - break; - case Calendar.SECOND: - result = MILLIS_PER_SECOND; - break; - case Calendar.MILLISECOND: - result = 1; - break; - default: throw new IllegalArgumentException("The unit " + unit + " cannot be represented is milleseconds"); - } - return result; - } - - //----------------------------------------------------------------------- - /** - *

Date iterator.

- */ - static class DateIterator implements Iterator { - private final Calendar endFinal; - private final Calendar spot; - - /** - * Constructs a DateIterator that ranges from one date to another. - * - * @param startFinal start date (inclusive) - * @param endFinal end date (not inclusive) - */ - DateIterator(Calendar startFinal, Calendar endFinal) { - super(); - this.endFinal = endFinal; - spot = startFinal; - spot.add(Calendar.DATE, -1); - } - - /** - * Has the iterator not reached the end date yet? - * - * @return true if the iterator has yet to reach the end date - */ - public boolean hasNext() { - return spot.before(endFinal); - } - - /** - * Return the next calendar in the iteration - * - * @return Object calendar for the next date - */ - public Calendar next() { - if (spot.equals(endFinal)) { - throw new NoSuchElementException(); - } - spot.add(Calendar.DATE, 1); - return (Calendar) spot.clone(); - } - - /** - * Always throws UnsupportedOperationException. - * - * @throws UnsupportedOperationException - * @see java.util.Iterator#remove() - */ - public void remove() { - throw new UnsupportedOperationException(); - } - } - -} diff --git a/src/org/apache/commons/lang3/time/DurationFormatUtils.java b/src/org/apache/commons/lang3/time/DurationFormatUtils.java deleted file mode 100644 index 9f8d622..0000000 --- a/src/org/apache/commons/lang3/time/DurationFormatUtils.java +++ /dev/null @@ -1,662 +0,0 @@ -/* - * 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; - -/** - *

Duration formatting utilities and constants. The following table describes the tokens - * used in the pattern language for formatting.

- * - * - * - * - * - * - * - * - * - *
characterduration element
yyears
Mmonths
ddays
Hhours
mminutes
sseconds
Smilliseconds
- * - * @since 2.1 - * @version $Id: DurationFormatUtils.java 1144993 2011-07-11 00:51:16Z ggregory $ - */ -public class DurationFormatUtils { - - /** - *

DurationFormatUtils instances should NOT be constructed in standard programming.

- * - *

This constructor is public to permit tools that require a JavaBean instance - * to operate.

- */ - public DurationFormatUtils() { - super(); - } - - /** - *

Pattern used with FastDateFormat and SimpleDateFormat - * for the ISO8601 period format used in durations.

- * - * @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.S'S'"; - - //----------------------------------------------------------------------- - /** - *

Formats the time gap as a string.

- * - *

The format used is ISO8601-like: - * H:m:s.S.

- * - * @param durationMillis the duration to format - * @return the formatted duration, not null - */ - public static String formatDurationHMS(long durationMillis) { - return formatDuration(durationMillis, "H:mm:ss.SSS"); - } - - /** - *

Formats the time gap as a string.

- * - *

The format used is the ISO8601 period format.

- * - *

This method formats durations using the days and lower fields of the - * ISO format pattern, such as P7D6TH5M4.321S.

- * - * @param durationMillis the duration to format - * @return the formatted duration, not null - */ - public static String formatDurationISO(long durationMillis) { - return formatDuration(durationMillis, ISO_EXTENDED_FORMAT_PATTERN, false); - } - - /** - *

Formats the time gap as a string, using the specified format, and padding with zeros and - * using the default timezone.

- * - *

This method formats durations using the days and lower fields of the - * format pattern. Months and larger are not used.

- * - * @param durationMillis the duration to format - * @param format the way in which to format the duration, not null - * @return the formatted duration, not null - */ - public static String formatDuration(long durationMillis, String format) { - return formatDuration(durationMillis, format, true); - } - - /** - *

Formats the time gap as a string, using the specified format. - * Padding the left hand side of numbers with zeroes is optional and - * the timezone may be specified.

- * - *

This method formats durations using the days and lower fields of the - * format pattern. Months and larger are not used.

- * - * @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 - */ - public static String formatDuration(long durationMillis, String format, boolean padWithZeros) { - - Token[] tokens = lexx(format); - - int days = 0; - int hours = 0; - int minutes = 0; - int seconds = 0; - int milliseconds = 0; - - if (Token.containsTokenWithValue(tokens, d) ) { - days = (int) (durationMillis / DateUtils.MILLIS_PER_DAY); - durationMillis = durationMillis - (days * DateUtils.MILLIS_PER_DAY); - } - if (Token.containsTokenWithValue(tokens, H) ) { - hours = (int) (durationMillis / DateUtils.MILLIS_PER_HOUR); - durationMillis = durationMillis - (hours * DateUtils.MILLIS_PER_HOUR); - } - if (Token.containsTokenWithValue(tokens, m) ) { - minutes = (int) (durationMillis / DateUtils.MILLIS_PER_MINUTE); - durationMillis = durationMillis - (minutes * DateUtils.MILLIS_PER_MINUTE); - } - if (Token.containsTokenWithValue(tokens, s) ) { - seconds = (int) (durationMillis / DateUtils.MILLIS_PER_SECOND); - durationMillis = durationMillis - (seconds * DateUtils.MILLIS_PER_SECOND); - } - if (Token.containsTokenWithValue(tokens, S) ) { - milliseconds = (int) durationMillis; - } - - return format(tokens, 0, 0, days, hours, minutes, seconds, milliseconds, padWithZeros); - } - - /** - *

Formats an elapsed time into a plurialization correct string.

- * - *

This method formats durations using the days and lower fields of the - * format pattern. Months and larger are not used.

- * - * @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 - */ - public static String formatDurationWords( - long durationMillis, - boolean suppressLeadingZeroElements, - boolean suppressTrailingZeroElements) { - - // This method is generally replacable 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", ""); - if (tmp.length() != duration.length()) { - duration = tmp; - tmp = StringUtils.replaceOnce(duration, " 0 hours", ""); - if (tmp.length() != duration.length()) { - duration = tmp; - tmp = StringUtils.replaceOnce(duration, " 0 minutes", ""); - duration = tmp; - if (tmp.length() != duration.length()) { - duration = StringUtils.replaceOnce(tmp, " 0 seconds", ""); - } - } - } - if (duration.length() != 0) { - // strip the space off again - duration = duration.substring(1); - } - } - if (suppressTrailingZeroElements) { - String tmp = StringUtils.replaceOnce(duration, " 0 seconds", ""); - if (tmp.length() != duration.length()) { - duration = tmp; - tmp = StringUtils.replaceOnce(duration, " 0 minutes", ""); - if (tmp.length() != duration.length()) { - duration = tmp; - tmp = StringUtils.replaceOnce(duration, " 0 hours", ""); - if (tmp.length() != duration.length()) { - duration = StringUtils.replaceOnce(tmp, " 0 days", ""); - } - } - } - } - // 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(); - } - - //----------------------------------------------------------------------- - /** - *

Formats the time gap as a string.

- * - *

The format used is the ISO8601 period format.

- * - * @param startMillis the start of the duration to format - * @param endMillis the end of the duration to format - * @return the formatted duration, not null - */ - public static String formatPeriodISO(long startMillis, long endMillis) { - return formatPeriod(startMillis, endMillis, ISO_EXTENDED_FORMAT_PATTERN, false, TimeZone.getDefault()); - } - - /** - *

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 - */ - public static String formatPeriod(long startMillis, long endMillis, String format) { - return formatPeriod(startMillis, endMillis, format, true, TimeZone.getDefault()); - } - - /** - *

Formats the time gap as a string, using the specified format. - * Padding the left hand side of numbers with zeroes is optional and - * the timezone may be specified.

- * - *

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.

- * - *

For more control, the Joda-Time - * library is recommended.

- * - * @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 - */ - public static String formatPeriod(long startMillis, long endMillis, String format, boolean padWithZeros, - TimeZone timezone) { - - // 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. - - Token[] tokens = lexx(format); - - // timezones get funky around 0, so normalizing everything to GMT - // stops the hours being off - Calendar start = Calendar.getInstance(timezone); - start.setTime(new Date(startMillis)); - 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); - } - - //----------------------------------------------------------------------- - /** - *

The internal method to do the formatting.

- * - * @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(Token[] tokens, int years, int months, int days, int hours, int minutes, int seconds, - int milliseconds, boolean padWithZeros) { - StringBuffer buffer = new StringBuffer(); - boolean lastOutputSeconds = false; - int sz = tokens.length; - for (int i = 0; i < sz; i++) { - Token token = tokens[i]; - Object value = token.getValue(); - int count = token.getCount(); - if (value instanceof StringBuffer) { - buffer.append(value.toString()); - } else { - if (value == y) { - buffer.append(padWithZeros ? StringUtils.leftPad(Integer.toString(years), count, '0') : Integer - .toString(years)); - lastOutputSeconds = false; - } else if (value == M) { - buffer.append(padWithZeros ? StringUtils.leftPad(Integer.toString(months), count, '0') : Integer - .toString(months)); - lastOutputSeconds = false; - } else if (value == d) { - buffer.append(padWithZeros ? StringUtils.leftPad(Integer.toString(days), count, '0') : Integer - .toString(days)); - lastOutputSeconds = false; - } else if (value == H) { - buffer.append(padWithZeros ? StringUtils.leftPad(Integer.toString(hours), count, '0') : Integer - .toString(hours)); - lastOutputSeconds = false; - } else if (value == m) { - buffer.append(padWithZeros ? StringUtils.leftPad(Integer.toString(minutes), count, '0') : Integer - .toString(minutes)); - lastOutputSeconds = false; - } else if (value == s) { - buffer.append(padWithZeros ? StringUtils.leftPad(Integer.toString(seconds), count, '0') : Integer - .toString(seconds)); - lastOutputSeconds = true; - } else if (value == S) { - if (lastOutputSeconds) { - milliseconds += 1000; - String str = padWithZeros - ? StringUtils.leftPad(Integer.toString(milliseconds), count, '0') - : Integer.toString(milliseconds); - buffer.append(str.substring(1)); - } else { - buffer.append(padWithZeros - ? StringUtils.leftPad(Integer.toString(milliseconds), count, '0') - : Integer.toString(milliseconds)); - } - lastOutputSeconds = false; - } - } - } - return buffer.toString(); - } - - static final Object y = "y"; - static final Object M = "M"; - static final Object d = "d"; - static final Object H = "H"; - static final Object m = "m"; - static final Object s = "s"; - static final Object 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(String format) { - char[] array = format.toCharArray(); - ArrayList list = new ArrayList(array.length); - - boolean inLiteral = false; - StringBuffer buffer = null; - Token previous = null; - int sz = array.length; - for(int i=0; itrue if contained - */ - static boolean containsTokenWithValue(Token[] tokens, Object value) { - int sz = tokens.length; - for (int i = 0; i < sz; i++) { - if (tokens[i].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(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(Object value, 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 true if equal - */ - @Override - public boolean equals(Object obj2) { - if (obj2 instanceof Token) { - Token tok2 = (Token) obj2; - if (this.value.getClass() != tok2.value.getClass()) { - return false; - } - if (this.count != tok2.count) { - return false; - } - if (this.value instanceof StringBuffer) { - 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); - } - } - -} diff --git a/src/org/apache/commons/lang3/time/FastDateFormat.java b/src/org/apache/commons/lang3/time/FastDateFormat.java deleted file mode 100644 index 3a60527..0000000 --- a/src/org/apache/commons/lang3/time/FastDateFormat.java +++ /dev/null @@ -1,1519 +0,0 @@ -/* - * 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.io.IOException; -import java.io.ObjectInputStream; -import java.text.DateFormat; -import java.text.DateFormatSymbols; -import java.text.FieldPosition; -import java.text.Format; -import java.text.ParsePosition; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.List; -import java.util.Locale; -import java.util.TimeZone; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import org.apache.commons.lang3.Validate; - -/** - *

FastDateFormat is a fast and thread-safe version of - * {@link java.text.SimpleDateFormat}.

- * - *

This class can be used as a direct replacement to - * {@code SimpleDateFormat} in most formatting 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. - *

- * - *

Only formatting is supported, but all patterns are compatible with - * SimpleDateFormat (except time zones and some year patterns - see below).

- * - *

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).

- * - *

In addition, the pattern {@code 'ZZ'} has been made to represent - * ISO8601 full 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.

- * - *

Javadoc cites for the year pattern: For formatting, if the number of - * pattern letters is 2, the year is truncated to 2 digits; otherwise it is - * interpreted as a number. 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.

- * - * @since 2.0 - * @version $Id: FastDateFormat.java 1146138 2011-07-13 17:01:37Z joehni $ - */ -public class FastDateFormat extends Format { - // A lot of the speed in this class comes from caching, but some comes - // from the special int to StringBuffer conversion. - // - // The following produces a padded 2 digit number: - // buffer.append((char)(value / 10 + '0')); - // buffer.append((char)(value % 10 + '0')); - // - // Note that the fastest append to StringBuffer is a single char (used here). - // Note that Integer.toString() is not called, the conversion is simply - // taking the value and adding (mathematically) the ASCII value for '0'. - // So, don't change this code! It works and is very fast. - - /** - * Required for serialization support. - * - * @see java.io.Serializable - */ - private static final long serialVersionUID = 1L; - - /** - * 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 cache= new FormatCache() { - @Override - protected FastDateFormat createInstance(String pattern, TimeZone timeZone, Locale locale) { - return new FastDateFormat(pattern, timeZone, locale); - } - }; - - private static ConcurrentMap cTimeZoneDisplayCache = - new ConcurrentHashMap(7); - - /** - * The pattern. - */ - private final String mPattern; - /** - * The time zone. - */ - private final TimeZone mTimeZone; - /** - * The locale. - */ - private final Locale mLocale; - /** - * The parsed rules. - */ - private transient Rule[] mRules; - /** - * The estimated maximum length. - */ - private transient int mMaxLengthEstimate; - - //----------------------------------------------------------------------- - /** - *

Gets a formatter instance using the default pattern in the - * default locale.

- * - * @return a date/time formatter - */ - public static FastDateFormat getInstance() { - return cache.getDateTimeInstance(SHORT, SHORT, null, null); - } - - /** - *

Gets a formatter instance using the specified pattern in the - * default locale.

- * - * @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(String pattern) { - return cache.getInstance(pattern, null, null); - } - - /** - *

Gets a formatter instance using the specified pattern and - * time zone.

- * - * @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(String pattern, TimeZone timeZone) { - return cache.getInstance(pattern, timeZone, null); - } - - /** - *

Gets a formatter instance using the specified pattern and - * locale.

- * - * @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(String pattern, Locale locale) { - return cache.getInstance(pattern, null, locale); - } - - /** - *

Gets a formatter instance using the specified pattern, time zone - * and locale.

- * - * @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(String pattern, TimeZone timeZone, Locale locale) { - return cache.getInstance(pattern, timeZone, locale); - } - - //----------------------------------------------------------------------- - /** - *

Gets a date formatter instance using the specified style in the - * default time zone and locale.

- * - * @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(int style) { - return cache.getDateTimeInstance(style, null, null, null); - } - - /** - *

Gets a date formatter instance using the specified style and - * locale in the default time zone.

- * - * @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(int style, Locale locale) { - return cache.getDateTimeInstance(style, null, null, locale); - } - - /** - *

Gets a date formatter instance using the specified style and - * time zone in the default locale.

- * - * @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(int style, TimeZone timeZone) { - return cache.getDateTimeInstance(style, null, timeZone, null); - } - - /** - *

Gets a date formatter instance using the specified style, time - * zone and locale.

- * - * @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(int style, TimeZone timeZone, Locale locale) { - return cache.getDateTimeInstance(style, null, timeZone, locale); - } - - //----------------------------------------------------------------------- - /** - *

Gets a time formatter instance using the specified style in the - * default time zone and locale.

- * - * @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(int style) { - return cache.getDateTimeInstance(null, style, null, null); - } - - /** - *

Gets a time formatter instance using the specified style and - * locale in the default time zone.

- * - * @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(int style, Locale locale) { - return cache.getDateTimeInstance(null, style, null, locale); - } - - /** - *

Gets a time formatter instance using the specified style and - * time zone in the default locale.

- * - * @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(int style, TimeZone timeZone) { - return cache.getDateTimeInstance(null, style, timeZone, null); - } - - /** - *

Gets a time formatter instance using the specified style, time - * zone and locale.

- * - * @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(int style, TimeZone timeZone, Locale locale) { - return cache.getDateTimeInstance(null, style, timeZone, locale); - } - - //----------------------------------------------------------------------- - /** - *

Gets a date/time formatter instance using the specified style - * in the default time zone and locale.

- * - * @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(int dateStyle, int timeStyle) { - return cache.getDateTimeInstance(dateStyle, timeStyle, null, null); - } - - /** - *

Gets a date/time formatter instance using the specified style and - * locale in the default time zone.

- * - * @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(int dateStyle, int timeStyle, Locale locale) { - return cache.getDateTimeInstance(dateStyle, timeStyle, null, locale); - } - - /** - *

Gets a date/time formatter instance using the specified style and - * time zone in the default 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 - * @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(int dateStyle, int timeStyle, TimeZone timeZone) { - return getDateTimeInstance(dateStyle, timeStyle, timeZone, null); - } - /** - *

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 - * @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( - int dateStyle, int timeStyle, TimeZone timeZone, Locale locale) { - return cache.getDateTimeInstance(dateStyle, timeStyle, timeZone, locale); - } - - //----------------------------------------------------------------------- - /** - *

Gets the time zone display name, using a cache for performance.

- * - * @param tz the zone to query - * @param daylight true if daylight savings - * @param style the style to use {@code TimeZone.LONG} or {@code TimeZone.SHORT} - * @param locale the locale to use - * @return the textual name of the time zone - */ - static String getTimeZoneDisplay(TimeZone tz, boolean daylight, int style, Locale locale) { - TimeZoneDisplayKey key = new TimeZoneDisplayKey(tz, daylight, style, locale); - String value = cTimeZoneDisplayCache.get(key); - if (value == null) { - // This is a very slow call, so cache the results. - value = tz.getDisplayName(daylight, style, locale); - String prior = cTimeZoneDisplayCache.putIfAbsent(key, value); - if (prior != null) { - value= prior; - } - } - return value; - } - - // Constructor - //----------------------------------------------------------------------- - /** - *

Constructs a new FastDateFormat.

- * - * @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(String pattern, TimeZone timeZone, Locale locale) { - mPattern = pattern; - mTimeZone = timeZone; - mLocale = locale; - - init(); - } - - /** - *

Initializes the instance for first use.

- */ - private void init() { - List rulesList = parsePattern(); - mRules = rulesList.toArray(new Rule[rulesList.size()]); - - int len = 0; - for (int i=mRules.length; --i >= 0; ) { - len += mRules[i].estimateLength(); - } - - mMaxLengthEstimate = len; - } - - // Parse the pattern - //----------------------------------------------------------------------- - /** - *

Returns a list of Rules given a pattern.

- * - * @return a {@code List} of Rule objects - * @throws IllegalArgumentException if pattern is invalid - */ - protected List parsePattern() { - DateFormatSymbols symbols = new DateFormatSymbols(mLocale); - List rules = new ArrayList(); - - String[] ERAs = symbols.getEras(); - String[] months = symbols.getMonths(); - String[] shortMonths = symbols.getShortMonths(); - String[] weekdays = symbols.getWeekdays(); - String[] shortWeekdays = symbols.getShortWeekdays(); - String[] AmPmStrings = symbols.getAmPmStrings(); - - int length = mPattern.length(); - int[] indexRef = new int[1]; - - for (int i = 0; i < length; i++) { - indexRef[0] = i; - String token = parseToken(mPattern, indexRef); - i = indexRef[0]; - - int tokenLen = token.length(); - if (tokenLen == 0) { - break; - } - - Rule rule; - char c = token.charAt(0); - - switch (c) { - case 'G': // era designator (text) - rule = new TextField(Calendar.ERA, ERAs); - break; - case 'y': // year (number) - if (tokenLen == 2) { - rule = TwoDigitYearField.INSTANCE; - } else { - rule = selectNumberRule(Calendar.YEAR, tokenLen < 4 ? 4 : tokenLen); - } - break; - case 'M': // month in year (text and number) - if (tokenLen >= 4) { - rule = new TextField(Calendar.MONTH, months); - } else if (tokenLen == 3) { - rule = new TextField(Calendar.MONTH, shortMonths); - } else if (tokenLen == 2) { - rule = TwoDigitMonthField.INSTANCE; - } else { - rule = UnpaddedMonthField.INSTANCE; - } - break; - case 'd': // day in month (number) - rule = selectNumberRule(Calendar.DAY_OF_MONTH, tokenLen); - break; - case 'h': // hour in am/pm (number, 1..12) - rule = new TwelveHourField(selectNumberRule(Calendar.HOUR, tokenLen)); - break; - case 'H': // hour in day (number, 0..23) - rule = selectNumberRule(Calendar.HOUR_OF_DAY, tokenLen); - break; - case 'm': // minute in hour (number) - rule = selectNumberRule(Calendar.MINUTE, tokenLen); - break; - case 's': // second in minute (number) - rule = selectNumberRule(Calendar.SECOND, tokenLen); - break; - case 'S': // millisecond (number) - rule = selectNumberRule(Calendar.MILLISECOND, tokenLen); - break; - case 'E': // day in week (text) - rule = new TextField(Calendar.DAY_OF_WEEK, tokenLen < 4 ? shortWeekdays : weekdays); - break; - case 'D': // day in year (number) - rule = selectNumberRule(Calendar.DAY_OF_YEAR, tokenLen); - break; - case 'F': // day of week in month (number) - rule = selectNumberRule(Calendar.DAY_OF_WEEK_IN_MONTH, tokenLen); - break; - case 'w': // week in year (number) - rule = selectNumberRule(Calendar.WEEK_OF_YEAR, tokenLen); - break; - case 'W': // week in month (number) - rule = selectNumberRule(Calendar.WEEK_OF_MONTH, tokenLen); - break; - case 'a': // am/pm marker (text) - rule = new TextField(Calendar.AM_PM, AmPmStrings); - break; - case 'k': // hour in day (1..24) - rule = new TwentyFourHourField(selectNumberRule(Calendar.HOUR_OF_DAY, tokenLen)); - break; - case 'K': // hour in am/pm (0..11) - rule = selectNumberRule(Calendar.HOUR, tokenLen); - break; - case 'z': // time zone (text) - if (tokenLen >= 4) { - rule = new TimeZoneNameRule(mTimeZone, mLocale, TimeZone.LONG); - } else { - rule = new TimeZoneNameRule(mTimeZone, mLocale, TimeZone.SHORT); - } - break; - case 'Z': // time zone (value) - if (tokenLen == 1) { - rule = TimeZoneNumberRule.INSTANCE_NO_COLON; - } else { - rule = TimeZoneNumberRule.INSTANCE_COLON; - } - break; - case '\'': // literal text - String sub = token.substring(1); - if (sub.length() == 1) { - rule = new CharacterLiteral(sub.charAt(0)); - } else { - rule = new StringLiteral(sub); - } - break; - default: - throw new IllegalArgumentException("Illegal pattern component: " + token); - } - - rules.add(rule); - } - - return rules; - } - - /** - *

Performs the parsing of tokens.

- * - * @param pattern the pattern - * @param indexRef index references - * @return parsed token - */ - protected String parseToken(String pattern, int[] indexRef) { - StringBuilder buf = new StringBuilder(); - - int i = indexRef[0]; - int length = pattern.length(); - - char c = pattern.charAt(i); - if (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z') { - // Scan a run of the same character, which indicates a time - // pattern. - buf.append(c); - - while (i + 1 < length) { - char peek = pattern.charAt(i + 1); - if (peek == c) { - buf.append(c); - i++; - } else { - break; - } - } - } else { - // This will identify token as text. - buf.append('\''); - - boolean inLiteral = false; - - for (; i < length; i++) { - c = pattern.charAt(i); - - if (c == '\'') { - if (i + 1 < length && pattern.charAt(i + 1) == '\'') { - // '' is treated as escaped ' - i++; - buf.append(c); - } else { - inLiteral = !inLiteral; - } - } else if (!inLiteral && - (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z')) { - i--; - break; - } else { - buf.append(c); - } - } - } - - indexRef[0] = i; - return buf.toString(); - } - - /** - *

Gets an appropriate rule for the padding required.

- * - * @param field the field to get a rule for - * @param padding the padding required - * @return a new rule with the correct padding - */ - protected NumberRule selectNumberRule(int field, int padding) { - switch (padding) { - case 1: - return new UnpaddedNumberField(field); - case 2: - return new TwoDigitNumberField(field); - default: - return new PaddedNumberField(field, padding); - } - } - - // Format methods - //----------------------------------------------------------------------- - /** - *

Formats a {@code Date}, {@code Calendar} or - * {@code Long} (milliseconds) object.

- * - * @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(Object obj, StringBuffer toAppendTo, FieldPosition pos) { - if (obj instanceof Date) { - return format((Date) obj, toAppendTo); - } else if (obj instanceof Calendar) { - return format((Calendar) obj, toAppendTo); - } else if (obj instanceof Long) { - return format(((Long) obj).longValue(), toAppendTo); - } else { - throw new IllegalArgumentException("Unknown class: " + - (obj == null ? "" : obj.getClass().getName())); - } - } - - /** - *

Formats a millisecond {@code long} value.

- * - * @param millis the millisecond value to format - * @return the formatted string - * @since 2.1 - */ - public String format(long millis) { - return format(new Date(millis)); - } - - /** - *

Formats a {@code Date} object using a {@code GregorianCalendar}.

- * - * @param date the date to format - * @return the formatted string - */ - public String format(Date date) { - Calendar c = new GregorianCalendar(mTimeZone, mLocale); // hard code GregorianCalendar - c.setTime(date); - return applyRules(c, new StringBuffer(mMaxLengthEstimate)).toString(); - } - - /** - *

Formats a {@code Calendar} object.

- * - * @param calendar the calendar to format - * @return the formatted string - */ - public String format(Calendar calendar) { - return format(calendar, new StringBuffer(mMaxLengthEstimate)).toString(); - } - - /** - *

Formats a milliseond {@code long} value into the - * supplied {@code StringBuffer}.

- * - * @param millis the millisecond value to format - * @param buf the buffer to format into - * @return the specified string buffer - * @since 2.1 - */ - public StringBuffer format(long millis, StringBuffer buf) { - return format(new Date(millis), buf); - } - - /** - *

Formats a {@code Date} object into the - * supplied {@code StringBuffer} using a {@code GregorianCalendar}.

- * - * @param date the date to format - * @param buf the buffer to format into - * @return the specified string buffer - */ - public StringBuffer format(Date date, StringBuffer buf) { - Calendar c = new GregorianCalendar(mTimeZone, mLocale); // hard code GregorianCalendar - c.setTime(date); - return applyRules(c, buf); - } - - /** - *

Formats a {@code Calendar} object into the - * supplied {@code StringBuffer}.

- * - * @param calendar the calendar to format - * @param buf the buffer to format into - * @return the specified string buffer - */ - public StringBuffer format(Calendar calendar, StringBuffer buf) { - return applyRules(calendar, buf); - } - - /** - *

Performs the formatting by applying the rules to the - * specified calendar.

- * - * @param calendar the calendar to format - * @param buf the buffer to format into - * @return the specified string buffer - */ - protected StringBuffer applyRules(Calendar calendar, StringBuffer buf) { - for (Rule rule : mRules) { - rule.appendTo(buf, calendar); - } - return buf; - } - - // Parsing - //----------------------------------------------------------------------- - /** - *

Parsing is not supported.

- * - * @param source the string to parse - * @param pos the parsing position - * @return {@code null} as not supported - */ - @Override - public Object parseObject(String source, ParsePosition pos) { - pos.setIndex(0); - pos.setErrorIndex(0); - return null; - } - - // Accessors - //----------------------------------------------------------------------- - /** - *

Gets the pattern used by this formatter.

- * - * @return the pattern, {@link java.text.SimpleDateFormat} compatible - */ - public String getPattern() { - return mPattern; - } - - /** - *

Gets the time zone used by this formatter.

- * - *

This zone is always used for {@code Date} formatting.

- * - * @return the time zone - */ - public TimeZone getTimeZone() { - return mTimeZone; - } - - /** - *

Gets the locale used by this formatter.

- * - * @return the locale - */ - public Locale getLocale() { - return mLocale; - } - - /** - *

Gets an estimate for the maximum string length that the - * formatter will produce.

- * - *

The actual formatted length will almost always be less than or - * equal to this amount.

- * - * @return the maximum formatted length - */ - public int getMaxLengthEstimate() { - return mMaxLengthEstimate; - } - - // Basics - //----------------------------------------------------------------------- - /** - *

Compares two objects for equality.

- * - * @param obj the object to compare to - * @return {@code true} if equal - */ - @Override - public boolean equals(Object obj) { - if (obj instanceof FastDateFormat == false) { - return false; - } - FastDateFormat other = (FastDateFormat) obj; - return mPattern.equals(other.mPattern) - && mTimeZone.equals(other.mTimeZone) - && mLocale.equals(other.mLocale); - } - - /** - *

Returns a hashcode compatible with equals.

- * - * @return a hashcode compatible with equals - */ - @Override - public int hashCode() { - return mPattern.hashCode() + 13 * (mTimeZone.hashCode() + 13 * mLocale.hashCode()); - } - - /** - *

Gets a debugging string version of this formatter.

- * - * @return a debugging string - */ - @Override - public String toString() { - return "FastDateFormat[" + mPattern + "]"; - } - - // Serializing - //----------------------------------------------------------------------- - /** - * Create the object after serialization. This implementation reinitializes the - * transient properties. - * - * @param in ObjectInputStream from which the object is being deserialized. - * @throws IOException if there is an IO issue. - * @throws ClassNotFoundException if a class cannot be found. - */ - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - in.defaultReadObject(); - init(); - } - - // Rules - //----------------------------------------------------------------------- - /** - *

Inner class defining a rule.

- */ - private interface Rule { - /** - * Returns the estimated lentgh of the result. - * - * @return the estimated length - */ - int estimateLength(); - - /** - * Appends the value of the specified calendar to the output buffer based on the rule implementation. - * - * @param buffer the output buffer - * @param calendar calendar to be appended - */ - void appendTo(StringBuffer buffer, Calendar calendar); - } - - /** - *

Inner class defining a numeric rule.

- */ - private interface NumberRule extends Rule { - /** - * Appends the specified value to the output buffer based on the rule implementation. - * - * @param buffer the output buffer - * @param value the value to be appended - */ - void appendTo(StringBuffer buffer, int value); - } - - /** - *

Inner class to output a constant single character.

- */ - private static class CharacterLiteral implements Rule { - private final char mValue; - - /** - * Constructs a new instance of {@code CharacterLiteral} - * to hold the specified value. - * - * @param value the character literal - */ - CharacterLiteral(char value) { - mValue = value; - } - - /** - * {@inheritDoc} - */ - public int estimateLength() { - return 1; - } - - /** - * {@inheritDoc} - */ - public void appendTo(StringBuffer buffer, Calendar calendar) { - buffer.append(mValue); - } - } - - /** - *

Inner class to output a constant string.

- */ - private static class StringLiteral implements Rule { - private final String mValue; - - /** - * Constructs a new instance of {@code StringLiteral} - * to hold the specified value. - * - * @param value the string literal - */ - StringLiteral(String value) { - mValue = value; - } - - /** - * {@inheritDoc} - */ - public int estimateLength() { - return mValue.length(); - } - - /** - * {@inheritDoc} - */ - public void appendTo(StringBuffer buffer, Calendar calendar) { - buffer.append(mValue); - } - } - - /** - *

Inner class to output one of a set of values.

- */ - private static class TextField implements Rule { - private final int mField; - private final String[] mValues; - - /** - * Constructs an instance of {@code TextField} - * with the specified field and values. - * - * @param field the field - * @param values the field values - */ - TextField(int field, String[] values) { - mField = field; - mValues = values; - } - - /** - * {@inheritDoc} - */ - public int estimateLength() { - int max = 0; - for (int i=mValues.length; --i >= 0; ) { - int len = mValues[i].length(); - if (len > max) { - max = len; - } - } - return max; - } - - /** - * {@inheritDoc} - */ - public void appendTo(StringBuffer buffer, Calendar calendar) { - buffer.append(mValues[calendar.get(mField)]); - } - } - - /** - *

Inner class to output an unpadded number.

- */ - private static class UnpaddedNumberField implements NumberRule { - private final int mField; - - /** - * Constructs an instance of {@code UnpadedNumberField} with the specified field. - * - * @param field the field - */ - UnpaddedNumberField(int field) { - mField = field; - } - - /** - * {@inheritDoc} - */ - public int estimateLength() { - return 4; - } - - /** - * {@inheritDoc} - */ - public void appendTo(StringBuffer buffer, Calendar calendar) { - appendTo(buffer, calendar.get(mField)); - } - - /** - * {@inheritDoc} - */ - public final void appendTo(StringBuffer buffer, int value) { - if (value < 10) { - buffer.append((char)(value + '0')); - } else if (value < 100) { - buffer.append((char)(value / 10 + '0')); - buffer.append((char)(value % 10 + '0')); - } else { - buffer.append(Integer.toString(value)); - } - } - } - - /** - *

Inner class to output an unpadded month.

- */ - private static class UnpaddedMonthField implements NumberRule { - static final UnpaddedMonthField INSTANCE = new UnpaddedMonthField(); - - /** - * Constructs an instance of {@code UnpaddedMonthField}. - * - */ - UnpaddedMonthField() { - super(); - } - - /** - * {@inheritDoc} - */ - public int estimateLength() { - return 2; - } - - /** - * {@inheritDoc} - */ - public void appendTo(StringBuffer buffer, Calendar calendar) { - appendTo(buffer, calendar.get(Calendar.MONTH) + 1); - } - - /** - * {@inheritDoc} - */ - public final void appendTo(StringBuffer buffer, int value) { - if (value < 10) { - buffer.append((char)(value + '0')); - } else { - buffer.append((char)(value / 10 + '0')); - buffer.append((char)(value % 10 + '0')); - } - } - } - - /** - *

Inner class to output a padded number.

- */ - private static class PaddedNumberField implements NumberRule { - private final int mField; - private final int mSize; - - /** - * Constructs an instance of {@code PaddedNumberField}. - * - * @param field the field - * @param size size of the output field - */ - PaddedNumberField(int field, int size) { - if (size < 3) { - // Should use UnpaddedNumberField or TwoDigitNumberField. - throw new IllegalArgumentException(); - } - mField = field; - mSize = size; - } - - /** - * {@inheritDoc} - */ - public int estimateLength() { - return 4; - } - - /** - * {@inheritDoc} - */ - public void appendTo(StringBuffer buffer, Calendar calendar) { - appendTo(buffer, calendar.get(mField)); - } - - /** - * {@inheritDoc} - */ - public final void appendTo(StringBuffer buffer, int value) { - if (value < 100) { - for (int i = mSize; --i >= 2; ) { - buffer.append('0'); - } - buffer.append((char)(value / 10 + '0')); - buffer.append((char)(value % 10 + '0')); - } else { - int digits; - if (value < 1000) { - digits = 3; - } else { - Validate.isTrue(value > -1, "Negative values should not be possible", value); - digits = Integer.toString(value).length(); - } - for (int i = mSize; --i >= digits; ) { - buffer.append('0'); - } - buffer.append(Integer.toString(value)); - } - } - } - - /** - *

Inner class to output a two digit number.

- */ - private static class TwoDigitNumberField implements NumberRule { - private final int mField; - - /** - * Constructs an instance of {@code TwoDigitNumberField} with the specified field. - * - * @param field the field - */ - TwoDigitNumberField(int field) { - mField = field; - } - - /** - * {@inheritDoc} - */ - public int estimateLength() { - return 2; - } - - /** - * {@inheritDoc} - */ - public void appendTo(StringBuffer buffer, Calendar calendar) { - appendTo(buffer, calendar.get(mField)); - } - - /** - * {@inheritDoc} - */ - public final void appendTo(StringBuffer buffer, int value) { - if (value < 100) { - buffer.append((char)(value / 10 + '0')); - buffer.append((char)(value % 10 + '0')); - } else { - buffer.append(Integer.toString(value)); - } - } - } - - /** - *

Inner class to output a two digit year.

- */ - private static class TwoDigitYearField implements NumberRule { - static final TwoDigitYearField INSTANCE = new TwoDigitYearField(); - - /** - * Constructs an instance of {@code TwoDigitYearField}. - */ - TwoDigitYearField() { - super(); - } - - /** - * {@inheritDoc} - */ - public int estimateLength() { - return 2; - } - - /** - * {@inheritDoc} - */ - public void appendTo(StringBuffer buffer, Calendar calendar) { - appendTo(buffer, calendar.get(Calendar.YEAR) % 100); - } - - /** - * {@inheritDoc} - */ - public final void appendTo(StringBuffer buffer, int value) { - buffer.append((char)(value / 10 + '0')); - buffer.append((char)(value % 10 + '0')); - } - } - - /** - *

Inner class to output a two digit month.

- */ - private static class TwoDigitMonthField implements NumberRule { - static final TwoDigitMonthField INSTANCE = new TwoDigitMonthField(); - - /** - * Constructs an instance of {@code TwoDigitMonthField}. - */ - TwoDigitMonthField() { - super(); - } - - /** - * {@inheritDoc} - */ - public int estimateLength() { - return 2; - } - - /** - * {@inheritDoc} - */ - public void appendTo(StringBuffer buffer, Calendar calendar) { - appendTo(buffer, calendar.get(Calendar.MONTH) + 1); - } - - /** - * {@inheritDoc} - */ - public final void appendTo(StringBuffer buffer, int value) { - buffer.append((char)(value / 10 + '0')); - buffer.append((char)(value % 10 + '0')); - } - } - - /** - *

Inner class to output the twelve hour field.

- */ - private static class TwelveHourField implements NumberRule { - private final NumberRule mRule; - - /** - * Constructs an instance of {@code TwelveHourField} with the specified - * {@code NumberRule}. - * - * @param rule the rule - */ - TwelveHourField(NumberRule rule) { - mRule = rule; - } - - /** - * {@inheritDoc} - */ - public int estimateLength() { - return mRule.estimateLength(); - } - - /** - * {@inheritDoc} - */ - public void appendTo(StringBuffer buffer, Calendar calendar) { - int value = calendar.get(Calendar.HOUR); - if (value == 0) { - value = calendar.getLeastMaximum(Calendar.HOUR) + 1; - } - mRule.appendTo(buffer, value); - } - - /** - * {@inheritDoc} - */ - public void appendTo(StringBuffer buffer, int value) { - mRule.appendTo(buffer, value); - } - } - - /** - *

Inner class to output the twenty four hour field.

- */ - private static class TwentyFourHourField implements NumberRule { - private final NumberRule mRule; - - /** - * Constructs an instance of {@code TwentyFourHourField} with the specified - * {@code NumberRule}. - * - * @param rule the rule - */ - TwentyFourHourField(NumberRule rule) { - mRule = rule; - } - - /** - * {@inheritDoc} - */ - public int estimateLength() { - return mRule.estimateLength(); - } - - /** - * {@inheritDoc} - */ - public void appendTo(StringBuffer buffer, Calendar calendar) { - int value = calendar.get(Calendar.HOUR_OF_DAY); - if (value == 0) { - value = calendar.getMaximum(Calendar.HOUR_OF_DAY) + 1; - } - mRule.appendTo(buffer, value); - } - - /** - * {@inheritDoc} - */ - public void appendTo(StringBuffer buffer, int value) { - mRule.appendTo(buffer, value); - } - } - - /** - *

Inner class to output a time zone name.

- */ - private static class TimeZoneNameRule implements Rule { - private final TimeZone mTimeZone; - private final String mStandard; - private final String mDaylight; - - /** - * Constructs an instance of {@code TimeZoneNameRule} with the specified properties. - * - * @param timeZone the time zone - * @param locale the locale - * @param style the style - */ - TimeZoneNameRule(TimeZone timeZone, Locale locale, int style) { - mTimeZone = timeZone; - - mStandard = getTimeZoneDisplay(timeZone, false, style, locale); - mDaylight = getTimeZoneDisplay(timeZone, true, style, locale); - } - - /** - * {@inheritDoc} - */ - public int estimateLength() { - return Math.max(mStandard.length(), mDaylight.length()); - } - - /** - * {@inheritDoc} - */ - public void appendTo(StringBuffer buffer, Calendar calendar) { - if (mTimeZone.useDaylightTime() && calendar.get(Calendar.DST_OFFSET) != 0) { - buffer.append(mDaylight); - } else { - buffer.append(mStandard); - } - } - } - - /** - *

Inner class to output a time zone as a number {@code +/-HHMM} - * or {@code +/-HH:MM}.

- */ - private static class TimeZoneNumberRule implements Rule { - static final TimeZoneNumberRule INSTANCE_COLON = new TimeZoneNumberRule(true); - static final TimeZoneNumberRule INSTANCE_NO_COLON = new TimeZoneNumberRule(false); - - final boolean mColon; - - /** - * Constructs an instance of {@code TimeZoneNumberRule} with the specified properties. - * - * @param colon add colon between HH and MM in the output if {@code true} - */ - TimeZoneNumberRule(boolean colon) { - mColon = colon; - } - - /** - * {@inheritDoc} - */ - public int estimateLength() { - return 5; - } - - /** - * {@inheritDoc} - */ - public void appendTo(StringBuffer buffer, Calendar calendar) { - int offset = calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET); - - if (offset < 0) { - buffer.append('-'); - offset = -offset; - } else { - buffer.append('+'); - } - - int hours = offset / (60 * 60 * 1000); - buffer.append((char)(hours / 10 + '0')); - buffer.append((char)(hours % 10 + '0')); - - if (mColon) { - buffer.append(':'); - } - - int minutes = offset / (60 * 1000) - 60 * hours; - buffer.append((char)(minutes / 10 + '0')); - buffer.append((char)(minutes % 10 + '0')); - } - } - - // ---------------------------------------------------------------------- - /** - *

Inner class that acts as a compound key for time zone names.

- */ - private static class TimeZoneDisplayKey { - private final TimeZone mTimeZone; - private final int mStyle; - private final Locale mLocale; - - /** - * Constructs an instance of {@code TimeZoneDisplayKey} with the specified properties. - * - * @param timeZone the time zone - * @param daylight adjust the style for daylight saving time if {@code true} - * @param style the timezone style - * @param locale the timezone locale - */ - TimeZoneDisplayKey(TimeZone timeZone, - boolean daylight, int style, Locale locale) { - mTimeZone = timeZone; - if (daylight) { - style |= 0x80000000; - } - mStyle = style; - mLocale = locale; - } - - /** - * {@inheritDoc} - */ - @Override - public int hashCode() { - return (mStyle * 31 + mLocale.hashCode() ) * 31 + mTimeZone.hashCode(); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj instanceof TimeZoneDisplayKey) { - TimeZoneDisplayKey other = (TimeZoneDisplayKey)obj; - return - mTimeZone.equals(other.mTimeZone) && - mStyle == other.mStyle && - mLocale.equals(other.mLocale); - } - return false; - } - } -} diff --git a/src/org/apache/commons/lang3/time/FormatCache.java b/src/org/apache/commons/lang3/time/FormatCache.java deleted file mode 100644 index 19ee53a..0000000 --- a/src/org/apache/commons/lang3/time/FormatCache.java +++ /dev/null @@ -1,202 +0,0 @@ -/* - * 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.Locale; -import java.util.TimeZone; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -/** - *

FormatCache is a cache and factory for {@link Format}s.

- * - * @since 3.0 - * @version $Id: FormatCache 892161 2009-12-18 07:21:10Z $ - */ -// TODO: Before making public move from getDateTimeInstance(Integer,...) to int; or some other approach. -abstract class FormatCache { - /** - * No date or no time. Used in same parameters as DateFormat.SHORT or DateFormat.LONG - */ - static final int NONE= -1; - - private final ConcurrentMap cInstanceCache - = new ConcurrentHashMap(7); - - private final ConcurrentMap cDateTimeInstanceCache - = new ConcurrentHashMap(7); - - /** - *

Gets a formatter instance using the default pattern in the - * default timezone 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 - * @param timeZone the non-null time zone - * @param locale the non-null locale - * @return a pattern based date/time formatter - * @throws IllegalArgumentException if pattern is invalid - * or null - */ - public F getInstance(String pattern, TimeZone timeZone, Locale locale) { - if (pattern == null) { - throw new NullPointerException("pattern must not be null"); - } - if (timeZone == null) { - timeZone = TimeZone.getDefault(); - } - if (locale == null) { - locale = Locale.getDefault(); - } - MultipartKey key = new MultipartKey(pattern, timeZone, locale); - F format = cInstanceCache.get(key); - if (format == null) { - format = createInstance(pattern, timeZone, locale); - 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 null - */ - abstract protected 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 - * @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 F getDateTimeInstance(Integer dateStyle, Integer timeStyle, TimeZone timeZone, Locale locale) { - if (locale == null) { - locale = Locale.getDefault(); - } - MultipartKey key = new MultipartKey(dateStyle, timeStyle, locale); - - String pattern = cDateTimeInstanceCache.get(key); - if (pattern == null) { - try { - DateFormat formatter; - if (dateStyle == null) { - formatter = DateFormat.getTimeInstance(timeStyle, locale); - } - else if (timeStyle == null) { - formatter = DateFormat.getDateInstance(dateStyle, locale); - } - else { - formatter = DateFormat.getDateTimeInstance(dateStyle, timeStyle, locale); - } - pattern = ((SimpleDateFormat)formatter).toPattern(); - 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 (ClassCastException ex) { - throw new IllegalArgumentException("No date time pattern for locale: " + locale); - } - } - - return getInstance(pattern, timeZone, locale); - } - - // ---------------------------------------------------------------------- - /** - *

Helper class to hold multi-part Map keys

- */ - private static class MultipartKey { - private final Object[] keys; - private int hashCode; - - /** - * Constructs an instance of MultipartKey to hold the specified objects. - * @param keys the set of objects that make up the key. Each key may be null. - */ - public MultipartKey(Object... keys) { - this.keys = keys; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if ( obj instanceof MultipartKey == false ) { - return false; - } - return Arrays.equals(keys, ((MultipartKey)obj).keys); - } - - /** - * {@inheritDoc} - */ - @Override - public int hashCode() { - if(hashCode==0) { - int rc= 0; - for(Object key : keys) { - if(key!=null) { - rc= rc*7 + key.hashCode(); - } - } - hashCode= rc; - } - return hashCode; - } - } - -} diff --git a/src/org/apache/commons/lang3/time/StopWatch.java b/src/org/apache/commons/lang3/time/StopWatch.java deleted file mode 100644 index f86ad85..0000000 --- a/src/org/apache/commons/lang3/time/StopWatch.java +++ /dev/null @@ -1,382 +0,0 @@ -/* - * 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; - -/** - *

- * StopWatch provides a convenient API for timings. - *

- * - *

- * To start the watch, call {@link #start()}. At this point you can: - *

- *
    - *
  • {@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.
  • - *
  • {@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.
  • - *
  • {@link #stop()} the watch to complete the timing session.
  • - *
- * - *

- * 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. - *

- * - *

- * 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. - *

- * - *

- * 1. split(), suspend(), or stop() cannot be invoked twice
- * 2. unsplit() may only be called if the watch has been split()
- * 3. resume() may only be called if the watch has been suspend()
- * 4. start() cannot be called twice without calling reset() - *

- * - *

This class is not thread-safe

- * - * @since 2.0 - * @version $Id: StopWatch.java 1088899 2011-04-05 05:31:27Z bayard $ - */ -public class StopWatch { - - private static final long NANO_2_MILLIS = 1000000L; - - // running states - private static final int STATE_UNSTARTED = 0; - - private static final int STATE_RUNNING = 1; - - private static final int STATE_STOPPED = 2; - - private static final int STATE_SUSPENDED = 3; - - // split state - private static final int STATE_UNSPLIT = 10; - - private static final int STATE_SPLIT = 11; - - /** - * The current running state of the StopWatch. - */ - private int runningState = STATE_UNSTARTED; - - /** - * Whether the stopwatch has a split time recorded. - */ - private int splitState = STATE_UNSPLIT; - - /** - * The start time. - */ - private long startTime; - - /** - * The start time in Millis - nanoTime is only for elapsed time so we - * need to also store the currentTimeMillis to maintain the old - * getStartTime API. - */ - private long startTimeMillis; - - /** - * The stop time. - */ - private long stopTime; - - /** - *

- * Constructor. - *

- */ - public StopWatch() { - super(); - } - - /** - *

- * Start the stopwatch. - *

- * - *

- * This method starts a new timing session, clearing any previous values. - *

- * - * @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.startTime = System.nanoTime(); - this.startTimeMillis = System.currentTimeMillis(); - this.runningState = STATE_RUNNING; - } - - /** - *

- * Stop the stopwatch. - *

- * - *

- * This method ends a new timing session, allowing the time to be retrieved. - *

- * - * @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.stopTime = System.nanoTime(); - } - this.runningState = STATE_STOPPED; - } - - /** - *

- * Resets the stopwatch. Stops it if need be. - *

- * - *

- * This method clears the internal values to allow the object to be reused. - *

- */ - public void reset() { - this.runningState = STATE_UNSTARTED; - this.splitState = STATE_UNSPLIT; - } - - /** - *

- * Split the time. - *

- * - *

- * 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. - *

- * - * @throws IllegalStateException - * if the StopWatch is not running. - */ - public void split() { - if (this.runningState != STATE_RUNNING) { - throw new IllegalStateException("Stopwatch is not running. "); - } - this.stopTime = System.nanoTime(); - this.splitState = STATE_SPLIT; - } - - /** - *

- * Remove a split. - *

- * - *

- * This method clears the stop time. The start time is unaffected, enabling timing from the original start point to - * continue. - *

- * - * @throws IllegalStateException - * if the StopWatch has not been split. - */ - public void unsplit() { - if (this.splitState != STATE_SPLIT) { - throw new IllegalStateException("Stopwatch has not been split. "); - } - this.splitState = STATE_UNSPLIT; - } - - /** - *

- * Suspend the stopwatch for later resumption. - *

- * - *

- * 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. - *

- * - * @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.stopTime = System.nanoTime(); - this.runningState = STATE_SUSPENDED; - } - - /** - *

- * Resume the stopwatch after a suspend. - *

- * - *

- * 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. - *

- * - * @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.startTime += (System.nanoTime() - this.stopTime); - this.runningState = STATE_RUNNING; - } - - /** - *

- * Get the time on the stopwatch. - *

- * - *

- * This is either the time between the start and the moment this method is called, or the amount of time between - * start and stop. - *

- * - * @return the time in milliseconds - */ - public long getTime() { - return getNanoTime() / NANO_2_MILLIS; - } - /** - *

- * Get the time on the stopwatch in nanoseconds. - *

- * - *

- * This is either the time between the start and the moment this method is called, or the amount of time between - * start and stop. - *

- * - * @return the time in nanoseconds - * @since 3.0 - */ - public long getNanoTime() { - if (this.runningState == STATE_STOPPED || this.runningState == STATE_SUSPENDED) { - return this.stopTime - this.startTime; - } else if (this.runningState == STATE_UNSTARTED) { - return 0; - } else if (this.runningState == STATE_RUNNING) { - return System.nanoTime() - this.startTime; - } - throw new RuntimeException("Illegal running state has occured. "); - } - - /** - *

- * Get the split time on the stopwatch. - *

- * - *

- * This is the time between start and latest split. - *

- * - * @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; - } - /** - *

- * Get the split time on the stopwatch in nanoseconds. - *

- * - *

- * This is the time between start and latest split. - *

- * - * @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 != STATE_SPLIT) { - throw new IllegalStateException("Stopwatch must be split to get the split time. "); - } - return this.stopTime - this.startTime; - } - - /** - * Returns the time this stopwatch was started. - * - * @return the time this stopwatch was started - * @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 a summary of the time that the stopwatch recorded as a string. - *

- * - *

- * The format used is ISO8601-like, hours:minutes:seconds.milliseconds. - *

- * - * @return the time as a String - */ - @Override - public String toString() { - return DurationFormatUtils.formatDurationHMS(getTime()); - } - - /** - *

- * Gets a summary of the split time that the stopwatch recorded as a string. - *

- * - *

- * The format used is ISO8601-like, hours:minutes:seconds.milliseconds. - *

- * - * @return the split time as a String - * @since 2.1 - */ - public String toSplitString() { - return DurationFormatUtils.formatDurationHMS(getSplitTime()); - } - -} -- cgit v1.1