diff --git a/src/java/org/apache/commons/lang/time/CalendarUtils.java b/src/java/org/apache/commons/lang/time/CalendarUtils.java
deleted file mode 100644
index 5b93c8932..000000000
--- a/src/java/org/apache/commons/lang/time/CalendarUtils.java
+++ /dev/null
@@ -1,506 +0,0 @@
-/* ====================================================================
- * The Apache Software License, Version 1.1
- *
- * Copyright (c) 2002-2003 The Apache Software Foundation. All rights
- * reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. The end-user documentation included with the redistribution, if
- * any, must include the following acknowlegement:
- * "This product includes software developed by the
- * Apache Software Foundation (http://www.apache.org/)."
- * Alternately, this acknowlegement may appear in the software itself,
- * if and wherever such third-party acknowlegements normally appear.
- *
- * 4. The names "The Jakarta Project", "Commons", and "Apache Software
- * Foundation" must not be used to endorse or promote products derived
- * from this software without prior written permission. For written
- * permission, please contact apache@apache.org.
- *
- * 5. Products derived from this software may not be called "Apache"
- * nor may "Apache" appear in their names without prior written
- * permission of the Apache Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation. For more
- * information on the Apache Software Foundation, please see
- * .
- */
-package org.apache.commons.lang.time;
-
-import java.text.*;
-import java.util.*;
-
-/**
- * A suite of utilities surrounding the use of the Calendar and Date object.
- *
- * @author Serge Knystautas
- * @since 2.1
- * @version $Id: CalendarUtils.java,v 1.3 2003/04/09 01:04:48 ggregory Exp $
- */
-public class CalendarUtils {
-
- /**
- * This is half a month, so this represents whether a date is in the top
- * or bottom half of the month.
- */
- public final static 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, CalendarUtils.SEMI_MONTH},
- {Calendar.YEAR},
- {Calendar.ERA}};
-
- private static DateFormat[] dateFormats = {
- //3/31/92 10:00:07 PST
- new SimpleDateFormat("M/dd/yy h:mm:ss z"),
- //January 23, 1987 10:05pm
- new SimpleDateFormat("MMM d, yyyy h:mm a"),
- //22:00 GMT
- new SimpleDateFormat("h:mm z")};
-
- /**
- * A week range, starting on Sunday.
- */
- public final static int RANGE_WEEK_SUNDAY = 1;
-
- /**
- * A week range, starting on Monday.
- */
- public final static int RANGE_WEEK_MONDAY = 2;
-
- /**
- * A week range, starting on the day focused.
- */
- public final static int RANGE_WEEK_RELATIVE = 3;
-
- /**
- * A week range, centered around the day focused.
- */
- public final static int RANGE_WEEK_CENTER = 4;
-
- /**
- * A month range, the week starting on Sunday.
- */
- public final static int RANGE_MONTH_SUNDAY = 5;
-
- /**
- * A month range, the week starting on Monday.
- */
- public final static int RANGE_MONTH_MONDAY = 6;
-
- /**
- * See the other round method. Works with a Date object.
- */
- public static Date round(Date val, int field) {
- GregorianCalendar gval = new GregorianCalendar();
- gval.setTime(val);
- modify(gval, field, true);
- 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.
- */
- public static Calendar round(Calendar val, int field) {
- Calendar rounded = (Calendar) val.clone();
- modify(rounded, field, true);
- return rounded;
- }
-
- /**
- * See the other round method. Works with an Object, trying to
- * use it as either a Date or Calendar.
- */
- public static Date round(Object val, int field) {
- if (val instanceof Date) {
- return round((Date) val, field);
- } else if (val instanceof Calendar) {
- return round((Calendar) val, field).getTime();
- } else {
- throw new ClassCastException("Could not round " + val);
- }
- }
-
- /**
- * See the other trunc method. Works with a Date.
- */
- public static Date trunc(Date val, int field) {
- GregorianCalendar gval = new GregorianCalendar();
- gval.setTime(val);
- modify(gval, field, false);
- 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.
- */
- public static Calendar trunc(Calendar val, int field) {
- Calendar truncated = (Calendar) val.clone();
- modify(truncated, field, false);
- return truncated;
- }
-
- /**
- * See the other trunc method. Works with an Object, trying to
- * use it as either a Date or Calendar.
- */
- public static Date trunc(Object val, int field) {
- if (val instanceof Date) {
- return trunc((Date) val, field);
- } else if (val instanceof Calendar) {
- return trunc((Calendar) val, field).getTime();
- } else {
- throw new ClassCastException("Could not trunc " + val);
- }
- }
-
- private static void modify(Calendar val, int field, boolean round) {
- boolean roundUp = false;
- for (int i = 0; i < fields.length; i++) {
- for (int j = 0; j < fields[i].length; j++) {
- if (fields[i][j] == field) {
- //This is our field... we stop looping
- if (round && roundUp) {
- if (field == CalendarUtils.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);
- }
- } else {
- //We need at add one to this field since the
- // last number causes us to round up
- val.add(fields[i][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 CalendarUtils.SEMI_MONTH:
- if (fields[i][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 (fields[i][0] == Calendar.HOUR) {
- //If we're going to drop the HOUR field's value,
- // we want to do this our own way.
- offset = val.get(Calendar.HOUR);
- if (offset >= 12) {
- offset -= 12;
- }
- roundUp = offset > 6;
- offsetSet = true;
- }
- break;
- }
- if (!offsetSet) {
- int min = val.getActualMinimum(fields[i][0]);
- int max = val.getActualMaximum(fields[i][0]);
- //Calculate the offset from the minimum allowed value
- offset = val.get(fields[i][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
- val.add(fields[i][0], -offset);
- }
- throw new RuntimeException("We do not support that field.");
-
- }
-
- /**
- * Parses strings the way that CVS supports it (very human readable).
- */
- public static Calendar parse(String original) {
- return parse(original, Locale.getDefault());
- }
-
- /**
- * Parses strings the way that CVS supports it (very human readable).
- */
- public static Calendar parse(String original, Locale locale) {
- //Get the symbol names
- DateFormatSymbols symbols = new DateFormatSymbols(locale);
-
- //Prep the string to parse
- String value = original.toLowerCase().trim();
-
- //Get the current date/time
- Calendar now = Calendar.getInstance();
- if (value.endsWith(" ago")) {
- //If this was a date that was "ago" the current time...
- //Strip out the ' ago' part
- value = value.substring(0, value.length() - 4);
-
- //Split the value and unit
- int start = value.indexOf(" ");
- if (start < 0) {
- throw new RuntimeException("Could not find space in between value and unit");
- }
- String unit = value.substring(start + 1);
- value = value.substring(0, start);
- //We support "a week", so we need to parse the value as "a"
- int val = 0;
- if (value.equals("a") || value.equals("an")) {
- val = 1;
- } else {
- val = Integer.parseInt(value);
- }
-
- //Determine the unit
- if (unit.equals("milliseconds") || unit.equals("millisecond")) {
- now.add(Calendar.MILLISECOND, -val);
- } else if (unit.equals("seconds") || unit.equals("second")) {
- now.add(Calendar.SECOND, -val);
- } else if (unit.equals("minutes") || unit.equals("minute")) {
- now.add(Calendar.MINUTE, -val);
- } else if (unit.equals("hours") || unit.equals("hour")) {
- now.add(Calendar.HOUR, -val);
- } else if (unit.equals("days") || unit.equals("day")) {
- now.add(Calendar.DATE, -val);
- } else if (unit.equals("weeks") || unit.equals("week")) {
- now.add(Calendar.DATE, -val * 7);
- } else if (unit.equals("fortnights") || unit.equals("fortnight")) {
- now.add(Calendar.DATE, -val * 14);
- } else if (unit.equals("months") || unit.equals("month")) {
- now.add(Calendar.MONTH, -val);
- } else if (unit.equals("years") || unit.equals("year")) {
- now.add(Calendar.YEAR, -val);
- } else {
- throw new RuntimeException("We do not understand that many units ago");
- }
- return now;
- } else if (value.startsWith("last ")) {
- //If this was the last time a certain field was met
- //Strip out the 'last ' part
- value = value.substring(5);
- //Get the current date/time
- String[] strings = symbols.getWeekdays();
- for (int i = 0; i < strings.length; i++) {
- if (value.equalsIgnoreCase(strings[i])) {
- //How many days after Sunday
- int daysAgo = now.get(Calendar.DAY_OF_WEEK) - i;
- if (daysAgo <= 0) {
- daysAgo += 7;
- }
- now.add(Calendar.DATE, -daysAgo);
- return now;
- }
- }
- strings = symbols.getMonths();
- for (int i = 0; i < strings.length; i++) {
- if (value.equalsIgnoreCase(strings[i])) {
- //How many days after January
- int monthsAgo = now.get(Calendar.MONTH) - i;
- if (monthsAgo <= 0) {
- monthsAgo += 12;
- }
- now.add(Calendar.MONTH, -monthsAgo);
- return now;
- }
- }
- if (value.equals("week")) {
- now.add(Calendar.DATE, -7);
- return now;
- }
- } else if (value.equals("yesterday")) {
- now.add(Calendar.DATE, -1);
- return now;
- } else if (value.equals("tomorrow")) {
- now.add(Calendar.DATE, 1);
- return now;
- }
- //Try to parse the date a number of different ways
- for (int i = 0; i < dateFormats.length; i++) {
- try {
- Date datetime = dateFormats[i].parse(original);
- Calendar cal = Calendar.getInstance();
- cal.setTime(datetime);
- return cal;
- } catch (ParseException pe) {
- //we ignore this and just keep trying
- }
- }
-
- throw new RuntimeException("Unable to parse '" + original + "'.");
- }
-
- /**
- * This constructs an Iterator that will start and stop over a date
- * range based on the focused date and the 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.
- */
- public static Iterator getCalendarIterator(Calendar focus, int rangeStyle) {
- 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 = trunc(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 = trunc(focus, Calendar.DATE);
- end = trunc(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 RuntimeException("The range style " + rangeStyle + " is not valid.");
- }
- if (startCutoff < Calendar.SUNDAY) {
- startCutoff += 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);
- }
- final Calendar startFinal = start;
- final Calendar endFinal = end;
- Iterator it = new Iterator() {
- Calendar spot = null;
- {
- spot = startFinal;
- spot.add(Calendar.DATE, -1);
- }
-
- public boolean hasNext() {
- return spot.before(endFinal);
- }
-
- public Object next() {
- if (spot.equals(endFinal)) {
- throw new NoSuchElementException();
- }
- spot.add(Calendar.DATE, 1);
- return spot.clone();
- }
-
- public void remove() {
- throw new UnsupportedOperationException();
- }
- };
- return it;
- }
-
- /**
- * See the other getCalendarIterator. Works with a Date.
- */
- public static Iterator getCalendarIterator(Date focus, int rangeStyle) {
- GregorianCalendar gval = new GregorianCalendar();
- gval.setTime(focus);
- return getCalendarIterator(gval, rangeStyle);
- }
-
- /**
- * See the other getCalendarIterator. Works with an Object, trying
- * to use it as a Date or Calendar.
- */
- public static Iterator getCalendarIterator(Object focus, int rangeStyle) {
- if (focus instanceof Date) {
- return getCalendarIterator((Date) focus, rangeStyle);
- } else if (focus instanceof Calendar) {
- return getCalendarIterator((Calendar) focus, rangeStyle);
- } else {
- throw new ClassCastException("Could not iterate based on " + focus);
- }
- }
-
-}
diff --git a/src/java/org/apache/commons/lang/time/DateFormatUtils.java b/src/java/org/apache/commons/lang/time/DateFormatUtils.java
new file mode 100644
index 000000000..1eaa996fc
--- /dev/null
+++ b/src/java/org/apache/commons/lang/time/DateFormatUtils.java
@@ -0,0 +1,297 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002-2003 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Commons", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+package org.apache.commons.lang.time;
+
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/**
+ * Date and time formatting utilites and constants.
+ *
+ * Formatting is performed using the
+ * {@link org.apache.commons.lang.time.FastDateFormat} class.
+ *
+ * @author Apache Ant - DateUtils
+ * @author Stephane Bailliez
+ * @author Stefan Bodewig
+ * @author Stephen Colebourne
+ * @since 2.0
+ * @version $Id: DateFormatUtils.java,v 1.1 2003/06/08 23:14:23 scolebourne Exp $
+ */
+public final class DateFormatUtils {
+
+ /**
+ * ISO8601 formatter for date-time witout timezone.
+ * 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 timezone.
+ * The format used is yyyy-MM-dd'T'HH:mm:ssZZ.
+ */
+ public static final FastDateFormat ISO_DATETIME_TIMEZONE_FORMAT
+ = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ssZZ");
+
+ /**
+ * ISO8601 formatter for date without timezone.
+ * 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 timezone.
+ * The format used is yyyy-MM-ddZZ.
+ * This pattern does not comply with the formal ISO8601 specification
+ * as the standard does not allow a timezone without a time.
+ */
+ public static final FastDateFormat ISO_DATE_TIMEZONE_FORMAT
+ = FastDateFormat.getInstance("yyyy-MM-ddZZ");
+
+ /**
+ * ISO8601 formatter for time without timezone.
+ * 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 timezone.
+ * The format used is 'T'HH:mm:ssZZ.
+ */
+ public static final FastDateFormat ISO_TIME_TIMEZONE_FORMAT
+ = FastDateFormat.getInstance("'T'HH:mm:ssZZ");
+
+ /**
+ * ISO8601-like formatter for time without timezone.
+ * 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 timezone.
+ * 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_TIMEZONE_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() {
+ }
+
+ /**
+ * Format a date/time into a specific pattern using the UTC timezone.
+ *
+ * @param millis the date to format expressed in milliseconds
+ * @param pattern the pattern to use to format the date
+ * @return the formatted date
+ */
+ public static String formatUTC(long millis, String pattern) {
+ return format(new Date(millis), pattern, DateUtils.UTC_TIMEZONE, null);
+ }
+
+ /**
+ * Format a date/time into a specific pattern using the UTC timezone.
+ *
+ * @param date the date to format
+ * @param pattern the pattern to use to format the date
+ * @return the formatted date
+ */
+ public static String formatUTC(Date date, String pattern) {
+ return format(date, pattern, DateUtils.UTC_TIMEZONE, null);
+ }
+
+ /**
+ * Format a date/time into a specific pattern using the UTC timezone.
+ *
+ * @param millis the date to format expressed in milliseconds
+ * @param pattern the pattern to use to format the date
+ * @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, DateUtils.UTC_TIMEZONE, locale);
+ }
+
+ /**
+ * Format a date/time into a specific pattern using the UTC timezone.
+ *
+ * @param date the date to format
+ * @param pattern the pattern to use to format the date
+ * @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, DateUtils.UTC_TIMEZONE, locale);
+ }
+
+ /**
+ * Format 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
+ * @return the formatted date
+ */
+ public static String format(long millis, String pattern) {
+ return format(new Date(millis), pattern, null, null);
+ }
+
+ /**
+ * Format a date/time into a specific pattern.
+ *
+ * @param date the date to format
+ * @param pattern the pattern to use to format the date
+ * @return the formatted date
+ */
+ public static String format(Date date, String pattern) {
+ return format(date, pattern, null, null);
+ }
+
+ /**
+ * Format a date/time into a specific pattern in a timezone.
+ *
+ * @param millis the time expressed in milliseconds
+ * @param pattern the pattern to use to format the date
+ * @param timeZone the timezone 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);
+ }
+
+ /**
+ * Format a date/time into a specific pattern in a timezone.
+ *
+ * @param date the date to format
+ * @param pattern the pattern to use to format the date
+ * @param timeZone the timezone 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);
+ }
+
+ /**
+ * Format 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
+ * @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);
+ }
+
+ /**
+ * Format a date/time into a specific pattern in a locale.
+ *
+ * @param date the date to format
+ * @param pattern the pattern to use to format the date
+ * @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);
+ }
+
+ /**
+ * Format a date/time into a specific pattern in a timezone and locale.
+ *
+ * @param millis the date to format expressed in milliseconds
+ * @param pattern the pattern to use to format the date
+ * @param timeZone the timezone 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);
+ }
+
+ /**
+ * Format a date/time into a specific pattern in a timezone and locale.
+ *
+ * @param date the date to format
+ * @param pattern the pattern to use to format the date
+ * @param timeZone the timezone 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);
+ }
+
+}
diff --git a/src/java/org/apache/commons/lang/time/DateUtils.java b/src/java/org/apache/commons/lang/time/DateUtils.java
index 8364a4d1c..89230dec5 100644
--- a/src/java/org/apache/commons/lang/time/DateUtils.java
+++ b/src/java/org/apache/commons/lang/time/DateUtils.java
@@ -53,209 +53,491 @@
*/
package org.apache.commons.lang.time;
-import java.text.ChoiceFormat;
import java.text.DateFormat;
-import java.text.MessageFormat;
+import java.text.DateFormatSymbols;
+import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.Iterator;
import java.util.Locale;
+import java.util.NoSuchElementException;
import java.util.TimeZone;
/**
- * Helper methods to deal with date/time formatting. [Relies heavily on
- * code taken from the DateUtils class of the jakarata-ant project.]
+ * A suite of utilities surrounding the use of the Calendar and Date object.
*
- * @author Stephane Bailliez
- * @author Stefan Bodewig
- * @since 2.1
- * @version $Id: DateUtils.java,v 1.2 2003/02/04 22:19:33 scolebourne Exp $
+ * @author Serge Knystautas
+ * @author Stephen Colebourne
+ * @since 2.0
+ * @version $Id: DateUtils.java,v 1.3 2003/06/08 23:14:23 scolebourne Exp $
*/
-public final class DateUtils {
+public class DateUtils {
+
+ /**
+ * The UTC timezone (often referred to as GMT).
+ */
+ public static final TimeZone UTC_TIMEZONE = TimeZone.getTimeZone("GMT");
+ /**
+ * Number of milliseconds in a standard second.
+ */
+ public static final int MILLIS_IN_SECOND = 1000;
+ /**
+ * Number of milliseconds in a standard minute.
+ */
+ public static final int MILLIS_IN_MINUTE = 60 * 1000;
+ /**
+ * Number of milliseconds in a standard hour.
+ */
+ public static final int MILLIS_IN_HOUR = 60 * 60 * 1000;
+ /**
+ * Number of milliseconds in a standard day.
+ */
+ public static final int MILLIS_IN_DAY = 24 * 60 * 60 * 1000;
/**
- * ISO8601-like pattern for date-time. It does not support timezone.
- * yyyy-MM-ddTHH:mm:ss
+ * This is half a month, so this represents whether a date is in the top
+ * or bottom half of the month.
*/
- public static final String ISO8601_DATETIME_PATTERN
- = "yyyy-MM-dd'T'HH:mm:ss";
+ public final static 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}};
+
+ private static DateFormat[] dateFormats = {
+ //3/31/92 10:00:07 PST
+ new SimpleDateFormat("M/dd/yy h:mm:ss z"),
+ //January 23, 1987 10:05pm
+ new SimpleDateFormat("MMM d, yyyy h:mm a"),
+ //22:00 GMT
+ new SimpleDateFormat("h:mm z")};
/**
- * ISO8601-like pattern for date. yyyy-MM-dd
+ * A week range, starting on Sunday.
*/
- public static final String ISO8601_DATE_PATTERN
- = "yyyy-MM-dd";
+ public final static int RANGE_WEEK_SUNDAY = 1;
/**
- * ISO8601-like pattern for time. HH:mm:ss
+ * A week range, starting on Monday.
*/
- public static final String ISO8601_TIME_PATTERN
- = "HH:mm:ss";
+ public final static int RANGE_WEEK_MONDAY = 2;
/**
- * Format used for SMTP (and probably other) Date headers.
+ * A week range, starting on the day focused.
*/
- public static final DateFormat DATE_HEADER_FORMAT
- = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss ", Locale.US);
+ public final static int RANGE_WEEK_RELATIVE = 3;
+ /**
+ * A week range, centered around the day focused.
+ */
+ public final static int RANGE_WEEK_CENTER = 4;
-// code from Magesh moved from DefaultLogger and slightly modified
- private static final MessageFormat MINUTE_SECONDS
- = new MessageFormat("{0}{1}");
+ /**
+ * A month range, the week starting on Sunday.
+ */
+ public final static int RANGE_MONTH_SUNDAY = 5;
- private static final double[] LIMITS = {0, 1, 2};
+ /**
+ * A month range, the week starting on Monday.
+ */
+ public final static int RANGE_MONTH_MONDAY = 6;
- private static final String[] MINUTES_PART =
- {"", "1 minute ", "{0,number} minutes "};
-
- private static final String[] SECONDS_PART =
- {"0 seconds", "1 second", "{1,number} seconds"};
-
- private static final ChoiceFormat MINUTES_FORMAT =
- new ChoiceFormat(LIMITS, MINUTES_PART);
-
- private static final ChoiceFormat SECONDS_FORMAT =
- new ChoiceFormat(LIMITS, SECONDS_PART);
-
- static {
- MINUTE_SECONDS.setFormat(0, MINUTES_FORMAT);
- MINUTE_SECONDS.setFormat(1, SECONDS_FORMAT);
+ /**
+ * See the other round method. Works with a Date object.
+ */
+ public static Date round(Date val, int field) {
+ GregorianCalendar gval = new GregorianCalendar();
+ gval.setTime(val);
+ modify(gval, field, true);
+ return gval.getTime();
}
/**
- *
DateUtils instances should NOT be constructed in standard programming.
- *
- * This constructor is public to permit tools that require a JavaBean instance
- * to operate.
+ * 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.
*/
- public DateUtils() {
- }
-
-
- /**
- * Format a date/time into a specific pattern.
- * @param date the date to format expressed in milliseconds.
- * @param pattern the pattern to use to format the date.
- * @return the formatted date.
- */
- public static String format(long date, String pattern) {
- return format(new Date(date), pattern);
- }
-
-
- /**
- * Format a date/time into a specific pattern.
- * @param date the date to format expressed in milliseconds.
- * @param pattern the pattern to use to format the date.
- * @return the formatted date.
- */
- public static String format(Date date, String pattern) {
- DateFormat df = createDateFormat(pattern);
- return df.format(date);
- }
-
-
- /**
- * Format an elapsed time into a plurialization correct string.
- * It is limited only to report elapsed time in minutes and
- * seconds and has the following behavior.
- *
- * - minutes are not displayed when 0. (ie: "45 seconds")
- * - seconds are always displayed in plural form (ie "0 seconds" or
- * "10 seconds") except for 1 (ie "1 second")
- *
- * @param time the elapsed time to report in milliseconds.
- * @return the formatted text in minutes/seconds.
- */
- public static String formatElapsedTime(long millis) {
- long seconds = millis / 1000;
- long minutes = seconds / 60;
- Object[] args = {new Long(minutes), new Long(seconds % 60)};
- return MINUTE_SECONDS.format(args);
+ public static Calendar round(Calendar val, int field) {
+ Calendar rounded = (Calendar) val.clone();
+ modify(rounded, field, true);
+ return rounded;
}
/**
- * return a lenient date format set to GMT time zone.
- * @param pattern the pattern used for date/time formatting.
- * @return the configured format for this pattern.
+ * See the other round method. Works with an Object, trying to
+ * use it as either a Date or Calendar.
*/
- private static DateFormat createDateFormat(String pattern) {
- SimpleDateFormat sdf = new SimpleDateFormat(pattern);
- TimeZone gmt = TimeZone.getTimeZone("GMT");
- sdf.setTimeZone(gmt);
- sdf.setLenient(true);
- return sdf;
- }
-
- /**
- * Calculate the phase of the moon for a given date.
- *
- * Code heavily influenced by hacklib.c in Nethack
- *
- * The Algorithm:
- *
- *
- * moon period = 29.53058 days ~= 30, year = 365.2422 days
- *
- * days moon phase advances on first day of year compared to preceding year
- * = 365.2422 - 12*29.53058 ~= 11
- *
- * years in Metonic cycle (time until same phases fall on the same days of
- * the month) = 18.6 ~= 19
- *
- * moon phase on first day of year (epact) ~= (11*(year%19) + 18) % 30
- * (18 as initial condition for 1900)
- *
- * current phase in days = first day phase + days elapsed in year
- *
- * 6 moons ~= 177 days
- * 177 ~= 8 reported phases * 22
- * + 11/22 for rounding
- *
- *
- * @return The phase of the moon as a number between 0 and 7 with
- * 0 meaning new moon and 4 meaning full moon.
- *
- * @since 1.2, Ant 1.5
- */
- public static int getPhaseOfMoon(Calendar cal) {
- int dayOfTheYear = cal.get(Calendar.DAY_OF_YEAR);
- int yearInMetonicCycle = ((cal.get(Calendar.YEAR) - 1900) % 19) + 1;
- int epact = (11 * yearInMetonicCycle + 18) % 30;
- if ((epact == 25 && yearInMetonicCycle > 11) || epact == 24) {
- epact++;
+ public static Date round(Object val, int field) {
+ if (val instanceof Date) {
+ return round((Date) val, field);
+ } else if (val instanceof Calendar) {
+ return round((Calendar) val, field).getTime();
+ } else {
+ throw new ClassCastException("Could not round " + val);
}
- return (((((dayOfTheYear + epact) * 6) + 11) % 177) / 22) & 7;
}
/**
- * Returns the current Date in a format suitable for a SMTP date
- * header.
- *
- * @since Ant 1.5.2
+ * See the other trunc method. Works with a Date.
*/
- public static String getDateForHeader() {
- Calendar cal = Calendar.getInstance();
- TimeZone tz = cal.getTimeZone();
- int offset = tz.getOffset(cal.get(Calendar.ERA),
- cal.get(Calendar.YEAR),
- cal.get(Calendar.MONTH),
- cal.get(Calendar.DAY_OF_MONTH),
- cal.get(Calendar.DAY_OF_WEEK),
- cal.get(Calendar.MILLISECOND));
- StringBuffer tzMarker = new StringBuffer(offset < 0 ? "-" : "+");
- offset = Math.abs(offset);
- int hours = offset / (60 * 60 * 1000);
- int minutes = offset / (60 * 1000) - 60 * hours;
- if (hours < 10) {
- tzMarker.append("0");
- }
- tzMarker.append(hours);
- if (minutes < 10) {
- tzMarker.append("0");
- }
- tzMarker.append(minutes);
- return DATE_HEADER_FORMAT.format(cal.getTime()) + tzMarker.toString();
+ public static Date trunc(Date val, int field) {
+ GregorianCalendar gval = new GregorianCalendar();
+ gval.setTime(val);
+ modify(gval, field, false);
+ 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.
+ */
+ public static Calendar trunc(Calendar val, int field) {
+ Calendar truncated = (Calendar) val.clone();
+ modify(truncated, field, false);
+ return truncated;
+ }
+
+ /**
+ * See the other trunc method. Works with an Object, trying to
+ * use it as either a Date or Calendar.
+ */
+ public static Date trunc(Object val, int field) {
+ if (val instanceof Date) {
+ return trunc((Date) val, field);
+ } else if (val instanceof Calendar) {
+ return trunc((Calendar) val, field).getTime();
+ } else {
+ throw new ClassCastException("Could not trunc " + val);
+ }
+ }
+
+ private static void modify(Calendar val, int field, boolean round) {
+ boolean roundUp = false;
+ for (int i = 0; i < fields.length; i++) {
+ for (int j = 0; j < fields[i].length; j++) {
+ if (fields[i][j] == field) {
+ //This is our field... we stop looping
+ if (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);
+ }
+ } else {
+ //We need at add one to this field since the
+ // last number causes us to round up
+ val.add(fields[i][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 (fields[i][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 (fields[i][0] == Calendar.HOUR) {
+ //If we're going to drop the HOUR field's value,
+ // we want to do this our own way.
+ offset = val.get(Calendar.HOUR);
+ if (offset >= 12) {
+ offset -= 12;
+ }
+ roundUp = offset > 6;
+ offsetSet = true;
+ }
+ break;
+ }
+ if (!offsetSet) {
+ int min = val.getActualMinimum(fields[i][0]);
+ int max = val.getActualMaximum(fields[i][0]);
+ //Calculate the offset from the minimum allowed value
+ offset = val.get(fields[i][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
+ val.add(fields[i][0], -offset);
+ }
+ throw new RuntimeException("We do not support that field.");
+
+ }
+
+ /**
+ * Parses strings the way that CVS supports it (very human readable).
+ */
+ public static Calendar parse(String original) {
+ return parse(original, Locale.getDefault());
+ }
+
+ /**
+ * Parses strings the way that CVS supports it (very human readable).
+ */
+ public static Calendar parse(String original, Locale locale) {
+ //Get the symbol names
+ DateFormatSymbols symbols = new DateFormatSymbols(locale);
+
+ //Prep the string to parse
+ String value = original.toLowerCase().trim();
+
+ //Get the current date/time
+ Calendar now = Calendar.getInstance();
+ if (value.endsWith(" ago")) {
+ //If this was a date that was "ago" the current time...
+ //Strip out the ' ago' part
+ value = value.substring(0, value.length() - 4);
+
+ //Split the value and unit
+ int start = value.indexOf(" ");
+ if (start < 0) {
+ throw new RuntimeException("Could not find space in between value and unit");
+ }
+ String unit = value.substring(start + 1);
+ value = value.substring(0, start);
+ //We support "a week", so we need to parse the value as "a"
+ int val = 0;
+ if (value.equals("a") || value.equals("an")) {
+ val = 1;
+ } else {
+ val = Integer.parseInt(value);
+ }
+
+ //Determine the unit
+ if (unit.equals("milliseconds") || unit.equals("millisecond")) {
+ now.add(Calendar.MILLISECOND, -val);
+ } else if (unit.equals("seconds") || unit.equals("second")) {
+ now.add(Calendar.SECOND, -val);
+ } else if (unit.equals("minutes") || unit.equals("minute")) {
+ now.add(Calendar.MINUTE, -val);
+ } else if (unit.equals("hours") || unit.equals("hour")) {
+ now.add(Calendar.HOUR, -val);
+ } else if (unit.equals("days") || unit.equals("day")) {
+ now.add(Calendar.DATE, -val);
+ } else if (unit.equals("weeks") || unit.equals("week")) {
+ now.add(Calendar.DATE, -val * 7);
+ } else if (unit.equals("fortnights") || unit.equals("fortnight")) {
+ now.add(Calendar.DATE, -val * 14);
+ } else if (unit.equals("months") || unit.equals("month")) {
+ now.add(Calendar.MONTH, -val);
+ } else if (unit.equals("years") || unit.equals("year")) {
+ now.add(Calendar.YEAR, -val);
+ } else {
+ throw new RuntimeException("We do not understand that many units ago");
+ }
+ return now;
+ } else if (value.startsWith("last ")) {
+ //If this was the last time a certain field was met
+ //Strip out the 'last ' part
+ value = value.substring(5);
+ //Get the current date/time
+ String[] strings = symbols.getWeekdays();
+ for (int i = 0; i < strings.length; i++) {
+ if (value.equalsIgnoreCase(strings[i])) {
+ //How many days after Sunday
+ int daysAgo = now.get(Calendar.DAY_OF_WEEK) - i;
+ if (daysAgo <= 0) {
+ daysAgo += 7;
+ }
+ now.add(Calendar.DATE, -daysAgo);
+ return now;
+ }
+ }
+ strings = symbols.getMonths();
+ for (int i = 0; i < strings.length; i++) {
+ if (value.equalsIgnoreCase(strings[i])) {
+ //How many days after January
+ int monthsAgo = now.get(Calendar.MONTH) - i;
+ if (monthsAgo <= 0) {
+ monthsAgo += 12;
+ }
+ now.add(Calendar.MONTH, -monthsAgo);
+ return now;
+ }
+ }
+ if (value.equals("week")) {
+ now.add(Calendar.DATE, -7);
+ return now;
+ }
+ } else if (value.equals("yesterday")) {
+ now.add(Calendar.DATE, -1);
+ return now;
+ } else if (value.equals("tomorrow")) {
+ now.add(Calendar.DATE, 1);
+ return now;
+ }
+ //Try to parse the date a number of different ways
+ for (int i = 0; i < dateFormats.length; i++) {
+ try {
+ Date datetime = dateFormats[i].parse(original);
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(datetime);
+ return cal;
+ } catch (ParseException pe) {
+ //we ignore this and just keep trying
+ }
+ }
+
+ throw new RuntimeException("Unable to parse '" + original + "'.");
+ }
+
+ /**
+ * This constructs an Iterator that will start and stop over a date
+ * range based on the focused date and the 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.
+ */
+ public static Iterator getCalendarIterator(Calendar focus, int rangeStyle) {
+ 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 = trunc(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 = trunc(focus, Calendar.DATE);
+ end = trunc(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 RuntimeException("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);
+ }
+ final Calendar startFinal = start;
+ final Calendar endFinal = end;
+ Iterator it = new Iterator() {
+ Calendar spot = null;
+ {
+ spot = startFinal;
+ spot.add(Calendar.DATE, -1);
+ }
+
+ public boolean hasNext() {
+ return spot.before(endFinal);
+ }
+
+ public Object next() {
+ if (spot.equals(endFinal)) {
+ throw new NoSuchElementException();
+ }
+ spot.add(Calendar.DATE, 1);
+ return spot.clone();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ return it;
+ }
+
+ /**
+ * See the other getCalendarIterator. Works with a Date.
+ */
+ public static Iterator getCalendarIterator(Date focus, int rangeStyle) {
+ GregorianCalendar gval = new GregorianCalendar();
+ gval.setTime(focus);
+ return getCalendarIterator(gval, rangeStyle);
+ }
+
+ /**
+ * See the other getCalendarIterator. Works with an Object, trying
+ * to use it as a Date or Calendar.
+ */
+ public static Iterator getCalendarIterator(Object focus, int rangeStyle) {
+ if (focus instanceof Date) {
+ return getCalendarIterator((Date) focus, rangeStyle);
+ } else if (focus instanceof Calendar) {
+ return getCalendarIterator((Calendar) focus, rangeStyle);
+ } else {
+ throw new ClassCastException("Could not iterate based on " + focus);
+ }
+ }
+
}
diff --git a/src/java/org/apache/commons/lang/time/DurationFormatUtils.java b/src/java/org/apache/commons/lang/time/DurationFormatUtils.java
new file mode 100644
index 000000000..c37851498
--- /dev/null
+++ b/src/java/org/apache/commons/lang/time/DurationFormatUtils.java
@@ -0,0 +1,167 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002-2003 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Commons", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+package org.apache.commons.lang.time;
+
+/**
+ * Duration formatting utilites and constants.
+ *
+ * @author Apache Ant - DateUtils
+ * @author Stephane Bailliez
+ * @author Stefan Bodewig
+ * @author Stephen Colebourne
+ * @since 2.0
+ * @version $Id: DurationFormatUtils.java,v 1.1 2003/06/08 23:14:23 scolebourne Exp $
+ */
+public final 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() {
+ }
+
+ /**
+ * Format an elapsed time into a plurialization correct string.
+ * It is limited only to report elapsed time in minutes and
+ * seconds and has the following behavior.
+ *
+ * - minutes are not displayed when 0. (ie: "45 seconds")
+ * - seconds are always displayed in plural form (ie "0 seconds" or
+ * "10 seconds") except for 1 (ie "1 second")
+ *
+ *
+ * @param millis the elapsed time to report in milliseconds
+ * @return the formatted text in minutes/seconds
+ */
+ public static String formatWords(long millis, boolean supressLeadingZeroElements, boolean supressTrailingZeroElements) {
+ long[] values = new long[4];
+ values[0] = millis / DateUtils.MILLIS_IN_DAY;
+ values[1] = (millis / DateUtils.MILLIS_IN_HOUR) % 24;
+ values[2] = (millis / DateUtils.MILLIS_IN_MINUTE) % 60;
+ values[3] = (millis / DateUtils.MILLIS_IN_SECOND) % 60;
+ String[] fieldsOne = {" day ", " hour ", " minute ", " second"};
+ String[] fieldsPlural = {" days ", " hours ", " minutes ", " seconds"};
+
+ StringBuffer buf = new StringBuffer(64);
+ boolean valueOutput = false;
+
+ for (int i = 0; i < 4; i++) {
+ long value = values[i];
+ if (value == 0) {
+ // handle zero
+ if (valueOutput) {
+ if (supressTrailingZeroElements == false) {
+ buf.append('0').append(fieldsPlural[i]);
+ }
+ } else {
+ if (supressLeadingZeroElements == false) {
+ buf.append('0').append(fieldsPlural[i]);
+ }
+ }
+ } else if (value == 1) {
+ // one
+ valueOutput = true;
+ buf.append('1').append(fieldsOne[i]);
+ } else {
+ // other
+ valueOutput = true;
+ buf.append(value).append(fieldsPlural[i]);
+ }
+ }
+
+ return buf.toString().trim();
+ }
+
+ /**
+ * Get the time gap as a string.
+ *
+ * The format used is ISO8601-like.
+ * hours:minutes:seconds.milliseconds.
+ *
+ * @param millis the duration to format
+ * @return the time as a String
+ */
+ public static String formatISO(long millis) {
+ int hours, minutes, seconds, milliseconds;
+ hours = (int) (millis / DateUtils.MILLIS_IN_HOUR);
+ millis = millis - (hours * DateUtils.MILLIS_IN_HOUR);
+ minutes = (int) (millis / DateUtils.MILLIS_IN_MINUTE);
+ millis = millis - (minutes * DateUtils.MILLIS_IN_MINUTE);
+ seconds = (int) (millis / DateUtils.MILLIS_IN_SECOND);
+ millis = millis - (seconds * DateUtils.MILLIS_IN_SECOND);
+ milliseconds = (int) millis;
+
+ StringBuffer buf = new StringBuffer(32);
+ buf.append(hours);
+ buf.append(':');
+ buf.append((char)(minutes / 10 + '0'));
+ buf.append((char)(minutes % 10 + '0'));
+ buf.append(':');
+ buf.append((char)(seconds / 10 + '0'));
+ buf.append((char)(seconds % 10 + '0'));
+ buf.append('.');
+ if (milliseconds < 10) {
+ buf.append('0').append('0');
+ } else if (milliseconds < 100) {
+ buf.append('0');
+ }
+ buf.append(milliseconds);
+ return buf.toString();
+ }
+
+}
diff --git a/src/java/org/apache/commons/lang/time/FastDateFormat.java b/src/java/org/apache/commons/lang/time/FastDateFormat.java
index e93278c2a..ff63b8913 100644
--- a/src/java/org/apache/commons/lang/time/FastDateFormat.java
+++ b/src/java/org/apache/commons/lang/time/FastDateFormat.java
@@ -53,7 +53,6 @@
*/
package org.apache.commons.lang.time;
-import java.io.Serializable;
import java.text.DateFormat;
import java.text.DateFormatSymbols;
import java.text.FieldPosition;
@@ -71,11 +70,18 @@ import java.util.Map;
import java.util.TimeZone;
/**
- * FastDateFormat is similar to {@link java.text.SimpleDateFormat}, but
- * faster and thread-safe.
+ * FastDateFormat is a fast and thread-safe version of {@link java.text.SimpleDateFormat}.
*
* Only formatting is supported, but all patterns are compatible with
- * SimpleDateFormat.
+ * SimpleDateFormat (except timezones - see below).
+ *
+ * Java 1.4 introduced a new pattern letter, 'Z', to represent time zones in
+ * RFC822 format (eg. +0800 or -1100). This pattern letter can be used here (on
+ * all JDK versions).
+ *
+ * In addition, the pattern 'ZZ' has been made to represent ISO8601 full format
+ * time zones (eg. +08:00 or -11:00). This introduces a minor incompatability with
+ * Java 1.4, but at a gain of useful functionality.
*
* NOTE: Code originally taken from the open source TreeTrove project.
*
@@ -84,24 +90,34 @@ import java.util.TimeZone;
* @author Gary Gregory
* @author Stephen Colebourne
* @since 2.0
- * @version $Id: FastDateFormat.java,v 1.5 2003/05/21 23:39:53 scolebourne Exp $
+ * @version $Id: FastDateFormat.java,v 1.6 2003/06/08 23:14:23 scolebourne Exp $
*/
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 vary fast.
- /** FULL date or time style */
+ /** FULL locale dependent date or time style */
public static final int FULL = SimpleDateFormat.FULL;
- /** LONG date or time style */
+ /** LONG locale dependent date or time style */
public static final int LONG = SimpleDateFormat.LONG;
- /** MEDIUM date or time style */
+ /** MEDIUM locale dependent date or time style */
public static final int MEDIUM = SimpleDateFormat.MEDIUM;
- /** SHORT date or time style */
+ /** SHORT locale dependent date or time style */
public static final int SHORT = SimpleDateFormat.SHORT;
// package scoped as used by inner class
static final double LOG_10 = Math.log(10);
private static String cDefaultPattern;
- private static TimeZone cDefaultTimeZone = TimeZone.getDefault();
private static Map cInstanceCache = new HashMap(7);
private static Map cDateInstanceCache = new HashMap(7);
@@ -113,12 +129,16 @@ public class FastDateFormat extends Format {
private final String mPattern;
/** The time zone */
private final TimeZone mTimeZone;
+ /** Whether the time zone overrides any on Calendars */
+ private final boolean mTimeZoneForced;
/** The locale */
private final Locale mLocale;
+ /** Whether the locale overrides the default */
+ private final boolean mLocaleForced;
/** The parsed rules */
- private final Rule[] mRules;
+ private Rule[] mRules;
/** The estimated maximum length */
- private final int mMaxLengthEstimate;
+ private int mMaxLengthEstimate;
//-----------------------------------------------------------------------
/**
@@ -172,25 +192,15 @@ public class FastDateFormat extends Format {
* @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
+ * @throws IllegalArgumentException if pattern is invalid or null
*/
public static synchronized FastDateFormat getInstance(String pattern, TimeZone timeZone, Locale locale) {
- Object key = pattern;
- if (timeZone != null) {
- key = new Pair(key, timeZone);
- }
- if (locale != null) {
- key = new Pair(key, locale);
- }
-
- FastDateFormat format = (FastDateFormat) cInstanceCache.get(key);
+ FastDateFormat emptyFormat = new FastDateFormat(pattern, timeZone, locale);
+ FastDateFormat format = (FastDateFormat) cInstanceCache.get(emptyFormat);
if (format == null) {
- if (locale == null) {
- locale = Locale.getDefault();
- }
-
- format = new FastDateFormat(pattern, timeZone, locale, new DateFormatSymbols(locale));
- cInstanceCache.put(key, format);
+ format = emptyFormat;
+ format.init(); // convert shell format into usable one
+ cInstanceCache.put(format, format); // this is OK!
}
return format;
}
@@ -342,17 +352,62 @@ public class FastDateFormat extends Format {
return cDefaultPattern;
}
+ // Constructor
+ //-----------------------------------------------------------------------
+ /**
+ * Constructs a new FastDateFormat.
+ *
+ * @param pattern {@link java.text.SimpleDateFormat} compatible pattern
+ * @param timeZone time zone to use, null means use default for Date and
+ * value within for Calendar
+ * @param locale locale, null means use system default
+ * @throws IllegalArgumentException if pattern is invalid or null
+ */
+ protected FastDateFormat(String pattern, TimeZone timeZone, Locale locale) {
+ super();
+ if (pattern == null) {
+ throw new IllegalArgumentException("The pattern must not be null");
+ }
+ mPattern = pattern;
+
+ mTimeZoneForced = (timeZone != null);
+ if (timeZone == null) {
+ timeZone = TimeZone.getDefault();
+ }
+ mTimeZone = timeZone;
+
+ mLocaleForced = (locale != null);
+ if (locale == null) {
+ locale = Locale.getDefault();
+ }
+ mLocale = locale;
+ }
+
+ /**
+ * Initialise the instance for first use.
+ */
+ protected void init() {
+ List rulesList = parsePattern();
+ mRules = (Rule[]) 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.
*
- * @param pattern the pattern to parse
- * @param timeZone the time zone to use
- * @param locale the locale to use
- * @param symbols the symbols to use
* @return a List of Rule objects
* @throws IllegalArgumentException if pattern is invalid
*/
- private static List parse(String pattern, TimeZone timeZone, Locale locale, DateFormatSymbols symbols) {
+ protected List parsePattern() {
+ DateFormatSymbols symbols = new DateFormatSymbols(mLocale);
List rules = new ArrayList();
String[] ERAs = symbols.getEras();
@@ -362,12 +417,12 @@ public class FastDateFormat extends Format {
String[] shortWeekdays = symbols.getShortWeekdays();
String[] AmPmStrings = symbols.getAmPmStrings();
- int length = pattern.length();
+ int length = mPattern.length();
int[] indexRef = new int[1];
for (int i = 0; i < length; i++) {
indexRef[0] = i;
- String token = parseToken(pattern, indexRef);
+ String token = parseToken(mPattern, indexRef);
i = indexRef[0];
int tokenLen = token.length();
@@ -384,9 +439,9 @@ public class FastDateFormat extends Format {
break;
case 'y': // year (number)
if (tokenLen >= 4) {
- rule = new UnpaddedNumberField(Calendar.YEAR);
+ rule = UnpaddedNumberField.INSTANCE_YEAR;
} else {
- rule = new TwoDigitYearField();
+ rule = TwoDigitYearField.INSTANCE;
}
break;
case 'M': // month in year (text and number)
@@ -395,9 +450,9 @@ public class FastDateFormat extends Format {
} else if (tokenLen == 3) {
rule = new TextField(Calendar.MONTH, shortMonths);
} else if (tokenLen == 2) {
- rule = new TwoDigitMonthField();
+ rule = TwoDigitMonthField.INSTANCE;
} else {
- rule = new UnpaddedMonthField();
+ rule = UnpaddedMonthField.INSTANCE;
}
break;
case 'd': // day in month (number)
@@ -444,9 +499,16 @@ public class FastDateFormat extends Format {
break;
case 'z': // time zone (text)
if (tokenLen >= 4) {
- rule = new TimeZoneRule(timeZone, locale, TimeZone.LONG);
+ rule = new TimeZoneNameRule(mTimeZone, mTimeZoneForced, mLocale, TimeZone.LONG);
} else {
- rule = new TimeZoneRule(timeZone, locale, TimeZone.SHORT);
+ rule = new TimeZoneNameRule(mTimeZone, mTimeZoneForced, 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
@@ -474,7 +536,7 @@ public class FastDateFormat extends Format {
* @param indexRef index references
* @return parsed token
*/
- private static String parseToken(String pattern, int[] indexRef) {
+ protected String parseToken(String pattern, int[] indexRef) {
StringBuffer buf = new StringBuffer();
int i = indexRef[0];
@@ -533,7 +595,7 @@ public class FastDateFormat extends Format {
* @param padding the padding required
* @return a new rule with the correct padding
*/
- private static NumberRule selectNumberRule(int field, int padding) {
+ protected NumberRule selectNumberRule(int field, int padding) {
switch (padding) {
case 1:
return new UnpaddedNumberField(field);
@@ -544,40 +606,7 @@ public class FastDateFormat extends Format {
}
}
- //-----------------------------------------------------------------------
- /**
- * Constructs a new FastDateFormat.
- *
- * @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
- * @param symbols optional date format symbols, overrides symbols for provided locale
- * @throws IllegalArgumentException if pattern is invalid
- */
- private FastDateFormat(String pattern, TimeZone timeZone, Locale locale, DateFormatSymbols symbols) {
- if (locale == null) {
- locale = Locale.getDefault();
- }
-
- mPattern = pattern;
- mTimeZone = timeZone;
- mLocale = locale;
-
- if (symbols == null) {
- symbols = new DateFormatSymbols(locale);
- }
-
- List rulesList = parse(pattern, timeZone, locale, symbols);
- mRules = (Rule[]) rulesList.toArray(new Rule[rulesList.size()]);
-
- int len = 0;
- for (int i=mRules.length; --i >= 0; ) {
- len += mRules[i].estimateLength();
- }
-
- mMaxLengthEstimate = len;
- }
-
+ // Format methods
//-----------------------------------------------------------------------
/**
* Format either a Date or a Calendar object.
@@ -605,11 +634,8 @@ public class FastDateFormat extends Format {
* @return the formatted string
*/
public String format(Date date) {
- Calendar c = new GregorianCalendar(cDefaultTimeZone);
+ Calendar c = new GregorianCalendar(mTimeZone);
c.setTime(date);
- if (mTimeZone != null) {
- c.setTimeZone(mTimeZone);
- }
return applyRules(c, new StringBuffer(mMaxLengthEstimate)).toString();
}
@@ -631,11 +657,8 @@ public class FastDateFormat extends Format {
* @return the specified string buffer
*/
public StringBuffer format(Date date, StringBuffer buf) {
- Calendar c = new GregorianCalendar(cDefaultTimeZone);
+ Calendar c = new GregorianCalendar(mTimeZone);
c.setTime(date);
- if (mTimeZone != null) {
- c.setTimeZone(mTimeZone);
- }
return applyRules(c, buf);
}
@@ -647,8 +670,8 @@ public class FastDateFormat extends Format {
* @return the specified string buffer
*/
public StringBuffer format(Calendar calendar, StringBuffer buf) {
- if (mTimeZone != null) {
- calendar = (Calendar)calendar.clone();
+ if (mTimeZoneForced) {
+ calendar = (Calendar) calendar.clone();
calendar.setTimeZone(mTimeZone);
}
return applyRules(calendar, buf);
@@ -661,7 +684,7 @@ public class FastDateFormat extends Format {
* @param buf the buffer to format into
* @return the specified string buffer
*/
- private StringBuffer applyRules(Calendar calendar, StringBuffer buf) {
+ protected StringBuffer applyRules(Calendar calendar, StringBuffer buf) {
Rule[] rules = mRules;
int len = mRules.length;
for (int i = 0; i < len; i++) {
@@ -670,6 +693,7 @@ public class FastDateFormat extends Format {
return buf;
}
+ // Parsing
//-----------------------------------------------------------------------
/**
* Parsing not supported.
@@ -684,6 +708,7 @@ public class FastDateFormat extends Format {
return null;
}
+ // Accessors
//-----------------------------------------------------------------------
/**
* Gets the pattern used by this formatter.
@@ -695,8 +720,11 @@ public class FastDateFormat extends Format {
}
/**
- * Gets the time zone used by this formatter, or null if time zone of
- * formatted dates is used instead.
+ * Gets the time zone used by this formatter.
+ *
+ * This zone is always used for Date formatting.
+ * If a Calendar is passed in to be formatted, the time zone on that may
+ * be used depending on {@link #getTimeZoneOverridesCalendar()}.
*
* @return the time zone
*/
@@ -704,6 +732,16 @@ public class FastDateFormat extends Format {
return mTimeZone;
}
+ /**
+ * Returns true if the time zone of the calendar overrides the time zone
+ * of the formatter
+ *
+ * @return true if time zone of formatter overridden for calendars
+ */
+ public boolean getTimeZoneOverridesCalendar() {
+ return mTimeZoneForced;
+ }
+
/**
* Gets the locale used by this formatter.
*
@@ -723,6 +761,56 @@ public class FastDateFormat extends Format {
return mMaxLengthEstimate;
}
+ // Basics
+ //-----------------------------------------------------------------------
+ /**
+ * Compare two objects for equality.
+ *
+ * @param obj the object to compare to
+ * @return true if equal
+ */
+ public boolean equals(Object obj) {
+ if (obj instanceof FastDateFormat == false) {
+ return false;
+ }
+ FastDateFormat other = (FastDateFormat) obj;
+ if (
+ (mPattern == other.mPattern || mPattern.equals(other.mPattern)) &&
+ (mTimeZone == other.mTimeZone || mTimeZone.equals(other.mTimeZone)) &&
+ (mLocale == other.mLocale || mLocale.equals(other.mLocale)) &&
+ (mTimeZoneForced == other.mTimeZoneForced) &&
+ (mLocaleForced == other.mLocaleForced)
+ ) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * A suitable hashcode.
+ *
+ * @return a hashcode compatable with equals
+ */
+ public int hashCode() {
+ int total = 0;
+ total += mPattern.hashCode();
+ total += mTimeZone.hashCode();
+ total += (mTimeZoneForced ? 1 : 0);
+ total += mLocale.hashCode();
+ total += (mLocaleForced ? 1 : 0);
+ return total;
+ }
+
+ /**
+ * Gets a debugging string version of this formatter.
+ *
+ * @return a debugging string
+ */
+ public String toString() {
+ return "FastDateFormat[" + mPattern + "]";
+ }
+
+ // Rules
//-----------------------------------------------------------------------
/**
* Inner class defining a rule.
@@ -809,6 +897,8 @@ public class FastDateFormat extends Format {
* Inner class to output an unpadded number.
*/
private static class UnpaddedNumberField implements NumberRule {
+ static final UnpaddedNumberField INSTANCE_YEAR = new UnpaddedNumberField(Calendar.YEAR);
+
private final int mField;
UnpaddedNumberField(int field) {
@@ -826,12 +916,10 @@ public class FastDateFormat extends Format {
public final void appendTo(StringBuffer buffer, int value) {
if (value < 10) {
buffer.append((char)(value + '0'));
- }
- else if (value < 100) {
+ } else if (value < 100) {
buffer.append((char)(value / 10 + '0'));
buffer.append((char)(value % 10 + '0'));
- }
- else {
+ } else {
buffer.append(Integer.toString(value));
}
}
@@ -841,6 +929,8 @@ public class FastDateFormat extends Format {
* Inner class to output an unpadded month.
*/
private static class UnpaddedMonthField implements NumberRule {
+ static final UnpaddedMonthField INSTANCE = new UnpaddedMonthField();
+
UnpaddedMonthField() {
}
@@ -855,8 +945,7 @@ public class FastDateFormat extends Format {
public final void appendTo(StringBuffer buffer, int value) {
if (value < 10) {
buffer.append((char)(value + '0'));
- }
- else {
+ } else {
buffer.append((char)(value / 10 + '0'));
buffer.append((char)(value % 10 + '0'));
}
@@ -894,13 +983,11 @@ public class FastDateFormat extends Format {
}
buffer.append((char)(value / 10 + '0'));
buffer.append((char)(value % 10 + '0'));
- }
- else {
+ } else {
int digits;
if (value < 1000) {
digits = 3;
- }
- else {
+ } else {
digits = (int)(Math.log(value) / LOG_10) + 1;
}
for (int i = mSize; --i >= digits; ) {
@@ -933,8 +1020,7 @@ public class FastDateFormat extends Format {
if (value < 100) {
buffer.append((char)(value / 10 + '0'));
buffer.append((char)(value % 10 + '0'));
- }
- else {
+ } else {
buffer.append(Integer.toString(value));
}
}
@@ -944,6 +1030,8 @@ public class FastDateFormat extends Format {
* Inner class to output a two digit year.
*/
private static class TwoDigitYearField implements NumberRule {
+ static final TwoDigitYearField INSTANCE = new TwoDigitYearField();
+
TwoDigitYearField() {
}
@@ -965,6 +1053,8 @@ public class FastDateFormat extends Format {
* Inner class to output a two digit month.
*/
private static class TwoDigitMonthField implements NumberRule {
+ static final TwoDigitMonthField INSTANCE = new TwoDigitMonthField();
+
TwoDigitMonthField() {
}
@@ -1037,71 +1127,101 @@ public class FastDateFormat extends Format {
}
/**
- * Inner class to output a time zone.
+ * Inner class to output a time zone name.
*/
- private static class TimeZoneRule implements Rule {
+ private static class TimeZoneNameRule implements Rule {
private final TimeZone mTimeZone;
+ private final boolean mTimeZoneForced;
private final Locale mLocale;
private final int mStyle;
private final String mStandard;
private final String mDaylight;
- TimeZoneRule(TimeZone timeZone, Locale locale, int style) {
+ TimeZoneNameRule(TimeZone timeZone, boolean timeZoneForced, Locale locale, int style) {
mTimeZone = timeZone;
+ mTimeZoneForced = timeZoneForced;
mLocale = locale;
mStyle = style;
- if (timeZone != null) {
+ if (timeZoneForced) {
mStandard = getTimeZoneDisplay(timeZone, false, style, locale);
mDaylight = getTimeZoneDisplay(timeZone, true, style, locale);
- }
- else {
+ } else {
mStandard = null;
mDaylight = null;
}
}
public int estimateLength() {
- if (mTimeZone != null) {
+ if (mTimeZoneForced) {
return Math.max(mStandard.length(), mDaylight.length());
- }
- else if (mStyle == TimeZone.SHORT) {
+ } else if (mStyle == TimeZone.SHORT) {
return 4;
- }
- else {
+ } else {
return 40;
}
}
public void appendTo(StringBuffer buffer, Calendar calendar) {
- TimeZone timeZone;
- if ((timeZone = mTimeZone) != null) {
- if (timeZone.useDaylightTime() &&
- calendar.get(Calendar.DST_OFFSET) != 0) {
-
+ if (mTimeZoneForced) {
+ if (mTimeZone.useDaylightTime() && calendar.get(Calendar.DST_OFFSET) != 0) {
buffer.append(mDaylight);
- }
- else {
+ } else {
buffer.append(mStandard);
}
- }
- else {
- timeZone = calendar.getTimeZone();
- if (timeZone.useDaylightTime() &&
- calendar.get(Calendar.DST_OFFSET) != 0) {
-
- buffer.append(getTimeZoneDisplay
- (timeZone, true, mStyle, mLocale));
- }
- else {
- buffer.append(getTimeZoneDisplay
- (timeZone, false, mStyle, mLocale));
+ } else {
+ TimeZone timeZone = calendar.getTimeZone();
+ if (timeZone.useDaylightTime() && calendar.get(Calendar.DST_OFFSET) != 0) {
+ buffer.append(getTimeZoneDisplay(timeZone, true, mStyle, mLocale));
+ } else {
+ buffer.append(getTimeZoneDisplay(timeZone, false, mStyle, mLocale));
}
}
}
}
- // ----------------------------------------------------------------------------------
+ /**
+ * Inner class to output a time zone as a number +/-HHMM or +/-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;
+
+ TimeZoneNumberRule(boolean colon) {
+ mColon = colon;
+ }
+
+ public int estimateLength() {
+ return 5;
+ }
+
+ 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.
*/
@@ -1139,12 +1259,12 @@ public class FastDateFormat extends Format {
}
}
- // ----------------------------------------------------------------------------------
+ // ----------------------------------------------------------------------
/**
* Helper class for creating compound objects. One use for this class is to create a
* hashtable key out of multiple objects.
*/
- private static class Pair implements Comparable, Serializable {
+ private static class Pair {
private final Object mObj1;
private final Object mObj2;
@@ -1153,56 +1273,6 @@ public class FastDateFormat extends Format {
mObj2 = obj2;
}
- public int compareTo(Object obj) {
- if (this == obj) {
- return 0;
- }
-
- Pair other = (Pair)obj;
-
- Object a = mObj1;
- Object b = other.mObj1;
-
- firstTest: {
- if (a == null) {
- if (b != null) {
- return 1;
- }
- // Both a and b are null.
- break firstTest;
- }
- else {
- if (b == null) {
- return -1;
- }
- }
-
- int result = ((Comparable)a).compareTo(b);
-
- if (result != 0) {
- return result;
- }
- }
-
- a = mObj2;
- b = other.mObj2;
-
- if (a == null) {
- if (b != null) {
- return 1;
- }
- // Both a and b are null.
- return 0;
- }
- else {
- if (b == null) {
- return -1;
- }
- }
-
- return ((Comparable)a).compareTo(b);
- }
-
public boolean equals(Object obj) {
if (this == obj) {
return true;
diff --git a/src/java/org/apache/commons/lang/time/StopWatch.java b/src/java/org/apache/commons/lang/time/StopWatch.java
index df6d61c94..793e49bbd 100644
--- a/src/java/org/apache/commons/lang/time/StopWatch.java
+++ b/src/java/org/apache/commons/lang/time/StopWatch.java
@@ -1,7 +1,7 @@
/* ====================================================================
* The Apache Software License, Version 1.1
*
- * Copyright (c) 1999-2003 The Apache Software Foundation. All rights
+ * Copyright (c) 2002-2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -77,13 +77,10 @@ package org.apache.commons.lang.time;
* @author Henri Yandell
* @author Stephen Colebourne
* @since 2.0
- * @version $Id: StopWatch.java,v 1.3 2003/05/21 23:37:20 scolebourne Exp $
+ * @version $Id: StopWatch.java,v 1.4 2003/06/08 23:14:23 scolebourne Exp $
*/
public class StopWatch {
- private static final int MILLIS_IN_HOUR = 60 * 60 * 1000;
- private static final int MILLIS_IN_MINUTE = 60 * 1000;
-
/** The start time */
private long startTime = -1;
/** The stop time */
@@ -187,53 +184,13 @@ public class StopWatch {
/**
*
Gets a summary of the time that the stopwatch recorded as a string.
*
- * The format used is ISO8601,
+ *
The format used is ISO8601-like,
* hours:minutes:seconds.milliseconds.
*
* @return the time as a String
*/
public String toString() {
- return StopWatch.toString(getTime());
- }
-
- /**
- * Get the time gap as a string.
- *
- * The format used is ISO8601,
- * hours:minutes:seconds.milliseconds.
- *
- * @return the time as a String
- */
- public static String toString(long time) {
- int hours, minutes, seconds, milliseconds;
- hours = (int) (time / MILLIS_IN_HOUR);
- time = time - (hours * MILLIS_IN_HOUR);
- minutes = (int) (time / MILLIS_IN_MINUTE);
- time = time - (minutes * MILLIS_IN_MINUTE);
- seconds = (int) (time / 1000);
- time = time - (seconds * 1000);
- milliseconds = (int) time;
-
- StringBuffer buf = new StringBuffer(32);
- buf.append(hours);
- buf.append(':');
- if (minutes < 10) {
- buf.append('0');
- }
- buf.append(minutes);
- buf.append(':');
- if (seconds < 10) {
- buf.append('0');
- }
- buf.append(seconds);
- buf.append('.');
- if (milliseconds < 10) {
- buf.append("00");
- } else if (milliseconds < 100) {
- buf.append('0');
- }
- buf.append(milliseconds);
- return buf.toString();
+ return DurationFormatUtils.formatISO(getTime());
}
}
diff --git a/src/test/org/apache/commons/lang/time/CalendarUtilsTest.java b/src/test/org/apache/commons/lang/time/CalendarUtilsTest.java
deleted file mode 100644
index abfb435ef..000000000
--- a/src/test/org/apache/commons/lang/time/CalendarUtilsTest.java
+++ /dev/null
@@ -1,379 +0,0 @@
-/* ====================================================================
- * The Apache Software License, Version 1.1
- *
- * Copyright (c) 2002-2003 The Apache Software Foundation. All rights
- * reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. The end-user documentation included with the redistribution, if
- * any, must include the following acknowlegement:
- * "This product includes software developed by the
- * Apache Software Foundation (http://www.apache.org/)."
- * Alternately, this acknowlegement may appear in the software itself,
- * if and wherever such third-party acknowlegements normally appear.
- *
- * 4. The names "The Jakarta Project", "Commons", and "Apache Software
- * Foundation" must not be used to endorse or promote products derived
- * from this software without prior written permission. For written
- * permission, please contact apache@apache.org.
- *
- * 5. Products derived from this software may not be called "Apache"
- * nor may "Apache" appear in their names without prior written
- * permission of the Apache Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation. For more
- * information on the Apache Software Foundation, please see
- * .
- */
-package org.apache.commons.lang.time;
-
-import java.text.DateFormat;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.Iterator;
-
-import junit.framework.AssertionFailedError;
-import junit.framework.Test;
-import junit.framework.TestCase;
-import junit.framework.TestSuite;
-import junit.textui.TestRunner;
-
-/**
- * Unit tests {@link org.apache.commons.lang.CalendarUtils}.
- *
- * @author Serge Knystautas
- */
-public class CalendarUtilsTest extends TestCase {
- DateFormat parser = null;
- Date date1 = null;
- Date date2 = null;
-
- public CalendarUtilsTest(String name) {
- super(name);
- }
-
- public static void main(String[] args) {
- TestRunner.run(suite());
- }
-
- public static Test suite() {
- TestSuite suite = new TestSuite(CalendarUtilsTest.class);
- suite.setName("CalendarUtilsTest Tests");
- return suite;
- }
-
- protected void setUp() throws Exception {
- super.setUp();
-
- parser = new java.text.SimpleDateFormat("MMM dd, yyyy H:mm:ss.SSS");
-
- date1 = parser.parse("February 12, 2002 12:34:56.789");
- date2 = parser.parse("November 18, 2001 1:23:11.321");
- }
-
- protected void tearDown() throws Exception {
- super.tearDown();
- }
-
- //-----------------------------------------------------------------------
-
-
- /**
- * Tests various values with the round method
- */
- public void testRound() throws Exception {
- assertEquals("round year-1 failed",
- new Date("2002 January 1"),
- CalendarUtils.round(date1, Calendar.YEAR));
- assertEquals("round year-2 failed",
- new Date("2002 January 1"),
- CalendarUtils.round(date2, Calendar.YEAR));
- assertEquals("round month-1 failed",
- new Date("2002 February 1"),
- CalendarUtils.round(date1, Calendar.MONTH));
- assertEquals("round month-2 failed",
- new Date("2001 December 1"),
- CalendarUtils.round(date2, Calendar.MONTH));
- assertEquals("round semimonth-1 failed",
- new Date("2002 February 16"),
- CalendarUtils.round(date1, CalendarUtils.SEMI_MONTH));
- assertEquals("round semimonth-2 failed",
- new Date("2001 November 16"),
- CalendarUtils.round(date2, CalendarUtils.SEMI_MONTH));
- assertEquals("round date-1 failed",
- new Date("2002 February 13"),
- CalendarUtils.round(date1, Calendar.DATE));
- assertEquals("round date-2 failed",
- new Date("2001 November 18"),
- CalendarUtils.round(date2, Calendar.DATE));
- assertEquals("round hour-1 failed",
- parser.parse("February 12, 2002 13:00:00.000"),
- CalendarUtils.round(date1, Calendar.HOUR));
- assertEquals("round hour-2 failed",
- parser.parse("November 18, 2001 1:00:00.000"),
- CalendarUtils.round(date2, Calendar.HOUR));
- assertEquals("round minute-1 failed",
- parser.parse("February 12, 2002 12:35:00.000"),
- CalendarUtils.round(date1, Calendar.MINUTE));
- assertEquals("round minute-2 failed",
- parser.parse("November 18, 2001 1:23:00.000"),
- CalendarUtils.round(date2, Calendar.MINUTE));
- assertEquals("round second-1 failed",
- parser.parse("February 12, 2002 12:34:57.000"),
- CalendarUtils.round(date1, Calendar.SECOND));
- assertEquals("round second-2 failed",
- parser.parse("November 18, 2001 1:23:11.000"),
- CalendarUtils.round(date2, Calendar.SECOND));
- }
-
- /**
- * Tests various values with the trunc method
- */
- public void testTrunc() throws Exception {
- assertEquals("trunc year-1 failed",
- new Date("2002 January 1"),
- CalendarUtils.trunc(date1, Calendar.YEAR));
- assertEquals("trunc year-2 failed",
- new Date("2001 January 1"),
- CalendarUtils.trunc(date2, Calendar.YEAR));
- assertEquals("trunc month-1 failed",
- new Date("2002 February 1"),
- CalendarUtils.trunc(date1, Calendar.MONTH));
- assertEquals("trunc month-2 failed",
- new Date("2001 November 1"),
- CalendarUtils.trunc(date2, Calendar.MONTH));
- assertEquals("trunc semimonth-1 failed",
- new Date("2002 February 1"),
- CalendarUtils.trunc(date1, CalendarUtils.SEMI_MONTH));
- assertEquals("trunc semimonth-2 failed",
- new Date("2001 November 16"),
- CalendarUtils.trunc(date2, CalendarUtils.SEMI_MONTH));
- assertEquals("trunc date-1 failed",
- new Date("2002 February 12"),
- CalendarUtils.trunc(date1, Calendar.DATE));
- assertEquals("trunc date-2 failed",
- new Date("2001 November 18"),
- CalendarUtils.trunc(date2, Calendar.DATE));
- assertEquals("trunc hour-1 failed",
- parser.parse("February 12, 2002 12:00:00.000"),
- CalendarUtils.trunc(date1, Calendar.HOUR));
- assertEquals("trunc hour-2 failed",
- parser.parse("November 18, 2001 1:00:00.000"),
- CalendarUtils.trunc(date2, Calendar.HOUR));
- assertEquals("trunc minute-1 failed",
- parser.parse("February 12, 2002 12:34:00.000"),
- CalendarUtils.trunc(date1, Calendar.MINUTE));
- assertEquals("trunc minute-2 failed",
- parser.parse("November 18, 2001 1:23:00.000"),
- CalendarUtils.trunc(date2, Calendar.MINUTE));
- assertEquals("trunc second-1 failed",
- parser.parse("February 12, 2002 12:34:56.000"),
- CalendarUtils.trunc(date1, Calendar.SECOND));
- assertEquals("trunc second-2 failed",
- parser.parse("November 18, 2001 1:23:11.000"),
- CalendarUtils.trunc(date2, Calendar.SECOND));
-
- }
-
- /**
- * Tests the parse method, which is supposed to handle various strings
- * as flexibly as CVS supports.
- */
- public void testParse() throws Exception {
- //This is difficult to test since the "now" used in the
- // parse function cannot be controlled. We could possibly control
- // it by trying before and after and making sure the value we expect
- // is between the two values calculated.
- //For now we're just using the custom assertEquals that takes a delta
-
- Calendar now = null;
-
- now = Calendar.getInstance();
- now.add(Calendar.MINUTE, -1);
- assertEquals("parse 1 minute ago",
- now, CalendarUtils.parse("1 minute ago"), 50);
- now = Calendar.getInstance();
- now.add(Calendar.MINUTE, -8);
- assertEquals("parse 8 minutes ago",
- now, CalendarUtils.parse("8 minutes ago"), 50);
-
- now = Calendar.getInstance();
- now.add(Calendar.DATE, -1);
- assertEquals("parse yesterday",
- now, CalendarUtils.parse("yesterday"), 50);
-
- now = Calendar.getInstance();
- now.add(Calendar.DATE, 1);
- assertEquals("parse tomorrow",
- now, CalendarUtils.parse("tomorrow"), 50);
-
- now = Calendar.getInstance();
- //Sunday would be 1, Saturday would be 7, so we walk back up to 6 days.
- if (now.get(Calendar.DATE) == 1) {
- //If Sunday already, we go back a full week
- now.add(Calendar.DATE, -7);
- } else {
- now.add(Calendar.DATE, 1 - now.get(Calendar.DAY_OF_WEEK));
- }
- assertEquals("parse last Sunday",
- now, CalendarUtils.parse("last Sunday"), 50);
-
- now = Calendar.getInstance();
- now.add(Calendar.DATE, -7);
- assertEquals("parse last week",
- now, CalendarUtils.parse("last week"), 50);
-
- now = Calendar.getInstance();
- //January would be 0, December would be 11, so we walk back up to 11 months
- if (now.get(Calendar.MONTH) == 0) {
- //If January already, we go back a full year
- now.add(Calendar.MONTH, -12);
- } else {
- now.add(Calendar.MONTH, 0 - now.get(Calendar.MONTH));
- }
- assertEquals("parse last January",
- now, CalendarUtils.parse("last January"), 50);
- }
-
- /**
- * Tests the calendar iterator for week ranges
- */
- public void testWeekIterator() throws Exception {
- Calendar now = Calendar.getInstance();
- Calendar today = CalendarUtils.trunc(now, Calendar.DATE);
- Calendar sunday = CalendarUtils.trunc(now, Calendar.DATE);
- sunday.add(Calendar.DATE, 1 - sunday.get(Calendar.DAY_OF_WEEK));
- Calendar monday = CalendarUtils.trunc(now, Calendar.DATE);
- if (monday.get(Calendar.DATE) == 1) {
- //This is sunday... roll back 6 days
- monday.add(Calendar.DATE, -6);
- } else {
- monday.add(Calendar.DATE, 2 - monday.get(Calendar.DAY_OF_WEEK));
- }
- Calendar centered = CalendarUtils.trunc(now, Calendar.DATE);
- centered.add(Calendar.DATE, -3);
-
- Iterator it = CalendarUtils.getCalendarIterator(now, CalendarUtils.RANGE_WEEK_SUNDAY);
- assertWeekIterator(it, sunday);
- it = CalendarUtils.getCalendarIterator(now, CalendarUtils.RANGE_WEEK_MONDAY);
- assertWeekIterator(it, monday);
- it = CalendarUtils.getCalendarIterator(now, CalendarUtils.RANGE_WEEK_RELATIVE);
- assertWeekIterator(it, today);
- it = CalendarUtils.getCalendarIterator(now, CalendarUtils.RANGE_WEEK_CENTER);
- assertWeekIterator(it, centered);
- }
-
- /**
- * Tests the calendar iterator for month-based ranges
- */
- public void testMonthIterator() throws Exception {
- Iterator it = CalendarUtils.getCalendarIterator(date1, CalendarUtils.RANGE_MONTH_SUNDAY);
- assertWeekIterator(it,
- new Date("January 27, 2002"),
- new Date("March 2, 2002"));
-
- it = CalendarUtils.getCalendarIterator(date1, CalendarUtils.RANGE_MONTH_MONDAY);
- assertWeekIterator(it,
- new Date("January 28, 2002"),
- new Date("March 3, 2002"));
-
- it = CalendarUtils.getCalendarIterator(date2, CalendarUtils.RANGE_MONTH_SUNDAY);
- assertWeekIterator(it,
- new Date("October 28, 2001"),
- new Date("December 1, 2001"));
-
- it = CalendarUtils.getCalendarIterator(date2, CalendarUtils.RANGE_MONTH_MONDAY);
- assertWeekIterator(it,
- new Date("October 29, 2001"),
- new Date("December 2, 2001"));
- }
-
- /**
- * This checks that this is a 7 element iterator of Calendar objects
- * that are dates (no time), and exactly 1 day spaced after each other.
- */
- private static void assertWeekIterator(Iterator it, Calendar start) {
- Calendar end = (Calendar) start.clone();
- end.add(Calendar.DATE, 6);
-
- assertWeekIterator(it, start, end);
- }
-
- /**
- * Convenience method for when working with Date objects
- */
- private static void assertWeekIterator(Iterator it, Date start, Date end) {
- Calendar calStart = Calendar.getInstance();
- calStart.setTime(start);
- Calendar calEnd = Calendar.getInstance();
- calEnd.setTime(end);
-
- assertWeekIterator(it, calStart, calEnd);
- }
-
- /**
- * This checks that this is a 7 divisble iterator of Calendar objects
- * that are dates (no time), and exactly 1 day spaced after each other
- * (in addition to the proper start and stop dates)
- */
- private static void assertWeekIterator(Iterator it, Calendar start, Calendar end) {
- Calendar cal = (Calendar) it.next();
- assertEquals("", start, cal, 0);
- Calendar last = null;
- int count = 1;
- while (it.hasNext()) {
- //Check this is just a date (no time component)
- assertEquals("", cal, CalendarUtils.trunc(cal, Calendar.DATE), 0);
-
- last = cal;
- cal = (Calendar) it.next();
- count++;
-
- //Check that this is one day more than the last date
- last.add(Calendar.DATE, 1);
- assertEquals("", last, cal, 0);
- }
- if (count % 7 != 0) {
- throw new AssertionFailedError("There were " + count + " days in this iterator");
- }
- assertEquals("", end, cal, 0);
- }
-
- /**
- * Used to check that Calendar objects are close enough
- * delta is in milliseconds
- */
- public static void assertEquals(String message, Calendar cal1, Calendar cal2, long delta) {
- if (Math.abs(cal1.getTime().getTime() - cal2.getTime().getTime()) > delta) {
- throw new AssertionFailedError(
- message + " expected " + cal1.getTime() + " but got " + cal2.getTime());
- }
- }
-}
-
diff --git a/src/test/org/apache/commons/lang/time/DateFormatUtilsTest.java b/src/test/org/apache/commons/lang/time/DateFormatUtilsTest.java
new file mode 100644
index 000000000..bd83416fa
--- /dev/null
+++ b/src/test/org/apache/commons/lang/time/DateFormatUtilsTest.java
@@ -0,0 +1,199 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002-2003 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Commons", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+package org.apache.commons.lang.time;
+
+import java.util.Calendar;
+import java.util.TimeZone;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import junit.textui.TestRunner;
+
+/**
+ * TestCase for DateFormatUtils.
+ *
+ * @author Apache Ant - DateUtilsTest
+ * @author Stephane Bailliez
+ * @author Stefan Bodewig
+ * @author Stephen Colebourne
+ */
+public class DateFormatUtilsTest extends TestCase {
+
+ public static void main(String[] args) {
+ TestRunner.run(suite());
+ }
+
+ public static Test suite() {
+ TestSuite suite = new TestSuite(DateFormatUtilsTest.class);
+ suite.setName("DateFormatUtils Tests");
+ return suite;
+ }
+
+ public DateFormatUtilsTest(String s) {
+ super(s);
+ }
+
+ public void testDateTimeISO(){
+ TimeZone timeZone = TimeZone.getTimeZone("GMT-3");
+ Calendar cal = Calendar.getInstance(timeZone);
+ cal.set(2002,1,23,9,11,12);
+ String text = DateFormatUtils.format(cal.getTime(),
+ DateFormatUtils.ISO_DATETIME_FORMAT.getPattern(), timeZone);
+ assertEquals("2002-02-23T09:11:12", text);
+ text = DateFormatUtils.format(cal.getTime().getTime(),
+ DateFormatUtils.ISO_DATETIME_FORMAT.getPattern(), timeZone);
+ assertEquals("2002-02-23T09:11:12", text);
+ text = DateFormatUtils.ISO_DATETIME_FORMAT.format(cal);
+ assertEquals("2002-02-23T09:11:12", text);
+
+ text = DateFormatUtils.format(cal.getTime(),
+ DateFormatUtils.ISO_DATETIME_TIMEZONE_FORMAT.getPattern(), timeZone);
+ assertEquals("2002-02-23T09:11:12-03:00", text);
+ text = DateFormatUtils.format(cal.getTime().getTime(),
+ DateFormatUtils.ISO_DATETIME_TIMEZONE_FORMAT.getPattern(), timeZone);
+ assertEquals("2002-02-23T09:11:12-03:00", text);
+ text = DateFormatUtils.ISO_DATETIME_TIMEZONE_FORMAT.format(cal);
+ assertEquals("2002-02-23T09:11:12-03:00", text);
+ }
+
+ public void testDateISO(){
+ TimeZone timeZone = TimeZone.getTimeZone("GMT-3");
+ Calendar cal = Calendar.getInstance(timeZone);
+ cal.set(2002,1,23,10,11,12);
+ String text = DateFormatUtils.format(cal.getTime(),
+ DateFormatUtils.ISO_DATE_FORMAT.getPattern(), timeZone);
+ assertEquals("2002-02-23", text);
+ text = DateFormatUtils.format(cal.getTime().getTime(),
+ DateFormatUtils.ISO_DATE_FORMAT.getPattern(), timeZone);
+ assertEquals("2002-02-23", text);
+ text = DateFormatUtils.ISO_DATE_FORMAT.format(cal);
+ assertEquals("2002-02-23", text);
+
+ text = DateFormatUtils.format(cal.getTime(),
+ DateFormatUtils.ISO_DATE_TIMEZONE_FORMAT.getPattern(), timeZone);
+ assertEquals("2002-02-23-03:00", text);
+ text = DateFormatUtils.format(cal.getTime().getTime(),
+ DateFormatUtils.ISO_DATE_TIMEZONE_FORMAT.getPattern(), timeZone);
+ assertEquals("2002-02-23-03:00", text);
+ text = DateFormatUtils.ISO_DATE_TIMEZONE_FORMAT.format(cal);
+ assertEquals("2002-02-23-03:00", text);
+ }
+
+ public void testTimeISO(){
+ TimeZone timeZone = TimeZone.getTimeZone("GMT-3");
+ Calendar cal = Calendar.getInstance(timeZone);
+ cal.set(2002,1,23,10,11,12);
+ String text = DateFormatUtils.format(cal.getTime(),
+ DateFormatUtils.ISO_TIME_FORMAT.getPattern(), timeZone);
+ assertEquals("T10:11:12", text);
+ text = DateFormatUtils.format(cal.getTime().getTime(),
+ DateFormatUtils.ISO_TIME_FORMAT.getPattern(), timeZone);
+ assertEquals("T10:11:12", text);
+ text = DateFormatUtils.ISO_TIME_FORMAT.format(cal);
+ assertEquals("T10:11:12", text);
+
+ text = DateFormatUtils.format(cal.getTime(),
+ DateFormatUtils.ISO_TIME_TIMEZONE_FORMAT.getPattern(), timeZone);
+ assertEquals("T10:11:12-03:00", text);
+ text = DateFormatUtils.format(cal.getTime().getTime(),
+ DateFormatUtils.ISO_TIME_TIMEZONE_FORMAT.getPattern(), timeZone);
+ assertEquals("T10:11:12-03:00", text);
+ text = DateFormatUtils.ISO_TIME_TIMEZONE_FORMAT.format(cal);
+ assertEquals("T10:11:12-03:00", text);
+ }
+
+ public void testTimeNoTISO(){
+ TimeZone timeZone = TimeZone.getTimeZone("GMT-3");
+ Calendar cal = Calendar.getInstance(timeZone);
+ cal.set(2002,1,23,10,11,12);
+ String text = DateFormatUtils.format(cal.getTime(),
+ DateFormatUtils.ISO_TIME_NO_T_FORMAT.getPattern(), timeZone);
+ assertEquals("10:11:12", text);
+ text = DateFormatUtils.format(cal.getTime().getTime(),
+ DateFormatUtils.ISO_TIME_NO_T_FORMAT.getPattern(), timeZone);
+ assertEquals("10:11:12", text);
+ text = DateFormatUtils.ISO_TIME_NO_T_FORMAT.format(cal);
+ assertEquals("10:11:12", text);
+
+ text = DateFormatUtils.format(cal.getTime(),
+ DateFormatUtils.ISO_TIME_NO_T_TIMEZONE_FORMAT.getPattern(), timeZone);
+ assertEquals("10:11:12-03:00", text);
+ text = DateFormatUtils.format(cal.getTime().getTime(),
+ DateFormatUtils.ISO_TIME_NO_T_TIMEZONE_FORMAT.getPattern(), timeZone);
+ assertEquals("10:11:12-03:00", text);
+ text = DateFormatUtils.ISO_TIME_NO_T_TIMEZONE_FORMAT.format(cal);
+ assertEquals("10:11:12-03:00", text);
+ }
+
+ public void testSMTP(){
+ TimeZone timeZone = TimeZone.getTimeZone("GMT-3");
+ Calendar cal = Calendar.getInstance(timeZone);
+ cal.set(2003,5,8,10,11,12);
+ String text = DateFormatUtils.format(cal.getTime(),
+ DateFormatUtils.SMTP_DATETIME_FORMAT.getPattern(), timeZone);
+ assertEquals("Sun, 08 Jun 2003 10:11:12 -0300", text);
+ text = DateFormatUtils.format(cal.getTime().getTime(),
+ DateFormatUtils.SMTP_DATETIME_FORMAT.getPattern(), timeZone);
+ assertEquals("Sun, 08 Jun 2003 10:11:12 -0300", text);
+ text = DateFormatUtils.SMTP_DATETIME_FORMAT.format(cal);
+ assertEquals("Sun, 08 Jun 2003 10:11:12 -0300", text);
+
+ // format UTC
+ text = DateFormatUtils.formatUTC(cal.getTime().getTime(),
+ DateFormatUtils.SMTP_DATETIME_FORMAT.getPattern());
+ assertEquals("Sun, 08 Jun 2003 13:11:12 +0000", text);
+ }
+
+}
diff --git a/src/test/org/apache/commons/lang/time/DateUtilsTest.java b/src/test/org/apache/commons/lang/time/DateUtilsTest.java
index d31a30a59..43a2dd10f 100644
--- a/src/test/org/apache/commons/lang/time/DateUtilsTest.java
+++ b/src/test/org/apache/commons/lang/time/DateUtilsTest.java
@@ -1,7 +1,7 @@
-/*
+/* ====================================================================
* The Apache Software License, Version 1.1
*
- * Copyright (c) 2002 The Apache Software Foundation. All rights
+ * Copyright (c) 2002-2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -23,14 +23,14 @@
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
- * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * 4. The names "The Jakarta Project", "Commons", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
- * permission of the Apache Group.
+ * permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
@@ -53,22 +53,32 @@
*/
package org.apache.commons.lang.time;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
import java.util.Calendar;
-import java.util.TimeZone;
+import java.util.Date;
+import java.util.Iterator;
+import junit.framework.AssertionFailedError;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import junit.textui.TestRunner;
/**
- * TestCase for DateUtils. [Relies heavily on code taken from the
- * DateUtilsTest class of the jakarata-ant project.]
+ * Unit tests {@link org.apache.commons.lang.CalendarUtils}.
*
- * @author Stephane Bailliez
- * @author Stefan Bodewig
+ * @author Serge Knystautas
*/
public class DateUtilsTest extends TestCase {
+ DateFormat dateParser = null;
+ DateFormat dateTimeParser = null;
+ Date date1 = null;
+ Date date2 = null;
+
+ public DateUtilsTest(String name) {
+ super(name);
+ }
public static void main(String[] args) {
TestRunner.run(suite());
@@ -76,69 +86,300 @@ public class DateUtilsTest extends TestCase {
public static Test suite() {
TestSuite suite = new TestSuite(DateUtilsTest.class);
- suite.setName("DateUtils Tests");
+ suite.setName("CalendarUtilsTest Tests");
return suite;
}
- public DateUtilsTest(String s) {
- super(s);
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ dateParser = new SimpleDateFormat("MMM dd, yyyy");
+ dateTimeParser = new SimpleDateFormat("MMM dd, yyyy H:mm:ss.SSS");
+
+ date1 = dateTimeParser.parse("February 12, 2002 12:34:56.789");
+ date2 = dateTimeParser.parse("November 18, 2001 1:23:11.321");
}
- public void testElapsedTime(){
- String text = DateUtils.formatElapsedTime(50*1000);
- assertEquals("50 seconds", text);
- text = DateUtils.formatElapsedTime(65*1000);
- assertEquals("1 minute 5 seconds", text);
- text = DateUtils.formatElapsedTime(120*1000);
- assertEquals("2 minutes 0 seconds", text);
- text = DateUtils.formatElapsedTime(121*1000);
- assertEquals("2 minutes 1 second", text);
+ protected void tearDown() throws Exception {
+ super.tearDown();
}
- public void testDateTimeISO(){
- TimeZone timeZone = TimeZone.getTimeZone("GMT+1");
- Calendar cal = Calendar.getInstance(timeZone);
- cal.set(2002,1,23,10,11,12);
- String text = DateUtils.format(cal.getTime(),
- DateUtils.ISO8601_DATETIME_PATTERN);
- assertEquals("2002-02-23T09:11:12", text);
+ //-----------------------------------------------------------------------
+
+
+ /**
+ * Tests various values with the round method
+ */
+ public void testRound() throws Exception {
+ assertEquals("round year-1 failed",
+ dateParser.parse("January 1, 2002"),
+ DateUtils.round(date1, Calendar.YEAR));
+ assertEquals("round year-2 failed",
+ dateParser.parse("January 1, 2002"),
+ DateUtils.round(date2, Calendar.YEAR));
+ assertEquals("round month-1 failed",
+ dateParser.parse("February 1, 2002"),
+ DateUtils.round(date1, Calendar.MONTH));
+ assertEquals("round month-2 failed",
+ dateParser.parse("December 1, 2001"),
+ DateUtils.round(date2, Calendar.MONTH));
+ assertEquals("round semimonth-1 failed",
+ dateParser.parse("February 16, 2002"),
+ DateUtils.round(date1, DateUtils.SEMI_MONTH));
+ assertEquals("round semimonth-2 failed",
+ dateParser.parse("November 16, 2001"),
+ DateUtils.round(date2, DateUtils.SEMI_MONTH));
+ assertEquals("round date-1 failed",
+ dateParser.parse("February 13, 2002"),
+ DateUtils.round(date1, Calendar.DATE));
+ assertEquals("round date-2 failed",
+ dateParser.parse("November 18, 2001"),
+ DateUtils.round(date2, Calendar.DATE));
+ assertEquals("round hour-1 failed",
+ dateTimeParser.parse("February 12, 2002 13:00:00.000"),
+ DateUtils.round(date1, Calendar.HOUR));
+ assertEquals("round hour-2 failed",
+ dateTimeParser.parse("November 18, 2001 1:00:00.000"),
+ DateUtils.round(date2, Calendar.HOUR));
+ assertEquals("round minute-1 failed",
+ dateTimeParser.parse("February 12, 2002 12:35:00.000"),
+ DateUtils.round(date1, Calendar.MINUTE));
+ assertEquals("round minute-2 failed",
+ dateTimeParser.parse("November 18, 2001 1:23:00.000"),
+ DateUtils.round(date2, Calendar.MINUTE));
+ assertEquals("round second-1 failed",
+ dateTimeParser.parse("February 12, 2002 12:34:57.000"),
+ DateUtils.round(date1, Calendar.SECOND));
+ assertEquals("round second-2 failed",
+ dateTimeParser.parse("November 18, 2001 1:23:11.000"),
+ DateUtils.round(date2, Calendar.SECOND));
}
- public void testDateISO(){
- TimeZone timeZone = TimeZone.getTimeZone("GMT");
- Calendar cal = Calendar.getInstance(timeZone);
- cal.set(2002,1,23);
- String text = DateUtils.format(cal.getTime(),
- DateUtils.ISO8601_DATE_PATTERN);
- assertEquals("2002-02-23", text);
+ /**
+ * Tests various values with the trunc method
+ */
+ public void testTrunc() throws Exception {
+ assertEquals("trunc year-1 failed",
+ dateParser.parse("January 1, 2002"),
+ DateUtils.trunc(date1, Calendar.YEAR));
+ assertEquals("trunc year-2 failed",
+ dateParser.parse("January 1, 2001"),
+ DateUtils.trunc(date2, Calendar.YEAR));
+ assertEquals("trunc month-1 failed",
+ dateParser.parse("February 1, 2002"),
+ DateUtils.trunc(date1, Calendar.MONTH));
+ assertEquals("trunc month-2 failed",
+ dateParser.parse("November 1, 2001"),
+ DateUtils.trunc(date2, Calendar.MONTH));
+ assertEquals("trunc semimonth-1 failed",
+ dateParser.parse("February 1, 2002"),
+ DateUtils.trunc(date1, DateUtils.SEMI_MONTH));
+ assertEquals("trunc semimonth-2 failed",
+ dateParser.parse("November 16, 2001"),
+ DateUtils.trunc(date2, DateUtils.SEMI_MONTH));
+ assertEquals("trunc date-1 failed",
+ dateParser.parse("February 12, 2002"),
+ DateUtils.trunc(date1, Calendar.DATE));
+ assertEquals("trunc date-2 failed",
+ dateParser.parse("November 18, 2001"),
+ DateUtils.trunc(date2, Calendar.DATE));
+ assertEquals("trunc hour-1 failed",
+ dateTimeParser.parse("February 12, 2002 12:00:00.000"),
+ DateUtils.trunc(date1, Calendar.HOUR));
+ assertEquals("trunc hour-2 failed",
+ dateTimeParser.parse("November 18, 2001 1:00:00.000"),
+ DateUtils.trunc(date2, Calendar.HOUR));
+ assertEquals("trunc minute-1 failed",
+ dateTimeParser.parse("February 12, 2002 12:34:00.000"),
+ DateUtils.trunc(date1, Calendar.MINUTE));
+ assertEquals("trunc minute-2 failed",
+ dateTimeParser.parse("November 18, 2001 1:23:00.000"),
+ DateUtils.trunc(date2, Calendar.MINUTE));
+ assertEquals("trunc second-1 failed",
+ dateTimeParser.parse("February 12, 2002 12:34:56.000"),
+ DateUtils.trunc(date1, Calendar.SECOND));
+ assertEquals("trunc second-2 failed",
+ dateTimeParser.parse("November 18, 2001 1:23:11.000"),
+ DateUtils.trunc(date2, Calendar.SECOND));
+
}
- public void testTimeISODate(){
- // make sure that elapsed time in set via date works
- TimeZone timeZone = TimeZone.getTimeZone("GMT+1");
- Calendar cal = Calendar.getInstance(timeZone);
- cal.set(2002,1,23, 21, 11, 12);
- String text = DateUtils.format(cal.getTime(),
- DateUtils.ISO8601_TIME_PATTERN);
- assertEquals("20:11:12", text);
+ /**
+ * Tests the parse method, which is supposed to handle various strings
+ * as flexibly as CVS supports.
+ */
+ public void testParse() throws Exception {
+ //This is difficult to test since the "now" used in the
+ // parse function cannot be controlled. We could possibly control
+ // it by trying before and after and making sure the value we expect
+ // is between the two values calculated.
+ //For now we're just using the custom assertEquals that takes a delta
+
+ Calendar now = null;
+
+ now = Calendar.getInstance();
+ now.add(Calendar.MINUTE, -1);
+ assertEquals("parse 1 minute ago",
+ now, DateUtils.parse("1 minute ago"), 50);
+ now = Calendar.getInstance();
+ now.add(Calendar.MINUTE, -8);
+ assertEquals("parse 8 minutes ago",
+ now, DateUtils.parse("8 minutes ago"), 50);
+
+ now = Calendar.getInstance();
+ now.add(Calendar.DATE, -1);
+ assertEquals("parse yesterday",
+ now, DateUtils.parse("yesterday"), 50);
+
+ now = Calendar.getInstance();
+ now.add(Calendar.DATE, 1);
+ assertEquals("parse tomorrow",
+ now, DateUtils.parse("tomorrow"), 50);
+
+ now = Calendar.getInstance();
+ //Sunday would be 1, Saturday would be 7, so we walk back up to 6 days.
+ if (now.get(Calendar.DAY_OF_WEEK) == 1) {
+ //If Sunday already, we go back a full week
+ now.add(Calendar.DATE, -7);
+ } else {
+ now.add(Calendar.DATE, 1 - now.get(Calendar.DAY_OF_WEEK));
+ }
+ assertEquals("parse last Sunday",
+ now, DateUtils.parse("last Sunday"), 50);
+
+ now = Calendar.getInstance();
+ now.add(Calendar.DATE, -7);
+ assertEquals("parse last week",
+ now, DateUtils.parse("last week"), 50);
+
+ now = Calendar.getInstance();
+ //January would be 0, December would be 11, so we walk back up to 11 months
+ if (now.get(Calendar.MONTH) == 0) {
+ //If January already, we go back a full year
+ now.add(Calendar.MONTH, -12);
+ } else {
+ now.add(Calendar.MONTH, 0 - now.get(Calendar.MONTH));
+ }
+ assertEquals("parse last January",
+ now, DateUtils.parse("last January"), 50);
}
- public void testTimeISO(){
- // make sure that elapsed time in ms works
- long ms = (20*3600 + 11*60 + 12)*1000;
- String text = DateUtils.format(ms,
- DateUtils.ISO8601_TIME_PATTERN);
- assertEquals("20:11:12", text);
+ /**
+ * Tests the calendar iterator for week ranges
+ */
+ public void testWeekIterator() throws Exception {
+ Calendar now = Calendar.getInstance();
+ for (int i = 0; i< 7; i++) {
+ Calendar today = DateUtils.trunc(now, Calendar.DATE);
+ Calendar sunday = DateUtils.trunc(now, Calendar.DATE);
+ sunday.add(Calendar.DATE, 1 - sunday.get(Calendar.DAY_OF_WEEK));
+ Calendar monday = DateUtils.trunc(now, Calendar.DATE);
+ if (monday.get(Calendar.DAY_OF_WEEK) == 1) {
+ //This is sunday... roll back 6 days
+ monday.add(Calendar.DATE, -6);
+ } else {
+ monday.add(Calendar.DATE, 2 - monday.get(Calendar.DAY_OF_WEEK));
+ }
+ Calendar centered = DateUtils.trunc(now, Calendar.DATE);
+ centered.add(Calendar.DATE, -3);
+
+ Iterator it = DateUtils.getCalendarIterator(now, DateUtils.RANGE_WEEK_SUNDAY);
+ assertWeekIterator(it, sunday);
+ it = DateUtils.getCalendarIterator(now, DateUtils.RANGE_WEEK_MONDAY);
+ assertWeekIterator(it, monday);
+ it = DateUtils.getCalendarIterator(now, DateUtils.RANGE_WEEK_RELATIVE);
+ assertWeekIterator(it, today);
+ it = DateUtils.getCalendarIterator(now, DateUtils.RANGE_WEEK_CENTER);
+ assertWeekIterator(it, centered);
+ now.add(Calendar.DATE,1);
+ }
}
- public void testPhaseOfMoon() {
- TimeZone timeZone = TimeZone.getTimeZone("GMT");
- Calendar cal = Calendar.getInstance(timeZone);
- // should be full moon
- cal.set(2002, 2, 27);
- assertEquals(4, DateUtils.getPhaseOfMoon(cal));
- // should be new moon
- cal.set(2002, 2, 12);
- assertEquals(0, DateUtils.getPhaseOfMoon(cal));
+ /**
+ * Tests the calendar iterator for month-based ranges
+ */
+ public void testMonthIterator() throws Exception {
+ Iterator it = DateUtils.getCalendarIterator(date1, DateUtils.RANGE_MONTH_SUNDAY);
+ assertWeekIterator(it,
+ dateParser.parse("January 27, 2002"),
+ dateParser.parse("March 2, 2002"));
+
+ it = DateUtils.getCalendarIterator(date1, DateUtils.RANGE_MONTH_MONDAY);
+ assertWeekIterator(it,
+ dateParser.parse("January 28, 2002"),
+ dateParser.parse("March 3, 2002"));
+
+ it = DateUtils.getCalendarIterator(date2, DateUtils.RANGE_MONTH_SUNDAY);
+ assertWeekIterator(it,
+ dateParser.parse("October 28, 2001"),
+ dateParser.parse("December 1, 2001"));
+
+ it = DateUtils.getCalendarIterator(date2, DateUtils.RANGE_MONTH_MONDAY);
+ assertWeekIterator(it,
+ dateParser.parse("October 29, 2001"),
+ dateParser.parse("December 2, 2001"));
+ }
+
+ /**
+ * This checks that this is a 7 element iterator of Calendar objects
+ * that are dates (no time), and exactly 1 day spaced after each other.
+ */
+ private static void assertWeekIterator(Iterator it, Calendar start) {
+ Calendar end = (Calendar) start.clone();
+ end.add(Calendar.DATE, 6);
+
+ assertWeekIterator(it, start, end);
+ }
+
+ /**
+ * Convenience method for when working with Date objects
+ */
+ private static void assertWeekIterator(Iterator it, Date start, Date end) {
+ Calendar calStart = Calendar.getInstance();
+ calStart.setTime(start);
+ Calendar calEnd = Calendar.getInstance();
+ calEnd.setTime(end);
+
+ assertWeekIterator(it, calStart, calEnd);
+ }
+
+ /**
+ * This checks that this is a 7 divisble iterator of Calendar objects
+ * that are dates (no time), and exactly 1 day spaced after each other
+ * (in addition to the proper start and stop dates)
+ */
+ private static void assertWeekIterator(Iterator it, Calendar start, Calendar end) {
+ Calendar cal = (Calendar) it.next();
+ assertEquals("", start, cal, 0);
+ Calendar last = null;
+ int count = 1;
+ while (it.hasNext()) {
+ //Check this is just a date (no time component)
+ assertEquals("", cal, DateUtils.trunc(cal, Calendar.DATE), 0);
+
+ last = cal;
+ cal = (Calendar) it.next();
+ count++;
+
+ //Check that this is one day more than the last date
+ last.add(Calendar.DATE, 1);
+ assertEquals("", last, cal, 0);
+ }
+ if (count % 7 != 0) {
+ throw new AssertionFailedError("There were " + count + " days in this iterator");
+ }
+ assertEquals("", end, cal, 0);
+ }
+
+ /**
+ * Used to check that Calendar objects are close enough
+ * delta is in milliseconds
+ */
+ public static void assertEquals(String message, Calendar cal1, Calendar cal2, long delta) {
+ if (Math.abs(cal1.getTime().getTime() - cal2.getTime().getTime()) > delta) {
+ throw new AssertionFailedError(
+ message + " expected " + cal1.getTime() + " but got " + cal2.getTime());
+ }
}
}
+
diff --git a/src/test/org/apache/commons/lang/time/DurationFormatUtilsTest.java b/src/test/org/apache/commons/lang/time/DurationFormatUtilsTest.java
new file mode 100644
index 000000000..75365b80c
--- /dev/null
+++ b/src/test/org/apache/commons/lang/time/DurationFormatUtilsTest.java
@@ -0,0 +1,162 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002-2003 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Commons", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ */
+package org.apache.commons.lang.time;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import junit.textui.TestRunner;
+
+/**
+ * TestCase for DurationFormatUtils.
+ *
+ * @author Apache Ant - DateUtilsTest
+ * @author Stephane Bailliez
+ * @author Stefan Bodewig
+ * @author Stephen Colebourne
+ */
+public class DurationFormatUtilsTest extends TestCase {
+
+ public static void main(String[] args) {
+ TestRunner.run(suite());
+ }
+
+ public static Test suite() {
+ TestSuite suite = new TestSuite(DurationFormatUtilsTest.class);
+ suite.setName("DurationFormatUtils Tests");
+ return suite;
+ }
+
+ public DurationFormatUtilsTest(String s) {
+ super(s);
+ }
+
+ public void testFormatWords(){
+ String text = null;
+
+ text = DurationFormatUtils.formatWords(50*1000, true, false);
+ assertEquals("50 seconds", text);
+ text = DurationFormatUtils.formatWords(65*1000, true, false);
+ assertEquals("1 minute 5 seconds", text);
+ text = DurationFormatUtils.formatWords(120*1000, true, false);
+ assertEquals("2 minutes 0 seconds", text);
+ text = DurationFormatUtils.formatWords(121*1000, true, false);
+ assertEquals("2 minutes 1 second", text);
+ text = DurationFormatUtils.formatWords(72*60*1000, true, false);
+ assertEquals("1 hour 12 minutes 0 seconds", text);
+
+ text = DurationFormatUtils.formatWords(50*1000, true, true);
+ assertEquals("50 seconds", text);
+ text = DurationFormatUtils.formatWords(65*1000, true, true);
+ assertEquals("1 minute 5 seconds", text);
+ text = DurationFormatUtils.formatWords(120*1000, true, true);
+ assertEquals("2 minutes", text);
+ text = DurationFormatUtils.formatWords(121*1000, true, true);
+ assertEquals("2 minutes 1 second", text);
+ text = DurationFormatUtils.formatWords(72*60*1000, true, true);
+ assertEquals("1 hour 12 minutes", text);
+
+ text = DurationFormatUtils.formatWords(50*1000, false, true);
+ assertEquals("0 days 0 hours 0 minutes 50 seconds", text);
+ text = DurationFormatUtils.formatWords(65*1000, false, true);
+ assertEquals("0 days 0 hours 1 minute 5 seconds", text);
+ text = DurationFormatUtils.formatWords(120*1000, false, true);
+ assertEquals("0 days 0 hours 2 minutes", text);
+ text = DurationFormatUtils.formatWords(121*1000, false, true);
+ assertEquals("0 days 0 hours 2 minutes 1 second", text);
+ text = DurationFormatUtils.formatWords(72*60*1000, false, true);
+ assertEquals("0 days 1 hour 12 minutes", text);
+
+ text = DurationFormatUtils.formatWords(50*1000, false, false);
+ assertEquals("0 days 0 hours 0 minutes 50 seconds", text);
+ text = DurationFormatUtils.formatWords(65*1000, false, false);
+ assertEquals("0 days 0 hours 1 minute 5 seconds", text);
+ text = DurationFormatUtils.formatWords(120*1000, false, false);
+ assertEquals("0 days 0 hours 2 minutes 0 seconds", text);
+ text = DurationFormatUtils.formatWords(121*1000, false, false);
+ assertEquals("0 days 0 hours 2 minutes 1 second", text);
+ text = DurationFormatUtils.formatWords(72*60*1000, false, false);
+ assertEquals("0 days 1 hour 12 minutes 0 seconds", text);
+ }
+
+ public void testFormatISOStyle(){
+ long time = 0;
+ assertEquals("0:00:00.000", DurationFormatUtils.formatISO(time));
+
+ time = 1;
+ assertEquals("0:00:00.001", DurationFormatUtils.formatISO(time));
+
+ time = 15;
+ assertEquals("0:00:00.015", DurationFormatUtils.formatISO(time));
+
+ time = 165;
+ assertEquals("0:00:00.165", DurationFormatUtils.formatISO(time));
+
+ time = 1675;
+ assertEquals("0:00:01.675", DurationFormatUtils.formatISO(time));
+
+ time = 13465;
+ assertEquals("0:00:13.465", DurationFormatUtils.formatISO(time));
+
+ time = 72789;
+ assertEquals("0:01:12.789", DurationFormatUtils.formatISO(time));
+
+ time = 12789 + 32 * 60000;
+ assertEquals("0:32:12.789", DurationFormatUtils.formatISO(time));
+
+ time = 12789 + 62 * 60000;
+ assertEquals("1:02:12.789", DurationFormatUtils.formatISO(time));
+ }
+
+}
diff --git a/src/test/org/apache/commons/lang/time/FastDateFormatTest.java b/src/test/org/apache/commons/lang/time/FastDateFormatTest.java
index 749efe43f..2b6511322 100644
--- a/src/test/org/apache/commons/lang/time/FastDateFormatTest.java
+++ b/src/test/org/apache/commons/lang/time/FastDateFormatTest.java
@@ -54,6 +54,8 @@
package org.apache.commons.lang.time;
import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.TimeZone;
@@ -67,7 +69,7 @@ import junit.textui.TestRunner;
*
* @author Sean Schofield
* @since 2.0
- * @version $Id: FastDateFormatTest.java,v 1.3 2003/05/21 23:41:21 scolebourne Exp $
+ * @version $Id: FastDateFormatTest.java,v 1.4 2003/06/08 23:14:23 scolebourne Exp $
*/
public class FastDateFormatTest extends TestCase {
@@ -106,9 +108,15 @@ public class FastDateFormatTest extends TestCase {
public void test_getInstance_String() {
FastDateFormat format1 = FastDateFormat.getInstance("MM/DD/yyyy");
FastDateFormat format2 = FastDateFormat.getInstance("MM-DD-yyyy");
+ FastDateFormat format3 = FastDateFormat.getInstance("MM-DD-yyyy");
+
assertTrue(format1 != format2); // -- junit 3.8 version -- assertFalse(format1 == format2);
- assertSame(format1, FastDateFormat.getInstance("MM/DD/yyyy"));
+ assertSame(format2, format3);
assertEquals("MM/DD/yyyy", format1.getPattern());
+ assertEquals(TimeZone.getDefault(), format1.getTimeZone());
+ assertEquals(TimeZone.getDefault(), format2.getTimeZone());
+ assertEquals(false, format1.getTimeZoneOverridesCalendar());
+ assertEquals(false, format2.getTimeZoneOverridesCalendar());
}
public void test_getInstance_String_TimeZone() {
@@ -124,12 +132,16 @@ public class FastDateFormatTest extends TestCase {
FastDateFormat format3 = FastDateFormat.getInstance("MM/DD/yyyy", TimeZone.getDefault());
FastDateFormat format4 = FastDateFormat.getInstance("MM/DD/yyyy", TimeZone.getDefault());
FastDateFormat format5 = FastDateFormat.getInstance("MM-DD-yyyy", TimeZone.getDefault());
+ FastDateFormat format6 = FastDateFormat.getInstance("MM-DD-yyyy");
assertTrue(format1 != format2); // -- junit 3.8 version -- assertFalse(format1 == format2);
- assertTrue(format1.getTimeZone().equals(TimeZone.getTimeZone("Atlantic/Reykjavik")));
- assertNull(format2.getTimeZone());
+ assertEquals(TimeZone.getTimeZone("Atlantic/Reykjavik"), format1.getTimeZone());
+ assertEquals(true, format1.getTimeZoneOverridesCalendar());
+ assertEquals(TimeZone.getDefault(), format2.getTimeZone());
+ assertEquals(false, format2.getTimeZoneOverridesCalendar());
assertSame(format3, format4);
assertTrue(format3 != format5); // -- junit 3.8 version -- assertFalse(format3 == format5);
+ assertTrue(format4 != format6); // -- junit 3.8 version -- assertFalse(format3 == format5);
} finally {
Locale.setDefault(realDefaultLocale);
@@ -168,10 +180,15 @@ public class FastDateFormatTest extends TestCase {
TimeZone.getDefault(), Locale.GERMANY);
assertTrue(format1 != format2); // -- junit 3.8 version -- assertNotSame(format1, format2);
- assertEquals(format1.getTimeZone(), TimeZone.getTimeZone("Atlantic/Reykjavik"));
- assertNull(format2.getTimeZone());
- assertEquals(format3.getTimeZone(), TimeZone.getDefault());
- assertEquals(format3.getTimeZone(), TimeZone.getTimeZone("America/New_York"));
+ assertEquals(TimeZone.getTimeZone("Atlantic/Reykjavik"), format1.getTimeZone());
+ assertEquals(TimeZone.getDefault(), format2.getTimeZone());
+ assertEquals(TimeZone.getDefault(), format3.getTimeZone());
+ assertEquals(true, format1.getTimeZoneOverridesCalendar());
+ assertEquals(false, format2.getTimeZoneOverridesCalendar());
+ assertEquals(true, format3.getTimeZoneOverridesCalendar());
+ assertEquals(Locale.GERMANY, format1.getLocale());
+ assertEquals(Locale.GERMANY, format2.getLocale());
+ assertEquals(Locale.GERMANY, format3.getLocale());
} finally {
Locale.setDefault(realDefaultLocale);
@@ -179,4 +196,55 @@ public class FastDateFormatTest extends TestCase {
}
}
+ public void testFormat() {
+ Locale realDefaultLocale = Locale.getDefault();
+ TimeZone realDefaultZone = TimeZone.getDefault();
+ try {
+ Locale.setDefault(Locale.US);
+ TimeZone.setDefault(TimeZone.getTimeZone("America/New_York"));
+ FastDateFormat fdf = null;
+ SimpleDateFormat sdf = null;
+
+ GregorianCalendar cal1 = new GregorianCalendar(2003, 0, 10, 15, 33, 20);
+ GregorianCalendar cal2 = new GregorianCalendar(2003, 6, 10, 9, 00, 00);
+ Date date1 = cal1.getTime();
+ Date date2 = cal2.getTime();
+
+ fdf = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss");
+ sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
+ assertEquals(sdf.format(date1), fdf.format(date1));
+ assertEquals("2003-01-10T15:33:20", fdf.format(date1));
+ assertEquals("2003-01-10T15:33:20", fdf.format(cal1));
+ assertEquals("2003-07-10T09:00:00", fdf.format(date2));
+ assertEquals("2003-07-10T09:00:00", fdf.format(cal2));
+
+ fdf = FastDateFormat.getInstance("Z");
+ assertEquals("-0500", fdf.format(date1));
+ assertEquals("-0500", fdf.format(cal1));
+
+ fdf = FastDateFormat.getInstance("Z");
+ assertEquals("-0400", fdf.format(date2));
+ assertEquals("-0400", fdf.format(cal2));
+
+ fdf = FastDateFormat.getInstance("ZZ");
+ assertEquals("-05:00", fdf.format(date1));
+ assertEquals("-05:00", fdf.format(cal1));
+
+ fdf = FastDateFormat.getInstance("ZZ");
+ assertEquals("-04:00", fdf.format(date2));
+ assertEquals("-04:00", fdf.format(cal2));
+
+ String pattern = "GGGG GGG GG G yyyy yyy yy y MMMM MMM MM M" +
+ " dddd ddd dd d DDDD DDD DD D EEEE EEE EE E aaaa aaa aa a zzzz zzz zz z";
+ fdf = FastDateFormat.getInstance(pattern);
+ sdf = new SimpleDateFormat(pattern);
+ assertEquals(sdf.format(date1), fdf.format(date1));
+ assertEquals(sdf.format(date2), fdf.format(date2));
+
+ } finally {
+ Locale.setDefault(realDefaultLocale);
+ TimeZone.setDefault(realDefaultZone);
+ }
+ }
+
}
diff --git a/src/test/org/apache/commons/lang/time/StopWatchTest.java b/src/test/org/apache/commons/lang/time/StopWatchTest.java
index 689825825..eeb055fc5 100644
--- a/src/test/org/apache/commons/lang/time/StopWatchTest.java
+++ b/src/test/org/apache/commons/lang/time/StopWatchTest.java
@@ -62,7 +62,7 @@ import junit.textui.TestRunner;
* TestCase for StopWatch.
*
* @author Stephen Colebourne
- * @version $Id: StopWatchTest.java,v 1.2 2003/05/21 23:40:24 scolebourne Exp $
+ * @version $Id: StopWatchTest.java,v 1.3 2003/06/08 23:14:23 scolebourne Exp $
*/
public class StopWatchTest extends TestCase {
@@ -80,35 +80,6 @@ public class StopWatchTest extends TestCase {
super(s);
}
- public void testToString(){
- long time = 0;
- assertEquals("0:00:00.000", StopWatch.toString(time));
-
- time = 1;
- assertEquals("0:00:00.001", StopWatch.toString(time));
-
- time = 15;
- assertEquals("0:00:00.015", StopWatch.toString(time));
-
- time = 165;
- assertEquals("0:00:00.165", StopWatch.toString(time));
-
- time = 1675;
- assertEquals("0:00:01.675", StopWatch.toString(time));
-
- time = 13465;
- assertEquals("0:00:13.465", StopWatch.toString(time));
-
- time = 72789;
- assertEquals("0:01:12.789", StopWatch.toString(time));
-
- time = 12789 + 32 * 60000;
- assertEquals("0:32:12.789", StopWatch.toString(time));
-
- time = 12789 + 62 * 60000;
- assertEquals("1:02:12.789", StopWatch.toString(time));
- }
-
public void testStopWatchSimple(){
StopWatch watch = new StopWatch();
assertEquals(0, watch.getTime());
diff --git a/src/test/org/apache/commons/lang/time/TimeTestSuite.java b/src/test/org/apache/commons/lang/time/TimeTestSuite.java
index c7e62424d..65c232b93 100644
--- a/src/test/org/apache/commons/lang/time/TimeTestSuite.java
+++ b/src/test/org/apache/commons/lang/time/TimeTestSuite.java
@@ -1,7 +1,7 @@
/* ====================================================================
* The Apache Software License, Version 1.1
*
- * Copyright (c) 2002 The Apache Software Foundation. All rights
+ * Copyright (c) 2002-2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -57,11 +57,12 @@ import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import junit.textui.TestRunner;
+
/**
* Test suite for the Time package.
*
* @author Stephen Colebourne
- * @version $Id: TimeTestSuite.java,v 1.3 2003/01/10 03:55:01 bayard Exp $
+ * @version $Id: TimeTestSuite.java,v 1.4 2003/06/08 23:14:23 scolebourne Exp $
*/
public class TimeTestSuite extends TestCase {
@@ -85,8 +86,9 @@ public class TimeTestSuite extends TestCase {
public static Test suite() {
TestSuite suite = new TestSuite();
suite.setName("Commons-Lang-Time Tests");
- suite.addTest(CalendarUtilsTest.suite());
suite.addTest(DateUtilsTest.suite());
+ suite.addTest(DateFormatUtilsTest.suite());
+ suite.addTest(DurationFormatUtilsTest.suite());
suite.addTest(StopWatchTest.suite());
suite.addTest(FastDateFormatTest.suite());
return suite;