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  package org.apache.commons.lang3.time;
18  
19  import static org.junit.jupiter.api.Assertions.assertEquals;
20  import static org.junit.jupiter.api.Assertions.assertFalse;
21  import static org.junit.jupiter.api.Assertions.assertNotNull;
22  import static org.junit.jupiter.api.Assertions.assertNotSame;
23  import static org.junit.jupiter.api.Assertions.assertThrows;
24  import static org.junit.jupiter.api.Assertions.assertTrue;
25  
26  import java.lang.reflect.Constructor;
27  import java.lang.reflect.Modifier;
28  import java.text.DateFormat;
29  import java.text.ParseException;
30  import java.text.SimpleDateFormat;
31  import java.util.Calendar;
32  import java.util.Date;
33  import java.util.GregorianCalendar;
34  import java.util.Iterator;
35  import java.util.Locale;
36  import java.util.NoSuchElementException;
37  import java.util.TimeZone;
38  
39  import org.apache.commons.lang3.AbstractLangTest;
40  import org.junit.jupiter.api.AfterEach;
41  import org.junit.jupiter.api.BeforeAll;
42  import org.junit.jupiter.api.BeforeEach;
43  import org.junit.jupiter.api.Test;
44  import org.junitpioneer.jupiter.DefaultLocale;
45  
46  /**
47   * Tests {@link org.apache.commons.lang3.time.DateUtils}.
48   * <p>
49   * NOT THREAD-SAFE.
50   * </p>
51   */
52  public class DateUtilsTest extends AbstractLangTest {
53  
54      private static Date BASE_DATE;
55      private static TimeZone DEFAULT_ZONE;
56  
57      /**
58       * Used to check that Calendar objects are close enough
59       * delta is in milliseconds
60       */
61      private static void assertCalendarsEquals(final String message, final Calendar cal1, final Calendar cal2, final long delta) {
62          assertFalse(Math.abs(cal1.getTime().getTime() - cal2.getTime().getTime()) > delta,
63                  message + " expected " + cal1.getTime() + " but got " + cal2.getTime());
64      }
65  
66      /**
67       * This checks that this is a 7 element iterator of Calendar objects
68       * that are dates (no time), and exactly 1 day spaced after each other.
69       */
70      private static void assertWeekIterator(final Iterator<?> it, final Calendar start) {
71          final Calendar end = (Calendar) start.clone();
72          end.add(Calendar.DATE, 6);
73  
74          assertWeekIterator(it, start, end);
75      }
76  
77      /**
78       * This checks that this is a 7 divisible iterator of Calendar objects
79       * that are dates (no time), and exactly 1 day spaced after each other
80       * (in addition to the proper start and stop dates)
81       */
82      private static void assertWeekIterator(final Iterator<?> it, final Calendar start, final Calendar end) {
83          Calendar cal = (Calendar) it.next();
84          assertCalendarsEquals("", start, cal, 0);
85          Calendar last = null;
86          int count = 1;
87          while (it.hasNext()) {
88              //Check this is just a date (no time component)
89              assertCalendarsEquals("", cal, DateUtils.truncate(cal, Calendar.DATE), 0);
90  
91              last = cal;
92              cal = (Calendar) it.next();
93              count++;
94  
95              //Check that this is one day more than the last date
96              last.add(Calendar.DATE, 1);
97              assertCalendarsEquals("", last, cal, 0);
98          }
99  
100         assertFalse(count % 7 != 0, "There were " + count + " days in this iterator");
101         assertCalendarsEquals("", end, cal, 0);
102     }
103 
104     /**
105      * Convenience method for when working with Date objects
106      */
107     private static void assertWeekIterator(final Iterator<?> it, final Date start, final Date end) {
108         final Calendar calStart = Calendar.getInstance();
109         calStart.setTime(start);
110         final Calendar calEnd = Calendar.getInstance();
111         calEnd.setTime(end);
112 
113         assertWeekIterator(it, calStart, calEnd);
114     }
115 
116     @BeforeAll
117     public static void classSetup() {
118         final GregorianCalendar cal = new GregorianCalendar(2000, 6, 5, 4, 3, 2);
119         cal.set(Calendar.MILLISECOND, 1);
120         BASE_DATE = cal.getTime();
121     }
122 
123     private DateFormat dateParser;
124     private DateFormat dateTimeParser;
125     private Date dateAmPm1;
126     private Date dateAmPm2;
127     private Date dateAmPm3;
128     private Date dateAmPm4;
129     private Date date0;
130     private Date date1;
131     private Date date2;
132     private Date date3;
133     private Date date4;
134     private Date date5;
135     private Date date6;
136     private Date date7;
137     private Date date8;
138     private Calendar calAmPm1;
139     private Calendar calAmPm2;
140     private Calendar calAmPm3;
141     private Calendar calAmPm4;
142     private Calendar cal1;
143     private Calendar cal2;
144     private Calendar cal3;
145     private Calendar cal4;
146     private Calendar cal5;
147     private Calendar cal6;
148 
149     private Calendar cal7;
150 
151     private Calendar cal8;
152 
153     private TimeZone zone;
154 
155     @AfterEach
156     public void afterEachResetTimeZone() {
157         TimeZone.setDefault(DEFAULT_ZONE);
158     }
159 
160     private void assertDate(final Date date, final int year, final int month, final int day, final int hour, final int min, final int sec, final int mil) {
161         final GregorianCalendar cal = new GregorianCalendar();
162         cal.setTime(date);
163         assertEquals(year, cal.get(Calendar.YEAR));
164         assertEquals(month, cal.get(Calendar.MONTH));
165         assertEquals(day, cal.get(Calendar.DAY_OF_MONTH));
166         assertEquals(hour, cal.get(Calendar.HOUR_OF_DAY));
167         assertEquals(min, cal.get(Calendar.MINUTE));
168         assertEquals(sec, cal.get(Calendar.SECOND));
169         assertEquals(mil, cal.get(Calendar.MILLISECOND));
170     }
171 
172     @BeforeEach
173     public void setUp() throws Exception {
174         dateParser = new SimpleDateFormat("MMM dd, yyyy", Locale.ENGLISH);
175         dateTimeParser = new SimpleDateFormat("MMM dd, yyyy H:mm:ss.SSS", Locale.ENGLISH);
176 
177         dateAmPm1 = dateTimeParser.parse("February 3, 2002 01:10:00.000");
178         dateAmPm2 = dateTimeParser.parse("February 3, 2002 11:10:00.000");
179         dateAmPm3 = dateTimeParser.parse("February 3, 2002 13:10:00.000");
180         dateAmPm4 = dateTimeParser.parse("February 3, 2002 19:10:00.000");
181         date0 = dateTimeParser.parse("February 3, 2002 12:34:56.789");
182         date1 = dateTimeParser.parse("February 12, 2002 12:34:56.789");
183         date2 = dateTimeParser.parse("November 18, 2001 1:23:11.321");
184         DEFAULT_ZONE = TimeZone.getDefault();
185         zone = TimeZone.getTimeZone("MET");
186         try {
187             TimeZone.setDefault(zone);
188             dateTimeParser.setTimeZone(zone);
189             date3 = dateTimeParser.parse("March 30, 2003 05:30:45.000");
190             date4 = dateTimeParser.parse("March 30, 2003 01:10:00.000");
191             date5 = dateTimeParser.parse("March 30, 2003 01:40:00.000");
192             date6 = dateTimeParser.parse("March 30, 2003 02:10:00.000");
193             date7 = dateTimeParser.parse("March 30, 2003 02:40:00.000");
194             date8 = dateTimeParser.parse("October 26, 2003 05:30:45.000");
195         } finally {
196             dateTimeParser.setTimeZone(DEFAULT_ZONE);
197             TimeZone.setDefault(DEFAULT_ZONE);
198         }
199         calAmPm1 = Calendar.getInstance();
200         calAmPm1.setTime(dateAmPm1);
201         calAmPm2 = Calendar.getInstance();
202         calAmPm2.setTime(dateAmPm2);
203         calAmPm3 = Calendar.getInstance();
204         calAmPm3.setTime(dateAmPm3);
205         calAmPm4 = Calendar.getInstance();
206         calAmPm4.setTime(dateAmPm4);
207         cal1 = Calendar.getInstance();
208         cal1.setTime(date1);
209         cal2 = Calendar.getInstance();
210         cal2.setTime(date2);
211         try {
212             TimeZone.setDefault(zone);
213             cal3 = Calendar.getInstance();
214             cal3.setTime(date3);
215             cal4 = Calendar.getInstance();
216             cal4.setTime(date4);
217             cal5 = Calendar.getInstance();
218             cal5.setTime(date5);
219             cal6 = Calendar.getInstance();
220             cal6.setTime(date6);
221             cal7 = Calendar.getInstance();
222             cal7.setTime(date7);
223             cal8 = Calendar.getInstance();
224             cal8.setTime(date8);
225         } finally {
226             TimeZone.setDefault(DEFAULT_ZONE);
227         }
228     }
229 
230     @Test
231     public void testAddDays() throws Exception {
232         Date result = DateUtils.addDays(BASE_DATE, 0);
233         assertNotSame(BASE_DATE, result);
234         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
235         assertDate(result, 2000, 6, 5, 4, 3, 2, 1);
236 
237         result = DateUtils.addDays(BASE_DATE, 1);
238         assertNotSame(BASE_DATE, result);
239         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
240         assertDate(result, 2000, 6, 6, 4, 3, 2, 1);
241 
242         result = DateUtils.addDays(BASE_DATE, -1);
243         assertNotSame(BASE_DATE, result);
244         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
245         assertDate(result, 2000, 6, 4, 4, 3, 2, 1);
246 
247         assertThrows(NullPointerException.class, () -> DateUtils.addDays(null, 0));
248     }
249 
250     @Test
251     public void testAddHours() throws Exception {
252         Date result = DateUtils.addHours(BASE_DATE, 0);
253         assertNotSame(BASE_DATE, result);
254         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
255         assertDate(result, 2000, 6, 5, 4, 3, 2, 1);
256 
257         result = DateUtils.addHours(BASE_DATE, 1);
258         assertNotSame(BASE_DATE, result);
259         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
260         assertDate(result, 2000, 6, 5, 5, 3, 2, 1);
261 
262         result = DateUtils.addHours(BASE_DATE, -1);
263         assertNotSame(BASE_DATE, result);
264         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
265         assertDate(result, 2000, 6, 5, 3, 3, 2, 1);
266 
267         assertThrows(NullPointerException.class, () -> DateUtils.addHours(null, 0));
268     }
269 
270     @Test
271     public void testAddMilliseconds() throws Exception {
272         Date result = DateUtils.addMilliseconds(BASE_DATE, 0);
273         assertNotSame(BASE_DATE, result);
274         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
275         assertDate(result, 2000, 6, 5, 4, 3, 2, 1);
276 
277         result = DateUtils.addMilliseconds(BASE_DATE, 1);
278         assertNotSame(BASE_DATE, result);
279         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
280         assertDate(result, 2000, 6, 5, 4, 3, 2, 2);
281 
282         result = DateUtils.addMilliseconds(BASE_DATE, -1);
283         assertNotSame(BASE_DATE, result);
284         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
285         assertDate(result, 2000, 6, 5, 4, 3, 2, 0);
286 
287         assertThrows(NullPointerException.class, () -> DateUtils.addMilliseconds(null, 0));
288     }
289 
290     @Test
291     public void testAddMinutes() throws Exception {
292         Date result = DateUtils.addMinutes(BASE_DATE, 0);
293         assertNotSame(BASE_DATE, result);
294         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
295         assertDate(result, 2000, 6, 5, 4, 3, 2, 1);
296 
297         result = DateUtils.addMinutes(BASE_DATE, 1);
298         assertNotSame(BASE_DATE, result);
299         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
300         assertDate(result, 2000, 6, 5, 4, 4, 2, 1);
301 
302         result = DateUtils.addMinutes(BASE_DATE, -1);
303         assertNotSame(BASE_DATE, result);
304         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
305         assertDate(result, 2000, 6, 5, 4, 2, 2, 1);
306 
307         assertThrows(NullPointerException.class, () -> DateUtils.addMinutes(null, 0));
308     }
309 
310     @Test
311     public void testAddMonths() throws Exception {
312         Date result = DateUtils.addMonths(BASE_DATE, 0);
313         assertNotSame(BASE_DATE, result);
314         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
315         assertDate(result, 2000, 6, 5, 4, 3, 2, 1);
316 
317         result = DateUtils.addMonths(BASE_DATE, 1);
318         assertNotSame(BASE_DATE, result);
319         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
320         assertDate(result, 2000, 7, 5, 4, 3, 2, 1);
321 
322         result = DateUtils.addMonths(BASE_DATE, -1);
323         assertNotSame(BASE_DATE, result);
324         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
325         assertDate(result, 2000, 5, 5, 4, 3, 2, 1);
326 
327         assertThrows(NullPointerException.class, () -> DateUtils.addMonths(null, 0));
328     }
329 
330     @Test
331     public void testAddSeconds() throws Exception {
332         Date result = DateUtils.addSeconds(BASE_DATE, 0);
333         assertNotSame(BASE_DATE, result);
334         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
335         assertDate(result, 2000, 6, 5, 4, 3, 2, 1);
336 
337         result = DateUtils.addSeconds(BASE_DATE, 1);
338         assertNotSame(BASE_DATE, result);
339         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
340         assertDate(result, 2000, 6, 5, 4, 3, 3, 1);
341 
342         result = DateUtils.addSeconds(BASE_DATE, -1);
343         assertNotSame(BASE_DATE, result);
344         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
345         assertDate(result, 2000, 6, 5, 4, 3, 1, 1);
346 
347         assertThrows(NullPointerException.class, () -> DateUtils.addSeconds(null, 0));
348     }
349 
350     @Test
351     public void testAddWeeks() throws Exception {
352         Date result = DateUtils.addWeeks(BASE_DATE, 0);
353         assertNotSame(BASE_DATE, result);
354         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
355         assertDate(result, 2000, 6, 5, 4, 3, 2, 1);
356 
357         result = DateUtils.addWeeks(BASE_DATE, 1);
358         assertNotSame(BASE_DATE, result);
359         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
360         assertDate(result, 2000, 6, 12, 4, 3, 2, 1);
361 
362         result = DateUtils.addWeeks(BASE_DATE, -1);
363         assertNotSame(BASE_DATE, result);
364         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);      // july
365         assertDate(result, 2000, 5, 28, 4, 3, 2, 1);   // june
366 
367         assertThrows(NullPointerException.class, () -> DateUtils.addMonths(null, 0));
368     }
369 
370     @Test
371     public void testAddYears() throws Exception {
372         Date result = DateUtils.addYears(BASE_DATE, 0);
373         assertNotSame(BASE_DATE, result);
374         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
375         assertDate(result, 2000, 6, 5, 4, 3, 2, 1);
376 
377         result = DateUtils.addYears(BASE_DATE, 1);
378         assertNotSame(BASE_DATE, result);
379         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
380         assertDate(result, 2001, 6, 5, 4, 3, 2, 1);
381 
382         result = DateUtils.addYears(BASE_DATE, -1);
383         assertNotSame(BASE_DATE, result);
384         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
385         assertDate(result, 1999, 6, 5, 4, 3, 2, 1);
386 
387         assertThrows(NullPointerException.class, () -> DateUtils.addYears(null, 0));
388     }
389 
390     /**
391      * Tests various values with the ceiling method
392      *
393      * @throws Exception so we don't have to catch it
394      */
395     @Test
396     public void testCeil() throws Exception {
397         // test javadoc
398         assertEquals(dateTimeParser.parse("March 28, 2002 14:00:00.000"),
399                 DateUtils.ceiling(
400                             dateTimeParser.parse("March 28, 2002 13:45:01.231"),
401                         Calendar.HOUR),
402                 "ceiling javadoc-1 failed");
403         assertEquals(dateTimeParser.parse("April 1, 2002 00:00:00.000"),
404                 DateUtils.ceiling(
405                             dateTimeParser.parse("March 28, 2002 13:45:01.231"),
406                         Calendar.MONTH),
407                 "ceiling javadoc-2 failed");
408 
409         // tests public static Date ceiling(Date date, int field)
410         assertEquals(dateParser.parse("January 1, 2003"),
411                 DateUtils.ceiling(date1, Calendar.YEAR),
412                 "ceiling year-1 failed");
413         assertEquals(dateParser.parse("January 1, 2002"),
414                 DateUtils.ceiling(date2, Calendar.YEAR),
415                 "ceiling year-2 failed");
416         assertEquals(dateParser.parse("March 1, 2002"),
417                 DateUtils.ceiling(date1, Calendar.MONTH),
418                 "ceiling month-1 failed");
419         assertEquals(dateParser.parse("December 1, 2001"),
420                 DateUtils.ceiling(date2, Calendar.MONTH),
421                 "ceiling month-2 failed");
422         assertEquals(dateParser.parse("February 16, 2002"),
423                 DateUtils.ceiling(date1, DateUtils.SEMI_MONTH),
424                 "ceiling semimonth-1 failed");
425         assertEquals(dateParser.parse("December 1, 2001"),
426                 DateUtils.ceiling(date2, DateUtils.SEMI_MONTH),
427                 "ceiling semimonth-2 failed");
428         assertEquals(dateParser.parse("February 13, 2002"),
429                 DateUtils.ceiling(date1, Calendar.DATE),
430                 "ceiling date-1 failed");
431         assertEquals(dateParser.parse("November 19, 2001"),
432                 DateUtils.ceiling(date2, Calendar.DATE),
433                 "ceiling date-2 failed");
434         assertEquals(dateTimeParser.parse("February 12, 2002 13:00:00.000"),
435                 DateUtils.ceiling(date1, Calendar.HOUR),
436                 "ceiling hour-1 failed");
437         assertEquals(dateTimeParser.parse("November 18, 2001 2:00:00.000"),
438                 DateUtils.ceiling(date2, Calendar.HOUR),
439                 "ceiling hour-2 failed");
440         assertEquals(dateTimeParser.parse("February 12, 2002 12:35:00.000"),
441                 DateUtils.ceiling(date1, Calendar.MINUTE),
442                 "ceiling minute-1 failed");
443         assertEquals(dateTimeParser.parse("November 18, 2001 1:24:00.000"),
444                 DateUtils.ceiling(date2, Calendar.MINUTE),
445                 "ceiling minute-2 failed");
446         assertEquals(dateTimeParser.parse("February 12, 2002 12:34:57.000"),
447                 DateUtils.ceiling(date1, Calendar.SECOND),
448                 "ceiling second-1 failed");
449         assertEquals(dateTimeParser.parse("November 18, 2001 1:23:12.000"),
450                 DateUtils.ceiling(date2, Calendar.SECOND),
451                 "ceiling second-2 failed");
452         assertEquals(dateTimeParser.parse("February 3, 2002 12:00:00.000"),
453                 DateUtils.ceiling(dateAmPm1, Calendar.AM_PM),
454                 "ceiling ampm-1 failed");
455         assertEquals(dateTimeParser.parse("February 3, 2002 12:00:00.000"),
456                 DateUtils.ceiling(dateAmPm2, Calendar.AM_PM),
457                 "ceiling ampm-2 failed");
458         assertEquals(dateTimeParser.parse("February 4, 2002 00:00:00.000"),
459                 DateUtils.ceiling(dateAmPm3, Calendar.AM_PM),
460                 "ceiling ampm-3 failed");
461         assertEquals(dateTimeParser.parse("February 4, 2002 00:00:00.000"),
462                 DateUtils.ceiling(dateAmPm4, Calendar.AM_PM),
463                 "ceiling ampm-4 failed");
464 
465      // tests public static Date ceiling(Object date, int field)
466         assertEquals(dateParser.parse("January 1, 2003"),
467                 DateUtils.ceiling((Object) date1, Calendar.YEAR),
468                 "ceiling year-1 failed");
469         assertEquals(dateParser.parse("January 1, 2002"),
470                 DateUtils.ceiling((Object) date2, Calendar.YEAR),
471                 "ceiling year-2 failed");
472         assertEquals(dateParser.parse("March 1, 2002"),
473                 DateUtils.ceiling((Object) date1, Calendar.MONTH),
474                 "ceiling month-1 failed");
475         assertEquals(dateParser.parse("December 1, 2001"),
476                 DateUtils.ceiling((Object) date2, Calendar.MONTH),
477                 "ceiling month-2 failed");
478         assertEquals(dateParser.parse("February 16, 2002"),
479                 DateUtils.ceiling((Object) date1, DateUtils.SEMI_MONTH),
480                 "ceiling semimonth-1 failed");
481         assertEquals(dateParser.parse("December 1, 2001"),
482                 DateUtils.ceiling((Object) date2, DateUtils.SEMI_MONTH),
483                 "ceiling semimonth-2 failed");
484         assertEquals(dateParser.parse("February 13, 2002"),
485                 DateUtils.ceiling((Object) date1, Calendar.DATE),
486                 "ceiling date-1 failed");
487         assertEquals(dateParser.parse("November 19, 2001"),
488                 DateUtils.ceiling((Object) date2, Calendar.DATE),
489                 "ceiling date-2 failed");
490         assertEquals(dateTimeParser.parse("February 12, 2002 13:00:00.000"),
491                 DateUtils.ceiling((Object) date1, Calendar.HOUR),
492                 "ceiling hour-1 failed");
493         assertEquals(dateTimeParser.parse("November 18, 2001 2:00:00.000"),
494                 DateUtils.ceiling((Object) date2, Calendar.HOUR),
495                 "ceiling hour-2 failed");
496         assertEquals(dateTimeParser.parse("February 12, 2002 12:35:00.000"),
497                 DateUtils.ceiling((Object) date1, Calendar.MINUTE),
498                 "ceiling minute-1 failed");
499         assertEquals(dateTimeParser.parse("November 18, 2001 1:24:00.000"),
500                 DateUtils.ceiling((Object) date2, Calendar.MINUTE),
501                 "ceiling minute-2 failed");
502         assertEquals(dateTimeParser.parse("February 12, 2002 12:34:57.000"),
503                 DateUtils.ceiling((Object) date1, Calendar.SECOND),
504                 "ceiling second-1 failed");
505         assertEquals(dateTimeParser.parse("November 18, 2001 1:23:12.000"),
506                 DateUtils.ceiling((Object) date2, Calendar.SECOND),
507                 "ceiling second-2 failed");
508         assertEquals(dateTimeParser.parse("February 3, 2002 12:00:00.000"),
509                 DateUtils.ceiling((Object) dateAmPm1, Calendar.AM_PM),
510                 "ceiling ampm-1 failed");
511         assertEquals(dateTimeParser.parse("February 3, 2002 12:00:00.000"),
512                 DateUtils.ceiling((Object) dateAmPm2, Calendar.AM_PM),
513                 "ceiling ampm-2 failed");
514         assertEquals(dateTimeParser.parse("February 4, 2002 00:00:00.000"),
515                 DateUtils.ceiling((Object) dateAmPm3, Calendar.AM_PM),
516                 "ceiling ampm-3 failed");
517         assertEquals(dateTimeParser.parse("February 4, 2002 00:00:00.000"),
518                 DateUtils.ceiling((Object) dateAmPm4, Calendar.AM_PM),
519                 "ceiling ampm-4 failed");
520 
521         assertEquals(dateTimeParser.parse("February 12, 2002 12:34:57.000"),
522                 DateUtils.ceiling((Object) cal1, Calendar.SECOND),
523                 "ceiling calendar second-1 failed");
524         assertEquals(dateTimeParser.parse("November 18, 2001 1:23:12.000"),
525                 DateUtils.ceiling((Object) cal2, Calendar.SECOND),
526                 "ceiling calendar second-2 failed");
527 
528         assertEquals(dateTimeParser.parse("February 3, 2002 12:00:00.000"),
529                 DateUtils.ceiling((Object) calAmPm1, Calendar.AM_PM),
530                 "ceiling ampm-1 failed");
531         assertEquals(dateTimeParser.parse("February 3, 2002 12:00:00.000"),
532                 DateUtils.ceiling((Object) calAmPm2, Calendar.AM_PM),
533                 "ceiling ampm-2 failed");
534         assertEquals(dateTimeParser.parse("February 4, 2002 00:00:00.000"),
535                 DateUtils.ceiling((Object) calAmPm3, Calendar.AM_PM),
536                 "ceiling ampm-3 failed");
537         assertEquals(dateTimeParser.parse("February 4, 2002 00:00:00.000"),
538                 DateUtils.ceiling((Object) calAmPm4, Calendar.AM_PM),
539                 "ceiling ampm-4 failed");
540 
541         assertThrows(NullPointerException.class, () -> DateUtils.ceiling((Date) null, Calendar.SECOND));
542         assertThrows(NullPointerException.class, () -> DateUtils.ceiling((Calendar) null, Calendar.SECOND));
543         assertThrows(NullPointerException.class, () -> DateUtils.ceiling((Object) null, Calendar.SECOND));
544         assertThrows(ClassCastException.class, () -> DateUtils.ceiling("", Calendar.SECOND));
545         assertThrows(IllegalArgumentException.class, () -> DateUtils.ceiling(date1, -9999));
546 
547         // Fix for https://issues.apache.org/bugzilla/show_bug.cgi?id=25560
548         // Test ceiling across the beginning of daylight saving time
549         try {
550             TimeZone.setDefault(zone);
551             dateTimeParser.setTimeZone(zone);
552 
553             assertEquals(dateTimeParser.parse("March 31, 2003 00:00:00.000"),
554                     DateUtils.ceiling(date4, Calendar.DATE),
555                     "ceiling MET date across DST change-over");
556             assertEquals(dateTimeParser.parse("March 31, 2003 00:00:00.000"),
557                     DateUtils.ceiling((Object) cal4, Calendar.DATE),
558                     "ceiling MET date across DST change-over");
559             assertEquals(dateTimeParser.parse("March 31, 2003 00:00:00.000"),
560                     DateUtils.ceiling(date5, Calendar.DATE),
561                     "ceiling MET date across DST change-over");
562             assertEquals(dateTimeParser.parse("March 31, 2003 00:00:00.000"),
563                     DateUtils.ceiling((Object) cal5, Calendar.DATE),
564                     "ceiling MET date across DST change-over");
565             assertEquals(dateTimeParser.parse("March 31, 2003 00:00:00.000"),
566                     DateUtils.ceiling(date6, Calendar.DATE),
567                     "ceiling MET date across DST change-over");
568             assertEquals(dateTimeParser.parse("March 31, 2003 00:00:00.000"),
569                     DateUtils.ceiling((Object) cal6, Calendar.DATE),
570                     "ceiling MET date across DST change-over");
571             assertEquals(dateTimeParser.parse("March 31, 2003 00:00:00.000"),
572                     DateUtils.ceiling(date7, Calendar.DATE),
573                     "ceiling MET date across DST change-over");
574             assertEquals(dateTimeParser.parse("March 31, 2003 00:00:00.000"),
575                     DateUtils.ceiling((Object) cal7, Calendar.DATE),
576                     "ceiling MET date across DST change-over");
577 
578             assertEquals(dateTimeParser.parse("March 30, 2003 03:00:00.000"),
579                     DateUtils.ceiling(date4, Calendar.HOUR_OF_DAY),
580                     "ceiling MET date across DST change-over");
581             assertEquals(dateTimeParser.parse("March 30, 2003 03:00:00.000"),
582                     DateUtils.ceiling((Object) cal4, Calendar.HOUR_OF_DAY),
583                     "ceiling MET date across DST change-over");
584             assertEquals(dateTimeParser.parse("March 30, 2003 03:00:00.000"),
585                     DateUtils.ceiling(date5, Calendar.HOUR_OF_DAY),
586                     "ceiling MET date across DST change-over");
587             assertEquals(dateTimeParser.parse("March 30, 2003 03:00:00.000"),
588                     DateUtils.ceiling((Object) cal5, Calendar.HOUR_OF_DAY),
589                     "ceiling MET date across DST change-over");
590             assertEquals(dateTimeParser.parse("March 30, 2003 04:00:00.000"),
591                     DateUtils.ceiling(date6, Calendar.HOUR_OF_DAY),
592                     "ceiling MET date across DST change-over");
593             assertEquals(dateTimeParser.parse("March 30, 2003 04:00:00.000"),
594                     DateUtils.ceiling((Object) cal6, Calendar.HOUR_OF_DAY),
595                     "ceiling MET date across DST change-over");
596             assertEquals(dateTimeParser.parse("March 30, 2003 04:00:00.000"),
597                     DateUtils.ceiling(date7, Calendar.HOUR_OF_DAY),
598                     "ceiling MET date across DST change-over");
599             assertEquals(dateTimeParser.parse("March 30, 2003 04:00:00.000"),
600                     DateUtils.ceiling((Object) cal7, Calendar.HOUR_OF_DAY),
601                     "ceiling MET date across DST change-over");
602 
603         } finally {
604             TimeZone.setDefault(DEFAULT_ZONE);
605             dateTimeParser.setTimeZone(DEFAULT_ZONE);
606         }
607 
608         // Bug 31395, large dates
609         final Date endOfTime = new Date(Long.MAX_VALUE); // fyi: Sun Aug 17 07:12:55 CET 292278994 -- 807 millis
610         final GregorianCalendar endCal = new GregorianCalendar();
611         endCal.setTime(endOfTime);
612         assertThrows(ArithmeticException.class, () -> DateUtils.ceiling(endCal, Calendar.DATE));
613         endCal.set(Calendar.YEAR, 280000001);
614         assertThrows(ArithmeticException.class, () -> DateUtils.ceiling(endCal, Calendar.DATE));
615         endCal.set(Calendar.YEAR, 280000000);
616         final Calendar cal = DateUtils.ceiling(endCal, Calendar.DATE);
617         assertEquals(0, cal.get(Calendar.HOUR));
618     }
619 
620     @Test
621     public void testConstructor() {
622         assertNotNull(new DateUtils());
623         final Constructor<?>[] cons = DateUtils.class.getDeclaredConstructors();
624         assertEquals(1, cons.length);
625         assertTrue(Modifier.isPublic(cons[0].getModifiers()));
626         assertTrue(Modifier.isPublic(DateUtils.class.getModifiers()));
627         assertFalse(Modifier.isFinal(DateUtils.class.getModifiers()));
628     }
629 
630     @Test
631     public void testIsSameDay_Cal() {
632         final GregorianCalendar cala = new GregorianCalendar(2004, 6, 9, 13, 45);
633         final GregorianCalendar calb = new GregorianCalendar(2004, 6, 9, 13, 45);
634         assertTrue(DateUtils.isSameDay(cala, calb));
635         calb.add(Calendar.DAY_OF_YEAR, 1);
636         assertFalse(DateUtils.isSameDay(cala, calb));
637         cala.add(Calendar.DAY_OF_YEAR, 1);
638         assertTrue(DateUtils.isSameDay(cala, calb));
639         calb.add(Calendar.YEAR, 1);
640         assertFalse(DateUtils.isSameDay(cala, calb));
641     }
642 
643     @Test
644     public void testIsSameDay_CalNotNullNull() {
645         assertThrows(NullPointerException.class, () -> DateUtils.isSameDay(Calendar.getInstance(), null));
646     }
647 
648     @Test
649     public void testIsSameDay_CalNullNotNull() {
650         assertThrows(NullPointerException.class, () -> DateUtils.isSameDay(null, Calendar.getInstance()));
651     }
652 
653     @Test
654     public void testIsSameDay_CalNullNull() {
655         assertThrows(NullPointerException.class, () -> DateUtils.isSameDay((Calendar) null, null));
656     }
657 
658     @Test
659     public void testIsSameDay_Date() {
660         Date datea = new GregorianCalendar(2004, 6, 9, 13, 45).getTime();
661         Date dateb = new GregorianCalendar(2004, 6, 9, 13, 45).getTime();
662         assertTrue(DateUtils.isSameDay(datea, dateb));
663         dateb = new GregorianCalendar(2004, 6, 10, 13, 45).getTime();
664         assertFalse(DateUtils.isSameDay(datea, dateb));
665         datea = new GregorianCalendar(2004, 6, 10, 13, 45).getTime();
666         assertTrue(DateUtils.isSameDay(datea, dateb));
667         dateb = new GregorianCalendar(2005, 6, 10, 13, 45).getTime();
668         assertFalse(DateUtils.isSameDay(datea, dateb));
669     }
670 
671     @Test
672     public void testIsSameDay_DateNotNullNull() {
673         assertThrows(NullPointerException.class, () -> DateUtils.isSameDay(new Date(), null));
674     }
675 
676     @Test
677     public void testIsSameDay_DateNullNotNull() {
678         assertThrows(NullPointerException.class, () -> DateUtils.isSameDay(null, new Date()));
679     }
680 
681     @Test
682     public void testIsSameDay_DateNullNull() {
683         assertThrows(NullPointerException.class, () -> DateUtils.isSameDay((Date) null, null));
684     }
685 
686     @Test
687     public void testIsSameInstant_Cal() {
688         final GregorianCalendar cala = new GregorianCalendar(TimeZone.getTimeZone("GMT+1"));
689         final GregorianCalendar calb = new GregorianCalendar(TimeZone.getTimeZone("GMT-1"));
690         cala.set(2004, Calendar.JULY, 9, 13, 45, 0);
691         cala.set(Calendar.MILLISECOND, 0);
692         calb.set(2004, Calendar.JULY, 9, 13, 45, 0);
693         calb.set(Calendar.MILLISECOND, 0);
694         assertFalse(DateUtils.isSameInstant(cala, calb));
695 
696         calb.set(2004, Calendar.JULY, 9, 11, 45, 0);
697         assertTrue(DateUtils.isSameInstant(cala, calb));
698     }
699 
700     @Test
701     public void testIsSameInstant_CalNotNullNull() {
702         assertThrows(NullPointerException.class, () -> DateUtils.isSameInstant(Calendar.getInstance(), null));
703     }
704 
705     @Test
706     public void testIsSameInstant_CalNullNotNull() {
707         assertThrows(NullPointerException.class, () -> DateUtils.isSameInstant(null, Calendar.getInstance()));
708     }
709 
710     @Test
711     public void testIsSameInstant_CalNullNull() {
712         assertThrows(NullPointerException.class, () -> DateUtils.isSameInstant((Calendar) null, null));
713     }
714 
715     @Test
716     public void testIsSameInstant_Date() {
717         Date datea = new GregorianCalendar(2004, 6, 9, 13, 45).getTime();
718         Date dateb = new GregorianCalendar(2004, 6, 9, 13, 45).getTime();
719         assertTrue(DateUtils.isSameInstant(datea, dateb));
720         dateb = new GregorianCalendar(2004, 6, 10, 13, 45).getTime();
721         assertFalse(DateUtils.isSameInstant(datea, dateb));
722         datea = new GregorianCalendar(2004, 6, 10, 13, 45).getTime();
723         assertTrue(DateUtils.isSameInstant(datea, dateb));
724         dateb = new GregorianCalendar(2005, 6, 10, 13, 45).getTime();
725         assertFalse(DateUtils.isSameInstant(datea, dateb));
726     }
727 
728     @Test
729     public void testIsSameInstant_DateNotNullNull() {
730         assertThrows(NullPointerException.class, () -> DateUtils.isSameInstant(new Date(), null));
731     }
732 
733     @Test
734     public void testIsSameInstant_DateNullNotNull() {
735         assertThrows(NullPointerException.class, () -> DateUtils.isSameInstant(null, new Date()));
736     }
737 
738     @Test
739     public void testIsSameInstant_DateNullNull() {
740         assertThrows(NullPointerException.class, () -> DateUtils.isSameInstant((Date) null, null));
741     }
742 
743     @Test
744     public void testIsSameLocalTime_Cal() {
745         final GregorianCalendar cala = new GregorianCalendar(TimeZone.getTimeZone("GMT+1"));
746         final GregorianCalendar calb = new GregorianCalendar(TimeZone.getTimeZone("GMT-1"));
747         cala.set(2004, Calendar.JULY, 9, 13, 45, 0);
748         cala.set(Calendar.MILLISECOND, 0);
749         calb.set(2004, Calendar.JULY, 9, 13, 45, 0);
750         calb.set(Calendar.MILLISECOND, 0);
751         assertTrue(DateUtils.isSameLocalTime(cala, calb));
752 
753         final Calendar calc = Calendar.getInstance();
754         final Calendar cald = Calendar.getInstance();
755         calc.set(2004, Calendar.JULY, 9, 4,  0, 0);
756         cald.set(2004, Calendar.JULY, 9, 16, 0, 0);
757         calc.set(Calendar.MILLISECOND, 0);
758         cald.set(Calendar.MILLISECOND, 0);
759         assertFalse(DateUtils.isSameLocalTime(calc, cald), "LANG-677");
760 
761         calb.set(2004, Calendar.JULY, 9, 11, 45, 0);
762         assertFalse(DateUtils.isSameLocalTime(cala, calb));
763     }
764 
765     @Test
766     public void testIsSameLocalTime_CalNotNullNull() {
767         assertThrows(NullPointerException.class, () -> DateUtils.isSameLocalTime(Calendar.getInstance(), null));
768     }
769 
770     @Test
771     public void testIsSameLocalTime_CalNullNotNull() {
772         assertThrows(NullPointerException.class, () -> DateUtils.isSameLocalTime(null, Calendar.getInstance()));
773     }
774 
775     @Test
776     public void testIsSameLocalTime_CalNullNull() {
777         assertThrows(NullPointerException.class, () -> DateUtils.isSameLocalTime(null, null));
778     }
779 
780     /**
781      * Tests the iterator exceptions
782      */
783     @Test
784     public void testIteratorEx() {
785         assertThrows(IllegalArgumentException.class, () -> DateUtils.iterator(Calendar.getInstance(), -9999));
786         assertThrows(NullPointerException.class, () -> DateUtils.iterator((Date) null, DateUtils.RANGE_WEEK_CENTER));
787         assertThrows(NullPointerException.class, () -> DateUtils.iterator((Calendar) null, DateUtils.RANGE_WEEK_CENTER));
788         assertThrows(NullPointerException.class, () -> DateUtils.iterator((Object) null, DateUtils.RANGE_WEEK_CENTER));
789         assertThrows(ClassCastException.class, () -> DateUtils.iterator("", DateUtils.RANGE_WEEK_CENTER));
790     }
791 
792     /** https://issues.apache.org/jira/browse/LANG-530 */
793     @SuppressWarnings("deprecation")
794     @Test
795     public void testLang530() throws ParseException {
796         final Date d = new Date();
797         final String isoDateStr = DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.format(d);
798         final Date d2 = DateUtils.parseDate(isoDateStr, DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.getPattern());
799         // the format loses milliseconds so have to reintroduce them
800         assertEquals(d.getTime(), d2.getTime() + d.getTime() % 1000, "Date not equal to itself ISO formatted and parsed");
801     }
802 
803     @Test
804     public void testLANG799() throws ParseException {
805         DateUtils.parseDateStrictly("09 abril 2008 23:55:38 GMT", new Locale("es"), "dd MMM yyyy HH:mm:ss zzz");
806     }
807 
808     /** Parse English date with German Locale. */
809     @DefaultLocale(language = "de")
810     @Test
811     public void testLANG799_DE_FAIL() {
812         assertThrows(ParseException.class, () -> DateUtils.parseDate("Wed, 09 Apr 2008 23:55:38 GMT", "EEE, dd MMM yyyy HH:mm:ss zzz"));
813     }
814 
815     @DefaultLocale(language = "de")
816     @Test
817     public void testLANG799_DE_OK() throws ParseException {
818         DateUtils.parseDate("Mi, 09 Apr 2008 23:55:38 GMT", "EEE, dd MMM yyyy HH:mm:ss zzz");
819         DateUtils.parseDateStrictly("Mi, 09 Apr 2008 23:55:38 GMT", "EEE, dd MMM yyyy HH:mm:ss zzz");
820     }
821 
822     // Parse German date with English Locale
823     @DefaultLocale(language = "en")
824     @Test
825     public void testLANG799_EN_FAIL() {
826         assertThrows(ParseException.class, () -> DateUtils.parseDate("Mi, 09 Apr 2008 23:55:38 GMT", "EEE, dd MMM yyyy HH:mm:ss zzz"));
827     }
828 
829     @DefaultLocale(language = "en")
830     @Test
831     public void testLANG799_EN_OK() throws ParseException {
832         DateUtils.parseDate("Wed, 09 Apr 2008 23:55:38 GMT", "EEE, dd MMM yyyy HH:mm:ss zzz");
833         DateUtils.parseDateStrictly("Wed, 09 Apr 2008 23:55:38 GMT", "EEE, dd MMM yyyy HH:mm:ss zzz");
834     }
835 
836     /** Parse German date with English Locale, specifying German Locale override. */
837     @DefaultLocale(language = "en")
838     @Test
839     public void testLANG799_EN_WITH_DE_LOCALE() throws ParseException {
840         DateUtils.parseDate("Mi, 09 Apr 2008 23:55:38 GMT", Locale.GERMAN, "EEE, dd MMM yyyy HH:mm:ss zzz");
841     }
842 
843     /**
844      * Tests the calendar iterator for month-based ranges
845      *
846      * @throws Exception so we don't have to catch it
847      */
848     @Test
849     public void testMonthIterator() throws Exception {
850         Iterator<?> it = DateUtils.iterator(date1, DateUtils.RANGE_MONTH_SUNDAY);
851         assertWeekIterator(it,
852                 dateParser.parse("January 27, 2002"),
853                 dateParser.parse("March 2, 2002"));
854 
855         it = DateUtils.iterator(date1, DateUtils.RANGE_MONTH_MONDAY);
856         assertWeekIterator(it,
857                 dateParser.parse("January 28, 2002"),
858                 dateParser.parse("March 3, 2002"));
859 
860         it = DateUtils.iterator(date2, DateUtils.RANGE_MONTH_SUNDAY);
861         assertWeekIterator(it,
862                 dateParser.parse("October 28, 2001"),
863                 dateParser.parse("December 1, 2001"));
864 
865         it = DateUtils.iterator(date2, DateUtils.RANGE_MONTH_MONDAY);
866         assertWeekIterator(it,
867                 dateParser.parse("October 29, 2001"),
868                 dateParser.parse("December 2, 2001"));
869     }
870 
871     @Test
872     public void testParse_EmptyParsers() {
873         assertThrows(ParseException.class, () -> DateUtils.parseDate("19721203"));
874     }
875 
876     @Test
877     public void testParse_NullParsers() {
878         assertThrows(NullPointerException.class, () -> DateUtils.parseDate("19721203", (String[]) null));
879     }
880 
881     @Test
882     public void testParseDate() throws Exception {
883         final GregorianCalendar cal = new GregorianCalendar(1972, 11, 3);
884         String dateStr = "1972-12-03";
885         final String[] parsers = {"yyyy'-'DDD", "yyyy'-'MM'-'dd", "yyyyMMdd"};
886         Date date = DateUtils.parseDate(dateStr, parsers);
887         assertEquals(cal.getTime(), date);
888 
889         dateStr = "1972-338";
890         date = DateUtils.parseDate(dateStr, parsers);
891         assertEquals(cal.getTime(), date);
892 
893         dateStr = "19721203";
894         date = DateUtils.parseDate(dateStr, parsers);
895         assertEquals(cal.getTime(), date);
896     }
897 
898     @Test
899     public void testParseDate_InvalidDateString() {
900         final String[] parsers = {"yyyy'-'DDD", "yyyy'-'MM'-'dd", "yyyyMMdd"};
901         assertThrows(ParseException.class, () -> DateUtils.parseDate("197212AB", parsers));
902     }
903 
904     @Test
905     public void testParseDate_NoDateString() {
906         final String[] parsers = {"yyyy'-'DDD", "yyyy'-'MM'-'dd", "yyyyMMdd"};
907         assertThrows(ParseException.class, () -> DateUtils.parseDate("PURPLE", parsers));
908     }
909 
910     @Test
911     public void testParseDate_Null() {
912         final String[] parsers = {"yyyy'-'DDD", "yyyy'-'MM'-'dd", "yyyyMMdd"};
913         assertThrows(NullPointerException.class, () -> DateUtils.parseDate(null, parsers));
914     }
915 
916     /** LANG-486 */
917     @Test
918     public void testParseDateWithLeniency() throws ParseException {
919         final GregorianCalendar cal = new GregorianCalendar(1998, 6, 30);
920         final String dateStr = "02 942, 1996";
921         final String[] parsers = {"MM DDD, yyyy"};
922 
923         final Date date = DateUtils.parseDate(dateStr, parsers);
924         assertEquals(cal.getTime(), date);
925 
926         assertThrows(ParseException.class, () -> DateUtils.parseDateStrictly(dateStr, parsers));
927     }
928 
929     /**
930      * Tests various values with the round method
931      *
932      * @throws Exception so we don't have to catch it
933      */
934     @Test
935     public void testRound() throws Exception {
936         // tests for public static Date round(Date date, int field)
937         assertEquals(dateParser.parse("January 1, 2002"),
938                 DateUtils.round(date1, Calendar.YEAR),
939                 "round year-1 failed");
940         assertEquals(dateParser.parse("January 1, 2002"),
941                 DateUtils.round(date2, Calendar.YEAR),
942                 "round year-2 failed");
943         assertEquals(dateParser.parse("February 1, 2002"),
944                 DateUtils.round(date1, Calendar.MONTH),
945                 "round month-1 failed");
946         assertEquals(dateParser.parse("December 1, 2001"),
947                 DateUtils.round(date2, Calendar.MONTH),
948                 "round month-2 failed");
949         assertEquals(dateParser.parse("February 1, 2002"),
950                 DateUtils.round(date0, DateUtils.SEMI_MONTH),
951                 "round semimonth-0 failed");
952         assertEquals(dateParser.parse("February 16, 2002"),
953                 DateUtils.round(date1, DateUtils.SEMI_MONTH),
954                 "round semimonth-1 failed");
955         assertEquals(dateParser.parse("November 16, 2001"),
956                 DateUtils.round(date2, DateUtils.SEMI_MONTH),
957                 "round semimonth-2 failed");
958 
959 
960         assertEquals(dateParser.parse("February 13, 2002"),
961                 DateUtils.round(date1, Calendar.DATE),
962                 "round date-1 failed");
963         assertEquals(dateParser.parse("November 18, 2001"),
964                 DateUtils.round(date2, Calendar.DATE),
965                 "round date-2 failed");
966         assertEquals(dateTimeParser.parse("February 12, 2002 13:00:00.000"),
967                 DateUtils.round(date1, Calendar.HOUR),
968                 "round hour-1 failed");
969         assertEquals(dateTimeParser.parse("November 18, 2001 1:00:00.000"),
970                 DateUtils.round(date2, Calendar.HOUR),
971                 "round hour-2 failed");
972         assertEquals(dateTimeParser.parse("February 12, 2002 12:35:00.000"),
973                 DateUtils.round(date1, Calendar.MINUTE),
974                 "round minute-1 failed");
975         assertEquals(dateTimeParser.parse("November 18, 2001 1:23:00.000"),
976                 DateUtils.round(date2, Calendar.MINUTE),
977                 "round minute-2 failed");
978         assertEquals(dateTimeParser.parse("February 12, 2002 12:34:57.000"),
979                 DateUtils.round(date1, Calendar.SECOND),
980                 "round second-1 failed");
981         assertEquals(dateTimeParser.parse("November 18, 2001 1:23:11.000"),
982                 DateUtils.round(date2, Calendar.SECOND),
983                 "round second-2 failed");
984         assertEquals(dateTimeParser.parse("February 3, 2002 00:00:00.000"),
985                 DateUtils.round(dateAmPm1, Calendar.AM_PM),
986                 "round ampm-1 failed");
987         assertEquals(dateTimeParser.parse("February 3, 2002 12:00:00.000"),
988                 DateUtils.round(dateAmPm2, Calendar.AM_PM),
989                 "round ampm-2 failed");
990         assertEquals(dateTimeParser.parse("February 3, 2002 12:00:00.000"),
991                 DateUtils.round(dateAmPm3, Calendar.AM_PM),
992                 "round ampm-3 failed");
993         assertEquals(dateTimeParser.parse("February 4, 2002 00:00:00.000"),
994                 DateUtils.round(dateAmPm4, Calendar.AM_PM),
995                 "round ampm-4 failed");
996 
997         // tests for public static Date round(Object date, int field)
998         assertEquals(dateParser.parse("January 1, 2002"),
999                 DateUtils.round((Object) date1, Calendar.YEAR),
1000                 "round year-1 failed");
1001         assertEquals(dateParser.parse("January 1, 2002"),
1002                 DateUtils.round((Object) date2, Calendar.YEAR),
1003                 "round year-2 failed");
1004         assertEquals(dateParser.parse("February 1, 2002"),
1005                 DateUtils.round((Object) date1, Calendar.MONTH),
1006                 "round month-1 failed");
1007         assertEquals(dateParser.parse("December 1, 2001"),
1008                 DateUtils.round((Object) date2, Calendar.MONTH),
1009                 "round month-2 failed");
1010         assertEquals(dateParser.parse("February 16, 2002"),
1011                 DateUtils.round((Object) date1, DateUtils.SEMI_MONTH),
1012                 "round semimonth-1 failed");
1013         assertEquals(dateParser.parse("November 16, 2001"),
1014                 DateUtils.round((Object) date2, DateUtils.SEMI_MONTH),
1015                 "round semimonth-2 failed");
1016         assertEquals(dateParser.parse("February 13, 2002"),
1017                 DateUtils.round((Object) date1, Calendar.DATE),
1018                 "round date-1 failed");
1019         assertEquals(dateParser.parse("November 18, 2001"),
1020                 DateUtils.round((Object) date2, Calendar.DATE),
1021                 "round date-2 failed");
1022         assertEquals(dateTimeParser.parse("February 12, 2002 13:00:00.000"),
1023                 DateUtils.round((Object) date1, Calendar.HOUR),
1024                 "round hour-1 failed");
1025         assertEquals(dateTimeParser.parse("November 18, 2001 1:00:00.000"),
1026                 DateUtils.round((Object) date2, Calendar.HOUR),
1027                 "round hour-2 failed");
1028         assertEquals(dateTimeParser.parse("February 12, 2002 12:35:00.000"),
1029                 DateUtils.round((Object) date1, Calendar.MINUTE),
1030                 "round minute-1 failed");
1031         assertEquals(dateTimeParser.parse("November 18, 2001 1:23:00.000"),
1032                 DateUtils.round((Object) date2, Calendar.MINUTE),
1033                 "round minute-2 failed");
1034         assertEquals(dateTimeParser.parse("February 12, 2002 12:34:57.000"),
1035                 DateUtils.round((Object) date1, Calendar.SECOND),
1036                 "round second-1 failed");
1037         assertEquals(dateTimeParser.parse("November 18, 2001 1:23:11.000"),
1038                 DateUtils.round((Object) date2, Calendar.SECOND),
1039                 "round second-2 failed");
1040         assertEquals(dateTimeParser.parse("February 12, 2002 12:34:57.000"),
1041                 DateUtils.round((Object) cal1, Calendar.SECOND),
1042                 "round calendar second-1 failed");
1043         assertEquals(dateTimeParser.parse("November 18, 2001 1:23:11.000"),
1044                 DateUtils.round((Object) cal2, Calendar.SECOND),
1045                 "round calendar second-2 failed");
1046         assertEquals(dateTimeParser.parse("February 3, 2002 00:00:00.000"),
1047                 DateUtils.round((Object) dateAmPm1, Calendar.AM_PM),
1048                 "round ampm-1 failed");
1049         assertEquals(dateTimeParser.parse("February 3, 2002 12:00:00.000"),
1050                 DateUtils.round((Object) dateAmPm2, Calendar.AM_PM),
1051                 "round ampm-2 failed");
1052         assertEquals(dateTimeParser.parse("February 3, 2002 12:00:00.000"),
1053                 DateUtils.round((Object) dateAmPm3, Calendar.AM_PM),
1054                 "round ampm-3 failed");
1055         assertEquals(dateTimeParser.parse("February 4, 2002 00:00:00.000"),
1056                 DateUtils.round((Object) dateAmPm4, Calendar.AM_PM),
1057                 "round ampm-4 failed");
1058 
1059         assertThrows(NullPointerException.class, () -> DateUtils.round((Date) null, Calendar.SECOND));
1060         assertThrows(NullPointerException.class, () -> DateUtils.round((Calendar) null, Calendar.SECOND));
1061         assertThrows(NullPointerException.class, () -> DateUtils.round((Object) null, Calendar.SECOND));
1062         assertThrows(ClassCastException.class, () -> DateUtils.round("", Calendar.SECOND));
1063         assertThrows(IllegalArgumentException.class, () -> DateUtils.round(date1, -9999));
1064 
1065         assertEquals(dateTimeParser.parse("February 3, 2002 00:00:00.000"),
1066                 DateUtils.round((Object) calAmPm1, Calendar.AM_PM),
1067                 "round ampm-1 failed");
1068         assertEquals(dateTimeParser.parse("February 3, 2002 12:00:00.000"),
1069                 DateUtils.round((Object) calAmPm2, Calendar.AM_PM),
1070                 "round ampm-2 failed");
1071         assertEquals(dateTimeParser.parse("February 3, 2002 12:00:00.000"),
1072                 DateUtils.round((Object) calAmPm3, Calendar.AM_PM),
1073                 "round ampm-3 failed");
1074         assertEquals(dateTimeParser.parse("February 4, 2002 00:00:00.000"),
1075                 DateUtils.round((Object) calAmPm4, Calendar.AM_PM),
1076                 "round ampm-4 failed");
1077 
1078         // Fix for https://issues.apache.org/bugzilla/show_bug.cgi?id=25560 / LANG-13
1079         // Test rounding across the beginning of daylight saving time
1080         try {
1081             TimeZone.setDefault(zone);
1082             dateTimeParser.setTimeZone(zone);
1083             assertEquals(dateTimeParser.parse("March 30, 2003 00:00:00.000"),
1084                     DateUtils.round(date4, Calendar.DATE),
1085                     "round MET date across DST change-over");
1086             assertEquals(dateTimeParser.parse("March 30, 2003 00:00:00.000"),
1087                     DateUtils.round((Object) cal4, Calendar.DATE),
1088                     "round MET date across DST change-over");
1089             assertEquals(dateTimeParser.parse("March 30, 2003 00:00:00.000"),
1090                     DateUtils.round(date5, Calendar.DATE),
1091                     "round MET date across DST change-over");
1092             assertEquals(dateTimeParser.parse("March 30, 2003 00:00:00.000"),
1093                     DateUtils.round((Object) cal5, Calendar.DATE),
1094                     "round MET date across DST change-over");
1095             assertEquals(dateTimeParser.parse("March 30, 2003 00:00:00.000"),
1096                     DateUtils.round(date6, Calendar.DATE),
1097                     "round MET date across DST change-over");
1098             assertEquals(dateTimeParser.parse("March 30, 2003 00:00:00.000"),
1099                     DateUtils.round((Object) cal6, Calendar.DATE),
1100                     "round MET date across DST change-over");
1101             assertEquals(dateTimeParser.parse("March 30, 2003 00:00:00.000"),
1102                     DateUtils.round(date7, Calendar.DATE),
1103                     "round MET date across DST change-over");
1104             assertEquals(dateTimeParser.parse("March 30, 2003 00:00:00.000"),
1105                     DateUtils.round((Object) cal7, Calendar.DATE),
1106                     "round MET date across DST change-over");
1107 
1108             assertEquals(dateTimeParser.parse("March 30, 2003 01:00:00.000"),
1109                     DateUtils.round(date4, Calendar.HOUR_OF_DAY),
1110                     "round MET date across DST change-over");
1111             assertEquals(dateTimeParser.parse("March 30, 2003 01:00:00.000"),
1112                     DateUtils.round((Object) cal4, Calendar.HOUR_OF_DAY),
1113                     "round MET date across DST change-over");
1114             assertEquals(dateTimeParser.parse("March 30, 2003 03:00:00.000"),
1115                     DateUtils.round(date5, Calendar.HOUR_OF_DAY),
1116                     "round MET date across DST change-over");
1117             assertEquals(dateTimeParser.parse("March 30, 2003 03:00:00.000"),
1118                     DateUtils.round((Object) cal5, Calendar.HOUR_OF_DAY),
1119                     "round MET date across DST change-over");
1120             assertEquals(dateTimeParser.parse("March 30, 2003 03:00:00.000"),
1121                     DateUtils.round(date6, Calendar.HOUR_OF_DAY),
1122                     "round MET date across DST change-over");
1123             assertEquals(dateTimeParser.parse("March 30, 2003 03:00:00.000"),
1124                     DateUtils.round((Object) cal6, Calendar.HOUR_OF_DAY),
1125                     "round MET date across DST change-over");
1126             assertEquals(dateTimeParser.parse("March 30, 2003 04:00:00.000"),
1127                     DateUtils.round(date7, Calendar.HOUR_OF_DAY),
1128                     "round MET date across DST change-over");
1129             assertEquals(dateTimeParser.parse("March 30, 2003 04:00:00.000"),
1130                     DateUtils.round((Object) cal7, Calendar.HOUR_OF_DAY),
1131                     "round MET date across DST change-over");
1132         } finally {
1133             TimeZone.setDefault(DEFAULT_ZONE);
1134             dateTimeParser.setTimeZone(DEFAULT_ZONE);
1135         }
1136     }
1137 
1138     /**
1139      * Tests the Changes Made by LANG-346 to the DateUtils.modify() private method invoked
1140      * by DateUtils.round().
1141      *
1142      * @throws Exception so we don't have to catch it
1143      */
1144     @Test
1145     public void testRoundLang346() throws Exception {
1146         final Calendar testCalendar = Calendar.getInstance();
1147         testCalendar.set(2007, Calendar.JULY, 2, 8, 8, 50);
1148         Date date = testCalendar.getTime();
1149         assertEquals(dateTimeParser.parse("July 2, 2007 08:09:00.000"),
1150                 DateUtils.round(date, Calendar.MINUTE),
1151                 "Minute Round Up Failed");
1152 
1153         testCalendar.set(2007, Calendar.JULY, 2, 8, 8, 20);
1154         date = testCalendar.getTime();
1155         assertEquals(dateTimeParser.parse("July 2, 2007 08:08:00.000"),
1156                 DateUtils.round(date, Calendar.MINUTE),
1157                 "Minute No Round Failed");
1158 
1159         testCalendar.set(2007, Calendar.JULY, 2, 8, 8, 50);
1160         testCalendar.set(Calendar.MILLISECOND, 600);
1161         date = testCalendar.getTime();
1162 
1163         assertEquals(dateTimeParser.parse("July 2, 2007 08:08:51.000"),
1164                 DateUtils.round(date, Calendar.SECOND),
1165                 "Second Round Up with 600 Milli Seconds Failed");
1166 
1167         testCalendar.set(2007, Calendar.JULY, 2, 8, 8, 50);
1168         testCalendar.set(Calendar.MILLISECOND, 200);
1169         date = testCalendar.getTime();
1170         assertEquals(dateTimeParser.parse("July 2, 2007 08:08:50.000"),
1171                 DateUtils.round(date, Calendar.SECOND),
1172                 "Second Round Down with 200 Milli Seconds Failed");
1173 
1174         testCalendar.set(2007, Calendar.JULY, 2, 8, 8, 20);
1175         testCalendar.set(Calendar.MILLISECOND, 600);
1176         date = testCalendar.getTime();
1177         assertEquals(dateTimeParser.parse("July 2, 2007 08:08:21.000"),
1178                 DateUtils.round(date, Calendar.SECOND),
1179                 "Second Round Up with 200 Milli Seconds Failed");
1180 
1181         testCalendar.set(2007, Calendar.JULY, 2, 8, 8, 20);
1182         testCalendar.set(Calendar.MILLISECOND, 200);
1183         date = testCalendar.getTime();
1184         assertEquals(dateTimeParser.parse("July 2, 2007 08:08:20.000"),
1185                 DateUtils.round(date, Calendar.SECOND),
1186                 "Second Round Down with 200 Milli Seconds Failed");
1187 
1188         testCalendar.set(2007, Calendar.JULY, 2, 8, 8, 50);
1189         date = testCalendar.getTime();
1190         assertEquals(dateTimeParser.parse("July 2, 2007 08:00:00.000"),
1191                 DateUtils.round(date, Calendar.HOUR),
1192                 "Hour Round Down Failed");
1193 
1194         testCalendar.set(2007, Calendar.JULY, 2, 8, 31, 50);
1195         date = testCalendar.getTime();
1196         assertEquals(dateTimeParser.parse("July 2, 2007 09:00:00.000"),
1197                 DateUtils.round(date, Calendar.HOUR),
1198                 "Hour Round Up Failed");
1199     }
1200 
1201     @Test
1202     public void testSetDays() throws Exception {
1203         Date result = DateUtils.setDays(BASE_DATE, 1);
1204         assertNotSame(BASE_DATE, result);
1205         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
1206         assertDate(result, 2000, 6, 1, 4, 3, 2, 1);
1207 
1208         result = DateUtils.setDays(BASE_DATE, 29);
1209         assertNotSame(BASE_DATE, result);
1210         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
1211         assertDate(result, 2000, 6, 29, 4, 3, 2, 1);
1212 
1213         final String outsideOfRangeAssertionMessage = "DateUtils.setDays did not throw an expected IllegalArgumentException for amount outside of range 1 to 31.";
1214         assertThrows(
1215                 IllegalArgumentException.class,
1216                 () -> DateUtils.setDays(BASE_DATE, 32),
1217                 outsideOfRangeAssertionMessage);
1218         assertThrows(
1219                 IllegalArgumentException.class,
1220                 () -> DateUtils.setDays(BASE_DATE, 0),
1221                 outsideOfRangeAssertionMessage);
1222 
1223         assertThrows(NullPointerException.class, () -> DateUtils.setDays(null, 1));
1224     }
1225 
1226     @Test
1227     public void testSetHours() throws Exception {
1228         Date result = DateUtils.setHours(BASE_DATE, 0);
1229         assertNotSame(BASE_DATE, result);
1230         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
1231         assertDate(result, 2000, 6, 5, 0, 3, 2, 1);
1232 
1233         result = DateUtils.setHours(BASE_DATE, 23);
1234         assertNotSame(BASE_DATE, result);
1235         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
1236         assertDate(result, 2000, 6, 5, 23, 3, 2, 1);
1237 
1238         final String outsideOfRangeAssertionMessage = "DateUtils.setHours did not throw an expected IllegalArgumentException for amount outside of range 0 to 23.";
1239         assertThrows(
1240                 IllegalArgumentException.class,
1241                 () -> DateUtils.setHours(BASE_DATE, 24),
1242                 outsideOfRangeAssertionMessage);
1243         assertThrows(
1244                 IllegalArgumentException.class,
1245                 () -> DateUtils.setHours(BASE_DATE, -1),
1246                 outsideOfRangeAssertionMessage);
1247 
1248         assertThrows(NullPointerException.class, () -> DateUtils.setHours(null, 0));
1249     }
1250 
1251     @Test
1252     public void testSetMilliseconds() throws Exception {
1253         Date result = DateUtils.setMilliseconds(BASE_DATE, 0);
1254         assertNotSame(BASE_DATE, result);
1255         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
1256         assertDate(result, 2000, 6, 5, 4, 3, 2, 0);
1257 
1258         result = DateUtils.setMilliseconds(BASE_DATE, 999);
1259         assertNotSame(BASE_DATE, result);
1260         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
1261         assertDate(result, 2000, 6, 5, 4, 3, 2, 999);
1262 
1263         final String outsideOfRangeAssertionMessage = "DateUtils.setMilliseconds did not throw an expected IllegalArgumentException for range outside of 0 to 999.";
1264         assertThrows(
1265                 IllegalArgumentException.class,
1266                 () -> DateUtils.setMilliseconds(BASE_DATE, 1000),
1267                 outsideOfRangeAssertionMessage);
1268         assertThrows(
1269                 IllegalArgumentException.class,
1270                 () -> DateUtils.setMilliseconds(BASE_DATE, -1),
1271                 outsideOfRangeAssertionMessage);
1272 
1273         assertThrows(NullPointerException.class, () -> DateUtils.setMilliseconds(null, 0));
1274     }
1275 
1276     @Test
1277     public void testSetMinutes() throws Exception {
1278         Date result = DateUtils.setMinutes(BASE_DATE, 0);
1279         assertNotSame(BASE_DATE, result);
1280         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
1281         assertDate(result, 2000, 6, 5, 4, 0, 2, 1);
1282 
1283         result = DateUtils.setMinutes(BASE_DATE, 59);
1284         assertNotSame(BASE_DATE, result);
1285         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
1286         assertDate(result, 2000, 6, 5, 4, 59, 2, 1);
1287 
1288         final String outsideOfRangeAssertionMessage = "DateUtils.setMinutes did not throw an expected IllegalArgumentException for amount outside of range 0 to 59.";
1289         assertThrows(
1290                 IllegalArgumentException.class,
1291                 () -> DateUtils.setMinutes(BASE_DATE, 60),
1292                 outsideOfRangeAssertionMessage);
1293         assertThrows(
1294                 IllegalArgumentException.class,
1295                 () -> DateUtils.setMinutes(BASE_DATE, -1),
1296                 outsideOfRangeAssertionMessage);
1297 
1298         assertThrows(NullPointerException.class, () -> DateUtils.setMinutes(null, 0));
1299     }
1300 
1301     @Test
1302     public void testSetMonths() throws Exception {
1303         Date result = DateUtils.setMonths(BASE_DATE, 5);
1304         assertNotSame(BASE_DATE, result);
1305         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
1306         assertDate(result, 2000, 5, 5, 4, 3, 2, 1);
1307 
1308         result = DateUtils.setMonths(BASE_DATE, 1);
1309         assertNotSame(BASE_DATE, result);
1310         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
1311         assertDate(result, 2000, 1, 5, 4, 3, 2, 1);
1312 
1313         result = DateUtils.setMonths(BASE_DATE, 0);
1314         assertNotSame(BASE_DATE, result);
1315         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
1316         assertDate(result, 2000, 0, 5, 4, 3, 2, 1);
1317 
1318         final String outsideOfRangeAssertionMessage = "DateUtils.setMonths did not throw an expected IllegalArgumentException for amount outside of range 0 to 11.";
1319         assertThrows(
1320                 IllegalArgumentException.class,
1321                 () -> DateUtils.setMonths(BASE_DATE, 12),
1322                 outsideOfRangeAssertionMessage);
1323         assertThrows(
1324                 IllegalArgumentException.class,
1325                 () -> DateUtils.setMonths(BASE_DATE, -1),
1326                 outsideOfRangeAssertionMessage);
1327 
1328         assertThrows(NullPointerException.class, () -> DateUtils.setMonths(null, 0));
1329     }
1330 
1331     @Test
1332     public void testSetSeconds() throws Exception {
1333         Date result = DateUtils.setSeconds(BASE_DATE, 0);
1334         assertNotSame(BASE_DATE, result);
1335         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
1336         assertDate(result, 2000, 6, 5, 4, 3, 0, 1);
1337 
1338         result = DateUtils.setSeconds(BASE_DATE, 59);
1339         assertNotSame(BASE_DATE, result);
1340         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
1341         assertDate(result, 2000, 6, 5, 4, 3, 59, 1);
1342 
1343         final String outsideOfRangeAssertionMessage = "DateUtils.setSeconds did not throw an expected IllegalArgumentException for amount outside of range 0 to 59.";
1344         assertThrows(
1345                 IllegalArgumentException.class,
1346                 () -> DateUtils.setSeconds(BASE_DATE, 60),
1347                 outsideOfRangeAssertionMessage);
1348         assertThrows(
1349                 IllegalArgumentException.class,
1350                 () -> DateUtils.setSeconds(BASE_DATE, -1),
1351                 outsideOfRangeAssertionMessage);
1352 
1353         assertThrows(NullPointerException.class, () -> DateUtils.setSeconds(null, 0));
1354     }
1355 
1356     @Test
1357     public void testSetYears() throws Exception {
1358         Date result = DateUtils.setYears(BASE_DATE, 2000);
1359         assertNotSame(BASE_DATE, result);
1360         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
1361         assertDate(result, 2000, 6, 5, 4, 3, 2, 1);
1362 
1363         result = DateUtils.setYears(BASE_DATE, 2008);
1364         assertNotSame(BASE_DATE, result);
1365         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
1366         assertDate(result, 2008, 6, 5, 4, 3, 2, 1);
1367 
1368         result = DateUtils.setYears(BASE_DATE, 2005);
1369         assertNotSame(BASE_DATE, result);
1370         assertDate(BASE_DATE, 2000, 6, 5, 4, 3, 2, 1);
1371         assertDate(result, 2005, 6, 5, 4, 3, 2, 1);
1372 
1373         assertThrows(NullPointerException.class, () -> DateUtils.setYears(null, 0));
1374     }
1375 
1376     @Test
1377     public void testToCalendar() {
1378         assertEquals(date1, DateUtils.toCalendar(date1).getTime(), "Failed to convert to a Calendar and back");
1379         assertThrows(NullPointerException.class, () -> DateUtils.toCalendar(null));
1380     }
1381 
1382     @Test
1383     public void testToCalendarWithDateAndTimeZoneNotNull() {
1384         final Calendar c = DateUtils.toCalendar(date2, DEFAULT_ZONE);
1385         assertEquals(date2, c.getTime(), "Convert Date and TimeZone to a Calendar, but failed to get the Date back");
1386         assertEquals(DEFAULT_ZONE, c.getTimeZone(), "Convert Date and TimeZone to a Calendar, but failed to get the TimeZone back");
1387     }
1388 
1389     @Test
1390     public void testToCalendarWithDateAndTimeZoneNull() {
1391         assertThrows(NullPointerException.class, () -> DateUtils.toCalendar(null, null));
1392     }
1393 
1394     @Test
1395     public void testToCalendarWithDateNull() {
1396         assertThrows(NullPointerException.class, () -> DateUtils.toCalendar(null, zone));
1397     }
1398 
1399     @Test
1400     public void testToCalendarWithTimeZoneNull() {
1401         assertThrows(NullPointerException.class, () -> DateUtils.toCalendar(date1, null));
1402     }
1403 
1404     /**
1405      * Tests various values with the trunc method
1406      *
1407      * @throws Exception so we don't have to catch it
1408      */
1409     @Test
1410     public void testTruncate() throws Exception {
1411         // tests public static Date truncate(Date date, int field)
1412         assertEquals(dateParser.parse("January 1, 2002"),
1413                 DateUtils.truncate(date1, Calendar.YEAR),
1414                 "truncate year-1 failed");
1415         assertEquals(dateParser.parse("January 1, 2001"),
1416                 DateUtils.truncate(date2, Calendar.YEAR),
1417                 "truncate year-2 failed");
1418         assertEquals(dateParser.parse("February 1, 2002"),
1419                 DateUtils.truncate(date1, Calendar.MONTH),
1420                 "truncate month-1 failed");
1421         assertEquals(dateParser.parse("November 1, 2001"),
1422                 DateUtils.truncate(date2, Calendar.MONTH),
1423                 "truncate month-2 failed");
1424         assertEquals(dateParser.parse("February 1, 2002"),
1425                 DateUtils.truncate(date1, DateUtils.SEMI_MONTH),
1426                 "truncate semimonth-1 failed");
1427         assertEquals(dateParser.parse("November 16, 2001"),
1428                 DateUtils.truncate(date2, DateUtils.SEMI_MONTH),
1429                 "truncate semimonth-2 failed");
1430         assertEquals(dateParser.parse("February 12, 2002"),
1431                 DateUtils.truncate(date1, Calendar.DATE),
1432                 "truncate date-1 failed");
1433         assertEquals(dateParser.parse("November 18, 2001"),
1434                 DateUtils.truncate(date2, Calendar.DATE),
1435                 "truncate date-2 failed");
1436         assertEquals(dateTimeParser.parse("February 12, 2002 12:00:00.000"),
1437                 DateUtils.truncate(date1, Calendar.HOUR),
1438                 "truncate hour-1 failed");
1439         assertEquals(dateTimeParser.parse("November 18, 2001 1:00:00.000"),
1440                 DateUtils.truncate(date2, Calendar.HOUR),
1441                 "truncate hour-2 failed");
1442         assertEquals(dateTimeParser.parse("February 12, 2002 12:34:00.000"),
1443                 DateUtils.truncate(date1, Calendar.MINUTE),
1444                 "truncate minute-1 failed");
1445         assertEquals(dateTimeParser.parse("November 18, 2001 1:23:00.000"),
1446                 DateUtils.truncate(date2, Calendar.MINUTE),
1447                 "truncate minute-2 failed");
1448         assertEquals(dateTimeParser.parse("February 12, 2002 12:34:56.000"),
1449                 DateUtils.truncate(date1, Calendar.SECOND),
1450                 "truncate second-1 failed");
1451         assertEquals(dateTimeParser.parse("November 18, 2001 1:23:11.000"),
1452                 DateUtils.truncate(date2, Calendar.SECOND),
1453                 "truncate second-2 failed");
1454         assertEquals(dateTimeParser.parse("February 3, 2002 00:00:00.000"),
1455                 DateUtils.truncate(dateAmPm1, Calendar.AM_PM),
1456                 "truncate ampm-1 failed");
1457         assertEquals(dateTimeParser.parse("February 3, 2002 00:00:00.000"),
1458                 DateUtils.truncate(dateAmPm2, Calendar.AM_PM),
1459                 "truncate ampm-2 failed");
1460         assertEquals(dateTimeParser.parse("February 3, 2002 12:00:00.000"),
1461                 DateUtils.truncate(dateAmPm3, Calendar.AM_PM),
1462                 "truncate ampm-3 failed");
1463         assertEquals(dateTimeParser.parse("February 3, 2002 12:00:00.000"),
1464                 DateUtils.truncate(dateAmPm4, Calendar.AM_PM),
1465                 "truncate ampm-4 failed");
1466 
1467         // tests public static Date truncate(Object date, int field)
1468         assertEquals(dateParser.parse("January 1, 2002"),
1469                 DateUtils.truncate((Object) date1, Calendar.YEAR),
1470                 "truncate year-1 failed");
1471         assertEquals(dateParser.parse("January 1, 2001"),
1472                 DateUtils.truncate((Object) date2, Calendar.YEAR),
1473                 "truncate year-2 failed");
1474         assertEquals(dateParser.parse("February 1, 2002"),
1475                 DateUtils.truncate((Object) date1, Calendar.MONTH),
1476                 "truncate month-1 failed");
1477         assertEquals(dateParser.parse("November 1, 2001"),
1478                 DateUtils.truncate((Object) date2, Calendar.MONTH),
1479                 "truncate month-2 failed");
1480         assertEquals(dateParser.parse("February 1, 2002"),
1481                 DateUtils.truncate((Object) date1, DateUtils.SEMI_MONTH),
1482                 "truncate semimonth-1 failed");
1483         assertEquals(dateParser.parse("November 16, 2001"),
1484                 DateUtils.truncate((Object) date2, DateUtils.SEMI_MONTH),
1485                 "truncate semimonth-2 failed");
1486         assertEquals(dateParser.parse("February 12, 2002"),
1487                 DateUtils.truncate((Object) date1, Calendar.DATE),
1488                 "truncate date-1 failed");
1489         assertEquals(dateParser.parse("November 18, 2001"),
1490                 DateUtils.truncate((Object) date2, Calendar.DATE),
1491                 "truncate date-2 failed");
1492         assertEquals(dateTimeParser.parse("February 12, 2002 12:00:00.000"),
1493                 DateUtils.truncate((Object) date1, Calendar.HOUR),
1494                 "truncate hour-1 failed");
1495         assertEquals(dateTimeParser.parse("November 18, 2001 1:00:00.000"),
1496                 DateUtils.truncate((Object) date2, Calendar.HOUR),
1497                 "truncate hour-2 failed");
1498         assertEquals(dateTimeParser.parse("February 12, 2002 12:34:00.000"),
1499                 DateUtils.truncate((Object) date1, Calendar.MINUTE),
1500                 "truncate minute-1 failed");
1501         assertEquals(dateTimeParser.parse("November 18, 2001 1:23:00.000"),
1502                 DateUtils.truncate((Object) date2, Calendar.MINUTE),
1503                 "truncate minute-2 failed");
1504         assertEquals(dateTimeParser.parse("February 12, 2002 12:34:56.000"),
1505                 DateUtils.truncate((Object) date1, Calendar.SECOND),
1506                 "truncate second-1 failed");
1507         assertEquals(dateTimeParser.parse("November 18, 2001 1:23:11.000"),
1508                 DateUtils.truncate((Object) date2, Calendar.SECOND),
1509                 "truncate second-2 failed");
1510         assertEquals(dateTimeParser.parse("February 3, 2002 00:00:00.000"),
1511                 DateUtils.truncate((Object) dateAmPm1, Calendar.AM_PM),
1512                 "truncate ampm-1 failed");
1513         assertEquals(dateTimeParser.parse("February 3, 2002 00:00:00.000"),
1514                 DateUtils.truncate((Object) dateAmPm2, Calendar.AM_PM),
1515                 "truncate ampm-2 failed");
1516         assertEquals(dateTimeParser.parse("February 3, 2002 12:00:00.000"),
1517                 DateUtils.truncate((Object) dateAmPm3, Calendar.AM_PM),
1518                 "truncate ampm-3 failed");
1519         assertEquals(dateTimeParser.parse("February 3, 2002 12:00:00.000"),
1520                 DateUtils.truncate((Object) dateAmPm4, Calendar.AM_PM),
1521                 "truncate ampm-4 failed");
1522 
1523         assertEquals(dateTimeParser.parse("February 12, 2002 12:34:56.000"),
1524                 DateUtils.truncate((Object) cal1, Calendar.SECOND),
1525                 "truncate calendar second-1 failed");
1526         assertEquals(dateTimeParser.parse("November 18, 2001 1:23:11.000"),
1527                 DateUtils.truncate((Object) cal2, Calendar.SECOND),
1528                 "truncate calendar second-2 failed");
1529 
1530         assertEquals(dateTimeParser.parse("February 3, 2002 00:00:00.000"),
1531                 DateUtils.truncate((Object) calAmPm1, Calendar.AM_PM),
1532                 "truncate ampm-1 failed");
1533         assertEquals(dateTimeParser.parse("February 3, 2002 00:00:00.000"),
1534                 DateUtils.truncate((Object) calAmPm2, Calendar.AM_PM),
1535                 "truncate ampm-2 failed");
1536         assertEquals(dateTimeParser.parse("February 3, 2002 12:00:00.000"),
1537                 DateUtils.truncate((Object) calAmPm3, Calendar.AM_PM),
1538                 "truncate ampm-3 failed");
1539         assertEquals(dateTimeParser.parse("February 3, 2002 12:00:00.000"),
1540                 DateUtils.truncate((Object) calAmPm4, Calendar.AM_PM),
1541                 "truncate ampm-4 failed");
1542 
1543         assertThrows(NullPointerException.class, () -> DateUtils.truncate((Date) null, Calendar.SECOND));
1544         assertThrows(NullPointerException.class, () -> DateUtils.truncate((Calendar) null, Calendar.SECOND));
1545         assertThrows(NullPointerException.class, () -> DateUtils.truncate((Object) null, Calendar.SECOND));
1546         assertThrows(ClassCastException.class, () -> DateUtils.truncate("", Calendar.SECOND));
1547 
1548         // Fix for https://issues.apache.org/bugzilla/show_bug.cgi?id=25560
1549         // Test truncate across beginning of daylight saving time
1550         try {
1551             TimeZone.setDefault(zone);
1552             dateTimeParser.setTimeZone(zone);
1553             assertEquals(dateTimeParser.parse("March 30, 2003 00:00:00.000"),
1554                     DateUtils.truncate(date3, Calendar.DATE),
1555                     "truncate MET date across DST change-over");
1556             assertEquals(dateTimeParser.parse("March 30, 2003 00:00:00.000"),
1557                     DateUtils.truncate((Object) cal3, Calendar.DATE),
1558                     "truncate MET date across DST change-over");
1559             // Test truncate across end of daylight saving time
1560             assertEquals(dateTimeParser.parse("October 26, 2003 00:00:00.000"),
1561                     DateUtils.truncate(date8, Calendar.DATE),
1562                     "truncate MET date across DST change-over");
1563             assertEquals(dateTimeParser.parse("October 26, 2003 00:00:00.000"),
1564                     DateUtils.truncate((Object) cal8, Calendar.DATE),
1565                     "truncate MET date across DST change-over");
1566         } finally {
1567             TimeZone.setDefault(DEFAULT_ZONE);
1568             dateTimeParser.setTimeZone(DEFAULT_ZONE);
1569         }
1570 
1571         // Bug 31395, large dates
1572         final Date endOfTime = new Date(Long.MAX_VALUE); // fyi: Sun Aug 17 07:12:55 CET 292278994 -- 807 millis
1573         final GregorianCalendar endCal = new GregorianCalendar();
1574         endCal.setTime(endOfTime);
1575         assertThrows(ArithmeticException.class, () -> DateUtils.truncate(endCal, Calendar.DATE));
1576         endCal.set(Calendar.YEAR, 280000001);
1577         assertThrows(ArithmeticException.class, () -> DateUtils.truncate(endCal, Calendar.DATE));
1578         endCal.set(Calendar.YEAR, 280000000);
1579         final Calendar cal = DateUtils.truncate(endCal, Calendar.DATE);
1580         assertEquals(0, cal.get(Calendar.HOUR));
1581     }
1582 
1583     /**
1584      * Tests for LANG-59
1585      *
1586      * see https://issues.apache.org/jira/browse/LANG-59
1587      */
1588     @Test
1589     public void testTruncateLang59() {
1590         try {
1591             // Set TimeZone to Mountain Time
1592             final TimeZone denverZone = TimeZone.getTimeZone("America/Denver");
1593             TimeZone.setDefault(denverZone);
1594             final DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS XXX");
1595             format.setTimeZone(denverZone);
1596 
1597             final Date oct31_01MDT = new Date(1099206000000L);
1598 
1599             final Date oct31MDT = new Date(oct31_01MDT.getTime() - 3600000L); // - 1 hour
1600             final Date oct31_01_02MDT = new Date(oct31_01MDT.getTime() + 120000L);  // + 2 minutes
1601             final Date oct31_01_02_03MDT = new Date(oct31_01_02MDT.getTime() + 3000L);    // + 3 seconds
1602             final Date oct31_01_02_03_04MDT = new Date(oct31_01_02_03MDT.getTime() + 4L);       // + 4 milliseconds
1603 
1604             assertEquals("2004-10-31 00:00:00.000 -06:00", format.format(oct31MDT), "Check 00:00:00.000");
1605             assertEquals("2004-10-31 01:00:00.000 -06:00", format.format(oct31_01MDT), "Check 01:00:00.000");
1606             assertEquals("2004-10-31 01:02:00.000 -06:00", format.format(oct31_01_02MDT), "Check 01:02:00.000");
1607             assertEquals("2004-10-31 01:02:03.000 -06:00", format.format(oct31_01_02_03MDT), "Check 01:02:03.000");
1608             assertEquals("2004-10-31 01:02:03.004 -06:00", format.format(oct31_01_02_03_04MDT), "Check 01:02:03.004");
1609 
1610             // ------- Demonstrate Problem -------
1611             final Calendar gval = Calendar.getInstance();
1612             gval.setTime(new Date(oct31_01MDT.getTime()));
1613             gval.set(Calendar.MINUTE, gval.get(Calendar.MINUTE)); // set minutes to the same value
1614             assertEquals(gval.getTime().getTime(), oct31_01MDT.getTime() + 3600000L, "Demonstrate Problem");
1615 
1616             // ---------- Test Truncate ----------
1617             assertEquals(oct31_01_02_03_04MDT, DateUtils.truncate(oct31_01_02_03_04MDT, Calendar.MILLISECOND),
1618                     "Truncate Calendar.MILLISECOND");
1619 
1620             assertEquals(oct31_01_02_03MDT, DateUtils.truncate(oct31_01_02_03_04MDT, Calendar.SECOND),
1621                     "Truncate Calendar.SECOND");
1622 
1623             assertEquals(oct31_01_02MDT, DateUtils.truncate(oct31_01_02_03_04MDT, Calendar.MINUTE),
1624                     "Truncate Calendar.MINUTE");
1625 
1626             assertEquals(oct31_01MDT, DateUtils.truncate(oct31_01_02_03_04MDT, Calendar.HOUR_OF_DAY),
1627                     "Truncate Calendar.HOUR_OF_DAY");
1628 
1629             assertEquals(oct31_01MDT, DateUtils.truncate(oct31_01_02_03_04MDT, Calendar.HOUR),
1630                     "Truncate Calendar.HOUR");
1631 
1632             assertEquals(oct31MDT, DateUtils.truncate(oct31_01_02_03_04MDT, Calendar.DATE),
1633                     "Truncate Calendar.DATE");
1634 
1635             // ---------- Test Round (down) ----------
1636             assertEquals(oct31_01_02_03_04MDT, DateUtils.round(oct31_01_02_03_04MDT, Calendar.MILLISECOND),
1637                     "Round Calendar.MILLISECOND");
1638 
1639             assertEquals(oct31_01_02_03MDT, DateUtils.round(oct31_01_02_03_04MDT, Calendar.SECOND),
1640                     "Round Calendar.SECOND");
1641 
1642             assertEquals(oct31_01_02MDT, DateUtils.round(oct31_01_02_03_04MDT, Calendar.MINUTE),
1643                     "Round Calendar.MINUTE");
1644 
1645             assertEquals(oct31_01MDT, DateUtils.round(oct31_01_02_03_04MDT, Calendar.HOUR_OF_DAY),
1646                     "Round Calendar.HOUR_OF_DAY");
1647 
1648             assertEquals(oct31_01MDT, DateUtils.round(oct31_01_02_03_04MDT, Calendar.HOUR),
1649                     "Round Calendar.HOUR");
1650 
1651             assertEquals(oct31MDT, DateUtils.round(oct31_01_02_03_04MDT, Calendar.DATE),
1652                     "Round Calendar.DATE");
1653         } finally {
1654             // restore default time zone
1655             TimeZone.setDefault(DEFAULT_ZONE);
1656         }
1657     }
1658 
1659     /**
1660      * Tests the calendar iterator for week ranges
1661      */
1662     @Test
1663     public void testWeekIterator() {
1664         final Calendar now = Calendar.getInstance();
1665         for (int i = 0; i< 7; i++) {
1666             final Calendar today = DateUtils.truncate(now, Calendar.DATE);
1667             final Calendar sunday = DateUtils.truncate(now, Calendar.DATE);
1668             sunday.add(Calendar.DATE, 1 - sunday.get(Calendar.DAY_OF_WEEK));
1669             final Calendar monday = DateUtils.truncate(now, Calendar.DATE);
1670             if (monday.get(Calendar.DAY_OF_WEEK) == 1) {
1671                 //This is sunday... roll back 6 days
1672                 monday.add(Calendar.DATE, -6);
1673             } else {
1674                 monday.add(Calendar.DATE, 2 - monday.get(Calendar.DAY_OF_WEEK));
1675             }
1676             final Calendar centered = DateUtils.truncate(now, Calendar.DATE);
1677             centered.add(Calendar.DATE, -3);
1678 
1679             Iterator<?> it = DateUtils.iterator(now, DateUtils.RANGE_WEEK_SUNDAY);
1680             assertWeekIterator(it, sunday);
1681             it = DateUtils.iterator(now, DateUtils.RANGE_WEEK_MONDAY);
1682             assertWeekIterator(it, monday);
1683             it = DateUtils.iterator(now, DateUtils.RANGE_WEEK_RELATIVE);
1684             assertWeekIterator(it, today);
1685             it = DateUtils.iterator(now, DateUtils.RANGE_WEEK_CENTER);
1686             assertWeekIterator(it, centered);
1687 
1688             it = DateUtils.iterator((Object) now, DateUtils.RANGE_WEEK_CENTER);
1689             assertWeekIterator(it, centered);
1690             final Iterator<?> it2 = DateUtils.iterator((Object) now.getTime(), DateUtils.RANGE_WEEK_CENTER);
1691             assertWeekIterator(it2, centered);
1692             assertThrows(NoSuchElementException.class, it2::next);
1693             final Iterator<?> it3 = DateUtils.iterator(now, DateUtils.RANGE_WEEK_CENTER);
1694             it3.next();
1695             assertThrows(UnsupportedOperationException.class, it3::remove);
1696 
1697             now.add(Calendar.DATE, 1);
1698         }
1699     }
1700 
1701 }
1702