1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.lang.time;
19  
20  import java.lang.reflect.Constructor;
21  import java.lang.reflect.Modifier;
22  import java.util.Calendar;
23  import java.util.TimeZone;
24  
25  import junit.framework.Test;
26  import junit.framework.TestCase;
27  import junit.framework.TestSuite;
28  import junit.textui.TestRunner;
29  
30  /**
31   * TestCase for DurationFormatUtils.
32   * 
33   * @author Apache Ant - DateUtilsTest
34   * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
35   * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
36   * @author Stephen Colebourne
37   * @author <a href="mailto:ggregory@seagullsw.com">Gary Gregory</a>
38   */
39  public class DurationFormatUtilsTest extends TestCase {
40  
41      public static void main(String[] args) {
42          TestRunner.run(suite());
43      }
44  
45      public static Test suite() {
46          TestSuite suite = new TestSuite(DurationFormatUtilsTest.class);
47          suite.setName("DurationFormatUtils Tests");
48          return suite;
49      }
50  
51      public DurationFormatUtilsTest(String s) {
52          super(s);
53      }
54  
55      // -----------------------------------------------------------------------
56      public void testConstructor() {
57          assertNotNull(new DurationFormatUtils());
58          Constructor[] cons = DurationFormatUtils.class.getDeclaredConstructors();
59          assertEquals(1, cons.length);
60          assertEquals(true, Modifier.isPublic(cons[0].getModifiers()));
61          assertEquals(true, Modifier.isPublic(DurationFormatUtils.class.getModifiers()));
62          assertEquals(false, Modifier.isFinal(DurationFormatUtils.class.getModifiers()));
63      }
64  
65      // -----------------------------------------------------------------------
66      public void testFormatDurationWords() {
67          String text = null;
68  
69          text = DurationFormatUtils.formatDurationWords(50 * 1000, true, false);
70          assertEquals("50 seconds", text);
71          text = DurationFormatUtils.formatDurationWords(65 * 1000, true, false);
72          assertEquals("1 minute 5 seconds", text);
73          text = DurationFormatUtils.formatDurationWords(120 * 1000, true, false);
74          assertEquals("2 minutes 0 seconds", text);
75          text = DurationFormatUtils.formatDurationWords(121 * 1000, true, false);
76          assertEquals("2 minutes 1 second", text);
77          text = DurationFormatUtils.formatDurationWords(72 * 60 * 1000, true, false);
78          assertEquals("1 hour 12 minutes 0 seconds", text);
79          text = DurationFormatUtils.formatDurationWords(24 * 60 * 60 * 1000, true, false);
80          assertEquals("1 day 0 hours 0 minutes 0 seconds", text);
81  
82          text = DurationFormatUtils.formatDurationWords(50 * 1000, true, true);
83          assertEquals("50 seconds", text);
84          text = DurationFormatUtils.formatDurationWords(65 * 1000, true, true);
85          assertEquals("1 minute 5 seconds", text);
86          text = DurationFormatUtils.formatDurationWords(120 * 1000, true, true);
87          assertEquals("2 minutes", text);
88          text = DurationFormatUtils.formatDurationWords(121 * 1000, true, true);
89          assertEquals("2 minutes 1 second", text);
90          text = DurationFormatUtils.formatDurationWords(72 * 60 * 1000, true, true);
91          assertEquals("1 hour 12 minutes", text);
92          text = DurationFormatUtils.formatDurationWords(24 * 60 * 60 * 1000, true, true);
93          assertEquals("1 day", text);
94  
95          text = DurationFormatUtils.formatDurationWords(50 * 1000, false, true);
96          assertEquals("0 days 0 hours 0 minutes 50 seconds", text);
97          text = DurationFormatUtils.formatDurationWords(65 * 1000, false, true);
98          assertEquals("0 days 0 hours 1 minute 5 seconds", text);
99          text = DurationFormatUtils.formatDurationWords(120 * 1000, false, true);
100         assertEquals("0 days 0 hours 2 minutes", text);
101         text = DurationFormatUtils.formatDurationWords(121 * 1000, false, true);
102         assertEquals("0 days 0 hours 2 minutes 1 second", text);
103         text = DurationFormatUtils.formatDurationWords(72 * 60 * 1000, false, true);
104         assertEquals("0 days 1 hour 12 minutes", text);
105         text = DurationFormatUtils.formatDurationWords(24 * 60 * 60 * 1000, false, true);
106         assertEquals("1 day", text);
107 
108         text = DurationFormatUtils.formatDurationWords(50 * 1000, false, false);
109         assertEquals("0 days 0 hours 0 minutes 50 seconds", text);
110         text = DurationFormatUtils.formatDurationWords(65 * 1000, false, false);
111         assertEquals("0 days 0 hours 1 minute 5 seconds", text);
112         text = DurationFormatUtils.formatDurationWords(120 * 1000, false, false);
113         assertEquals("0 days 0 hours 2 minutes 0 seconds", text);
114         text = DurationFormatUtils.formatDurationWords(121 * 1000, false, false);
115         assertEquals("0 days 0 hours 2 minutes 1 second", text);
116         text = DurationFormatUtils.formatDurationWords(72 * 60 * 1000, false, false);
117         assertEquals("0 days 1 hour 12 minutes 0 seconds", text);
118         text = DurationFormatUtils.formatDurationWords(24 * 60 * 60 * 1000 + 72 * 60 * 1000, false, false);
119         assertEquals("1 day 1 hour 12 minutes 0 seconds", text);
120         text = DurationFormatUtils.formatDurationWords(2 * 24 * 60 * 60 * 1000 + 72 * 60 * 1000, false, false);
121         assertEquals("2 days 1 hour 12 minutes 0 seconds", text);
122         for (int i = 2; i < 31; i++) {
123             text = DurationFormatUtils.formatDurationWords(i * 24 * 60 * 60 * 1000, false, false);
124             // assertEquals(i + " days 0 hours 0 minutes 0 seconds", text);
125             //            
126             // junit.framework.ComparisonFailure: expected:<25 days 0 hours 0 minutes 0...> but was:<-24 days -17 hours
127             // -2 minutes -47...>
128             // at junit.framework.Assert.assertEquals(Assert.java:81)
129             // at junit.framework.Assert.assertEquals(Assert.java:87)
130             // at
131             // org.apache.commons.lang.time.DurationFormatUtilsTest.testFormatDurationWords(DurationFormatUtilsTest.java:124)
132             // at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
133             // at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
134             // at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
135             // at java.lang.reflect.Method.invoke(Method.java:324)
136             // at junit.framework.TestCase.runTest(TestCase.java:154)
137             // at junit.framework.TestCase.runBare(TestCase.java:127)
138             // at junit.framework.TestResult$1.protect(TestResult.java:106)
139             // at junit.framework.TestResult.runProtected(TestResult.java:124)
140             // at junit.framework.TestResult.run(TestResult.java:109)
141             // at junit.framework.TestCase.run(TestCase.java:118)
142             // at junit.framework.TestSuite.runTest(TestSuite.java:208)
143             // at junit.framework.TestSuite.run(TestSuite.java:203)
144             // at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:478)
145             // at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:344)
146             // at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
147         }
148     }
149 
150     /**
151      * Tests that "1 <unit>s" gets converted to "1 <unit>" but that "11 <unit>s" is left alone.
152      */
153     public void testFormatDurationPluralWords() {
154         long oneSecond = 1000;
155         long oneMinute = oneSecond * 60;
156         long oneHour = oneMinute * 60;
157         long oneDay = oneHour * 24;
158         String text = null;
159 
160         text = DurationFormatUtils.formatDurationWords(oneSecond, false, false);
161         assertEquals("0 days 0 hours 0 minutes 1 second", text);
162         text = DurationFormatUtils.formatDurationWords(oneSecond * 2, false, false);
163         assertEquals("0 days 0 hours 0 minutes 2 seconds", text);
164         text = DurationFormatUtils.formatDurationWords(oneSecond * 11, false, false);
165         assertEquals("0 days 0 hours 0 minutes 11 seconds", text);
166 
167         text = DurationFormatUtils.formatDurationWords(oneMinute, false, false);
168         assertEquals("0 days 0 hours 1 minute 0 seconds", text);
169         text = DurationFormatUtils.formatDurationWords(oneMinute * 2, false, false);
170         assertEquals("0 days 0 hours 2 minutes 0 seconds", text);
171         text = DurationFormatUtils.formatDurationWords(oneMinute * 11, false, false);
172         assertEquals("0 days 0 hours 11 minutes 0 seconds", text);
173         text = DurationFormatUtils.formatDurationWords(oneMinute + oneSecond, false, false);
174         assertEquals("0 days 0 hours 1 minute 1 second", text);
175 
176         text = DurationFormatUtils.formatDurationWords(oneHour, false, false);
177         assertEquals("0 days 1 hour 0 minutes 0 seconds", text);
178         text = DurationFormatUtils.formatDurationWords(oneHour * 2, false, false);
179         assertEquals("0 days 2 hours 0 minutes 0 seconds", text);
180         text = DurationFormatUtils.formatDurationWords(oneHour * 11, false, false);
181         assertEquals("0 days 11 hours 0 minutes 0 seconds", text);
182         text = DurationFormatUtils.formatDurationWords(oneHour + oneMinute + oneSecond, false, false);
183         assertEquals("0 days 1 hour 1 minute 1 second", text);
184 
185         text = DurationFormatUtils.formatDurationWords(oneDay, false, false);
186         assertEquals("1 day 0 hours 0 minutes 0 seconds", text);
187         text = DurationFormatUtils.formatDurationWords(oneDay * 2, false, false);
188         assertEquals("2 days 0 hours 0 minutes 0 seconds", text);
189         text = DurationFormatUtils.formatDurationWords(oneDay * 11, false, false);
190         assertEquals("11 days 0 hours 0 minutes 0 seconds", text);
191         text = DurationFormatUtils.formatDurationWords(oneDay + oneHour + oneMinute + oneSecond, false, false);
192         assertEquals("1 day 1 hour 1 minute 1 second", text);
193     }
194 
195     public void testFormatDurationHMS() {
196         long time = 0;
197         assertEquals("0:00:00.000", DurationFormatUtils.formatDurationHMS(time));
198 
199         time = 1;
200         assertEquals("0:00:00.001", DurationFormatUtils.formatDurationHMS(time));
201 
202         time = 15;
203         assertEquals("0:00:00.015", DurationFormatUtils.formatDurationHMS(time));
204 
205         time = 165;
206         assertEquals("0:00:00.165", DurationFormatUtils.formatDurationHMS(time));
207 
208         time = 1675;
209         assertEquals("0:00:01.675", DurationFormatUtils.formatDurationHMS(time));
210 
211         time = 13465;
212         assertEquals("0:00:13.465", DurationFormatUtils.formatDurationHMS(time));
213 
214         time = 72789;
215         assertEquals("0:01:12.789", DurationFormatUtils.formatDurationHMS(time));
216 
217         time = 12789 + 32 * 60000;
218         assertEquals("0:32:12.789", DurationFormatUtils.formatDurationHMS(time));
219 
220         time = 12789 + 62 * 60000;
221         assertEquals("1:02:12.789", DurationFormatUtils.formatDurationHMS(time));
222     }
223 
224     public void testFormatDurationISO() {
225         assertEquals("P0Y0M0DT0H0M0.000S", DurationFormatUtils.formatDurationISO(0L));
226         assertEquals("P0Y0M0DT0H0M0.001S", DurationFormatUtils.formatDurationISO(1L));
227         assertEquals("P0Y0M0DT0H0M0.010S", DurationFormatUtils.formatDurationISO(10L));
228         assertEquals("P0Y0M0DT0H0M0.100S", DurationFormatUtils.formatDurationISO(100L));
229         assertEquals("P0Y0M0DT0H1M15.321S", DurationFormatUtils.formatDurationISO(75321L));
230     }
231 
232     public void testFormatDuration() {
233         long duration = 0;
234         assertEquals("0", DurationFormatUtils.formatDuration(duration, "y"));
235         assertEquals("0", DurationFormatUtils.formatDuration(duration, "M"));
236         assertEquals("0", DurationFormatUtils.formatDuration(duration, "d"));
237         assertEquals("0", DurationFormatUtils.formatDuration(duration, "H"));
238         assertEquals("0", DurationFormatUtils.formatDuration(duration, "m"));
239         assertEquals("0", DurationFormatUtils.formatDuration(duration, "s"));
240         assertEquals("0", DurationFormatUtils.formatDuration(duration, "S"));
241         assertEquals("0000", DurationFormatUtils.formatDuration(duration, "SSSS"));
242         assertEquals("0000", DurationFormatUtils.formatDuration(duration, "yyyy"));
243         assertEquals("0000", DurationFormatUtils.formatDuration(duration, "yyMM"));
244 
245         duration = 60 * 1000;
246         assertEquals("0", DurationFormatUtils.formatDuration(duration, "y"));
247         assertEquals("0", DurationFormatUtils.formatDuration(duration, "M"));
248         assertEquals("0", DurationFormatUtils.formatDuration(duration, "d"));
249         assertEquals("0", DurationFormatUtils.formatDuration(duration, "H"));
250         assertEquals("1", DurationFormatUtils.formatDuration(duration, "m"));
251         assertEquals("60", DurationFormatUtils.formatDuration(duration, "s"));
252         assertEquals("60000", DurationFormatUtils.formatDuration(duration, "S"));
253         assertEquals("01:00", DurationFormatUtils.formatDuration(duration, "mm:ss"));
254 
255         Calendar base = Calendar.getInstance();
256         base.set(2000, 0, 1, 0, 0, 0);
257         base.set(Calendar.MILLISECOND, 0);
258 
259         Calendar cal = Calendar.getInstance();
260         cal.set(2003, 1, 1, 0, 0, 0);
261         cal.set(Calendar.MILLISECOND, 0);
262         duration = cal.getTime().getTime() - base.getTime().getTime(); // duration from 2000-01-01 to cal
263         // don't use 1970 in test as time zones were less reliable in 1970 than now
264         // remember that duration formatting ignores time zones, working on strict hour lengths
265         int days = 366 + 365 + 365 + 31;
266         assertEquals("0 0 " + days, DurationFormatUtils.formatDuration(duration, "y M d"));
267     }
268 
269     public void testFormatPeriodISO() {
270         TimeZone timeZone = TimeZone.getTimeZone("GMT-3");
271         Calendar base = Calendar.getInstance(timeZone);
272         base.set(1970, 0, 1, 0, 0, 0);
273         base.set(Calendar.MILLISECOND, 0);
274 
275         Calendar cal = Calendar.getInstance(timeZone);
276         cal.set(2002, 1, 23, 9, 11, 12);
277         cal.set(Calendar.MILLISECOND, 1);
278         String text;
279         // repeat a test from testDateTimeISO to compare extended and not extended.
280         text = DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.format(cal);
281         assertEquals("2002-02-23T09:11:12-03:00", text);
282         // test fixture is the same as above, but now with extended format.
283         text = DurationFormatUtils.formatPeriod(base.getTime().getTime(), cal.getTime().getTime(),
284                 DurationFormatUtils.ISO_EXTENDED_FORMAT_PATTERN, false, timeZone);
285         assertEquals("P32Y1M22DT9H11M12.001S", text);
286         // test fixture from example in http://www.w3.org/TR/xmlschema-2/#duration
287         cal.set(1971, 1, 3, 10, 30, 0);
288         cal.set(Calendar.MILLISECOND, 0);
289         text = DurationFormatUtils.formatPeriod(base.getTime().getTime(), cal.getTime().getTime(),
290                 DurationFormatUtils.ISO_EXTENDED_FORMAT_PATTERN, false, timeZone);
291         assertEquals("P1Y1M2DT10H30M0.000S", text);
292         // want a way to say 'don't print the seconds in format()' or other fields for that matter:
293         // assertEquals("P1Y2M3DT10H30M", text);
294     }
295 
296     public void testFormatPeriod() {
297         Calendar cal1970 = Calendar.getInstance();
298         cal1970.set(1970, 0, 1, 0, 0, 0);
299         cal1970.set(Calendar.MILLISECOND, 0);
300         long time1970 = cal1970.getTime().getTime();
301 
302         assertEquals("0", DurationFormatUtils.formatPeriod(time1970, time1970, "y"));
303         assertEquals("0", DurationFormatUtils.formatPeriod(time1970, time1970, "M"));
304         assertEquals("0", DurationFormatUtils.formatPeriod(time1970, time1970, "d"));
305         assertEquals("0", DurationFormatUtils.formatPeriod(time1970, time1970, "H"));
306         assertEquals("0", DurationFormatUtils.formatPeriod(time1970, time1970, "m"));
307         assertEquals("0", DurationFormatUtils.formatPeriod(time1970, time1970, "s"));
308         assertEquals("0", DurationFormatUtils.formatPeriod(time1970, time1970, "S"));
309         assertEquals("0000", DurationFormatUtils.formatPeriod(time1970, time1970, "SSSS"));
310         assertEquals("0000", DurationFormatUtils.formatPeriod(time1970, time1970, "yyyy"));
311         assertEquals("0000", DurationFormatUtils.formatPeriod(time1970, time1970, "yyMM"));
312 
313         long time = time1970 + 60 * 1000;
314         assertEquals("0", DurationFormatUtils.formatPeriod(time1970, time, "y"));
315         assertEquals("0", DurationFormatUtils.formatPeriod(time1970, time, "M"));
316         assertEquals("0", DurationFormatUtils.formatPeriod(time1970, time, "d"));
317         assertEquals("0", DurationFormatUtils.formatPeriod(time1970, time, "H"));
318         assertEquals("1", DurationFormatUtils.formatPeriod(time1970, time, "m"));
319         assertEquals("60", DurationFormatUtils.formatPeriod(time1970, time, "s"));
320         assertEquals("60000", DurationFormatUtils.formatPeriod(time1970, time, "S"));
321         assertEquals("01:00", DurationFormatUtils.formatPeriod(time1970, time, "mm:ss"));
322 
323         Calendar cal = Calendar.getInstance();
324         cal.set(1973, 6, 1, 0, 0, 0);
325         cal.set(Calendar.MILLISECOND, 0);
326         time = cal.getTime().getTime();
327         assertEquals("36", DurationFormatUtils.formatPeriod(time1970, time, "yM"));
328         assertEquals("3 years 6 months", DurationFormatUtils.formatPeriod(time1970, time, "y' years 'M' months'"));
329         assertEquals("03/06", DurationFormatUtils.formatPeriod(time1970, time, "yy/MM"));
330 
331         cal.set(1973, 10, 1, 0, 0, 0);
332         cal.set(Calendar.MILLISECOND, 0);
333         time = cal.getTime().getTime();
334         assertEquals("310", DurationFormatUtils.formatPeriod(time1970, time, "yM"));
335         assertEquals("3 years 10 months", DurationFormatUtils.formatPeriod(time1970, time, "y' years 'M' months'"));
336         assertEquals("03/10", DurationFormatUtils.formatPeriod(time1970, time, "yy/MM"));
337 
338         cal.set(1974, 0, 1, 0, 0, 0);
339         cal.set(Calendar.MILLISECOND, 0);
340         time = cal.getTime().getTime();
341         assertEquals("40", DurationFormatUtils.formatPeriod(time1970, time, "yM"));
342         assertEquals("4 years 0 months", DurationFormatUtils.formatPeriod(time1970, time, "y' years 'M' months'"));
343         assertEquals("04/00", DurationFormatUtils.formatPeriod(time1970, time, "yy/MM"));
344         assertEquals("48", DurationFormatUtils.formatPeriod(time1970, time, "M"));
345         assertEquals("48", DurationFormatUtils.formatPeriod(time1970, time, "MM"));
346         assertEquals("048", DurationFormatUtils.formatPeriod(time1970, time, "MMM"));
347     }
348 
349     public void testLexx() {
350         // tests each constant
351         assertArrayEquals(new DurationFormatUtils.Token[]{
352             new DurationFormatUtils.Token(DurationFormatUtils.y, 1),
353             new DurationFormatUtils.Token(DurationFormatUtils.M, 1),
354             new DurationFormatUtils.Token(DurationFormatUtils.d, 1),
355             new DurationFormatUtils.Token(DurationFormatUtils.H, 1),
356             new DurationFormatUtils.Token(DurationFormatUtils.m, 1),
357             new DurationFormatUtils.Token(DurationFormatUtils.s, 1),
358             new DurationFormatUtils.Token(DurationFormatUtils.S, 1)}, DurationFormatUtils.lexx("yMdHmsS"));
359 
360         // tests the ISO8601-like
361         assertArrayEquals(new DurationFormatUtils.Token[]{
362             new DurationFormatUtils.Token(DurationFormatUtils.H, 1),
363             new DurationFormatUtils.Token(new StringBuffer(":"), 1),
364             new DurationFormatUtils.Token(DurationFormatUtils.m, 2),
365             new DurationFormatUtils.Token(new StringBuffer(":"), 1),
366             new DurationFormatUtils.Token(DurationFormatUtils.s, 2),
367             new DurationFormatUtils.Token(new StringBuffer("."), 1),
368             new DurationFormatUtils.Token(DurationFormatUtils.S, 3)}, DurationFormatUtils.lexx("H:mm:ss.SSS"));
369 
370         // test the iso extended format
371         assertArrayEquals(new DurationFormatUtils.Token[]{
372             new DurationFormatUtils.Token(new StringBuffer("P"), 1),
373             new DurationFormatUtils.Token(DurationFormatUtils.y, 4),
374             new DurationFormatUtils.Token(new StringBuffer("Y"), 1),
375             new DurationFormatUtils.Token(DurationFormatUtils.M, 1),
376             new DurationFormatUtils.Token(new StringBuffer("M"), 1),
377             new DurationFormatUtils.Token(DurationFormatUtils.d, 1),
378             new DurationFormatUtils.Token(new StringBuffer("DT"), 1),
379             new DurationFormatUtils.Token(DurationFormatUtils.H, 1),
380             new DurationFormatUtils.Token(new StringBuffer("H"), 1),
381             new DurationFormatUtils.Token(DurationFormatUtils.m, 1),
382             new DurationFormatUtils.Token(new StringBuffer("M"), 1),
383             new DurationFormatUtils.Token(DurationFormatUtils.s, 1),
384             new DurationFormatUtils.Token(new StringBuffer("."), 1),
385             new DurationFormatUtils.Token(DurationFormatUtils.S, 1),
386             new DurationFormatUtils.Token(new StringBuffer("S"), 1)}, DurationFormatUtils
387                 .lexx(DurationFormatUtils.ISO_EXTENDED_FORMAT_PATTERN));
388 
389         // test failures in equals
390         DurationFormatUtils.Token token = new DurationFormatUtils.Token(DurationFormatUtils.y, 4);
391         assertFalse("Token equal to non-Token class. ", token.equals(new Object()));
392         assertFalse("Token equal to Token with wrong value class. ", token.equals(new DurationFormatUtils.Token(
393                 new Object())));
394         assertFalse("Token equal to Token with different count. ", token.equals(new DurationFormatUtils.Token(
395                 DurationFormatUtils.y, 1)));
396         DurationFormatUtils.Token numToken = new DurationFormatUtils.Token(new Integer(1), 4);
397         assertTrue("Token with Number value not equal to itself. ", numToken.equals(numToken));
398     }
399 
400 
401     // http://issues.apache.org/bugzilla/show_bug.cgi?id=38401
402     public void testBugzilla38401() {
403         assertEqualDuration( "0000/00/30 16:00:00 000", new int[] { 2006, 0, 26, 18, 47, 34 }, 
404                              new int[] { 2006, 1, 26, 10, 47, 34 }, "yyyy/MM/dd HH:mm:ss SSS");
405     }
406 
407     // https://issues.apache.org/jira/browse/LANG-281
408     public void testJiraLang281() {
409         assertEqualDuration( "09", new int[] { 2005, 11, 31, 0, 0, 0 }, 
410                              new int[] { 2006, 9, 6, 0, 0, 0 }, "MM");
411     }
412     
413     // Testing the under a day range in DurationFormatUtils.formatPeriod
414     public void testLowDurations() {
415         for(int hr=0; hr < 24; hr++) {
416             for(int min=0; min < 60; min++) {
417                 for(int sec=0; sec < 60; sec++) {
418                     assertEqualDuration( hr + ":" + min + ":" + sec, 
419                                          new int[] { 2000, 0, 1, 0, 0, 0, 0 },
420                                          new int[] { 2000, 0, 1, hr, min, sec },
421                                          "H:m:s"
422                                        );
423                 }
424             }
425         }
426     }
427 
428     // Attempting to test edge cases in DurationFormatUtils.formatPeriod
429     public void testEdgeDurations() {
430         assertEqualDuration( "01", new int[] { 2006, 0, 15, 0, 0, 0 }, 
431                              new int[] { 2006, 2, 10, 0, 0, 0 }, "MM");
432         assertEqualDuration( "12", new int[] { 2005, 0, 15, 0, 0, 0 }, 
433                              new int[] { 2006, 0, 15, 0, 0, 0 }, "MM");
434         assertEqualDuration( "12", new int[] { 2005, 0, 15, 0, 0, 0 }, 
435                              new int[] { 2006, 0, 16, 0, 0, 0 }, "MM");
436         assertEqualDuration( "11", new int[] { 2005, 0, 15, 0, 0, 0 }, 
437                              new int[] { 2006, 0, 14, 0, 0, 0 }, "MM");
438         
439         assertEqualDuration( "01 26", new int[] { 2006, 0, 15, 0, 0, 0 },
440                              new int[] { 2006, 2, 10, 0, 0, 0 }, "MM dd");
441         assertEqualDuration( "54", new int[] { 2006, 0, 15, 0, 0, 0 },
442                              new int[] { 2006, 2, 10, 0, 0, 0 }, "dd"); 
443         
444         assertEqualDuration( "09 12", new int[] { 2006, 1, 20, 0, 0, 0 },
445                              new int[] { 2006, 11, 4, 0, 0, 0 }, "MM dd");
446         assertEqualDuration( "287", new int[] { 2006, 1, 20, 0, 0, 0 },
447                              new int[] { 2006, 11, 4, 0, 0, 0 }, "dd"); 
448 
449         assertEqualDuration( "11 30", new int[] { 2006, 0, 2, 0, 0, 0 },
450                              new int[] { 2007, 0, 1, 0, 0, 0 }, "MM dd"); 
451         assertEqualDuration( "364", new int[] { 2006, 0, 2, 0, 0, 0 },
452                              new int[] { 2007, 0, 1, 0, 0, 0 }, "dd"); 
453 
454         assertEqualDuration( "12 00", new int[] { 2006, 0, 1, 0, 0, 0 },
455                              new int[] { 2007, 0, 1, 0, 0, 0 }, "MM dd"); 
456         assertEqualDuration( "365", new int[] { 2006, 0, 1, 0, 0, 0 },
457                              new int[] { 2007, 0, 1, 0, 0, 0 }, "dd"); 
458     
459         assertEqualDuration( "31", new int[] { 2006, 0, 1, 0, 0, 0 },
460                 new int[] { 2006, 1, 1, 0, 0, 0 }, "dd"); 
461         
462         assertEqualDuration( "92", new int[] { 2005, 9, 1, 0, 0, 0 },
463                 new int[] { 2006, 0, 1, 0, 0, 0 }, "dd"); 
464         assertEqualDuration( "77", new int[] { 2005, 9, 16, 0, 0, 0 },
465                 new int[] { 2006, 0, 1, 0, 0, 0 }, "dd"); 
466 
467         // test month larger in start than end
468         assertEqualDuration( "136", new int[] { 2005, 9, 16, 0, 0, 0 },
469                 new int[] { 2006, 2, 1, 0, 0, 0 }, "dd"); 
470         // test when start in leap year
471         assertEqualDuration( "136", new int[] { 2004, 9, 16, 0, 0, 0 },
472                 new int[] { 2005, 2, 1, 0, 0, 0 }, "dd"); 
473         // test when end in leap year
474         assertEqualDuration( "137", new int[] { 2003, 9, 16, 0, 0, 0 },
475                 new int[] { 2004, 2, 1, 0, 0, 0 }, "dd");         
476         // test when end in leap year but less than end of feb
477         assertEqualDuration( "135", new int[] { 2003, 9, 16, 0, 0, 0 },
478                 new int[] { 2004, 1, 28, 0, 0, 0 }, "dd"); 
479 
480         assertEqualDuration( "364", new int[] { 2007, 0, 2, 0, 0, 0 },
481                 new int[] { 2008, 0, 1, 0, 0, 0 }, "dd"); 
482         assertEqualDuration( "729", new int[] { 2006, 0, 2, 0, 0, 0 },
483                 new int[] { 2008, 0, 1, 0, 0, 0 }, "dd"); 
484 
485         assertEqualDuration( "365", new int[] { 2007, 2, 2, 0, 0, 0 },
486                 new int[] { 2008, 2, 1, 0, 0, 0 }, "dd"); 
487         assertEqualDuration( "333", new int[] { 2007, 1, 2, 0, 0, 0 },
488                 new int[] { 2008, 0, 1, 0, 0, 0 }, "dd"); 
489 
490         assertEqualDuration( "28", new int[] { 2008, 1, 2, 0, 0, 0 },
491                 new int[] { 2008, 2, 1, 0, 0, 0 }, "dd"); 
492         assertEqualDuration( "393", new int[] { 2007, 1, 2, 0, 0, 0 },
493                 new int[] { 2008, 2, 1, 0, 0, 0 }, "dd"); 
494 
495         assertEqualDuration( "369", new int[] { 2004, 0, 29, 0, 0, 0 },
496                 new int[] { 2005, 1, 1, 0, 0, 0 }, "dd"); 
497 
498         assertEqualDuration( "338", new int[] { 2004, 1, 29, 0, 0, 0 },
499                 new int[] { 2005, 1, 1, 0, 0, 0 }, "dd"); 
500 
501         assertEqualDuration( "28", new int[] { 2004, 2, 8, 0, 0, 0 },
502                 new int[] { 2004, 3, 5, 0, 0, 0 }, "dd"); 
503 
504         assertEqualDuration( "48", new int[] { 1992, 1, 29, 0, 0, 0 },
505                 new int[] { 1996, 1, 29, 0, 0, 0 }, "M"); 
506         
507         
508         // this seems odd - and will fail if I throw it in as a brute force 
509         // below as it expects the answer to be 12. It's a tricky edge case
510         assertEqualDuration( "11", new int[] { 1996, 1, 29, 0, 0, 0 },
511                 new int[] { 1997, 1, 28, 0, 0, 0 }, "M"); 
512         // again - this seems odd
513         assertEqualDuration( "11 28", new int[] { 1996, 1, 29, 0, 0, 0 },
514                 new int[] { 1997, 1, 28, 0, 0, 0 }, "M d"); 
515         
516     }
517     
518     public void testDurationsByBruteForce() {
519         bruteForce(2006, 0, 1, "d", Calendar.DAY_OF_MONTH);
520         bruteForce(2006, 0, 2, "d", Calendar.DAY_OF_MONTH);
521         bruteForce(2007, 1, 2, "d", Calendar.DAY_OF_MONTH);
522         bruteForce(2004, 1, 29, "d", Calendar.DAY_OF_MONTH);
523         bruteForce(1996, 1, 29, "d", Calendar.DAY_OF_MONTH);
524 
525         bruteForce(1969, 1, 28, "M", Calendar.MONTH);  // tests for 48 years
526         //bruteForce(1996, 1, 29, "M", Calendar.MONTH);  // this will fail
527     }
528     
529     private int FOUR_YEARS = 365 * 3 + 366;
530     
531     // Takes a minute to run, so generally turned off
532 //    public void testBrutally() {
533 //        Calendar c = Calendar.getInstance();
534 //        c.set(2004, 0, 1, 0, 0, 0);
535 //        for (int i=0; i < FOUR_YEARS; i++) {
536 //            bruteForce(c.get(Calendar.YEAR), c.get(Calendar.MONTH), c.get(Calendar.DAY_OF_MONTH), "d", Calendar.DAY_OF_MONTH );
537 //            c.add(Calendar.DAY_OF_MONTH, 1);
538 //        }
539 //    }        
540     
541     private void bruteForce(int year, int month, int day, String format, int calendarType) {
542         String msg = year + "-" + month + "-" + day + " to ";
543         Calendar c = Calendar.getInstance();
544         c.set(year, month, day, 0, 0, 0);
545         int[] array1 = new int[] { year, month, day, 0, 0, 0 };
546         int[] array2 = new int[] { year, month, day, 0, 0, 0 };
547         for (int i=0; i < FOUR_YEARS; i++) {
548             array2[0] = c.get(Calendar.YEAR);
549             array2[1] = c.get(Calendar.MONTH);
550             array2[2] = c.get(Calendar.DAY_OF_MONTH);
551             String tmpMsg = msg + array2[0] + "-" + array2[1] + "-" + array2[2] + " at ";
552             assertEqualDuration( tmpMsg + i, Integer.toString(i), array1, array2, format );
553             c.add(calendarType, 1);
554         }
555     }
556 
557     private void assertEqualDuration(String expected, int[] start, int[] end, String format) {
558         assertEqualDuration(null, expected, start, end, format);
559     }
560     private void assertEqualDuration(String message, String expected, int[] start, int[] end, String format) {
561         Calendar cal1 = Calendar.getInstance();
562         cal1.set(start[0], start[1], start[2], start[3], start[4], start[5]);
563         cal1.set(Calendar.MILLISECOND, 0);
564         Calendar cal2 = Calendar.getInstance();
565         cal2.set(end[0], end[1], end[2], end[3], end[4], end[5]);
566         cal2.set(Calendar.MILLISECOND, 0);
567         long milli1 = cal1.getTime().getTime();
568         long milli2 = cal2.getTime().getTime();
569         String result = DurationFormatUtils.formatPeriod(milli1, milli2, format);
570         if (message == null) {
571             assertEquals(expected, result);
572         } else {
573             assertEquals(message, expected, result);
574         }
575     }
576 
577     private void assertArrayEquals(DurationFormatUtils.Token[] obj1, DurationFormatUtils.Token[] obj2) {
578         assertEquals("Arrays are unequal length. ", obj1.length, obj2.length);
579         for (int i = 0; i < obj1.length; i++) {
580             assertTrue("Index " + i + " not equal, " + obj1[i] + " vs " + obj2, obj1[i].equals(obj2[i]));
581         }
582     }
583 
584 }