diff --git a/src/java/org/apache/commons/lang/time/DurationFormatUtils.java b/src/java/org/apache/commons/lang/time/DurationFormatUtils.java index 4e54fd62f..4ee6cca5c 100644 --- a/src/java/org/apache/commons/lang/time/DurationFormatUtils.java +++ b/src/java/org/apache/commons/lang/time/DurationFormatUtils.java @@ -312,37 +312,49 @@ public static String formatPeriod(long startMillis, long endMillis, String forma hours += 24; days -= 1; } - while (days < 0) { - end.add(Calendar.MONTH, -1); - days += end.getActualMaximum(Calendar.DAY_OF_MONTH); - // HEN: It's a tricky subject. Jan 15th to March 10th. If I count days-first it is + if (days < 0) { + days += start.getActualMaximum(Calendar.DAY_OF_MONTH); + // It's a tricky subject. Jan 15th to March 10th. If I count days-first it is // 1 month and 26 days, but if I count month-first then it is 1 month and 23 days. + // Here we choose the former. // Also it's contextual - if asked for no M in the format then I should probably // be doing no calculating here. months -= 1; - end.add(Calendar.MONTH, 1); } while (months < 0) { months += 12; years -= 1; + start.add(Calendar.YEAR, 1); } - // This next block of code adds in values that + // This rest of this code adds in values that // aren't requested. This allows the user to ask for the // number of months and get the real count and not just 0->11. + if (!Token.containsTokenWithValue(tokens, y)) { if (Token.containsTokenWithValue(tokens, M)) { months += 12 * years; years = 0; } else { - // TODO: this is a bit weak, needs work to know about leap years - days += 365 * years; + while(start.get(Calendar.YEAR) != end.get(Calendar.YEAR)) { + days += start.getActualMaximum(Calendar.DAY_OF_YEAR); + start.add(Calendar.YEAR, 1); + } years = 0; } } - if (!Token.containsTokenWithValue(tokens, M)) { + + if (!Token.containsTokenWithValue(tokens, M) && months != 0) { + start.set(start.get(Calendar.YEAR), start.get(Calendar.MONTH), 0, 0, 0, 0); + start.add(Calendar.MONTH, 1); + end.set(end.get(Calendar.YEAR), end.get(Calendar.MONTH), 0, 0, 0, 0); days += end.get(Calendar.DAY_OF_YEAR) - start.get(Calendar.DAY_OF_YEAR); months = 0; + + // WARNING: For performance sake the Calendar instances are not being + // cloned but modified inline. They should not be trusted after this point + start = null; + end = null; } if (!Token.containsTokenWithValue(tokens, d)) { hours += 24 * days; diff --git a/src/test/org/apache/commons/lang/time/DurationFormatUtilsTest.java b/src/test/org/apache/commons/lang/time/DurationFormatUtilsTest.java index c60890ed5..e1e60239b 100644 --- a/src/test/org/apache/commons/lang/time/DurationFormatUtilsTest.java +++ b/src/test/org/apache/commons/lang/time/DurationFormatUtilsTest.java @@ -420,6 +420,27 @@ public void testEdgeDurations() { new int[] { 2006, 0, 16, 0, 0, 0 }, "MM"); assertEqualDuration( "11", new int[] { 2005, 0, 15, 0, 0, 0 }, new int[] { 2006, 0, 14, 0, 0, 0 }, "MM"); + + assertEqualDuration( "01 26", new int[] { 2006, 0, 15, 0, 0, 0 }, + new int[] { 2006, 2, 10, 0, 0, 0 }, "MM dd"); + assertEqualDuration( "54", new int[] { 2006, 0, 15, 0, 0, 0 }, + new int[] { 2006, 2, 10, 0, 0, 0 }, "dd"); + + assertEqualDuration( "09 12", new int[] { 2006, 1, 20, 0, 0, 0 }, + new int[] { 2006, 11, 4, 0, 0, 0 }, "MM dd"); + assertEqualDuration( "287", new int[] { 2006, 1, 20, 0, 0, 0 }, + new int[] { 2006, 11, 4, 0, 0, 0 }, "dd"); + + assertEqualDuration( "11 30", new int[] { 2006, 0, 2, 0, 0, 0 }, + new int[] { 2007, 0, 1, 0, 0, 0 }, "MM dd"); + assertEqualDuration( "364", new int[] { 2006, 0, 2, 0, 0, 0 }, + new int[] { 2007, 0, 1, 0, 0, 0 }, "dd"); + + assertEqualDuration( "12 00", new int[] { 2006, 0, 1, 0, 0, 0 }, + new int[] { 2007, 0, 1, 0, 0, 0 }, "MM dd"); + assertEqualDuration( "365", new int[] { 2006, 0, 1, 0, 0, 0 }, + new int[] { 2007, 0, 1, 0, 0, 0 }, "dd"); + } private void assertEqualDuration(String expected, int[] start, int[] end, String format) { @@ -429,7 +450,9 @@ private void assertEqualDuration(String expected, int[] start, int[] end, String Calendar cal2 = Calendar.getInstance(); cal2.set(end[0], end[1], end[2], end[3], end[4], end[5]); cal2.set(Calendar.MILLISECOND, 0); - String result = DurationFormatUtils.formatPeriod(cal1.getTime().getTime(), cal2.getTime().getTime(), format); + long milli1 = cal1.getTime().getTime(); + long milli2 = cal2.getTime().getTime(); + String result = DurationFormatUtils.formatPeriod(milli1, milli2, format); assertEquals(expected, result); }