1 /*
   2  * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package test.java.time.chrono;
  27 
  28 import static java.time.temporal.ChronoField.DAY_OF_MONTH;
  29 import static java.time.temporal.ChronoField.DAY_OF_YEAR;
  30 import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
  31 import static java.time.temporal.ChronoField.YEAR;
  32 import static org.testng.Assert.assertEquals;
  33 import static org.testng.Assert.assertFalse;
  34 import static org.testng.Assert.assertTrue;
  35 import static org.testng.Assert.fail;
  36 
  37 import java.time.DateTimeException;
  38 import java.time.DayOfWeek;
  39 import java.time.LocalDate;
  40 import java.time.LocalDateTime;
  41 import java.time.LocalTime;
  42 import java.time.OffsetDateTime;
  43 import java.time.ZoneId;
  44 import java.time.ZoneOffset;
  45 import java.time.ZonedDateTime;
  46 import java.time.chrono.ChronoLocalDate;
  47 import java.time.chrono.ChronoLocalDateTime;
  48 import java.time.chrono.ChronoPeriod;
  49 import java.time.chrono.ChronoZonedDateTime;
  50 import java.time.chrono.Chronology;
  51 import java.time.chrono.HijrahChronology;
  52 import java.time.chrono.HijrahDate;
  53 import java.time.chrono.JapaneseChronology;
  54 import java.time.chrono.JapaneseDate;
  55 import java.time.chrono.MinguoChronology;
  56 import java.time.chrono.MinguoDate;
  57 import java.time.chrono.ThaiBuddhistChronology;
  58 import java.time.chrono.ThaiBuddhistDate;
  59 import java.time.format.DateTimeFormatter;
  60 import java.time.format.FormatStyle;
  61 import java.time.temporal.ChronoField;
  62 import java.time.temporal.ChronoUnit;
  63 import java.time.temporal.TemporalAccessor;
  64 import java.time.temporal.TemporalAdjusters;
  65 import java.time.temporal.ValueRange;
  66 import java.time.temporal.WeekFields;
  67 import java.util.Locale;
  68 
  69 import org.testng.annotations.DataProvider;
  70 import org.testng.annotations.Test;
  71 
  72 /**
  73  * Tests for the Umm alQura chronology and data.
  74  * Note: The dates used for testing are just a sample of calendar data.
  75  * @bug 8067800
  76  */
  77 @Test
  78 public class TestUmmAlQuraChronology {
  79 
  80     private static final ZoneOffset OFFSET_PTWO = ZoneOffset.ofHours(2);
  81     private static final ZoneId ZONE_RIYADH = ZoneId.of("Asia/Riyadh");
  82 
  83     // Test for HijrahChronology Aliases
  84     @Test
  85     public void test_aliases() {
  86         HijrahChronology hc = (HijrahChronology) Chronology.of("Hijrah");
  87         assertEquals(hc, HijrahChronology.INSTANCE, "Alias for Hijrah-umalqura");
  88         hc = (HijrahChronology) Chronology.of("islamic");
  89         assertEquals(hc, HijrahChronology.INSTANCE, "Alias for Hijrah-umalqura");
  90     }
  91 
  92     // Test to check if the exception is thrown for an incorrect chronology id
  93     @Test(expectedExceptions=DateTimeException.class)
  94     public void test_badChronology() {
  95         Chronology test = Chronology.of("Hijrah-ummalqura");
  96     }
  97 
  98     //--------------------------------------------------------------------------
  99     // regular data factory for Umm alQura dates and the corresponding ISO dates
 100     //--------------------------------------------------------------------------
 101     @DataProvider(name = "UmmAlQuraVsISODates")
 102     Object[][] data_UmmAlQuraVsISODates() {
 103         return new Object[][] {
 104             {HijrahDate.of(1318, 1, 1), LocalDate.of(1900, 04, 30)},
 105             {HijrahDate.of(1318, 12, 29), LocalDate.of(1901, 04, 19)},
 106             {HijrahDate.of(1319, 01, 01), LocalDate.of(1901, 04, 20)},
 107             {HijrahDate.of(1433, 12, 29), LocalDate.of(2012, 11, 14)},
 108             {HijrahDate.of(1434, 01, 01), LocalDate.of(2012, 11, 15)},
 109             {HijrahDate.of(1434, 02, 18), LocalDate.of(2012, 12, 31)},
 110             {HijrahDate.of(1502, 12, 29), LocalDate.of(2079, 10, 25)},
 111         };
 112     }
 113 
 114     // Test to verify the epoch days for given Hijrah & ISO date instances
 115     @Test(dataProvider="UmmAlQuraVsISODates")
 116         public void Test_UmmAlQuraVsISODates(HijrahDate hd, LocalDate ld) {
 117         assertEquals(hd.toEpochDay(), ld.toEpochDay(), "Umm alQura date and ISO date should have same epochDay");
 118     }
 119 
 120     // UmmAlQura chronology ranges for year, month and days for the HijrahChronology
 121     @Test
 122     public void Test_UmmAlQuraChronoRange() {
 123         HijrahChronology chrono = HijrahChronology.INSTANCE;
 124         ValueRange year = chrono.range(YEAR);
 125         assertEquals(year.getMinimum(), 1300, "Minimum year");
 126         assertEquals(year.getLargestMinimum(), 1300, "Largest minimum year");
 127         assertEquals(year.getMaximum(), 1600, "Largest year");
 128         assertEquals(year.getSmallestMaximum(), 1600, "Smallest Maximum year");
 129 
 130         ValueRange month = chrono.range(MONTH_OF_YEAR);
 131         assertEquals(month.getMinimum(), 1, "Minimum month");
 132         assertEquals(month.getLargestMinimum(), 1, "Largest minimum month");
 133         assertEquals(month.getMaximum(), 12, "Largest month");
 134         assertEquals(month.getSmallestMaximum(), 12, "Smallest Maximum month");
 135 
 136         ValueRange day = chrono.range(DAY_OF_MONTH);
 137         assertEquals(day.getMinimum(), 1, "Minimum day");
 138         assertEquals(day.getLargestMinimum(), 1, "Largest minimum day");
 139         assertEquals(day.getMaximum(), 30, "Largest day");
 140         assertEquals(day.getSmallestMaximum(), 29, "Smallest Maximum day");
 141     }
 142 
 143     //-----------------------------------------------------------------------
 144     // regular data factory for dates and the corresponding range values
 145     //-----------------------------------------------------------------------
 146     @DataProvider(name = "dates")
 147     Object[][] data_dates() {
 148         return new Object[][]{
 149             {HijrahDate.of(1300, 5, 1), 1300, 1600, 1, 12, 1, 30, 30},
 150             {HijrahDate.of(1300, 6, 1), 1300, 1600, 1, 12, 1, 29, 30},
 151             {HijrahDate.of(1434, 12, 1), 1300, 1600, 1, 12, 1, 29, 30},
 152             {HijrahDate.of(1500, 4, 1), 1300, 1600, 1, 12, 1, 30, 30},
 153             {HijrahDate.of(1600, 6, 1), 1300, 1600, 1, 12, 1, 29, 30},
 154         };
 155     }
 156 
 157     // Test to verify the min/max field ranges for given dates
 158     @Test(dataProvider="dates")
 159     public void Test_UmmAlQuraRanges(HijrahDate date,
 160                         int minYear, int maxYear,
 161                         int minMonth, int maxMonth,
 162                         int minDay, int maxDay, int maxChronoDay) {
 163         // Check the chronology ranges
 164         HijrahChronology chrono = date.getChronology();
 165         ValueRange yearRange = chrono.range(YEAR);
 166         assertEquals(yearRange.getMinimum(), minYear, "Minimum year for Hijrah chronology");
 167         assertEquals(yearRange.getLargestMinimum(), minYear, "Largest minimum year for Hijrah chronology");
 168         assertEquals(yearRange.getMaximum(), maxYear, "Maximum year for Hijrah chronology");
 169         assertEquals(yearRange.getSmallestMaximum(), maxYear, "Smallest Maximum year for Hijrah chronology");
 170 
 171         ValueRange monthRange = chrono.range(MONTH_OF_YEAR);
 172         assertEquals(monthRange.getMinimum(), minMonth, "Minimum month for Hijrah chronology");
 173         assertEquals(monthRange.getMaximum(), maxMonth, "Maximum month for Hijrah chronology");
 174 
 175         ValueRange daysRange = chrono.range(DAY_OF_MONTH);
 176         assertEquals(daysRange.getMinimum(), minDay, "Minimum day for chronology");
 177         assertEquals(daysRange.getMaximum(), maxChronoDay, "Maximum day for Hijrah chronology");
 178 
 179         // Check the date ranges
 180         yearRange = date.range(YEAR);
 181         assertEquals(yearRange.getMinimum(), minYear, "Minimum year for Hijrah date");
 182         assertEquals(yearRange.getLargestMinimum(), minYear, "Largest minimum  year for Hijrah date");
 183         assertEquals(yearRange.getMaximum(), maxYear, "Maximum year for Hijrah date");
 184         assertEquals(yearRange.getSmallestMaximum(), maxYear, "Smallest maximum year for Hijrah date");
 185 
 186         monthRange = date.range(MONTH_OF_YEAR);
 187         assertEquals(monthRange.getMinimum(), minMonth, "Minimum month for HijrahDate");
 188         assertEquals(monthRange.getMaximum(), maxMonth, "Maximum month for HijrahDate");
 189 
 190         daysRange = date.range(DAY_OF_MONTH);
 191         assertEquals(daysRange.getMinimum(), minDay, "Minimum day for HijrahDate");
 192         assertEquals(daysRange.getMaximum(), maxDay, "Maximum day for HijrahDate");
 193 
 194     }
 195 
 196     // Check the date limits
 197     @Test
 198     public void test_hijrahDateLimits() {
 199         HijrahChronology chrono = HijrahChronology.INSTANCE;
 200         ValueRange yearRange = chrono.range(YEAR);
 201         ValueRange monthRange = chrono.range(MONTH_OF_YEAR);
 202         ValueRange dayRange = chrono.range(DAY_OF_MONTH);
 203 
 204         HijrahDate xx = chrono.date(1434, 1, 1);
 205         HijrahDate minDate = chrono.date((int)yearRange.getLargestMinimum(),
 206                 (int)monthRange.getMinimum(), (int)dayRange.getMinimum());
 207         try {
 208             HijrahDate before = minDate.minus(1, ChronoUnit.DAYS);
 209             fail("Exception did not occur, minDate: " + minDate + ".minus(1, DAYS) = " + before);
 210 
 211         } catch (DateTimeException ex) {
 212             // ignore, this exception was expected
 213         }
 214 
 215         HijrahDate maxDate = chrono.date((int)yearRange.getSmallestMaximum(),
 216                 (int)monthRange.getMaximum(), 1);
 217         int monthLen = maxDate.lengthOfMonth();
 218         maxDate = maxDate.with(DAY_OF_MONTH, monthLen);
 219         try {
 220             HijrahDate after = maxDate.plus(1, ChronoUnit.DAYS);
 221             fail("Exception did not occur, maxDate: " + maxDate + ".plus(1, DAYS) = " + after);
 222         } catch (DateTimeException ex) {
 223             // ignore, this exception was expected
 224         }
 225     }
 226 
 227     // Data provider to verify the dateYearDay() method
 228     @DataProvider(name="dateYearDay")
 229     Object[][] data_dateYearDay() {
 230         return new Object[][] {
 231             {HijrahChronology.INSTANCE.dateYearDay(1434, 42), HijrahChronology.INSTANCE.date(1434, 02, 13)},
 232             {HijrahChronology.INSTANCE.dateYearDay(1330, 354), HijrahChronology.INSTANCE.date(1330, 12, 29)},
 233             {HijrahChronology.INSTANCE.dateYearDay(1600, 1), HijrahChronology.INSTANCE.date(1600, 1, 1)},
 234             {HijrahChronology.INSTANCE.dateYearDay(1400, 175), HijrahChronology.INSTANCE.date(1400, 6, 28)},
 235             {HijrahChronology.INSTANCE.dateYearDay(1520, 190), HijrahChronology.INSTANCE.date(1520, 7, 13)},
 236             {HijrahChronology.INSTANCE.dateYearDay(1521, 112), HijrahChronology.INSTANCE.date(1521, 4, 25)},
 237         };
 238     }
 239 
 240     // Test to verify the dateYearDay() method
 241     @Test(dataProvider="dateYearDay")
 242     public void test_DateYearDay(ChronoLocalDate date1,   ChronoLocalDate date2) {
 243        assertEquals(date1, date2);
 244     }
 245 
 246     //-----------------------------------------------------------------------
 247     // HijrahDate.with(DAY_OF_YEAR, n)
 248     //-----------------------------------------------------------------------
 249     @Test
 250     public void test_getDayOfYear() {
 251         HijrahDate hd1 = HijrahChronology.INSTANCE.dateYearDay(1434, 1);
 252         for (int i = 1; i <= hd1.lengthOfYear(); i++) {
 253             HijrahDate hd = HijrahChronology.INSTANCE.dateYearDay(1434, i);
 254             int doy = hd.get(DAY_OF_YEAR);
 255             assertEquals(doy, i, "get(DAY_OF_YEAR) incorrect for " + i);
 256         }
 257     }
 258 
 259     @Test
 260     public void test_withDayOfYear() {
 261         HijrahDate hd = HijrahChronology.INSTANCE.dateYearDay(1434, 1);
 262         for (int i = 1; i <= hd.lengthOfYear(); i++) {
 263             HijrahDate hd2 = hd.with(DAY_OF_YEAR, i);
 264             int doy = hd2.get(DAY_OF_YEAR);
 265             assertEquals(doy, i, "with(DAY_OF_YEAR) incorrect for " + i + " " + hd2);
 266         }
 267     }
 268 
 269     @Test(expectedExceptions=java.time.DateTimeException.class)
 270     public void test_withDayOfYearTooSmall() {
 271         HijrahDate hd = HijrahChronology.INSTANCE.dateYearDay(1435, 1);
 272         HijrahDate hd2 = hd.with(DAY_OF_YEAR, 0);
 273     }
 274 
 275     @Test(expectedExceptions=java.time.DateTimeException.class)
 276     public void test_withDayOfYearTooLarge() {
 277         HijrahDate hd = HijrahChronology.INSTANCE.dateYearDay(1435, 1);
 278         HijrahDate hd2 = hd.with(DAY_OF_YEAR, hd.lengthOfYear() + 1);
 279     }
 280 
 281     // Test to verify the with() method with ChronoField is set to DAY_OF_WEEK
 282     @Test
 283     public void test_adjustWithDayOfWeek() {
 284         assertEquals(HijrahChronology.INSTANCE.date(1320, 1, 15).with(ChronoField.DAY_OF_WEEK, 4), HijrahDate.of(1320, 1, 15));
 285         assertEquals(HijrahChronology.INSTANCE.date(1421, 11, 15).with(ChronoField.DAY_OF_WEEK, 1), HijrahDate.of(1421, 11, 11));
 286         assertEquals(HijrahChronology.INSTANCE.date(1529, 7, 18).with(ChronoField.DAY_OF_WEEK, 6), HijrahDate.of(1529, 7, 20));
 287         assertEquals(HijrahChronology.INSTANCE.date(1534, 2, 10).with(ChronoField.DAY_OF_WEEK, 5), HijrahDate.of(1534, 2, 12));
 288         assertEquals(HijrahChronology.INSTANCE.date(1552, 4, 1).with(ChronoField.DAY_OF_WEEK, 2), HijrahDate.of(1552, 3, 26));
 289     }
 290 
 291     // Test to verify the with() method with ChronoField is set to DAY_OF_MONTH
 292     @Test
 293     public void test_adjustWithDayOfMonth() {
 294         assertEquals(HijrahChronology.INSTANCE.date(1320, 1, 15).with(ChronoField.DAY_OF_MONTH, 2), HijrahDate.of(1320, 1, 2));
 295         assertEquals(HijrahChronology.INSTANCE.date(1421, 11, 15).with(ChronoField.DAY_OF_MONTH, 9), HijrahDate.of(1421, 11, 9));
 296         assertEquals(HijrahChronology.INSTANCE.date(1529, 7, 18).with(ChronoField.DAY_OF_MONTH, 13), HijrahDate.of(1529, 7, 13));
 297         assertEquals(HijrahChronology.INSTANCE.date(1534, 12, 10).with(ChronoField.DAY_OF_MONTH, 29), HijrahDate.of(1534, 12, 29));
 298         assertEquals(HijrahChronology.INSTANCE.date(1552, 4, 1).with(ChronoField.DAY_OF_MONTH, 6), HijrahDate.of(1552, 4, 6));
 299     }
 300 
 301     // Test to verify the with() method with ChronoField is set to DAY_OF_YEAR
 302     @Test
 303     public void test_adjustWithDayOfYear() {
 304         assertEquals(HijrahChronology.INSTANCE.date(1320, 1, 15).with(ChronoField.DAY_OF_YEAR, 24), HijrahDate.of(1320, 1, 24));
 305         assertEquals(HijrahChronology.INSTANCE.date(1421, 11, 15).with(ChronoField.DAY_OF_YEAR, 135), HijrahDate.of(1421, 5, 18));
 306         assertEquals(HijrahChronology.INSTANCE.date(1529, 7, 18).with(ChronoField.DAY_OF_YEAR, 64), HijrahDate.of(1529, 3, 5));
 307         assertEquals(HijrahChronology.INSTANCE.date(1534, 2, 10).with(ChronoField.DAY_OF_YEAR, 354), HijrahDate.of(1534, 12, 29));
 308         assertEquals(HijrahChronology.INSTANCE.date(1552, 4, 1).with(ChronoField.DAY_OF_YEAR, 291), HijrahDate.of(1552, 10, 26));
 309     }
 310 
 311     // Data provider to get the difference between two dates in terms of days, months and years
 312     @DataProvider(name="datesForDiff")
 313     Object[][] data_datesForDiffs() {
 314         return new Object[][] {
 315             {HijrahDate.of(1350, 5, 15), HijrahDate.of(1351, 12, 29), 574, 19, 1},
 316             {HijrahDate.of(1434, 5, 1), HijrahDate.of(1434,6, 12), 40, 1, 0},
 317             {HijrahDate.of(1436, 1, 1), HijrahDate.of(1475, 12, 29), 14173, 479, 39},
 318             {HijrahDate.of(1500, 6, 12), HijrahDate.of(1551, 7, 12), 18102, 613, 51},
 319             {HijrahDate.of(1550, 3, 11), HijrahDate.of(1551, 4, 11), 384, 13, 1},
 320         };
 321     }
 322 
 323     // Test to verify the difference between two given dates in terms of days, months and years
 324     @Test(dataProvider="datesForDiff")
 325     public void test_diffBetweenDates(ChronoLocalDate from, ChronoLocalDate to, long days, long months, long years) {
 326           assertEquals(from.until(to, ChronoUnit.DAYS), days);
 327           assertEquals(from.until(to, ChronoUnit.MONTHS), months);
 328           assertEquals(from.until(to, ChronoUnit.YEARS), years);
 329     }
 330 
 331     // Data provider to get the difference between two dates as a period
 332     @DataProvider(name="datesForPeriod")
 333     Object[][] data_Period() {
 334         return new Object[][] {
 335             {HijrahDate.of(1350, 5, 15), HijrahDate.of(1434, 7, 20), HijrahChronology.INSTANCE.period(84, 2, 5)},
 336             {HijrahDate.of(1403, 5, 28), HijrahDate.of(1434, 7, 20), HijrahChronology.INSTANCE.period(31, 1, 22)},
 337             {HijrahDate.of(1434, 7, 20), HijrahDate.of(1484, 2, 15), HijrahChronology.INSTANCE.period(49, 6, 24)},
 338             {HijrahDate.of(1500, 6, 12), HijrahDate.of(1450, 4, 21), HijrahChronology.INSTANCE.period(-50, -1, -20)},
 339             {HijrahDate.of(1549, 3, 11), HijrahDate.of(1550, 3, 10), HijrahChronology.INSTANCE.period(0, 11, 28)},
 340         };
 341     }
 342 
 343     // Test to get the Period between two given dates
 344     @Test(dataProvider="datesForPeriod")
 345     public void test_until(HijrahDate h1, HijrahDate h2, ChronoPeriod p) {
 346         ChronoPeriod period = h1.until(h2);
 347         assertEquals(period, p);
 348     }
 349 
 350     // Test to get the Period between dates in different chronologies
 351     @Test(dataProvider="datesForPeriod")
 352     public void test_periodUntilDiffChrono(HijrahDate h1, HijrahDate h2, ChronoPeriod p) {
 353         MinguoDate m = MinguoChronology.INSTANCE.date(h2);
 354         ChronoPeriod period = h1.until(m);
 355         assertEquals(period, p);
 356     }
 357 
 358     // Test to get the adjusted date from a given date using TemporalAdjuster methods
 359     @Test
 360     public void test_temporalDayAdjustments() {
 361         HijrahDate date = HijrahDate.of(1554, 7, 21);
 362         assertEquals(date.with(TemporalAdjusters.firstDayOfMonth()), HijrahDate.of(1554, 7, 1));
 363         assertEquals(date.with(TemporalAdjusters.lastDayOfMonth()), HijrahDate.of(1554, 7, 29));
 364         assertEquals(date.with(TemporalAdjusters.firstDayOfNextMonth()), HijrahDate.of(1554, 8, 1));
 365         assertEquals(date.with(TemporalAdjusters.firstDayOfNextYear()), HijrahDate.of(1555, 1, 1));
 366         assertEquals(date.with(TemporalAdjusters.firstDayOfYear()), HijrahDate.of(1554, 1, 1));
 367         assertEquals(date.with(TemporalAdjusters.lastDayOfYear()), HijrahDate.of(1554, 12, 30));
 368     }
 369 
 370     // Data provider for string representation of the date instances
 371     @DataProvider(name="toString")
 372     Object[][] data_toString() {
 373         return new Object[][] {
 374             {HijrahChronology.INSTANCE.date(1320, 1, 1), "Hijrah-umalqura AH 1320-01-01"},
 375             {HijrahChronology.INSTANCE.date(1500, 10, 28), "Hijrah-umalqura AH 1500-10-28"},
 376             {HijrahChronology.INSTANCE.date(1500, 10, 29), "Hijrah-umalqura AH 1500-10-29"},
 377             {HijrahChronology.INSTANCE.date(1434, 12, 5), "Hijrah-umalqura AH 1434-12-05"},
 378             {HijrahChronology.INSTANCE.date(1434, 12, 6), "Hijrah-umalqura AH 1434-12-06"},
 379         };
 380     }
 381 
 382     // Test to verify the returned string value of a given date instance
 383     @Test(dataProvider="toString")
 384     public void test_toString(ChronoLocalDate hijrahDate, String expected) {
 385         assertEquals(hijrahDate.toString(), expected);
 386     }
 387 
 388     // Data provider for maximum number of days
 389     @DataProvider(name="monthDays")
 390     Object[][] data_monthDays() {
 391         return new Object[][] {
 392             {1432, 1, 29},
 393             {1432, 4, 30},
 394             {1433, 12, 29},
 395             {1434, 1, 29},
 396             {1435, 8, 29},
 397             {1435, 9, 30},
 398         };
 399     }
 400 
 401     // Test to verify the maximum number of days by adding one month to a given date
 402     @Test (dataProvider="monthDays")
 403     public void test_valueRange_monthDays(int year, int month, int maxlength) {
 404         ChronoLocalDate date = HijrahChronology.INSTANCE.date(year, month, 1);
 405         ValueRange range = null;
 406         for (int i=1; i<=12; i++) {
 407             range = date.range(ChronoField.DAY_OF_MONTH);
 408             date = date.plus(1, ChronoUnit.MONTHS);
 409             assertEquals(range.getMaximum(), month, maxlength);
 410         }
 411     }
 412 
 413     // Test to get the last day of the month by adjusting the date with lastDayOfMonth() method
 414     @Test(dataProvider="monthDays")
 415     public void test_lastDayOfMonth(int year, int month, int numDays) {
 416         HijrahDate hDate = HijrahChronology.INSTANCE.date(year, month, 1);
 417         hDate = hDate.with(TemporalAdjusters.lastDayOfMonth());
 418         assertEquals(hDate.get(ChronoField.DAY_OF_MONTH), numDays);
 419     }
 420 
 421     // Data provider for the 12 islamic month names in a formatted date
 422     @DataProvider(name="patternMonthNames")
 423     Object[][] data_patternMonthNames() {
 424         return new Object[][] {
 425             {1434, 1, 1, "01 AH Thu Muharram 1434"},
 426             {1434, 2, 1, "01 AH Fri Safar 1434"},
 427             {1434, 3, 1, "01 AH Sun Rabi\u02bb I 1434"},//the actual month name is Rabi Al-Awwal, but the locale data contains short form.
 428             {1434, 4, 1, "01 AH Mon Rabi\u02bb II 1434"},//the actual month name is Rabi Al-Akhar, but the locale data contains short form.
 429             {1434, 5, 1, "01 AH Wed Jumada I 1434"},//the actual month name is Jumada Al-Awwal, but the locale data contains short form.
 430             {1434, 6, 1, "01 AH Thu Jumada II 1434"},//the actual month name is Jumada Al-Akhar, but the locale data contains short form.
 431             {1434, 7, 1, "01 AH Sat Rajab 1434"},
 432             {1434, 8, 1, "01 AH Mon Sha\u02bbban 1434"},
 433             {1434, 9, 1, "01 AH Tue Ramadan 1434"},
 434             {1434, 10, 1, "01 AH Thu Shawwal 1434"},
 435             {1434, 11, 1, "01 AH Sat Dhu\u02bbl-Qi\u02bbdah 1434"},
 436             {1434, 12, 1, "01 AH Sun Dhu\u02bbl-Hijjah 1434"},
 437         };
 438     }
 439 
 440     // Test to verify the formatted dates
 441     @Test(dataProvider="patternMonthNames")
 442     public void test_ofPattern(int year, int month, int day, String expected) {
 443         DateTimeFormatter test = DateTimeFormatter.ofPattern("dd G E MMMM yyyy", Locale.US);
 444         assertEquals(test.format(HijrahDate.of(year, month, day)), expected);
 445     }
 446 
 447     // Data provider for localized dates
 448     @DataProvider(name="chronoDateTimes")
 449    Object[][] data_chronodatetimes() {
 450         return new Object[][] {
 451             {1432, 12, 29, "Safar 1, 1434 AH"},
 452             {1433, 1, 30, "Safar 30, 1434 AH"},
 453             {1434, 6, 30, "Rajab 30, 1435 AH"},
 454         };
 455     }
 456 
 457     // Test to verify the localized dates using ofLocalizedDate() method
 458     @Test(dataProvider="chronoDateTimes")
 459     public void test_formatterOfLocalizedDate(int year, int month, int day, String expected) {
 460         HijrahDate hd = HijrahChronology.INSTANCE.date(year, month, day);
 461         ChronoLocalDateTime<HijrahDate> hdt = hd.atTime(LocalTime.NOON);
 462         hdt = hdt.plus(1, ChronoUnit.YEARS);
 463         hdt = hdt.plus(1, ChronoUnit.MONTHS);
 464         hdt = hdt.plus(1, ChronoUnit.DAYS);
 465         hdt = hdt.plus(1, ChronoUnit.HOURS);
 466         hdt = hdt.plus(1, ChronoUnit.MINUTES);
 467         hdt = hdt.plus(1, ChronoUnit.SECONDS);
 468         DateTimeFormatter df = DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG).withChronology(Chronology.of("Hijrah-umalqura")).withLocale(Locale.US);
 469         assertEquals(df.format(hdt), expected);
 470     }
 471 
 472     // Data provider to get the day of the week in a given date
 473     // The day of the week varies if the week starts with a saturday or sunday
 474     @DataProvider(name="dayOfWeek")
 475     Object[][] data_dayOfweek() {
 476         return new Object[][] {
 477             {HijrahDate.of(1434, 6, 24), 1, 7},
 478             {HijrahDate.of(1432, 9, 3), 5, 4},
 479             {HijrahDate.of(1334, 12, 29), 7, 6},
 480             {HijrahDate.of(1354, 5, 24), 1, 7},
 481             {HijrahDate.of(1465, 10, 2), 2, 1},
 482         };
 483     }
 484 
 485     // Test to get the day of the week based on a Saturday/Sunday as the first day of the week
 486     @Test(dataProvider="dayOfWeek")
 487     public void test_dayOfWeek(HijrahDate date, int satStart, int sunStart) {
 488         assertEquals(date.get(WeekFields.of(DayOfWeek.SATURDAY, 7).dayOfWeek()), satStart);
 489         assertEquals(date.get(WeekFields.of(DayOfWeek.SUNDAY, 7).dayOfWeek()), sunStart);
 490     }
 491 
 492     // Data sample to get the epoch days of a date instance
 493     @DataProvider(name="epochDays")
 494     Object[][] data_epochdays() {
 495         return new Object[][] {
 496             {1332, -20486},
 497             {1334, -19777},
 498             {1336, -19068},
 499             {1432, 14950},
 500             {1434, 15659},
 501             {1534, 51096},
 502             {1535, 51450},
 503         };
 504     }
 505 
 506     // Test to verify the number of epoch days of a date instance
 507     @Test(dataProvider="epochDays")
 508     public void test_epochDays(int y, long epoch) {
 509         HijrahDate date = HijrahDate.of(y, 1, 1);
 510         assertEquals(date.toEpochDay(), epoch);
 511     }
 512 
 513     // Data provider to verify whether a given hijrah year is a leap year or not
 514     @DataProvider(name="leapYears")
 515     Object[][] data_leapyears() {
 516         return new Object[][] {
 517             {1302, true},
 518             {1305, false},
 519             {1315, false},
 520             {1534, false},
 521             {1411, true},
 522             {1429, false},
 523             {1433, true},
 524             {1443, true},
 525         };
 526     }
 527 
 528     // Test to verify whether a given hijrah year is a leap year or not
 529     @Test(dataProvider="leapYears")
 530     public void test_leapYears(int y, boolean leapyear) {
 531         HijrahDate date = HijrahDate.of(y, 1, 1);
 532         assertEquals(date.isLeapYear(), leapyear);
 533     }
 534 
 535     // Data provider to verify that a given hijrah year is outside the range of supported years
 536     // The values are dependent on the currently configured UmmAlQura calendar data
 537     @DataProvider(name="OutOfRangeLeapYears")
 538     Object[][] data_invalid_leapyears() {
 539         return new Object[][] {
 540                 {1299},
 541                 {1601},
 542                 {Integer.MAX_VALUE},
 543                 {Integer.MIN_VALUE},
 544         };
 545     }
 546 
 547     @Test(dataProvider="OutOfRangeLeapYears")
 548     public void test_notLeapYears(int y) {
 549         assertFalse(HijrahChronology.INSTANCE.isLeapYear(y), "Out of range leap year");
 550     }
 551 
 552 
 553     // Date samples to convert HijrahDate to LocalDate and vice versa
 554     @DataProvider(name="samples")
 555     Object[][] data_samples() {
 556         return new Object[][] {
 557             {HijrahChronology.INSTANCE.date(1319, 12, 30), LocalDate.of(1902, 4, 9)},
 558             {HijrahChronology.INSTANCE.date(1320, 1, 1), LocalDate.of(1902, 4, 10)},
 559             {HijrahChronology.INSTANCE.date(1321, 12, 30), LocalDate.of(1904, 3, 18)},
 560             {HijrahChronology.INSTANCE.date(1433, 7, 29), LocalDate.of(2012, 6, 19)},
 561             {HijrahChronology.INSTANCE.date(1434, 10, 12), LocalDate.of(2013, 8, 19)},
 562             {HijrahChronology.INSTANCE.date(1500, 3, 3), LocalDate.of(2077, 1, 28)},
 563         };
 564     }
 565 
 566     // Test to get LocalDate instance from a given HijrahDate
 567     @Test(dataProvider="samples")
 568     public void test_toLocalDate(ChronoLocalDate hijrahDate, LocalDate iso) {
 569         assertEquals(LocalDate.from(hijrahDate), iso);
 570     }
 571 
 572     // Test to adjust HijrahDate with a given LocalDate
 573     @Test(dataProvider="samples")
 574     public void test_adjust_toLocalDate(ChronoLocalDate hijrahDate, LocalDate iso) {
 575         assertEquals(hijrahDate.with(iso), hijrahDate);
 576     }
 577 
 578     // Test to get a HijrahDate from a calendrical
 579     @Test(dataProvider="samples")
 580     public void test_fromCalendrical(ChronoLocalDate hijrahDate, LocalDate iso) {
 581         assertEquals(HijrahChronology.INSTANCE.date(iso), hijrahDate);
 582     }
 583 
 584     // Test to verify the day of week of a given HijrahDate and LocalDate
 585     @Test(dataProvider="samples")
 586     public void test_dayOfWeekEqualIsoDayOfWeek(ChronoLocalDate hijrahDate, LocalDate iso) {
 587         assertEquals(hijrahDate.get(ChronoField.DAY_OF_WEEK), iso.get(ChronoField.DAY_OF_WEEK), "Hijrah day of week should be same as ISO day of week");
 588     }
 589 
 590     // Test to get the local date by applying the MIN adjustment with hijrah date
 591     @Test(dataProvider="samples")
 592     public void test_LocalDate_adjustToHijrahDate(ChronoLocalDate hijrahDate, LocalDate localDate) {
 593         LocalDate test = LocalDate.MIN.with(hijrahDate);
 594         assertEquals(test, localDate);
 595     }
 596 
 597     // Test to get the local date time by applying the MIN adjustment with hijrah date
 598     @Test(dataProvider="samples")
 599     public void test_LocalDateTime_adjustToHijrahDate(ChronoLocalDate hijrahDate, LocalDate localDate) {
 600         LocalDateTime test = LocalDateTime.MIN.with(hijrahDate);
 601         assertEquals(test, LocalDateTime.of(localDate, LocalTime.MIDNIGHT));
 602     }
 603 
 604     // Sample dates for comparison
 605     @DataProvider(name="datesForComparison")
 606     Object[][] data_datesForComparison() {
 607         return new Object[][] {
 608             {HijrahChronology.INSTANCE.date(1434, 6, 26), LocalDate.of(2013, 5, 5), -1, 1},
 609             {HijrahChronology.INSTANCE.date(1433, 4, 15), LocalDate.of(2012, 3, 15), 1, -1},
 610             {HijrahChronology.INSTANCE.date(1432, 5, 21), LocalDate.of(2011, 4, 22), -1, 1},
 611             {HijrahChronology.INSTANCE.date(1433, 7, 29), LocalDate.of(2012, 6, 2), -1, 1},
 612             {HijrahChronology.INSTANCE.date(1434, 10, 12), LocalDate.of(2013, 8, 2), -1, 1},
 613         };
 614     }
 615 
 616     // Test to compare dates in both forward and reverse order
 617     @Test(dataProvider="datesForComparison")
 618     public void test_compareDates(HijrahDate hdate, LocalDate ldate, int result1, int result2) {
 619         assertEquals(ldate.compareTo(hdate), result1);
 620         assertEquals(hdate.compareTo(ldate), result2);
 621     }
 622 
 623     // Test to verify the values of various chrono fields for a given hijrah date instance
 624     @Test
 625     public void test_chronoFields() {
 626         ChronoLocalDate hdate = HijrahChronology.INSTANCE.date(1434, 6, 28);
 627         assertEquals(hdate.get(ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH), 3);
 628         assertEquals(hdate.get(ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR), 7);
 629         assertEquals(hdate.get(ChronoField.ALIGNED_WEEK_OF_MONTH), 4);
 630         assertEquals(hdate.get(ChronoField.ALIGNED_WEEK_OF_YEAR), 25);
 631         assertEquals(hdate.get(ChronoField.ERA), 1);
 632         assertEquals(hdate.get(ChronoField.YEAR_OF_ERA), 1434);
 633         assertEquals(hdate.get(ChronoField.MONTH_OF_YEAR), 6);
 634         assertEquals(hdate.get(ChronoField.DAY_OF_MONTH), 28);
 635         assertEquals(hdate.get(ChronoField.DAY_OF_WEEK), 3);
 636         assertEquals(hdate.get(ChronoField.DAY_OF_YEAR), 175);
 637     }
 638 
 639     // Test to verify the returned hijrah date after adjusting the day of week as Saturday
 640     @Test
 641     public void test_adjustInto() {
 642         assertEquals(DayOfWeek.SATURDAY.adjustInto(HijrahDate.of(1434, 6, 28)), HijrahDate.of(1434, 7, 1));
 643         assertEquals(DayOfWeek.SATURDAY.adjustInto(HijrahDate.of(1432, 4, 13)), HijrahDate.of(1432, 4, 14));
 644         assertEquals(DayOfWeek.SATURDAY.adjustInto(HijrahDate.of(1433, 11, 29)), HijrahDate.of(1433, 12, 4));
 645         assertEquals(DayOfWeek.SATURDAY.adjustInto(HijrahDate.of(1434, 5, 10)), HijrahDate.of(1434, 5, 11));
 646         assertEquals(DayOfWeek.SATURDAY.adjustInto(HijrahDate.of(1434, 9, 11)), HijrahDate.of(1434, 9, 12));
 647     }
 648 
 649     //-----------------------------------------------------------------------
 650     // zonedDateTime(TemporalAccessor)
 651     //-----------------------------------------------------------------------
 652     @DataProvider(name="zonedDateTime")
 653     Object[][] data_zonedDateTime() {
 654         return new Object[][] {
 655             {ZonedDateTime.of(2012, 2, 29, 2, 7, 1, 1, ZONE_RIYADH), HijrahChronology.INSTANCE.date(1433, 4, 7), LocalTime.of(2, 7, 1, 1), null},
 656             {OffsetDateTime.of(2012, 2, 29, 2, 7, 1, 1, OFFSET_PTWO), HijrahChronology.INSTANCE.date(1433, 4, 7), LocalTime.of(2, 7, 1, 1), null},
 657             {LocalDateTime.of(2012, 2, 29, 2, 7), null, null, DateTimeException.class},
 658             {JapaneseDate.of(2012, 2, 29), null, null, DateTimeException.class},
 659             {ThaiBuddhistDate.of(2012 + 543, 2, 29), null, null, DateTimeException.class},
 660             {LocalDate.of(2012, 2, 29), null, null, DateTimeException.class},
 661             {LocalTime.of(20, 30, 29, 0), null, null, DateTimeException.class},
 662         };
 663     }
 664 
 665     // Test to check the zoned date times
 666     @Test(dataProvider="zonedDateTime")
 667     public void test_zonedDateTime(TemporalAccessor accessor,  HijrahDate expectedDate, LocalTime expectedTime, Class<?> expectedEx) {
 668         if (expectedEx == null) {
 669             ChronoZonedDateTime<HijrahDate> result = HijrahChronology.INSTANCE.zonedDateTime(accessor);
 670             assertEquals(result.toLocalDate(), expectedDate);
 671             assertEquals(HijrahDate.from(accessor), expectedDate);
 672             assertEquals(result.toLocalTime(), expectedTime);
 673 
 674         } else {
 675             try {
 676                 ChronoZonedDateTime<HijrahDate> result = HijrahChronology.INSTANCE.zonedDateTime(accessor);
 677                 fail();
 678             } catch (Exception ex) {
 679                 assertTrue(expectedEx.isInstance(ex));
 680             }
 681         }
 682     }
 683 
 684     //-----------------------------------------------------------------------
 685     // zonedDateTime(Instant, ZoneId )
 686     //-----------------------------------------------------------------------
 687     @Test
 688     public void test_Instant_zonedDateTime() {
 689         OffsetDateTime offsetDateTime = OffsetDateTime.of(2012, 2, 29, 2, 7, 1, 1, OFFSET_PTWO);
 690         ZonedDateTime zonedDateTime = ZonedDateTime.of(2012, 2, 29, 2, 7, 1, 1, ZONE_RIYADH);
 691 
 692         ChronoZonedDateTime<HijrahDate> result = HijrahChronology.INSTANCE.zonedDateTime(offsetDateTime.toInstant(), offsetDateTime.getOffset());
 693         assertEquals(result.toLocalDate(), HijrahChronology.INSTANCE.date(1433, 4, 7));
 694         assertEquals(result.toLocalTime(), LocalTime.of(2, 7, 1, 1));
 695 
 696         result = HijrahChronology.INSTANCE.zonedDateTime(zonedDateTime.toInstant(), zonedDateTime.getOffset());
 697         assertEquals(result.toLocalDate(), HijrahChronology.INSTANCE.date(1433, 4, 7));
 698         assertEquals(result.toLocalTime(), LocalTime.of(2, 7, 1, 1));
 699     }
 700 
 701     //-----------------------------------------------------------------------
 702     // localDateTime()
 703     //-----------------------------------------------------------------------
 704     @DataProvider(name="localDateTime")
 705     Object[][] data_localDateTime() {
 706         return new Object[][] {
 707             {LocalDateTime.of(2012, 2, 29, 2, 7), HijrahChronology.INSTANCE.date(1433, 4, 7), LocalTime.of(2, 7), null},
 708             {ZonedDateTime.of(2012, 2, 29, 2, 7, 1, 1, ZONE_RIYADH), HijrahChronology.INSTANCE.date(1433, 4, 7), LocalTime.of(2, 7, 1, 1), null},
 709             {OffsetDateTime.of(2012, 2, 29, 2, 7, 1, 1, OFFSET_PTWO), HijrahChronology.INSTANCE.date(1433, 4, 7), LocalTime.of(2, 7, 1, 1), null},
 710             {JapaneseDate.of(2012, 2, 29), null, null, DateTimeException.class},
 711             {ThaiBuddhistDate.of(2012 + 543, 2, 29), null, null, DateTimeException.class},
 712             {LocalDate.of(2012, 2, 29), null, null, DateTimeException.class},
 713             {LocalTime.of(20, 30, 29, 0), null, null, DateTimeException.class},
 714         };
 715     }
 716 
 717     // Test to verify local date time values from various date instances defined in the localDateTime data provider
 718     @Test(dataProvider="localDateTime")
 719     public void test_localDateTime(TemporalAccessor accessor,  HijrahDate expectedDate, LocalTime expectedTime, Class<?> expectedEx) {
 720         if (expectedEx == null) {
 721             ChronoLocalDateTime<HijrahDate> result = HijrahChronology.INSTANCE.localDateTime(accessor);
 722             assertEquals(result.toLocalDate(), expectedDate);
 723             assertEquals(HijrahDate.from(accessor), expectedDate);
 724             assertEquals(result.toLocalTime(), expectedTime);
 725         } else {
 726             try {
 727                 ChronoLocalDateTime<HijrahDate> result = HijrahChronology.INSTANCE.localDateTime(accessor);
 728                 fail();
 729             } catch (Exception ex) {
 730                 assertTrue(expectedEx.isInstance(ex));
 731             }
 732         }
 733     }
 734 
 735     // Sample Hijrah & Minguo Dates
 736     @DataProvider(name="hijrahToMinguo")
 737     Object[][] data_hijrahToMinguo() {
 738         return new Object[][] {
 739             {HijrahDate.of(1350,5,15), MinguoDate.of(20,9,28)},
 740             {HijrahDate.of(1434,5,1), MinguoDate.of(102,3,13)},
 741             {HijrahDate.of(1436,1,1), MinguoDate.of(103,10,25)},
 742             {HijrahDate.of(1500,6,12), MinguoDate.of(166,5,5)},
 743             {HijrahDate.of(1550,3,11), MinguoDate.of(214,8,11)},
 744         };
 745     }
 746 
 747     // Test to verify the date conversion from Hijrah to Minguo chronology
 748     @Test(dataProvider="hijrahToMinguo")
 749     public void test_hijrahToMinguo(HijrahDate hijrah, MinguoDate minguo) {
 750         assertEquals(MinguoChronology.INSTANCE.date(hijrah), minguo);
 751     }
 752 
 753     // Sample Hijrah & Thai Dates
 754     @DataProvider(name="hijrahToThai")
 755     Object[][] data_hijrahToThai() {
 756         return new Object[][] {
 757             {HijrahDate.of(1350,5,15), ThaiBuddhistDate.of(2474,9,28)},
 758             {HijrahDate.of(1434,5,1), ThaiBuddhistDate.of(2556,3,13)},
 759             {HijrahDate.of(1436,1,1), ThaiBuddhistDate.of(2557,10,25)},
 760             {HijrahDate.of(1500,6,12), ThaiBuddhistDate.of(2620,5,5)},
 761             {HijrahDate.of(1550,3,11), ThaiBuddhistDate.of(2668,8,11)},
 762         };
 763     }
 764 
 765     // Test to verify the date conversion from Hijrah to Thai chronology
 766     @Test(dataProvider="hijrahToThai")
 767     public void test_hijrahToThai(HijrahDate hijrah, ThaiBuddhistDate thai) {
 768         assertEquals(ThaiBuddhistChronology.INSTANCE.date(hijrah), thai);
 769     }
 770 
 771     // Sample Hijrah & Japanese Dates
 772     @DataProvider(name="hijrahToJapanese")
 773     Object[][] data_hijrahToJapanese() {
 774         return new Object[][] {
 775             {HijrahDate.of(1350,5,15), "Japanese Showa 6-09-28"},
 776             {HijrahDate.of(1434,5,1), "Japanese Heisei 25-03-13"},
 777             {HijrahDate.of(1436,1,1), "Japanese Heisei 26-10-25"},
 778             {HijrahDate.of(1500,6,12), "Japanese Heisei 89-05-05"},
 779             {HijrahDate.of(1550,3,11), "Japanese Heisei 137-08-11"},
 780         };
 781     }
 782 
 783     // Test to verify the date conversion from Hijrah to Japanese chronology
 784     @Test(dataProvider="hijrahToJapanese")
 785       public void test_hijrahToJapanese(HijrahDate hijrah, String japanese) {
 786           assertEquals(JapaneseChronology.INSTANCE.date(hijrah).toString(), japanese);
 787     }
 788 }