You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by sc...@apache.org on 2004/10/16 01:11:31 UTC

cvs commit: jakarta-commons/lang/src/test/org/apache/commons/lang/time DurationFormatUtilsTest.java

scolebourne    2004/10/15 16:11:31

  Modified:    lang/src/java/org/apache/commons/lang/time
                        DurationFormatUtils.java StopWatch.java
               lang/src/test/org/apache/commons/lang/time
                        DurationFormatUtilsTest.java
  Log:
  Rework DurationFormatUtils to have clearer API based on two types of formatting
  Fix millisecond formatting bug
  
  Revision  Changes    Path
  1.21      +266 -253  jakarta-commons/lang/src/java/org/apache/commons/lang/time/DurationFormatUtils.java
  
  Index: DurationFormatUtils.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/lang/src/java/org/apache/commons/lang/time/DurationFormatUtils.java,v
  retrieving revision 1.20
  retrieving revision 1.21
  diff -u -r1.20 -r1.21
  --- DurationFormatUtils.java	2 Oct 2004 01:40:30 -0000	1.20
  +++ DurationFormatUtils.java	15 Oct 2004 23:11:31 -0000	1.21
  @@ -53,174 +53,182 @@
        * to operate.</p>
        */
       public DurationFormatUtils() {
  +        super();
       }
   
       /**
  -     * <p>Pattern used with <code>FastDateFormat</code> and <code>SimpleDateFormat</code> for the ISO8601 
  -     * date time extended format used in durations.</p>
  +     * <p>Pattern used with <code>FastDateFormat</code> and <code>SimpleDateFormat</code>
  +     * for the ISO8601 period format used in durations.</p>
        * 
        * @see org.apache.commons.lang.time.FastDateFormat
        * @see java.text.SimpleDateFormat
        */
       public static final String ISO_EXTENDED_FORMAT_PATTERN = "'P'yyyy'Y'M'M'd'DT'H'H'm'M's.S'S'";
   
  +    //-----------------------------------------------------------------------
       /**
  -     * <p>ISO8601 formatter for the date time extended format used in durations, 
  -     * with XML Schema durations particularly in mind.</p>
  +     * <p>Get the time gap as a string.</p>
        * 
  -     * <p>This format represents the Gregorian year, month, day, hour, minute, and second components defined 
  -     * in section 5.5.3.2 of ISO 8601, respectively. These components are ordered in their significance by their order 
  -     * of appearance i.e. as year, month, day, hour, minute, and second.</p>
  -     * 
  -     * <p>The ISO8601 extended format P<i>n</i>Y<i>n</i>M<i>n</i>DT<i>n</i>H<i>n</i>M<i>n</i>S, where <i>n</i>Y 
  -     * represents the number of years, <i>n</i>M the number of months, <i>n</i>D the number of days, 
  -     * 'T' is the date/time separator, <i>n</i>H the number of hours, <i>n</i>M the number of minutes and 
  -     * <i>n</i>S the number of seconds. The number of seconds can include decimal digits to arbitrary precision.</p>
  +     * <p>The format used is ISO8601-like:
  +     * <i>H</i>:<i>m</i>:<i>s</i>.<i>S</i>.</p>
        * 
  -     * @see #ISO_EXTENDED_FORMAT_PATTERN
  -     * @see <a href="http://www.w3.org/TR/xmlschema-2/#duration">http://www.w3.org/TR/xmlschema-2/#duration</a>
  +     * @param durationMillis  the duration to format
  +     * @return the time as a String
        */
  -//    public static final FastDateFormat ISO_EXTENDED_FORMAT =
  -//        FastDateFormat.getInstance(ISO_EXTENDED_FORMAT_PATTERN);
  +    public static String formatDurationHMS(long durationMillis) {
  +        return formatDuration(durationMillis, "H:mm:ss.SSS");
  +    }
   
       /**
        * <p>Get the time gap as a string.</p>
        * 
  -     * <p>The format used is ISO8601-like:
  -     * <i>H</i>:<i>m</i>:<i>s</i>.<i>S</i>.</p>
  +     * <p>The format used is the ISO8601 period format.</p>
        * 
  -     * @param millis  the duration to format
  +     * <p>This method formats durations using the days and lower fields of the
  +     * ISO format pattern, such as P7D6H5M4.321S.</p>
  +     * 
  +     * @param durationMillis  the duration to format
        * @return the time as a String
        */
  -    public static String formatISO(long millis) {
  -        return format(millis, "H:mm:ss.SSS");
  -    }
  -
  -    public static String format(long millis) {
  -        return format(millis, ISO_EXTENDED_FORMAT_PATTERN, false, TimeZone.getDefault() );
  -    }
  -    public static String format(long startMillis, long endMillis) {
  -        return format(startMillis, endMillis, ISO_EXTENDED_FORMAT_PATTERN, false, TimeZone.getDefault() );
  +    public static String formatDurationISO(long durationMillis) {
  +        return formatDuration(durationMillis, ISO_EXTENDED_FORMAT_PATTERN, false);
       }
   
  -
       /**
        * <p>Get the time gap as a string, using the specified format, and padding with zeros and 
        * using the default timezone.</p>
        * 
  -     * @param millis  the duration to format
  +     * <p>This method formats durations using the days and lower fields of the
  +     * format pattern. Months and larger are not used.</p>
  +     * 
  +     * @param durationMillis  the duration to format
        * @param format  the way in which to format the duration
        * @return the time as a String
        */
  -    public static String format(long millis, String format) {
  -        return format(millis, format, true, TimeZone.getDefault());
  +    public static String formatDuration(long durationMillis, String format) {
  +        return formatDuration(durationMillis, format, true);
       }
  +
       /**
        * <p>Get the time gap as a string, using the specified format.
        * Padding the left hand side of numbers with zeroes is optional and 
  -     * the timezone may be specified. 
  +     * the timezone may be specified.</p>
        * 
  -     * @param millis  the duration to format
  +     * <p>This method formats durations using the days and lower fields of the
  +     * format pattern. Months and larger are not used.</p>
  +     * 
  +     * @param durationMillis  the duration to format
        * @param format  the way in which to format the duration
  -     * @param padWithZeros whether to pad the left hand side of numbers with 0's
  -     * @param timezone the millis are defined in
  +     * @param padWithZeros  whether to pad the left hand side of numbers with 0's
        * @return the time as a String
        */
  -    public static String format(long millis, String format, boolean padWithZeros, TimeZone timezone) {
  -
  -        if(millis >= 28 * DateUtils.MILLIS_PER_DAY) {
  -            Calendar c = Calendar.getInstance(timezone);
  -            c.set(1970, 0, 1, 0, 0, 0);
  -            c.set(Calendar.MILLISECOND, 0);
  -            return format(c.getTime().getTime(), millis, format, padWithZeros, timezone);
  -        }
  +    public static String formatDuration(long durationMillis, String format, boolean padWithZeros) {
   
           Token[] tokens = lexx(format);
   
  -        int years        = 0;
  -        int months       = 0;
           int days         = 0;
           int hours        = 0;
           int minutes      = 0;
           int seconds      = 0;
           int milliseconds = 0;
  -
  -        /*  This will never be evaluated
  -        if(Token.containsTokenWithValue(tokens, y) ) {
  -            years = (int) (millis / DateUtils.MILLIS_PER_YEAR);
  -            millis = millis - (years * DateUtils.MILLIS_PER_YEAR);
  -        }
  -        if(Token.containsTokenWithValue(tokens, M) ) {
  -            months = (int) (millis / DateUtils.MILLIS_PER_MONTH);
  -            millis = millis - (months * DateUtils.MILLIS_PER_MONTH);
  -            // as MONTH * 12 != YEAR, this fixes issues
  -            if(months == 12) {
  -                years++;
  -                months = 0;
  -            }
  -        }
  -        */
  -        if(Token.containsTokenWithValue(tokens, d) ) {
  -            days = (int) (millis / DateUtils.MILLIS_PER_DAY);
  -            millis = millis - (days * DateUtils.MILLIS_PER_DAY);
  +        
  +        if (Token.containsTokenWithValue(tokens, d) ) {
  +            days = (int) (durationMillis / DateUtils.MILLIS_PER_DAY);
  +            durationMillis = durationMillis - (days * DateUtils.MILLIS_PER_DAY);
           }
  -        if(Token.containsTokenWithValue(tokens, H) ) {
  -            hours = (int) (millis / DateUtils.MILLIS_PER_HOUR);
  -            millis = millis - (hours * DateUtils.MILLIS_PER_HOUR);
  +        if (Token.containsTokenWithValue(tokens, H) ) {
  +            hours = (int) (durationMillis / DateUtils.MILLIS_PER_HOUR);
  +            durationMillis = durationMillis - (hours * DateUtils.MILLIS_PER_HOUR);
           }
  -        if(Token.containsTokenWithValue(tokens, m) ) {
  -            minutes = (int) (millis / DateUtils.MILLIS_PER_MINUTE);
  -            millis = millis - (minutes * DateUtils.MILLIS_PER_MINUTE);
  +        if (Token.containsTokenWithValue(tokens, m) ) {
  +            minutes = (int) (durationMillis / DateUtils.MILLIS_PER_MINUTE);
  +            durationMillis = durationMillis - (minutes * DateUtils.MILLIS_PER_MINUTE);
           }
  -        if(Token.containsTokenWithValue(tokens, s) ) {
  -            seconds = (int) (millis / DateUtils.MILLIS_PER_SECOND);
  -            millis = millis - (seconds * DateUtils.MILLIS_PER_SECOND);
  +        if (Token.containsTokenWithValue(tokens, s) ) {
  +            seconds = (int) (durationMillis / DateUtils.MILLIS_PER_SECOND);
  +            durationMillis = durationMillis - (seconds * DateUtils.MILLIS_PER_SECOND);
           }
  -        if(Token.containsTokenWithValue(tokens, S) ) {
  -            milliseconds = (int) millis;
  +        if (Token.containsTokenWithValue(tokens, S) ) {
  +            milliseconds = (int) durationMillis;
           }
   
  -        return formatDuration(tokens, years, months, days, hours, minutes, seconds, milliseconds, padWithZeros);
  +        return format(tokens, 0, 0, days, hours, minutes, seconds, milliseconds, padWithZeros);
       }
   
  +    /**
  +     * <p>Format an elapsed time into a plurialization correct string.</p>
  +     * 
  +     * <p>This method formats durations using the days and lower fields of the
  +     * format pattern. Months and larger are not used.</p>
  +     * 
  +     * @param durationMillis  the elapsed time to report in milliseconds
  +     * @param suppressLeadingZeroElements  suppresses leading 0 elements
  +     * @param suppressTrailingZeroElements  suppresses trailing 0 elements
  +     * @return the formatted text in days/hours/minutes/seconds
  +     */
  +    public static String formatDurationWords(
  +        long durationMillis,
  +        boolean suppressLeadingZeroElements,
  +        boolean suppressTrailingZeroElements) {
   
  -    static String formatDuration(Token[] tokens, int years, int months, int days, int hours, 
  -                                 int minutes, int seconds, int milliseconds, boolean padWithZeros) 
  -    { 
  -        StringBuffer buffer = new StringBuffer();
  -        int sz = tokens.length;
  -        for(int i=0; i<sz; i++) {
  -            Token token = tokens[i];
  -            Object value = token.getValue();
  -            int count = token.getCount();
  -            if(value instanceof StringBuffer) {
  -                buffer.append(value.toString());
  -            } else {
  -                if(value == y) {
  -                    buffer.append( padWithZeros ? StringUtils.leftPad(""+years, count, "0") : ""+years ); 
  -                } else
  -                if(value == M) {
  -                    buffer.append( padWithZeros ? StringUtils.leftPad(""+months, count, "0") : ""+months ); 
  -                } else
  -                if(value == d) {
  -                    buffer.append( padWithZeros ? StringUtils.leftPad(""+days, count, "0") : ""+days ); 
  -                } else
  -                if(value == H) {
  -                    buffer.append( padWithZeros ? StringUtils.leftPad(""+hours, count, "0") : ""+hours ); 
  -                } else
  -                if(value == m) {
  -                    buffer.append( padWithZeros ? StringUtils.leftPad(""+minutes, count, "0") : ""+minutes ); 
  -                } else
  -                if(value == s) {
  -                    buffer.append( padWithZeros ? StringUtils.leftPad(""+seconds, count, "0") : ""+seconds ); 
  -                } else
  -                if(value == S) {
  -                    buffer.append( padWithZeros ? StringUtils.leftPad(""+milliseconds, count, "0") : ""+milliseconds ); 
  +        // This method is generally replacable by the format method, but 
  +        // there are a series of tweaks and special cases that require 
  +        // trickery to replicate.
  +        String duration = formatDuration(durationMillis, "d' days 'H' hours 'm' minutes 's' seconds'");
  +        if (suppressLeadingZeroElements) {
  +            // this is a temporary marker on the front. Like ^ in regexp.
  +            duration = " " + duration;
  +            String tmp = StringUtils.replaceOnce(duration, " 0 days", "");
  +            if (tmp.length() != duration.length()) {
  +                duration = tmp;
  +                tmp = StringUtils.replaceOnce(duration, " 0 hours", "");
  +                if (tmp.length() != duration.length()) {
  +                    duration = tmp;
  +                    tmp = StringUtils.replaceOnce(duration, " 0 minutes", "");
  +                    duration = tmp;
  +                    if (tmp.length() != duration.length()) {
  +                        duration = StringUtils.replaceOnce(tmp, " 0 seconds", "");
  +                    }
                   }
               }
  +            if (duration.length() != 0) {
  +                // strip the space off again
  +                duration = duration.substring(1);
  +            }
           }
  -        
  -        return buffer.toString();
  +        if (suppressTrailingZeroElements) {
  +            String tmp = StringUtils.replaceOnce(duration, " 0 seconds", "");
  +            if (tmp.length() != duration.length()) {
  +                duration = tmp;
  +                tmp = StringUtils.replaceOnce(duration, " 0 minutes", "");
  +                if (tmp.length() != duration.length()) {
  +                    duration = tmp;
  +                    tmp = StringUtils.replaceOnce(duration, " 0 hours", "");
  +                    if (tmp.length() != duration.length()) {
  +                        duration = StringUtils.replaceOnce(tmp, " 0 days", "");
  +                    }
  +                }
  +            }
  +        }
  +        // handle plurals
  +        duration = StringUtils.replaceOnce(duration, "1 seconds", "1 second");
  +        duration = StringUtils.replaceOnce(duration, "1 minutes", "1 minute");
  +        duration = StringUtils.replaceOnce(duration, "1 hours", "1 hour");
  +        duration = StringUtils.replaceOnce(duration, "1 days", "1 day");
  +        return duration;
  +    }
  +
  +    //-----------------------------------------------------------------------
  +    /**
  +     * <p>Get the time gap as a string.</p>
  +     * 
  +     * <p>The format used is the ISO8601 period format.</p>
  +     * 
  +     * @param millis  the duration to format
  +     * @return the time as a String
  +     */
  +    public static String formatPeriodISO(long startMillis, long endMillis) {
  +        return formatPeriod(startMillis, endMillis, ISO_EXTENDED_FORMAT_PATTERN, false, TimeZone.getDefault() );
       }
   
       /**
  @@ -232,9 +240,10 @@
        * @param format  the way in which to format the duration
        * @return the time as a String
        */
  -    public static String format(long startMillis, long endMillis, String format) {
  -        return format(startMillis, endMillis, format, true, TimeZone.getDefault());
  +    public static String formatPeriod(long startMillis, long endMillis, String format) {
  +        return formatPeriod(startMillis, endMillis, format, true, TimeZone.getDefault());
       }
  +
       /**
        * <p>Get the time gap as a string, using the specified format.
        * Padding the left hand side of numbers with zeroes is optional and 
  @@ -247,11 +256,11 @@
        * @param timezone the millis are defined in
        * @return the time as a String
        */
  -    public static String format(long startMillis, long endMillis, String format, boolean padWithZeros, TimeZone timezone) {
  +    public static String formatPeriod(long startMillis, long endMillis, String format, boolean padWithZeros, TimeZone timezone) {
   
           long millis = endMillis - startMillis;
  -        if(millis < 28 * DateUtils.MILLIS_PER_DAY) {
  -            return format(millis, format, padWithZeros, timezone);
  +        if (millis < 28 * DateUtils.MILLIS_PER_DAY) {
  +            return formatDuration(millis, format, padWithZeros);
           }
   
           Token[] tokens = lexx(format);
  @@ -267,50 +276,50 @@
           int years = end.get(Calendar.YEAR) - start.get(Calendar.YEAR);
           int months = end.get(Calendar.MONTH) - start.get(Calendar.MONTH);
           // each initial estimate is adjusted in case it is under 0
  -        while(months < 0) {
  +        while (months < 0) {
               months += 12;
               years -= 1;
           }
           int days = end.get(Calendar.DAY_OF_MONTH) - start.get(Calendar.DAY_OF_MONTH);
  -        while(days < 0) {
  -            days += 31;  // such overshooting is taken care of later on
  +        while (days < 0) {
  +            days += 31; // such overshooting is taken care of later on
               months -= 1;
           }
           int hours = end.get(Calendar.HOUR_OF_DAY) - start.get(Calendar.HOUR_OF_DAY);
  -        while(hours < 0) {
  +        while (hours < 0) {
               hours += 24;
               days -= 1;
           }
           int minutes = end.get(Calendar.MINUTE) - start.get(Calendar.MINUTE);
  -        while(minutes < 0) {
  +        while (minutes < 0) {
               minutes += 60;
               hours -= 1;
           }
           int seconds = end.get(Calendar.SECOND) - start.get(Calendar.SECOND);
  -        while(seconds < 0) {
  +        while (seconds < 0) {
               seconds += 60;
               minutes -= 1;
           }
           int milliseconds = end.get(Calendar.MILLISECOND) - start.get(Calendar.MILLISECOND);
  -        while(milliseconds < 0) {
  +        while (milliseconds < 0) {
               milliseconds += 1000;
               seconds -= 1;
           }
   
           // take estimates off of end to see if we can equal start, when it overshoots recalculate
  -        milliseconds -= reduceAndCorrect( start, end, Calendar.MILLISECOND, milliseconds );
  -        seconds -= reduceAndCorrect( start, end, Calendar.SECOND, seconds );
  -        minutes -= reduceAndCorrect( start, end, Calendar.MINUTE, minutes );
  -        hours -= reduceAndCorrect( start, end, Calendar.HOUR_OF_DAY, hours );
  -        days -= reduceAndCorrect( start, end, Calendar.DAY_OF_MONTH, days );
  -        months -= reduceAndCorrect( start, end, Calendar.MONTH, months );
  -        years -= reduceAndCorrect( start, end, Calendar.YEAR, years );
  +        milliseconds -= reduceAndCorrect(start, end, Calendar.MILLISECOND, milliseconds);
  +        seconds -= reduceAndCorrect(start, end, Calendar.SECOND, seconds);
  +        minutes -= reduceAndCorrect(start, end, Calendar.MINUTE, minutes);
  +        hours -= reduceAndCorrect(start, end, Calendar.HOUR_OF_DAY, hours);
  +        days -= reduceAndCorrect(start, end, Calendar.DAY_OF_MONTH, days);
  +        months -= reduceAndCorrect(start, end, Calendar.MONTH, months);
  +        years -= reduceAndCorrect(start, end, Calendar.YEAR, years);
   
           // This next block of code adds in values that 
           // aren't requested. This allows the user to ask for the 
           // number of months and get the real count and not just 0->11.
  -        if(!Token.containsTokenWithValue(tokens, y) ) {
  -            if(Token.containsTokenWithValue(tokens, M) ) {
  +        if (!Token.containsTokenWithValue(tokens, y)) {
  +            if (Token.containsTokenWithValue(tokens, M)) {
                   months += 12 * years;
                   years = 0;
               } else {
  @@ -319,37 +328,101 @@
                   years = 0;
               }
           }
  -        if(!Token.containsTokenWithValue(tokens, M) ) {
  +        if (!Token.containsTokenWithValue(tokens, M)) {
               days += end.get(Calendar.DAY_OF_YEAR) - start.get(Calendar.DAY_OF_YEAR);
               months = 0;
           }
  -        if(!Token.containsTokenWithValue(tokens, d) ) {
  +        if (!Token.containsTokenWithValue(tokens, d)) {
               hours += 24 * days;
               days = 0;
           }
  -        if(!Token.containsTokenWithValue(tokens, H) ) {
  +        if (!Token.containsTokenWithValue(tokens, H)) {
               minutes += 60 * hours;
               hours = 0;
           }
  -        if(!Token.containsTokenWithValue(tokens, m) ) {
  +        if (!Token.containsTokenWithValue(tokens, m)) {
               seconds += 60 * minutes;
               minutes = 0;
           }
  -        if(!Token.containsTokenWithValue(tokens, s) ) {
  +        if (!Token.containsTokenWithValue(tokens, s)) {
               milliseconds += 1000 * seconds;
               seconds = 0;
           }
   
  -        return formatDuration(tokens, years, months, days, hours, minutes, seconds, milliseconds, padWithZeros);
  +        return format(tokens, years, months, days, hours, minutes, seconds, milliseconds, padWithZeros);
       }
   
  -    // Reduces by difference, then if it overshot, calculates the overshot amount and 
  -    // fixes and returns the amount to change by
  +    //-----------------------------------------------------------------------
  +    /**
  +     * <p>The internal method to do the formatting.</p>
  +     * 
  +     * @param tokens  the tokens
  +     * @param years  the number of years
  +     * @param months  the number of months
  +     * @param days  the number of days
  +     * @param hours  the number of hours
  +     * @param minutes  the number of minutes
  +     * @param seconds  the number of seconds
  +     * @param milliseconds  the number of millis
  +     * @param padWithZeros  whether to pad
  +     * @return the formetted string
  +     */
  +    static String format(Token[] tokens, int years, int months, int days, int hours, 
  +                                 int minutes, int seconds, int milliseconds, boolean padWithZeros) 
  +    { 
  +        StringBuffer buffer = new StringBuffer();
  +        boolean lastOutputSeconds = false;
  +        int sz = tokens.length;
  +        for (int i = 0; i < sz; i++) {
  +            Token token = tokens[i];
  +            Object value = token.getValue();
  +            int count = token.getCount();
  +            if(value instanceof StringBuffer) {
  +                buffer.append(value.toString());
  +            } else {
  +                if (value == y) {
  +                    buffer.append(padWithZeros ? StringUtils.leftPad(Integer.toString(years), count, '0') : Integer.toString(years));
  +                    lastOutputSeconds = false;
  +                } else if (value == M) {
  +                    buffer.append(padWithZeros ? StringUtils.leftPad(Integer.toString(months), count, '0') : Integer.toString(months));
  +                    lastOutputSeconds = false;
  +                } else if (value == d) {
  +                    buffer.append(padWithZeros ? StringUtils.leftPad(Integer.toString(days), count, '0') : Integer.toString(days));
  +                    lastOutputSeconds = false;
  +                } else if (value == H) {
  +                    buffer.append(padWithZeros ? StringUtils.leftPad(Integer.toString(hours), count, '0') : Integer.toString(hours));
  +                    lastOutputSeconds = false;
  +                } else if (value == m) {
  +                    buffer.append(padWithZeros ? StringUtils.leftPad(Integer.toString(minutes), count, '0') : Integer.toString(minutes));
  +                    lastOutputSeconds = false;
  +                } else if (value == s) {
  +                    buffer.append(padWithZeros ? StringUtils.leftPad(Integer.toString(seconds), count, '0') : Integer.toString(seconds));
  +                    lastOutputSeconds = true;
  +                } else if (value == S) {
  +                    if (lastOutputSeconds) {
  +                        milliseconds += 1000;
  +                        String str = padWithZeros ? StringUtils.leftPad(Integer.toString(milliseconds), count, '0') : Integer.toString(milliseconds);
  +                        buffer.append(str.substring(1));
  +                    } else {
  +                        buffer.append(padWithZeros ? StringUtils.leftPad(Integer.toString(milliseconds), count, '0') : Integer.toString(milliseconds));
  +                    }
  +                    lastOutputSeconds = false;
  +                }
  +            }
  +        }
  +        
  +        return buffer.toString();
  +    }
  +
  +    /**
  +     * Reduces by difference, then if it overshot, calculates the overshot amount and 
  +     * fixes and returns the amount to change by.
  +     */
       static int reduceAndCorrect(Calendar start, Calendar end, int field, int difference) {
           end.add( field, -1 * difference );
           int endValue = end.get(field);
           int startValue = start.get(field);
  -        if(endValue < startValue) {
  +        if (endValue < startValue) {
               int newdiff = startValue - endValue;
               end.add( field, newdiff );
               return newdiff;
  @@ -358,66 +431,6 @@
           }
       }
   
  -    /**
  -     * <p>Format an elapsed time into a plurialization correct string.</p>
  -     * 
  -     * @param millis  the elapsed time to report in milliseconds
  -     * @param suppressLeadingZeroElements suppresses leading 0 elements
  -     * @param suppressTrailingZeroElements suppresses trailing 0 elements
  -     * @return the formatted text in days/hours/minutes/seconds
  -     */
  -    public static String formatWords(
  -        long millis,
  -        boolean suppressLeadingZeroElements,
  -        boolean suppressTrailingZeroElements) {
  -
  -        // This method is generally replacable by the format method, but 
  -        // there are a series of tweaks and special cases that require 
  -        // trickery to replicate.
  -        String duration = format(millis, "d' days 'H' hours 'm' minutes 's' seconds'");
  -        if(suppressLeadingZeroElements) {
  -            // this is a temporary marker on the front. Like ^ in regexp.
  -            duration = " " + duration;
  -            String tmp = StringUtils.replaceOnce(duration, " 0 days", "");
  -            if(tmp.length() != duration.length()) {
  -                duration = tmp;
  -                tmp = StringUtils.replaceOnce(duration, " 0 hours", "");
  -                if(tmp.length() != duration.length()) {
  -                    duration = tmp;
  -                    tmp = StringUtils.replaceOnce(duration, " 0 minutes", "");
  -                    duration = tmp;
  -                    if(tmp.length() != duration.length()) {
  -                        duration = StringUtils.replaceOnce(tmp, " 0 seconds", "");
  -                    }
  -                }
  -            }
  -            if(duration.length() != 0) {
  -                // strip the space off again
  -                duration = duration.substring(1);
  -            }
  -        }
  -        if(suppressTrailingZeroElements) {
  -            String tmp = StringUtils.replaceOnce(duration, " 0 seconds", "");
  -            if(tmp.length() != duration.length()) {
  -                duration = tmp;
  -                tmp = StringUtils.replaceOnce(duration, " 0 minutes", "");
  -                if(tmp.length() != duration.length()) {
  -                    duration = tmp;
  -                    tmp = StringUtils.replaceOnce(duration, " 0 hours", "");
  -                    if(tmp.length() != duration.length()) {
  -                        duration = StringUtils.replaceOnce(tmp, " 0 days", "");
  -                    }
  -                }
  -            }
  -        }
  -        // handle plurals
  -        duration = StringUtils.replaceOnce(duration, "1 seconds", "1 second");
  -        duration = StringUtils.replaceOnce(duration, "1 minutes", "1 minute");
  -        duration = StringUtils.replaceOnce(duration, "1 hours", "1 hour");
  -        duration = StringUtils.replaceOnce(duration, "1 days", "1 day");
  -        return duration;
  -    }
  -
       static final Object y = "y";
       static final Object M = "M";
       static final Object d = "d";
  @@ -482,71 +495,71 @@
           return (Token[]) list.toArray( new Token[0] );
       }
   
  -}
  -
  -// Represents an element of the format-mini-language.
  -class Token {
  +    /**
  +     * Element that is parsed from the format pattern.
  +     */
  +    static class Token {
   
  -    // will only work for the tokens, not for stringbuffers/numbers
  -    static boolean containsTokenWithValue(Token[] tokens, Object value) {
  -        int sz = tokens.length;
  -        for(int i=0; i<sz; i++) {
  -            if(tokens[i].getValue() == value) {
  -                return true;
  +        // will only work for the tokens, not for stringbuffers/numbers
  +        static boolean containsTokenWithValue(Token[] tokens, Object value) {
  +            int sz = tokens.length;
  +            for (int i = 0; i < sz; i++) {
  +                if (tokens[i].getValue() == value) {
  +                    return true;
  +                }
               }
  +            return false;
           }
  -        return false;
  -    }
   
  -    private Object value;
  -    private int count;
  +        private Object value;
  +        private int count;
   
  -    public Token(Object value) {
  -        this.value = value;
  -        this.count = 1;
  -    }
  +        Token(Object value) {
  +            this.value = value;
  +            this.count = 1;
  +        }
   
  -    Token(Object value, int count) {
  -        this.value = value;
  -        this.count = count;
  -    }
  +        Token(Object value, int count) {
  +            this.value = value;
  +            this.count = count;
  +        }
   
  -    public void increment() { 
  -        count++;
  -    }
  +        void increment() { 
  +            count++;
  +        }
   
  -    public int getCount() {
  -        return count;
  -    }
  +        int getCount() {
  +            return count;
  +        }
   
  -    public Object getValue() {
  -        return value;
  -    }
  +        Object getValue() {
  +            return value;
  +        }
   
  -    public boolean equals(Object obj2) {
  -        if(obj2 instanceof Token) {
  -            Token tok2 = (Token) obj2;
  -            if(this.value.getClass() != tok2.value.getClass()) {
  -                return false;
  -            }
  -            if(this.count != tok2.count) {
  -                return false;
  -            }
  -            if(this.value instanceof StringBuffer) {
  -                return this.value.toString().equals(tok2.value.toString());
  -            } else
  -            if(this.value instanceof Number) {
  -                return this.value.equals(tok2.value);
  +        public boolean equals(Object obj2) {
  +            if (obj2 instanceof Token) {
  +                Token tok2 = (Token) obj2;
  +                if (this.value.getClass() != tok2.value.getClass()) {
  +                    return false;
  +                }
  +                if (this.count != tok2.count) {
  +                    return false;
  +                }
  +                if (this.value instanceof StringBuffer) {
  +                    return this.value.toString().equals(tok2.value.toString());
  +                } else if (this.value instanceof Number) {
  +                    return this.value.equals(tok2.value);
  +                } else {
  +                    return this.value == tok2.value;
  +                }
               } else {
  -                return this.value == tok2.value;
  +                return false;
               }
  -        } else {
  -            return false;
           }
  -    }
   
  -    public String toString() {
  -        return StringUtils.repeat(this.value.toString(), this.count);
  +        public String toString() {
  +            return StringUtils.repeat(this.value.toString(), this.count);
  +        }
       }
   
   }
  
  
  
  1.11      +3 -3      jakarta-commons/lang/src/java/org/apache/commons/lang/time/StopWatch.java
  
  Index: StopWatch.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/lang/src/java/org/apache/commons/lang/time/StopWatch.java,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- StopWatch.java	8 Oct 2004 00:09:01 -0000	1.10
  +++ StopWatch.java	15 Oct 2004 23:11:31 -0000	1.11
  @@ -244,7 +244,7 @@
        * @return the time as a String
        */
       public String toString() {
  -        return DurationFormatUtils.formatISO(getTime());
  +        return DurationFormatUtils.formatDurationHMS(getTime());
       }
   
       /**
  @@ -257,7 +257,7 @@
        * @since 2.1
        */
       public String toSplitString() {
  -        return DurationFormatUtils.formatISO(getSplitTime());
  +        return DurationFormatUtils.formatDurationHMS(getSplitTime());
       }
   
   }
  
  
  
  1.14      +160 -108  jakarta-commons/lang/src/test/org/apache/commons/lang/time/DurationFormatUtilsTest.java
  
  Index: DurationFormatUtilsTest.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/lang/src/test/org/apache/commons/lang/time/DurationFormatUtilsTest.java,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- DurationFormatUtilsTest.java	27 Sep 2004 04:46:47 -0000	1.13
  +++ DurationFormatUtilsTest.java	15 Oct 2004 23:11:31 -0000	1.14
  @@ -62,93 +62,142 @@
       }
       
       //-----------------------------------------------------------------------
  -    public void testFormatWords(){
  +    public void testFormatDurationWords(){
           String text = null;
           
  -        text = DurationFormatUtils.formatWords(50*1000, true, false);
  +        text = DurationFormatUtils.formatDurationWords(50*1000, true, false);
           assertEquals("50 seconds", text);
  -        text = DurationFormatUtils.formatWords(65*1000, true, false);
  +        text = DurationFormatUtils.formatDurationWords(65*1000, true, false);
           assertEquals("1 minute 5 seconds", text);
  -        text = DurationFormatUtils.formatWords(120*1000, true, false);
  +        text = DurationFormatUtils.formatDurationWords(120*1000, true, false);
           assertEquals("2 minutes 0 seconds", text);
  -        text = DurationFormatUtils.formatWords(121*1000, true, false);
  +        text = DurationFormatUtils.formatDurationWords(121*1000, true, false);
           assertEquals("2 minutes 1 second", text);
  -        text = DurationFormatUtils.formatWords(72*60*1000, true, false);
  +        text = DurationFormatUtils.formatDurationWords(72*60*1000, true, false);
           assertEquals("1 hour 12 minutes 0 seconds", text);
  -        text = DurationFormatUtils.formatWords(24*60*60*1000, true, false);
  +        text = DurationFormatUtils.formatDurationWords(24*60*60*1000, true, false);
           assertEquals("1 day 0 hours 0 minutes 0 seconds", text);
           
  -        text = DurationFormatUtils.formatWords(50*1000, true, true);
  +        text = DurationFormatUtils.formatDurationWords(50*1000, true, true);
           assertEquals("50 seconds", text);
  -        text = DurationFormatUtils.formatWords(65*1000, true, true);
  +        text = DurationFormatUtils.formatDurationWords(65*1000, true, true);
           assertEquals("1 minute 5 seconds", text);
  -        text = DurationFormatUtils.formatWords(120*1000, true, true);
  +        text = DurationFormatUtils.formatDurationWords(120*1000, true, true);
           assertEquals("2 minutes", text);
  -        text = DurationFormatUtils.formatWords(121*1000, true, true);
  +        text = DurationFormatUtils.formatDurationWords(121*1000, true, true);
           assertEquals("2 minutes 1 second", text);
  -        text = DurationFormatUtils.formatWords(72*60*1000, true, true);
  +        text = DurationFormatUtils.formatDurationWords(72*60*1000, true, true);
           assertEquals("1 hour 12 minutes", text);
  -        text = DurationFormatUtils.formatWords(24*60*60*1000, true, true);
  +        text = DurationFormatUtils.formatDurationWords(24*60*60*1000, true, true);
           assertEquals("1 day", text);
           
  -        text = DurationFormatUtils.formatWords(50*1000, false, true);
  +        text = DurationFormatUtils.formatDurationWords(50*1000, false, true);
           assertEquals("0 days 0 hours 0 minutes 50 seconds", text);
  -        text = DurationFormatUtils.formatWords(65*1000, false, true);
  +        text = DurationFormatUtils.formatDurationWords(65*1000, false, true);
           assertEquals("0 days 0 hours 1 minute 5 seconds", text);
  -        text = DurationFormatUtils.formatWords(120*1000, false, true);
  +        text = DurationFormatUtils.formatDurationWords(120*1000, false, true);
           assertEquals("0 days 0 hours 2 minutes", text);
  -        text = DurationFormatUtils.formatWords(121*1000, false, true);
  +        text = DurationFormatUtils.formatDurationWords(121*1000, false, true);
           assertEquals("0 days 0 hours 2 minutes 1 second", text);
  -        text = DurationFormatUtils.formatWords(72*60*1000, false, true);
  +        text = DurationFormatUtils.formatDurationWords(72*60*1000, false, true);
           assertEquals("0 days 1 hour 12 minutes", text);
  -        text = DurationFormatUtils.formatWords(24*60*60*1000, false, true);
  +        text = DurationFormatUtils.formatDurationWords(24*60*60*1000, false, true);
           assertEquals("1 day", text);
           
  -        text = DurationFormatUtils.formatWords(50*1000, false, false);
  +        text = DurationFormatUtils.formatDurationWords(50*1000, false, false);
           assertEquals("0 days 0 hours 0 minutes 50 seconds", text);
  -        text = DurationFormatUtils.formatWords(65*1000, false, false);
  +        text = DurationFormatUtils.formatDurationWords(65*1000, false, false);
           assertEquals("0 days 0 hours 1 minute 5 seconds", text);
  -        text = DurationFormatUtils.formatWords(120*1000, false, false);
  +        text = DurationFormatUtils.formatDurationWords(120*1000, false, false);
           assertEquals("0 days 0 hours 2 minutes 0 seconds", text);
  -        text = DurationFormatUtils.formatWords(121*1000, false, false);
  +        text = DurationFormatUtils.formatDurationWords(121*1000, false, false);
           assertEquals("0 days 0 hours 2 minutes 1 second", text);
  -        text = DurationFormatUtils.formatWords(72*60*1000, false, false);
  +        text = DurationFormatUtils.formatDurationWords(72*60*1000, false, false);
           assertEquals("0 days 1 hour 12 minutes 0 seconds", text);
  -        text = DurationFormatUtils.formatWords(48*60*60*1000 + 72*60*1000 , false, false);
  +        text = DurationFormatUtils.formatDurationWords(48*60*60*1000 + 72*60*1000 , false, false);
           assertEquals("2 days 1 hour 12 minutes 0 seconds", text);
       }
   
  -    public void testFormatISOStyle(){
  +    public void testFormatDurationHMS(){
           long time = 0;
  -        assertEquals("0:00:00.000", DurationFormatUtils.formatISO(time));
  +        assertEquals("0:00:00.000", DurationFormatUtils.formatDurationHMS(time));
           
           time = 1;
  -        assertEquals("0:00:00.001", DurationFormatUtils.formatISO(time));
  +        assertEquals("0:00:00.001", DurationFormatUtils.formatDurationHMS(time));
           
           time = 15;
  -        assertEquals("0:00:00.015", DurationFormatUtils.formatISO(time));
  +        assertEquals("0:00:00.015", DurationFormatUtils.formatDurationHMS(time));
           
           time = 165;
  -        assertEquals("0:00:00.165", DurationFormatUtils.formatISO(time));
  +        assertEquals("0:00:00.165", DurationFormatUtils.formatDurationHMS(time));
           
           time = 1675;
  -        assertEquals("0:00:01.675", DurationFormatUtils.formatISO(time));
  +        assertEquals("0:00:01.675", DurationFormatUtils.formatDurationHMS(time));
           
           time = 13465;
  -        assertEquals("0:00:13.465", DurationFormatUtils.formatISO(time));
  +        assertEquals("0:00:13.465", DurationFormatUtils.formatDurationHMS(time));
           
           time = 72789;
  -        assertEquals("0:01:12.789", DurationFormatUtils.formatISO(time));
  +        assertEquals("0:01:12.789", DurationFormatUtils.formatDurationHMS(time));
           
           time = 12789 + 32 * 60000;
  -        assertEquals("0:32:12.789", DurationFormatUtils.formatISO(time));
  +        assertEquals("0:32:12.789", DurationFormatUtils.formatDurationHMS(time));
           
           time = 12789 + 62 * 60000;
  -        assertEquals("1:02:12.789", DurationFormatUtils.formatISO(time));
  +        assertEquals("1:02:12.789", DurationFormatUtils.formatDurationHMS(time));
       }
   
  -    public void testISODurationFormat(){
  +    public void testFormatDurationISO() {
  +        assertEquals("P0Y0M0DT0H0M0.000S", DurationFormatUtils.formatDurationISO(0L));
  +        assertEquals("P0Y0M0DT0H0M0.001S", DurationFormatUtils.formatDurationISO(1L));
  +        assertEquals("P0Y0M0DT0H0M0.010S", DurationFormatUtils.formatDurationISO(10L));
  +        assertEquals("P0Y0M0DT0H0M0.100S", DurationFormatUtils.formatDurationISO(100L));
  +        assertEquals("P0Y0M0DT0H1M15.321S", DurationFormatUtils.formatDurationISO(75321L));
  +    }
  +
  +    public void testFormatDuration() {
  +        long duration = 0;
  +        assertEquals( "0", DurationFormatUtils.formatDuration(duration, "y") );
  +        assertEquals( "0", DurationFormatUtils.formatDuration(duration, "M") );
  +        assertEquals( "0", DurationFormatUtils.formatDuration(duration, "d") );
  +        assertEquals( "0", DurationFormatUtils.formatDuration(duration, "H") );
  +        assertEquals( "0", DurationFormatUtils.formatDuration(duration, "m") );
  +        assertEquals( "0", DurationFormatUtils.formatDuration(duration, "s") );
  +        assertEquals( "0", DurationFormatUtils.formatDuration(duration, "S") );
  +        assertEquals( "0000", DurationFormatUtils.formatDuration(duration, "SSSS") );
  +        assertEquals( "0000", DurationFormatUtils.formatDuration(duration, "yyyy") );
  +        assertEquals( "0000", DurationFormatUtils.formatDuration(duration, "yyMM") );
  +
  +        duration = 60 * 1000;
  +        assertEquals( "0", DurationFormatUtils.formatDuration(duration, "y") );
  +        assertEquals( "0", DurationFormatUtils.formatDuration(duration, "M") );
  +        assertEquals( "0", DurationFormatUtils.formatDuration(duration, "d") );
  +        assertEquals( "0", DurationFormatUtils.formatDuration(duration, "H") );
  +        assertEquals( "1", DurationFormatUtils.formatDuration(duration, "m") );
  +        assertEquals( "60", DurationFormatUtils.formatDuration(duration, "s") );
  +        assertEquals( "60000", DurationFormatUtils.formatDuration(duration, "S") );
  +        assertEquals( "01:00", DurationFormatUtils.formatDuration(duration, "mm:ss") );
  +
  +        Calendar base = Calendar.getInstance();
  +        base.set(2000, 0, 1, 0, 0, 0);
  +        base.set(Calendar.MILLISECOND, 0);
  +        
  +        Calendar cal = Calendar.getInstance();
  +        cal.set(2003, 1, 1, 0, 0, 0);
  +        cal.set(Calendar.MILLISECOND, 0);
  +        duration = cal.getTime().getTime() - base.getTime().getTime(); // duration from 2000-01-01 to cal
  +        // don't use 1970 in test as time zones were less reliable in 1970 than now
  +        // remember that duration formatting ignores time zones, working on strict hour lengths
  +        int days = 366 + 365 + 365 + 31;
  +        assertEquals( "0 0 " + days, DurationFormatUtils.formatDuration(duration, "y M d") );
  +    }
  +
  +    public void testFormatPeriodISO(){
           TimeZone timeZone = TimeZone.getTimeZone("GMT-3");
  +        Calendar base = Calendar.getInstance(timeZone);
  +        base.set(1970, 0, 1, 0, 0, 0);
  +        base.set(Calendar.MILLISECOND, 0);
  +        
           Calendar cal = Calendar.getInstance(timeZone);
           cal.set(2002, 1, 23, 9, 11, 12);
           cal.set(Calendar.MILLISECOND, 1);
  @@ -157,121 +206,124 @@
           text = DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.format(cal);
           assertEquals("2002-02-23T09:11:12-03:00", text);
           // test fixture is the same as above, but now with extended format.
  -        text = DurationFormatUtils.format(cal.getTime().getTime(), DurationFormatUtils.ISO_EXTENDED_FORMAT_PATTERN, false, timeZone);
  -        assertEquals("P32Y1M22DT9H11M12.1S", text);
  +        text = DurationFormatUtils.formatPeriod(base.getTime().getTime(), cal.getTime().getTime(), DurationFormatUtils.ISO_EXTENDED_FORMAT_PATTERN, false, timeZone);
  +        assertEquals("P32Y1M22DT9H11M12.001S", text);
           // test fixture from example in http://www.w3.org/TR/xmlschema-2/#duration
           cal.set(1971, 1, 3, 10, 30, 0);
           cal.set(Calendar.MILLISECOND, 0);
  -        text = DurationFormatUtils.format(cal.getTime().getTime(), DurationFormatUtils.ISO_EXTENDED_FORMAT_PATTERN, false, timeZone);
  -        assertEquals("P1Y1M2DT10H30M0.0S", text);
  +        text = DurationFormatUtils.formatPeriod(base.getTime().getTime(), cal.getTime().getTime(), DurationFormatUtils.ISO_EXTENDED_FORMAT_PATTERN, false, timeZone);
  +        assertEquals("P1Y1M2DT10H30M0.000S", text);
           // want a way to say 'don't print the seconds in format()' or other fields for that matter:
           //assertEquals("P1Y2M3DT10H30M", text);
       }
   
  -    public void testFormat() {
  -        long time = 0;
  -        assertEquals( "0", DurationFormatUtils.format(time, "y") );
  -        assertEquals( "0", DurationFormatUtils.format(time, "M") );
  -        assertEquals( "0", DurationFormatUtils.format(time, "d") );
  -        assertEquals( "0", DurationFormatUtils.format(time, "H") );
  -        assertEquals( "0", DurationFormatUtils.format(time, "m") );
  -        assertEquals( "0", DurationFormatUtils.format(time, "s") );
  -        assertEquals( "0", DurationFormatUtils.format(time, "S") );
  -        assertEquals( "0000", DurationFormatUtils.format(time, "SSSS") );
  -        assertEquals( "0000", DurationFormatUtils.format(time, "yyyy") );
  -        assertEquals( "0000", DurationFormatUtils.format(time, "yyMM") );
  -
  -        time = 60 * 1000;
  -        assertEquals( "0", DurationFormatUtils.format(time, "y") );
  -        assertEquals( "0", DurationFormatUtils.format(time, "M") );
  -        assertEquals( "0", DurationFormatUtils.format(time, "d") );
  -        assertEquals( "0", DurationFormatUtils.format(time, "H") );
  -        assertEquals( "1", DurationFormatUtils.format(time, "m") );
  -        assertEquals( "60", DurationFormatUtils.format(time, "s") );
  -        assertEquals( "60000", DurationFormatUtils.format(time, "S") );
  -        assertEquals( "01:00", DurationFormatUtils.format(time, "mm:ss") );
  +    public void testFormatPeriod() {
  +        Calendar cal1970 = Calendar.getInstance();
  +        cal1970.set(1970, 0, 1, 0, 0, 0);
  +        cal1970.set(Calendar.MILLISECOND, 0);
  +        long time1970 = cal1970.getTime().getTime();
  +        
  +        assertEquals( "0", DurationFormatUtils.formatPeriod(time1970, time1970, "y") );
  +        assertEquals( "0", DurationFormatUtils.formatPeriod(time1970, time1970, "M") );
  +        assertEquals( "0", DurationFormatUtils.formatPeriod(time1970, time1970, "d") );
  +        assertEquals( "0", DurationFormatUtils.formatPeriod(time1970, time1970, "H") );
  +        assertEquals( "0", DurationFormatUtils.formatPeriod(time1970, time1970, "m") );
  +        assertEquals( "0", DurationFormatUtils.formatPeriod(time1970, time1970, "s") );
  +        assertEquals( "0", DurationFormatUtils.formatPeriod(time1970, time1970, "S") );
  +        assertEquals( "0000", DurationFormatUtils.formatPeriod(time1970, time1970, "SSSS") );
  +        assertEquals( "0000", DurationFormatUtils.formatPeriod(time1970, time1970, "yyyy") );
  +        assertEquals( "0000", DurationFormatUtils.formatPeriod(time1970, time1970, "yyMM") );
  +
  +        long time = time1970 + 60 * 1000;
  +        assertEquals( "0", DurationFormatUtils.formatPeriod(time1970, time, "y") );
  +        assertEquals( "0", DurationFormatUtils.formatPeriod(time1970, time, "M") );
  +        assertEquals( "0", DurationFormatUtils.formatPeriod(time1970, time, "d") );
  +        assertEquals( "0", DurationFormatUtils.formatPeriod(time1970, time, "H") );
  +        assertEquals( "1", DurationFormatUtils.formatPeriod(time1970, time, "m") );
  +        assertEquals( "60", DurationFormatUtils.formatPeriod(time1970, time, "s") );
  +        assertEquals( "60000", DurationFormatUtils.formatPeriod(time1970, time, "S") );
  +        assertEquals( "01:00", DurationFormatUtils.formatPeriod(time1970, time, "mm:ss") );
   
           Calendar cal = Calendar.getInstance();
           cal.set(1973, 6, 1, 0, 0, 0);
           cal.set(Calendar.MILLISECOND, 0);
           time = cal.getTime().getTime();
  -        assertEquals( "36", DurationFormatUtils.format(time, "yM") );
  -        assertEquals( "3 years 6 months", DurationFormatUtils.format(time, "y' years 'M' months'") );
  -        assertEquals( "03/06", DurationFormatUtils.format(time, "yy/MM") );
  +        assertEquals( "36", DurationFormatUtils.formatPeriod(time1970, time, "yM") );
  +        assertEquals( "3 years 6 months", DurationFormatUtils.formatPeriod(time1970, time, "y' years 'M' months'") );
  +        assertEquals( "03/06", DurationFormatUtils.formatPeriod(time1970, time, "yy/MM") );
   
           cal.set(1973, 10, 1, 0, 0, 0);
           cal.set(Calendar.MILLISECOND, 0);
           time = cal.getTime().getTime();
  -        assertEquals( "310", DurationFormatUtils.format(time, "yM") );
  -        assertEquals( "3 years 10 months", DurationFormatUtils.format(time, "y' years 'M' months'") );
  -        assertEquals( "03/10", DurationFormatUtils.format(time, "yy/MM") );
  +        assertEquals( "310", DurationFormatUtils.formatPeriod(time1970, time, "yM") );
  +        assertEquals( "3 years 10 months", DurationFormatUtils.formatPeriod(time1970, time, "y' years 'M' months'") );
  +        assertEquals( "03/10", DurationFormatUtils.formatPeriod(time1970, time, "yy/MM") );
   
           cal.set(1974, 0, 1, 0, 0, 0);
           cal.set(Calendar.MILLISECOND, 0);
           time = cal.getTime().getTime();
  -        assertEquals( "40", DurationFormatUtils.format(time, "yM") );
  -        assertEquals( "4 years 0 months", DurationFormatUtils.format(time, "y' years 'M' months'") );
  -        assertEquals( "04/00", DurationFormatUtils.format(time, "yy/MM") );
  -        assertEquals( "48", DurationFormatUtils.format(time, "M") );
  -        assertEquals( "48", DurationFormatUtils.format(time, "MM") );
  -        assertEquals( "048", DurationFormatUtils.format(time, "MMM") );
  +        assertEquals( "40", DurationFormatUtils.formatPeriod(time1970, time, "yM") );
  +        assertEquals( "4 years 0 months", DurationFormatUtils.formatPeriod(time1970, time, "y' years 'M' months'") );
  +        assertEquals( "04/00", DurationFormatUtils.formatPeriod(time1970, time, "yy/MM") );
  +        assertEquals( "48", DurationFormatUtils.formatPeriod(time1970, time, "M") );
  +        assertEquals( "48", DurationFormatUtils.formatPeriod(time1970, time, "MM") );
  +        assertEquals( "048", DurationFormatUtils.formatPeriod(time1970, time, "MMM") );
       }
   
       public void testLexx() {
           // tests each constant
           assertArrayEquals( 
  -          new Token[] { 
  -            new Token( DurationFormatUtils.y, 1),
  -            new Token( DurationFormatUtils.M, 1),
  -            new Token( DurationFormatUtils.d, 1),
  -            new Token( DurationFormatUtils.H, 1),
  -            new Token( DurationFormatUtils.m, 1),
  -            new Token( DurationFormatUtils.s, 1),
  -            new Token( DurationFormatUtils.S, 1)
  +          new DurationFormatUtils.Token[] { 
  +            new DurationFormatUtils.Token( DurationFormatUtils.y, 1),
  +            new DurationFormatUtils.Token( DurationFormatUtils.M, 1),
  +            new DurationFormatUtils.Token( DurationFormatUtils.d, 1),
  +            new DurationFormatUtils.Token( DurationFormatUtils.H, 1),
  +            new DurationFormatUtils.Token( DurationFormatUtils.m, 1),
  +            new DurationFormatUtils.Token( DurationFormatUtils.s, 1),
  +            new DurationFormatUtils.Token( DurationFormatUtils.S, 1)
             }, DurationFormatUtils.lexx("yMdHmsS") 
           );
   
           // tests the ISO8601-like
           assertArrayEquals( 
  -          new Token[] { 
  -            new Token( DurationFormatUtils.H, 1),
  -            new Token( new StringBuffer(":"), 1),
  -            new Token( DurationFormatUtils.m, 2),
  -            new Token( new StringBuffer(":"), 1),
  -            new Token( DurationFormatUtils.s, 2),
  -            new Token( new StringBuffer("."), 1),
  -            new Token( DurationFormatUtils.S, 3)
  +          new DurationFormatUtils.Token[] { 
  +            new DurationFormatUtils.Token( DurationFormatUtils.H, 1),
  +            new DurationFormatUtils.Token( new StringBuffer(":"), 1),
  +            new DurationFormatUtils.Token( DurationFormatUtils.m, 2),
  +            new DurationFormatUtils.Token( new StringBuffer(":"), 1),
  +            new DurationFormatUtils.Token( DurationFormatUtils.s, 2),
  +            new DurationFormatUtils.Token( new StringBuffer("."), 1),
  +            new DurationFormatUtils.Token( DurationFormatUtils.S, 3)
             }, DurationFormatUtils.lexx("H:mm:ss.SSS")
           );
   
           // test the iso extended format
           assertArrayEquals( 
  -          new Token[] { 
  -            new Token( new StringBuffer("P"), 1),
  -            new Token( DurationFormatUtils.y, 4),
  -            new Token( new StringBuffer("Y"), 1),
  -            new Token( DurationFormatUtils.M, 1),
  -            new Token( new StringBuffer("M"), 1),
  -            new Token( DurationFormatUtils.d, 1),
  -            new Token( new StringBuffer("DT"), 1),
  -            new Token( DurationFormatUtils.H, 1),
  -            new Token( new StringBuffer("H"), 1),
  -            new Token( DurationFormatUtils.m, 1),
  -            new Token( new StringBuffer("M"), 1),
  -            new Token( DurationFormatUtils.s, 1),
  -            new Token( new StringBuffer("."), 1),
  -            new Token( DurationFormatUtils.S, 1),
  -            new Token( new StringBuffer("S"), 1)
  +          new DurationFormatUtils.Token[] { 
  +            new DurationFormatUtils.Token( new StringBuffer("P"), 1),
  +            new DurationFormatUtils.Token( DurationFormatUtils.y, 4),
  +            new DurationFormatUtils.Token( new StringBuffer("Y"), 1),
  +            new DurationFormatUtils.Token( DurationFormatUtils.M, 1),
  +            new DurationFormatUtils.Token( new StringBuffer("M"), 1),
  +            new DurationFormatUtils.Token( DurationFormatUtils.d, 1),
  +            new DurationFormatUtils.Token( new StringBuffer("DT"), 1),
  +            new DurationFormatUtils.Token( DurationFormatUtils.H, 1),
  +            new DurationFormatUtils.Token( new StringBuffer("H"), 1),
  +            new DurationFormatUtils.Token( DurationFormatUtils.m, 1),
  +            new DurationFormatUtils.Token( new StringBuffer("M"), 1),
  +            new DurationFormatUtils.Token( DurationFormatUtils.s, 1),
  +            new DurationFormatUtils.Token( new StringBuffer("."), 1),
  +            new DurationFormatUtils.Token( DurationFormatUtils.S, 1),
  +            new DurationFormatUtils.Token( new StringBuffer("S"), 1)
             }, 
             DurationFormatUtils.lexx(DurationFormatUtils.ISO_EXTENDED_FORMAT_PATTERN)
           );
       }
  -    private void assertArrayEquals(Token[] obj1, Token[] obj2) {
  +    private void assertArrayEquals(DurationFormatUtils.Token[] obj1, DurationFormatUtils.Token[] obj2) {
           assertEquals( "Arrays are unequal length. ", obj1.length, obj2.length );
           for(int i=0; i<obj1.length; i++) {
               assertTrue( "Index " + i + " not equal, " + obj1[i] + " vs " + obj2, obj1[i].equals(obj2[i]));
           }
       }
   
  -    
   }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org