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