12d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert// © 2016 and later: Unicode, Inc. and others. 22d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert// License & terms of use: http://www.unicode.org/copyright.html#License 37935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/* 47935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ******************************************************************************* 57935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Copyright (C) 1996-2010, International Business Machines Corporation and * 67935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * others. All Rights Reserved. * 77935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ******************************************************************************* 87935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 97935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpackage com.ibm.icu.dev.test.calendar; 117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Date; 137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.HashMap; 147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Locale; 157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Map; 167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.dev.test.TestFmwk; 187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.DateFormat; 197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.SimpleDateFormat; 207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.Calendar; 217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.ChineseCalendar; 227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.GregorianCalendar; 237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.SimpleTimeZone; 247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/** 267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * A base class for classes that test individual Calendar subclasses. 277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Defines various useful utility methods and constants 287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 292d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubertpublic class CalendarTestFmwk extends TestFmwk { 307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Constants for use by subclasses, solely to save typing 327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final static int SUN = Calendar.SUNDAY; 337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final static int MON = Calendar.MONDAY; 347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final static int TUE = Calendar.TUESDAY; 357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final static int WED = Calendar.WEDNESDAY; 367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final static int THU = Calendar.THURSDAY; 377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final static int FRI = Calendar.FRIDAY; 387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final static int SAT = Calendar.SATURDAY; 397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final static int ERA = Calendar.ERA; 417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final static int YEAR = Calendar.YEAR; 427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final static int MONTH = Calendar.MONTH; 437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final static int DATE = Calendar.DATE; 447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final static int HOUR = Calendar.HOUR; 457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final static int MINUTE = Calendar.MINUTE; 467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final static int SECOND = Calendar.SECOND; 477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final static int DOY = Calendar.DAY_OF_YEAR; 487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final static int WOY = Calendar.WEEK_OF_YEAR; 497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final static int WOM = Calendar.WEEK_OF_MONTH; 507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final static int DOW = Calendar.DAY_OF_WEEK; 517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final static int DOWM = Calendar.DAY_OF_WEEK_IN_MONTH; 527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final static SimpleTimeZone UTC = new SimpleTimeZone(0, "GMT"); 547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final String[] FIELD_NAME = { 567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "ERA", "YEAR", "MONTH", "WEEK_OF_YEAR", "WEEK_OF_MONTH", 577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "DAY_OF_MONTH", "DAY_OF_YEAR", "DAY_OF_WEEK", 587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "DAY_OF_WEEK_IN_MONTH", "AM_PM", "HOUR", "HOUR_OF_DAY", 597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "MINUTE", "SECOND", "MILLISECOND", "ZONE_OFFSET", 607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "DST_OFFSET", "YEAR_WOY", "DOW_LOCAL", "EXTENDED_YEAR", 617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "JULIAN_DAY", "MILLISECONDS_IN_DAY", 627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "IS_LEAP_MONTH" // (ChineseCalendar only) 637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert }; 647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final String fieldName(int f) { 667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return (f>=0 && f<FIELD_NAME.length) ? 677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert FIELD_NAME[f] : ("<Field " + f + ">"); 687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Iterates through a list of calendar <code>TestCase</code> objects and 727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * makes sure that the time-to-fields and fields-to-time calculations work 737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * correnctly for the values in each test case. 747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 752d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert protected void doTestCases(TestCase[] cases, Calendar cal) 767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { 777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cal.setTimeZone(UTC); 787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Get a format to use for printing dates in the calendar system we're testing 807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert DateFormat format = DateFormat.getDateTimeInstance(cal, DateFormat.SHORT, -1, Locale.getDefault()); 817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert final String pattern = (cal instanceof ChineseCalendar) ? 837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "E MMl/dd/y G HH:mm:ss.S z" : 847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "E, MM/dd/yyyy G HH:mm:ss.S z"; 857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ((SimpleDateFormat)format).applyPattern(pattern); 877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // This format is used for printing Gregorian dates. 897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert DateFormat gregFormat = new SimpleDateFormat(pattern); 907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert gregFormat.setTimeZone(UTC); 917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert GregorianCalendar pureGreg = new GregorianCalendar(UTC); 937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert pureGreg.setGregorianChange(new Date(Long.MIN_VALUE)); 947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert DateFormat pureGregFmt = new SimpleDateFormat("E M/d/yyyy G"); 957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert pureGregFmt.setCalendar(pureGreg); 967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Now iterate through the test cases and see what happens 987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < cases.length; i++) 997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { 1007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert logln("\ntest case: " + i); 1017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert TestCase test = cases[i]; 1027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // 1047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // First we want to make sure that the millis -> fields calculation works 1057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // test.applyTime will call setTime() on the calendar object, and 1067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // test.fieldsEqual will retrieve all of the field values and make sure 1077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // that they're the same as the ones in the testcase 1087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // 1097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert test.applyTime(cal); 1107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!test.fieldsEqual(cal, this)) { 1117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert errln("Fail: (millis=>fields) " + 1127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert gregFormat.format(test.getTime()) + " => " + 1137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert format.format(cal.getTime()) + 1147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ", expected " + test); 1157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // 1187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // If that was OK, check the fields -> millis calculation 1197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // test.applyFields will set all of the calendar's fields to 1207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // match those in the test case. 1217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // 1227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cal.clear(); 1237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert test.applyFields(cal); 1247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!test.equals(cal)) { 1257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert errln("Fail: (fields=>millis) " + test + " => " + 1267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert pureGregFmt.format(cal.getTime()) + 1277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ", expected " + pureGregFmt.format(test.getTime())); 1287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static public final boolean ROLL = true; 1337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static public final boolean ADD = false; 1347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Process test cases for <code>add</code> and <code>roll</code> methods. 1377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Each test case is an array of integers, as follows: 1387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <ul> 1397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <li>0: input year 1407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <li>1: month (zero-based) 1417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <li>2: day 1427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <li>3: field to roll or add to 1437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <li>4: amount to roll or add 1447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <li>5: result year 1457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <li>6: month (zero-based) 1467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <li>7: day 1477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </ul> 1487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * For example: 1497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <pre> 1507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * // input add by output 1517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * // year month day field amount year month day 1527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * { 5759, HESHVAN, 2, MONTH, 1, 5759, KISLEV, 2 }, 1537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </pre> 1547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 1557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param roll <code>true</code> or <code>ROLL</code> to test the <code>roll</code> method; 1567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <code>false</code> or <code>ADD</code> to test the <code>add</code method 1577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1582d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert protected void doRollAdd(boolean roll, Calendar cal, int[][] tests) 1597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { 1607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String name = roll ? "rolling" : "adding"; 1617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < tests.length; i++) { 1637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int[] test = tests[i]; 1647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cal.clear(); 1667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (cal instanceof ChineseCalendar) { 1677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cal.set(Calendar.EXTENDED_YEAR, test[0]); 1687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cal.set(Calendar.MONTH, test[1]); 1697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cal.set(Calendar.DAY_OF_MONTH, test[2]); 1707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 1717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cal.set(test[0], test[1], test[2]); 1727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert double day0 = getJulianDay(cal); 1747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (roll) { 1757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cal.roll(test[3], test[4]); 1767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 1777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cal.add(test[3], test[4]); 1787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int y = cal.get(cal instanceof ChineseCalendar ? 1807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Calendar.EXTENDED_YEAR : YEAR); 1817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (y != test[5] || cal.get(MONTH) != test[6] 1827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert || cal.get(DATE) != test[7]) 1837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { 1847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert errln("Fail: " + name + " "+ ymdToString(test[0], test[1], test[2]) 1857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert + " (" + day0 + ")" 1867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert + " " + FIELD_NAME[test[3]] + " by " + test[4] 1877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert + ": expected " + ymdToString(test[5], test[6], test[7]) 1887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert + ", got " + ymdToString(cal)); 1897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (isVerbose()) { 1907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert logln("OK: " + name + " "+ ymdToString(test[0], test[1], test[2]) 1917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert + " (" + day0 + ")" 1927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert + " " + FIELD_NAME[test[3]] + " by " + test[4] 1937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert + ": got " + ymdToString(cal)); 1947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Test the functions getXxxMinimum() and getXxxMaximum() by marching a 2007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * test calendar 'cal' through 'numberOfDays' sequential days starting 2017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * with 'startDate'. For each date, read a field value along with its 2027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * reported actual minimum and actual maximum. These values are 2037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * checked against one another as well as against getMinimum(), 2047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * getGreatestMinimum(), getLeastMaximum(), and getMaximum(). We 2057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * expect to see: 2067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 2077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 1. minimum <= actualMinimum <= greatestMinimum <= 2087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * leastMaximum <= actualMaximum <= maximum 2097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 2107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 2. actualMinimum <= value <= actualMaximum 2117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 2127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Note: In addition to outright failures, this test reports some 2137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * results as warnings. These are not generally of concern, but they 2147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * should be evaluated by a human. To see these, run this test in 2157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * verbose mode. 2167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param cal the calendar to be tested 2177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param fieldsToTest an array of field values to be tested, e.g., new 2187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * int[] { Calendar.MONTH, Calendar.DAY_OF_MONTH }. It only makes 2197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * sense to test the day fields; the time fields are not tested by this 2207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * method. If null, then test all standard fields. 2217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param startDate the first date to test 2227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param testDuration if positive, the number of days to be tested. 2237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * If negative, the number of seconds to run the test. 2247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2252d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert protected void doLimitsTest(Calendar cal, int[] fieldsToTest, 2267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Date startDate, int testDuration) { 2277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert GregorianCalendar greg = new GregorianCalendar(); 2287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert greg.setTime(startDate); 2297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert logln("Start: " + startDate); 2307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (fieldsToTest == null) { 2327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert fieldsToTest = new int[] { 2337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Calendar.ERA, Calendar.YEAR, Calendar.MONTH, 2347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Calendar.WEEK_OF_YEAR, Calendar.WEEK_OF_MONTH, 2357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Calendar.DAY_OF_MONTH, Calendar.DAY_OF_YEAR, 2367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Calendar.DAY_OF_WEEK_IN_MONTH, Calendar.YEAR_WOY, 2377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Calendar.EXTENDED_YEAR 2387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert }; 2397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Keep a record of minima and maxima that we actually see. 2427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // These are kept in an array of arrays of hashes. 2437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Map[][] limits = new Map[fieldsToTest.length][2]; 2447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Object nub = new Object(); // Meaningless placeholder 2457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // This test can run for a long time; show progress. 2477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert long millis = System.currentTimeMillis(); 2487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert long mark = millis + 5000; // 5 sec 2497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert millis -= testDuration * 1000; // stop time if testDuration<0 2507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i=0; 2527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert testDuration>0 ? i<testDuration 2537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert : System.currentTimeMillis()<millis; 2547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ++i) { 2557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (System.currentTimeMillis() >= mark) { 2567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert logln("(" + i + " days)"); 2577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert mark += 5000; // 5 sec 2587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cal.setTimeInMillis(greg.getTimeInMillis()); 2607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int j=0; j<fieldsToTest.length; ++j) { 2617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int f = fieldsToTest[j]; 2627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int v = cal.get(f); 2637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int minActual = cal.getActualMinimum(f); 2647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int maxActual = cal.getActualMaximum(f); 2657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int minLow = cal.getMinimum(f); 2667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int minHigh = cal.getGreatestMinimum(f); 2677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int maxLow = cal.getLeastMaximum(f); 2687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int maxHigh = cal.getMaximum(f); 2697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Fetch the hash for this field and keep track of the 2717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // minima and maxima. 2727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Map[] h = limits[j]; 2737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (h[0] == null) { 2747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert h[0] = new HashMap(); 2757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert h[1] = new HashMap(); 2767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert h[0].put(new Integer(minActual), nub); 2787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert h[1].put(new Integer(maxActual), nub); 2797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (minActual < minLow || minActual > minHigh) { 2817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert errln("Fail: " + ymdToString(cal) + 2827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert " Range for min of " + FIELD_NAME[f] + "(" + f + 2837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ")=" + minLow + ".." + minHigh + 2847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ", actual_min=" + minActual); 2857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (maxActual < maxLow || maxActual > maxHigh) { 2877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert errln("Fail: " + ymdToString(cal) + 2887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert " Range for max of " + FIELD_NAME[f] + "(" + f + 2897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ")=" + maxLow + ".." + maxHigh + 2907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ", actual_max=" + maxActual); 2917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (v < minActual || v > maxActual) { 2937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert errln("Fail: " + ymdToString(cal) + 2947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert " " + FIELD_NAME[f] + "(" + f + ")=" + v + 2957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ", actual range=" + minActual + ".." + maxActual + 2967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ", allowed=(" + minLow + ".." + minHigh + ")..(" + 2977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert maxLow + ".." + maxHigh + ")"); 2987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert greg.add(Calendar.DAY_OF_YEAR, 1); 3017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Check actual maxima and minima seen against ranges returned 3047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // by API. 3057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuffer buf = new StringBuffer(); 3067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int j=0; j<fieldsToTest.length; ++j) { 3077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int f = fieldsToTest[j]; 3087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.setLength(0); 3097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(FIELD_NAME[f]); 3107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Map[] h = limits[j]; 3117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean fullRangeSeen = true; 3127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int k=0; k<2; ++k) { 3137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int rangeLow = (k==0) ? 3147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cal.getMinimum(f) : cal.getLeastMaximum(f); 3157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int rangeHigh = (k==0) ? 3167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cal.getGreatestMinimum(f) : cal.getMaximum(f); 3177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // If either the top of the range or the bottom was never 3187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // seen, then there may be a problem. 3197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (h[k].get(new Integer(rangeLow)) == null || 3207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert h[k].get(new Integer(rangeHigh)) == null) { 3217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert fullRangeSeen = false; 3227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(k==0 ? " minima seen=(" : "; maxima seen=("); 3247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (Object v : h[k].keySet()) { 3257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(" " + v); 3267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(") range=" + rangeLow + ".." + rangeHigh); 3287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (fullRangeSeen) { 3307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert logln("OK: " + buf.toString()); 3317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 3327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // This may or may not be an error -- if the range of dates 3337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // we scan over doesn't happen to contain a minimum or 3347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // maximum, it doesn't mean some other range won't. 3357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert logln("Warning: " + buf.toString()); 3367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert logln("End: " + greg.getTime()); 3407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 3437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * doLimitsTest with default test duration 3447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3452d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert protected void doLimitsTest(Calendar cal, int[] fieldsToTest, Date startDate) { 3462d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert int testTime = TestFmwk.getExhaustiveness() <= 5 ? -3 : -120; // in seconds 3477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert doLimitsTest(cal, fieldsToTest, startDate, testTime); 3487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 3517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Test the functions getMaximum/getGeratestMinimum logically correct. 3527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This method assumes day of week cycle is consistent. 3537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param cal The calendar instance to be tested. 3547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param leapMonth true if the calendar system has leap months 3557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3562d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert protected void doTheoreticalLimitsTest(Calendar cal, boolean leapMonth) { 3577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int nDOW = cal.getMaximum(Calendar.DAY_OF_WEEK); 3587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int maxDOY = cal.getMaximum(Calendar.DAY_OF_YEAR); 3597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int lmaxDOW = cal.getLeastMaximum(Calendar.DAY_OF_YEAR); 3607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int maxWOY = cal.getMaximum(Calendar.WEEK_OF_YEAR); 3617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int lmaxWOY = cal.getLeastMaximum(Calendar.WEEK_OF_YEAR); 3627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int maxM = cal.getMaximum(Calendar.MONTH) + 1; 3637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int lmaxM = cal.getLeastMaximum(Calendar.MONTH) + 1; 3647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int maxDOM = cal.getMaximum(Calendar.DAY_OF_MONTH); 3657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int lmaxDOM = cal.getLeastMaximum(Calendar.DAY_OF_MONTH); 3667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int maxDOWIM = cal.getMaximum(Calendar.DAY_OF_WEEK_IN_MONTH); 3677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int lmaxDOWIM = cal.getLeastMaximum(Calendar.DAY_OF_WEEK_IN_MONTH); 3687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int maxWOM = cal.getMaximum(Calendar.WEEK_OF_MONTH); 3697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int lmaxWOM = cal.getLeastMaximum(Calendar.WEEK_OF_MONTH); 3707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int minDaysInFirstWeek = cal.getMinimalDaysInFirstWeek(); 3717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Day of year 3737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int expected; 3747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!leapMonth) { 3757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert expected = maxM*maxDOM; 3767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (maxDOY > expected) { 3777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert errln("FAIL: Maximum value of DAY_OF_YEAR is too big: " + maxDOY + "/expected: <=" + expected); 3787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert expected = lmaxM*lmaxDOM; 3807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (lmaxDOW < expected) { 3817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert errln("FAIL: Least maximum value of DAY_OF_YEAR is too small: " + lmaxDOW + "/expected: >=" + expected); 3827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Week of year 3867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert expected = maxDOY/nDOW + 1; 3877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (maxWOY > expected) { 3887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert errln("FAIL: Maximum value of WEEK_OF_YEAR is too big: " + maxWOY + "/expected: <=" + expected); 3897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert expected = lmaxDOW/nDOW; 3917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (lmaxWOY < expected) { 3927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert errln("FAIL: Least maximum value of WEEK_OF_YEAR is too small: " + lmaxWOY + "/expected >=" + expected); 3937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Day of week in month 3967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert expected = (maxDOM + nDOW - 1)/nDOW; 3977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (maxDOWIM != expected) { 3987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert errln("FAIL: Maximum value of DAY_OF_WEEK_IN_MONTH is incorrect: " + maxDOWIM + "/expected: " + expected); 3997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert expected = (lmaxDOM + nDOW - 1)/nDOW; 4017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (lmaxDOWIM != expected) { 4027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert errln("FAIL: Least maximum value of DAY_OF_WEEK_IN_MONTH is incorrect: " + lmaxDOWIM + "/expected: " + expected); 4037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Week of month 4067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert expected = (maxDOM + (nDOW - 1) + (nDOW - minDaysInFirstWeek)) / nDOW; 4077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (maxWOM != expected) { 4087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert errln("FAIL: Maximum value of WEEK_OF_MONTH is incorrect: " + maxWOM + "/expected: " + expected); 4097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert expected = (lmaxDOM + (nDOW - minDaysInFirstWeek)) / nDOW; 4117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (lmaxWOM != expected) { 4127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert errln("FAIL: Least maximum value of WEEK_OF_MONTH is incorrect: " + lmaxWOM + "/expected: " + expected); 4137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Convert year,month,day values to the form "year/month/day". 4187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * On input the month value is zero-based, but in the result string it is one-based. 4197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static public String ymdToString(int year, int month, int day) { 4217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return "" + year + "/" + (month+1) + "/" + day; 4227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Convert year,month,day values to the form "year/month/day". 4267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static public String ymdToString(Calendar cal) { 4287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert double day = getJulianDay(cal); 4297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (cal instanceof ChineseCalendar) { 4307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return "" + cal.get(Calendar.EXTENDED_YEAR) + "/" + 4317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert (cal.get(Calendar.MONTH)+1) + 4327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert (cal.get(Calendar.IS_LEAP_MONTH)==1?"(leap)":"") + "/" + 4337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cal.get(Calendar.DATE) + " (" + day + ", time=" + cal.getTimeInMillis() + ")"; 4347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return ymdToString(cal.get(Calendar.EXTENDED_YEAR), 4367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cal.get(MONTH), cal.get(DATE)) + 4377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert " (" + day + ", time=" + cal.getTimeInMillis() + ")"; 4387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static double getJulianDay(Calendar cal) { 4417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return (cal.getTime().getTime() - JULIAN_EPOCH) / DAY_MS; 4427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static final double DAY_MS = 24*60*60*1000.0; 4457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static final long JULIAN_EPOCH = -210866760000000L; // 1/1/4713 BC 12:00 4467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert} 447