2 *******************************************************************************
3 * Copyright (C) 1996-2013, International Business Machines Corporation and *
4 * others. All Rights Reserved. *
5 *******************************************************************************
7 package com.ibm.icu.dev.test.calendar;
9 import java.io.ByteArrayInputStream;
10 import java.io.ByteArrayOutputStream;
11 import java.io.IOException;
12 import java.io.ObjectInputStream;
13 import java.io.ObjectOutputStream;
14 import java.util.Date;
15 import java.util.Locale;
17 import com.ibm.icu.impl.LocaleUtility;
18 import com.ibm.icu.text.DateFormat;
19 import com.ibm.icu.text.SimpleDateFormat;
20 import com.ibm.icu.util.Calendar;
21 import com.ibm.icu.util.IslamicCalendar;
22 import com.ibm.icu.util.IslamicCalendar.CalculationType;
23 import com.ibm.icu.util.TimeZone;
24 import com.ibm.icu.util.ULocale;
27 * Tests for the <code>IslamicCalendar</code> class.
29 public class IslamicTest extends CalendarTest {
30 public static void main(String args[]) throws Exception {
31 new IslamicTest().run(args);
34 /** Constants to save typing. */
35 public static final int MUHARRAM = IslamicCalendar.MUHARRAM;
36 public static final int SAFAR = IslamicCalendar.SAFAR;
37 public static final int RABI_1 = IslamicCalendar.RABI_1;
38 public static final int RABI_2 = IslamicCalendar.RABI_2;
39 public static final int JUMADA_1 = IslamicCalendar.JUMADA_1;
40 public static final int JUMADA_2 = IslamicCalendar.JUMADA_2;
41 public static final int RAJAB = IslamicCalendar.RAJAB;
42 public static final int SHABAN = IslamicCalendar.SHABAN;
43 public static final int RAMADAN = IslamicCalendar.RAMADAN;
44 public static final int SHAWWAL = IslamicCalendar.SHAWWAL;
45 public static final int QIDAH = IslamicCalendar.DHU_AL_QIDAH;
46 public static final int HIJJAH = IslamicCalendar.DHU_AL_HIJJAH;
48 public void TestRoll() {
49 int[][] tests = new int[][] {
50 // input roll by output
51 // year month day field amount year month day
53 { 0001, QIDAH, 2, MONTH, 1, 0001, HIJJAH, 2 }, // non-leap years
54 { 0001, QIDAH, 2, MONTH, 2, 0001, MUHARRAM, 2 },
55 { 0001, QIDAH, 2, MONTH, -1, 0001, SHAWWAL, 2 },
56 { 0001, MUHARRAM, 2, MONTH, 12, 0001, MUHARRAM, 2 },
57 { 0001, MUHARRAM, 2, MONTH, 13, 0001, SAFAR, 2 },
59 { 0001, HIJJAH, 1, DATE, 30, 0001, HIJJAH, 2 }, // 29-day month
60 { 0002, HIJJAH, 1, DATE, 31, 0002, HIJJAH, 2 }, // 30-day month
62 // Try some rolls that require other fields to be adjusted
63 { 0001, MUHARRAM, 30, MONTH, 1, 0001, SAFAR, 29 },
64 { 0002, HIJJAH, 30, YEAR, -1, 0001, HIJJAH, 29 },
67 IslamicCalendar cal = newCivil();
68 doRollAdd(ROLL, cal, tests);
70 cal = newIslamicUmalqura();
71 doRollAdd(ROLL, cal, tests);
75 * A huge list of test cases to make sure that computeTime and computeFields
76 * work properly for a wide range of data in the civil calendar.
78 public void TestCivilCases()
80 final TestCase[] tests = {
82 // Most of these test cases were taken from the back of
83 // "Calendrical Calculations", with some extras added to help
84 // debug a few of the problems that cropped up in development.
86 // The months in this table are 1-based rather than 0-based,
87 // because it's easier to edit that way.
89 // Julian Day Era Year Month Day WkDay Hour Min Sec
90 new TestCase(1507231.5, 0, -1245, 12, 9, SUN, 0, 0, 0),
91 new TestCase(1660037.5, 0, -813, 2, 23, WED, 0, 0, 0),
92 new TestCase(1746893.5, 0, -568, 4, 1, WED, 0, 0, 0),
93 new TestCase(1770641.5, 0, -501, 4, 6, SUN, 0, 0, 0),
94 new TestCase(1892731.5, 0, -157, 10, 17, WED, 0, 0, 0),
95 new TestCase(1931579.5, 0, -47, 6, 3, MON, 0, 0, 0),
96 new TestCase(1974851.5, 0, 75, 7, 13, SAT, 0, 0, 0),
97 new TestCase(2091164.5, 0, 403, 10, 5, SUN, 0, 0, 0),
98 new TestCase(2121509.5, 0, 489, 5, 22, SUN, 0, 0, 0),
99 new TestCase(2155779.5, 0, 586, 2, 7, FRI, 0, 0, 0),
100 new TestCase(2174029.5, 0, 637, 8, 7, SAT, 0, 0, 0),
101 new TestCase(2191584.5, 0, 687, 2, 20, FRI, 0, 0, 0),
102 new TestCase(2195261.5, 0, 697, 7, 7, SUN, 0, 0, 0),
103 new TestCase(2229274.5, 0, 793, 7, 1, SUN, 0, 0, 0),
104 new TestCase(2245580.5, 0, 839, 7, 6, WED, 0, 0, 0),
105 new TestCase(2266100.5, 0, 897, 6, 1, SAT, 0, 0, 0),
106 new TestCase(2288542.5, 0, 960, 9, 30, SAT, 0, 0, 0),
107 new TestCase(2290901.5, 0, 967, 5, 27, SAT, 0, 0, 0),
108 new TestCase(2323140.5, 0, 1058, 5, 18, WED, 0, 0, 0),
109 new TestCase(2334848.5, 0, 1091, 6, 2, SUN, 0, 0, 0),
110 new TestCase(2348020.5, 0, 1128, 8, 4, FRI, 0, 0, 0),
111 new TestCase(2366978.5, 0, 1182, 2, 3, SUN, 0, 0, 0),
112 new TestCase(2385648.5, 0, 1234, 10, 10, MON, 0, 0, 0),
113 new TestCase(2392825.5, 0, 1255, 1, 11, WED, 0, 0, 0),
114 new TestCase(2416223.5, 0, 1321, 1, 21, SUN, 0, 0, 0),
115 new TestCase(2425848.5, 0, 1348, 3, 19, SUN, 0, 0, 0),
116 new TestCase(2430266.5, 0, 1360, 9, 8, MON, 0, 0, 0),
117 new TestCase(2430833.5, 0, 1362, 4, 13, MON, 0, 0, 0),
118 new TestCase(2431004.5, 0, 1362, 10, 7, THU, 0, 0, 0),
119 new TestCase(2448698.5, 0, 1412, 9, 13, TUE, 0, 0, 0),
120 new TestCase(2450138.5, 0, 1416, 10, 5, SUN, 0, 0, 0),
121 new TestCase(2465737.5, 0, 1460, 10, 12, WED, 0, 0, 0),
122 new TestCase(2486076.5, 0, 1518, 3, 5, SUN, 0, 0, 0),
125 IslamicCalendar civilCalendar = newCivil();
126 civilCalendar.setLenient(true);
127 doTestCases(tests, civilCalendar);
130 public void TestBasic() {
131 IslamicCalendar cal = newCivil();
133 cal.set(1000, 0, 30);
134 logln("1000/0/30 -> " +
135 cal.get(YEAR) + "/" +
136 cal.get(MONTH) + "/" +
141 cal.get(YEAR) + "/" +
142 cal.get(MONTH) + "/" +
147 * Test limits of the Islamic calendar
149 public void TestLimits() {
150 Calendar cal = Calendar.getInstance();
151 cal.set(2007, Calendar.JANUARY, 1);
152 IslamicCalendar islamic = newCivil();
153 doLimitsTest(islamic, null, cal.getTime());
154 doTheoreticalLimitsTest(islamic, true);
157 // number of days to test - Islamic calendar starts to exhibit
158 // rounding errors after year AH3954 - about 2500 years out.
160 IslamicCalendar islamic2 = new IslamicCalendar();
161 islamic2.setType(CalculationType.ISLAMIC);
162 int testTime = getInclusion() <= 5 ? 20000 : 800000;
163 doLimitsTest(islamic2, null, cal.getTime(), testTime);
164 doTheoreticalLimitsTest(islamic2, true);
167 public void Test7427() {
168 // Test the add month in a leap year problem as reported in ticket #7427
169 IslamicCalendar cal = new IslamicCalendar();
171 cal.set(IslamicCalendar.YEAR,1431);
172 cal.set(IslamicCalendar.MONTH, IslamicCalendar.DHU_AL_HIJJAH);
173 cal.add(IslamicCalendar.MONTH,1);
174 if ( cal.get(IslamicCalendar.MONTH) != IslamicCalendar.MUHARRAM ||
175 ( cal.get(IslamicCalendar.YEAR) != 1432 )) {
176 errln("Error incrementing month at the end of a leap year. Expected Month:0 Year:1432 - Got Month:" +
177 cal.get(IslamicCalendar.MONTH) + " Year:" + cal.get(IslamicCalendar.YEAR));
180 public void TestCoverage() {
182 // new IslamicCalendar(TimeZone)
183 IslamicCalendar cal = new IslamicCalendar(TimeZone.getDefault());
185 errln("could not create IslamicCalendar with TimeZone");
190 // new IslamicCalendar(ULocale)
191 IslamicCalendar cal = new IslamicCalendar(ULocale.getDefault());
193 errln("could not create IslamicCalendar with ULocale");
198 // new IslamicCalendar(Locale)
199 IslamicCalendar cal = new IslamicCalendar(Locale.getDefault());
201 errln("could not create IslamicCalendar with Locale");
206 // new IslamicCalendar(Date)
207 IslamicCalendar cal = new IslamicCalendar(new Date());
209 errln("could not create IslamicCalendar with Date");
214 // new IslamicCalendar(int year, int month, int date)
215 IslamicCalendar cal = new IslamicCalendar(800, IslamicCalendar.RAMADAN, 1);
217 errln("could not create IslamicCalendar with year,month,date");
222 // new IslamicCalendar(int year, int month, int date, int hour, int minute, int second)
223 IslamicCalendar cal = new IslamicCalendar(800, IslamicCalendar.RAMADAN, 1, 1, 1, 1);
225 errln("could not create IslamicCalendar with year,month,date,hour,minute,second");
231 // operations on non-civil calendar
232 IslamicCalendar cal = new IslamicCalendar(800, IslamicCalendar.RAMADAN, 1, 1, 1, 1);
235 errln("islamic calendar is civil");
238 // since setCivil/isCivil are now deprecated, make sure same test works for setType
239 // operations on non-civil calendar
240 cal = new IslamicCalendar(800, IslamicCalendar.RAMADAN, 1, 1, 1, 1);
241 cal.setType(CalculationType.ISLAMIC);
243 errln("islamic calendar is civil");
246 Date now = new Date();
249 Date then = cal.getTime();
250 if (!now.equals(then)) {
251 errln("get/set time failed with non-civil islamic calendar");
254 logln(then.toString());
256 cal.add(Calendar.MONTH, 1);
257 cal.add(Calendar.DAY_OF_MONTH, 1);
258 cal.add(Calendar.YEAR, 1);
260 logln(cal.getTime().toString());
265 IslamicCalendar cal = new IslamicCalendar(800, IslamicCalendar.RAMADAN, 1);
266 Date time = cal.getTime();
268 String[] calendarLocales = {
269 "ar_AE", "ar_BH", "ar_DZ", "ar_EG", "ar_JO", "ar_KW", "ar_OM",
270 "ar_QA", "ar_SA", "ar_SY", "ar_YE", "ms_MY"
273 String[] formatLocales = {
274 "en", "ar", "fi", "fr", "hu", "iw", "nl"
276 for (int i = 0; i < calendarLocales.length; ++i) {
277 String calLocName = calendarLocales[i];
278 Locale calLocale = LocaleUtility.getLocaleFromName(calLocName);
279 cal = new IslamicCalendar(calLocale);
281 for (int j = 0; j < formatLocales.length; ++j) {
282 String locName = formatLocales[j];
283 Locale formatLocale = LocaleUtility.getLocaleFromName(locName);
284 DateFormat format = DateFormat.getDateTimeInstance(cal, DateFormat.FULL, DateFormat.FULL, formatLocale);
285 logln(calLocName + "/" + locName + " --> " + format.format(time));
291 private static IslamicCalendar newCivil() {
292 IslamicCalendar civilCalendar = new IslamicCalendar();
293 civilCalendar.setType(CalculationType.ISLAMIC_CIVIL);
294 return civilCalendar;
296 private static IslamicCalendar newIslamic() {
297 IslamicCalendar civilCalendar = new IslamicCalendar();
298 civilCalendar.setType(CalculationType.ISLAMIC);
299 return civilCalendar;
302 private static IslamicCalendar newIslamicUmalqura() {
303 IslamicCalendar civilCalendar = new IslamicCalendar();
304 civilCalendar.setType(CalculationType.ISLAMIC_UMALQURA);
305 return civilCalendar;
308 private void verifyType(Calendar c, String expectType) {
309 String theType = c.getType();
310 if(!theType.equals(expectType)) {
311 errln("Expected calendar to be type " + expectType + " but instead it is " + theType);
315 public void Test8822() {
316 verifyType(newIslamic(),"islamic");
317 verifyType(newCivil(),"islamic-civil");
318 verifyType(newIslamicUmalqura(), "islamic-umalqura");
321 private void setAndTestCalendar(IslamicCalendar cal, int initMonth, int initDay, int initYear) {
323 cal.setLenient(false);
324 cal.set(initYear, initMonth, initDay);
325 int day = cal.get(Calendar.DAY_OF_MONTH);
326 int month = cal.get(Calendar.MONTH);
327 int year = cal.get(Calendar.YEAR);
328 if(initDay != day || initMonth != month || initYear != year)
330 errln("year init values:\tmonth "+initMonth+"\tday "+initDay+"\tyear "+initYear);
331 errln("values post set():\tmonth "+month+"\tday "+day+"\tyear "+year);
335 private void setAndTestWholeYear(IslamicCalendar cal, int startYear) {
336 for(int startMonth = 0; startMonth < 12; startMonth++) {
337 for(int startDay = 1; startDay < 31; startDay++ ) {
339 setAndTestCalendar(cal, startMonth, startDay, startYear);
340 } catch(IllegalArgumentException iae) {
342 errln("unexpected exception that wasn't for trying to set a date to '30'. errmsg - " + iae.getLocalizedMessage());
350 public void TestIslamicUmAlQura() {
351 int firstYear = 1318;
352 //* use either 1 or 2 leading slashes to toggle
353 int lastYear = 1368; // just enough to be pretty sure
355 int lastYear = 1480; // the whole shootin' match
358 IslamicCalendar tstCal = newIslamicUmalqura();
360 tstCal.setLenient(false);
362 int day=0, month=0, year=0, initDay = 27, initMonth = IslamicCalendar.RAJAB, initYear = 1434;
365 for( int startYear = firstYear; startYear <= lastYear; startYear++) {
366 setAndTestWholeYear(tstCal, startYear);
368 } catch(Throwable t) {
369 errln("unexpected exception thrown - message=" +t.getLocalizedMessage());
373 initMonth = IslamicCalendar.RABI_2;
377 setAndTestCalendar( tstCal, initMonth, initDay, initYear);
378 for(int x=1; x<=loopCnt; x++) {
379 day = tstCal.get(Calendar.DAY_OF_MONTH);
380 month = tstCal.get(Calendar.MONTH);
381 year = tstCal.get(Calendar.YEAR);
382 tstCal.roll(Calendar.DAY_OF_MONTH, true);
384 if(day != (initDay + loopCnt - 1) || month != IslamicCalendar.RABI_2 || year != 1434)
385 errln("invalid values for RABI_2 date after roll of " + loopCnt);
386 } catch(IllegalArgumentException iae) {
387 errln("unexpected exception received!!!");
394 setAndTestCalendar( tstCal, initMonth, initDay, initYear);
395 errln("expected exception NOT thrown");
396 } catch(IllegalArgumentException iae) {
404 setAndTestCalendar( tstCal, initMonth, initDay, initYear);
405 } catch(IllegalArgumentException iae) {
406 errln("unexpected exception received!!!");
410 SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
411 Date date = formatter.parse("1975-05-06");
412 ULocale islamicLoc = new ULocale("ar_SA@calendar=islamic-umalqura");
413 IslamicCalendar is_cal = new IslamicCalendar();
414 is_cal.setType(CalculationType.ISLAMIC_UMALQURA);
415 is_cal.setTime(date);
416 SimpleDateFormat formatterIslamic = (SimpleDateFormat) is_cal.getDateTimeFormat(0,0,islamicLoc);
417 formatterIslamic.applyPattern("yyyy-MMMM-dd");
418 String str = formatterIslamic.format(is_cal.getTime());
421 int is_day = is_cal.get(Calendar.DAY_OF_MONTH);
422 int is_month = is_cal.get(Calendar.MONTH);
423 int is_year = is_cal.get(Calendar.YEAR);
424 if(is_day != 29 || is_month != IslamicCalendar.RABI_2 || is_year != 1395)
425 errln("unexpected conversion date: "+is_day+" "+is_month+" "+is_year);
427 String expectedFormatResult = "\u0661\u0663\u0669\u0665-\u0631\u0628\u064A\u0639 \u0627\u0644\u0622\u062E\u0631-\u0662\u0669";
428 if(!str.equals(expectedFormatResult))
429 errln("unexpected formatted result: "+str);
432 errln(e.getLocalizedMessage());
436 public void TestSerialization8449() {
438 ByteArrayOutputStream icuStream = new ByteArrayOutputStream();
440 IslamicCalendar tstCalendar = new IslamicCalendar();
441 tstCalendar.setCivil(false);
443 long expectMillis = 1187912520931L; // with seconds (not ms) cleared.
444 tstCalendar.setTimeInMillis(expectMillis);
446 logln("instantiated: "+tstCalendar);
447 logln("getMillis: "+tstCalendar.getTimeInMillis());
448 tstCalendar.set(IslamicCalendar.SECOND, 0);
449 logln("setSecond=0: "+tstCalendar);
451 long gotMillis = tstCalendar.getTimeInMillis();
452 if(gotMillis != expectMillis) {
453 errln("expect millis "+expectMillis+" but got "+gotMillis);
455 logln("getMillis: "+gotMillis);
458 ObjectOutputStream icuOut = new ObjectOutputStream(icuStream);
459 icuOut.writeObject(tstCalendar);
463 ObjectInputStream icuIn = new ObjectInputStream(new ByteArrayInputStream(icuStream.toByteArray()));
465 tstCalendar = (IslamicCalendar)icuIn.readObject();
467 logln("serialized back in: "+tstCalendar);
469 long gotMillis = tstCalendar.getTimeInMillis();
470 if(gotMillis != expectMillis) {
471 errln("expect millis "+expectMillis+" but got "+gotMillis);
473 logln("getMillis: "+gotMillis);
477 tstCalendar.set(IslamicCalendar.SECOND, 0);
479 logln("setSecond=0: "+tstCalendar);
481 long gotMillis = tstCalendar.getTimeInMillis();
482 if(gotMillis != expectMillis) {
483 errln("expect millis "+expectMillis+" after stream and setSecond but got "+gotMillis);
485 logln("getMillis after stream and setSecond: "+gotMillis);
488 } catch(IOException e) {
491 } catch(ClassNotFoundException cnf) {
492 errln(cnf.toString());
493 cnf.printStackTrace();
497 public void TestIslamicTabularDates() {
498 SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
501 date = formatter.parse("1975-05-06");
503 errln("unable to parse test date string - errMsg:" +e.getLocalizedMessage());
506 IslamicCalendar is_cal = new IslamicCalendar();
507 is_cal.setType(CalculationType.ISLAMIC_CIVIL);
508 is_cal.setTime(date);
509 IslamicCalendar is_cal2 = new IslamicCalendar();
510 is_cal2.setType(CalculationType.ISLAMIC_TBLA);
511 is_cal2.setTime(date);
513 int is_month = is_cal.get(Calendar.MONTH);
514 int is_month2 = is_cal2.get(Calendar.MONTH);
515 int is_year = is_cal.get(Calendar.YEAR);
516 int is_year2 = is_cal2.get(Calendar.YEAR);
517 if( (is_month != is_month2) || (is_year != is_year2))
518 errln("unexpected difference between islamic and tbla month "+is_month+" : "+is_month2+" and/or year "+is_year+" : "+is_year2);
520 int is_day = is_cal.get(Calendar.DAY_OF_MONTH);
521 int is_day2 = is_cal2.get(Calendar.DAY_OF_MONTH);
522 if(is_day2 - is_day != 1)
523 errln("unexpected difference between civil and tbla: "+is_day2+" : "+is_day);
527 public void TestCreationByLocale() {
528 ULocale islamicLoc = new ULocale("ar_SA@calendar=islamic-umalqura");
529 IslamicCalendar is_cal = new IslamicCalendar(islamicLoc);
530 String thisCalcType = is_cal.getType();
531 if(!"islamic-umalqura".equalsIgnoreCase(thisCalcType)) {
532 errln("non umalqura calc type generated - " + thisCalcType);
535 islamicLoc = new ULocale("ar_SA@calendar=islamic-civil");
536 is_cal = new IslamicCalendar(islamicLoc);
537 thisCalcType = is_cal.getType();
538 if(!"islamic-civil".equalsIgnoreCase(thisCalcType)) {
539 errln("non civil calc type generated - " + thisCalcType);
542 islamicLoc = new ULocale("ar_SA@calendar=islamic-tbla");
543 is_cal = new IslamicCalendar(islamicLoc);
544 thisCalcType = is_cal.getType();
545 if(!"islamic-tbla".equalsIgnoreCase(thisCalcType)) {
546 errln("non tbla calc type generated - " + thisCalcType);
549 islamicLoc = new ULocale("ar_SA@calendar=islamic-xyzzy");
550 is_cal = new IslamicCalendar(islamicLoc);
551 thisCalcType = is_cal.getType();
552 if(!"islamic".equalsIgnoreCase(thisCalcType)) {
553 errln("incorrect default calc type generated - " + thisCalcType);