View Javadoc

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