2 *******************************************************************************
3 * Copyright (C) 2000-2013, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 *******************************************************************************
7 package com.ibm.icu.dev.test.calendar;
9 import java.text.ParseException;
10 import java.util.Date;
11 import java.util.Locale;
14 import com.ibm.icu.impl.CalendarAstronomer;
15 import com.ibm.icu.impl.LocaleUtility;
16 import com.ibm.icu.impl.ZoneMeta;
17 import com.ibm.icu.text.DateFormat;
18 import com.ibm.icu.text.SimpleDateFormat;
19 import com.ibm.icu.util.BuddhistCalendar;
20 import com.ibm.icu.util.Calendar;
21 import com.ibm.icu.util.ChineseCalendar;
22 import com.ibm.icu.util.GregorianCalendar;
23 import com.ibm.icu.util.JapaneseCalendar;
24 import com.ibm.icu.util.TaiwanCalendar;
25 import com.ibm.icu.util.TimeZone;
26 import com.ibm.icu.util.TimeZone.SystemTimeZoneType;
27 import com.ibm.icu.util.ULocale;
30 * @summary Tests of new functionality in IBMCalendar
32 public class IBMCalendarTest extends CalendarTest {
34 public static void main(String[] args) throws Exception {
35 new IBMCalendarTest().run(args);
39 * Test weekend support in IBMCalendar.
41 * NOTE: This test will have to be updated when the isWeekend() etc.
42 * API is finalized later.
44 * In particular, the test will have to be rewritten to instantiate
45 * a Calendar in the given locale (using getInstance()) and call
46 * that Calendar's isWeekend() etc. methods.
48 public void TestWeekend() {
49 SimpleDateFormat fmt = new SimpleDateFormat("EEE MMM dd yyyy G HH:mm:ss.SSS");
52 // This test tests for specific locale data. This is probably okay
53 // as far as US data is concerned, but if the Arabic/Yemen data
54 // changes, this test will have to be updated.
58 Locale.US, new int[] { // Saturday:Sunday
59 2000, Calendar.MARCH, 17, 23, 0, 0, // Fri 23:00
60 2000, Calendar.MARCH, 18, 0, -1, 0, // Fri 23:59:59.999
61 2000, Calendar.MARCH, 18, 0, 0, 1, // Sat 00:00
62 2000, Calendar.MARCH, 18, 15, 0, 1, // Sat 15:00
63 2000, Calendar.MARCH, 19, 23, 0, 1, // Sun 23:00
64 2000, Calendar.MARCH, 20, 0, -1, 1, // Sun 23:59:59.999
65 2000, Calendar.MARCH, 20, 0, 0, 0, // Mon 00:00
66 2000, Calendar.MARCH, 20, 8, 0, 0, // Mon 08:00
68 new Locale("ar", "OM"), new int[] { // Thursday:Friday
69 2000, Calendar.MARCH, 15, 23, 0, 0, // Wed 23:00
70 2000, Calendar.MARCH, 16, 0, -1, 0, // Wed 23:59:59.999
71 2000, Calendar.MARCH, 16, 0, 0, 1, // Thu 00:00
72 2000, Calendar.MARCH, 16, 15, 0, 1, // Thu 15:00
73 2000, Calendar.MARCH, 17, 23, 0, 1, // Fri 23:00
74 2000, Calendar.MARCH, 18, 0, -1, 1, // Fri 23:59:59.999
75 2000, Calendar.MARCH, 18, 0, 0, 0, // Sat 00:00
76 2000, Calendar.MARCH, 18, 8, 0, 0, // Sat 08:00
80 // Test days of the week
82 Locale.US, new int[] {
83 Calendar.MONDAY, Calendar.WEEKDAY,
84 Calendar.FRIDAY, Calendar.WEEKDAY,
85 Calendar.SATURDAY, Calendar.WEEKEND,
86 Calendar.SUNDAY, Calendar.WEEKEND,
88 new Locale("ar", "OM"), new int[] { // Thursday:Friday
89 Calendar.WEDNESDAY,Calendar.WEEKDAY,
90 Calendar.SATURDAY, Calendar.WEEKDAY,
91 Calendar.THURSDAY, Calendar.WEEKEND,
92 Calendar.FRIDAY, Calendar.WEEKEND,
94 new Locale("hi", "IN"), new int[] { // Sunday only
95 Calendar.MONDAY, Calendar.WEEKDAY,
96 Calendar.FRIDAY, Calendar.WEEKDAY,
97 Calendar.SATURDAY, Calendar.WEEKDAY,
98 Calendar.SUNDAY, Calendar.WEEKEND,
102 // We only test the getDayOfWeekType() and isWeekend() APIs.
103 // The getWeekendTransition() API is tested indirectly via the
104 // isWeekend() API, which calls it.
106 for (int i1=0; i1<DATA1.length; i1+=2) {
107 Locale loc = (Locale)DATA1[i1];
108 int[] data = (int[]) DATA1[i1+1];
109 Calendar cal = Calendar.getInstance(loc);
110 logln("Locale: " + loc);
111 for (int i=0; i<data.length; i+=6) {
113 cal.set(data[i], data[i+1], data[i+2], data[i+3], 0, 0);
114 if (data[i+4] != 0) {
115 cal.setTime(new Date(cal.getTime().getTime() + data[i+4]));
117 boolean isWeekend = cal.isWeekend();
118 boolean ok = isWeekend == (data[i+5] != 0);
120 logln("Ok: " + fmt.format(cal.getTime()) + " isWeekend=" + isWeekend);
122 errln("FAIL: " + fmt.format(cal.getTime()) + " isWeekend=" + isWeekend +
123 ", expected=" + (!isWeekend));
128 for (int i2=0; i2<DATA2.length; i2+=2) {
129 Locale loc = (Locale)DATA2[i2];
130 int[] data = (int[]) DATA2[i2+1];
131 logln("Locale: " + loc);
132 Calendar cal = Calendar.getInstance(loc);
133 for (int i=0; i<data.length; i+=2) {
134 int type = cal.getDayOfWeekType(data[i]);
137 logln("Ok: DOW " + data[i] + " type=" + type);
139 errln("FAIL: DOW " + data[i] + " type=" + type +
140 ", expected=" + exp);
147 * Run a test of a quasi-Gregorian calendar. This is a calendar
148 * that behaves like a Gregorian but has different year/era mappings.
149 * The int[] data array should have the format:
151 * { era, year, gregorianYear, month, dayOfMonth, ... }
153 void quasiGregorianTest(Calendar cal, int[] data) {
154 // As of JDK 1.4.1_01, using the Sun JDK GregorianCalendar as
155 // a reference throws us off by one hour. This is most likely
156 // due to the JDK 1.4 incorporation of historical time zones.
157 //java.util.Calendar grego = java.util.Calendar.getInstance();
158 Calendar grego = Calendar.getInstance();
159 for (int i=0; i<data.length; ) {
161 int year = data[i++];
162 int gregorianYear = data[i++];
163 int month = data[i++];
164 int dayOfMonth = data[i++];
167 grego.set(gregorianYear, month, dayOfMonth);
168 Date D = grego.getTime();
171 cal.set(Calendar.ERA, era);
172 cal.set(year, month, dayOfMonth);
173 Date d = cal.getTime();
175 logln("OK: " + era + ":" + year + "/" + (month+1) + "/" + dayOfMonth +
178 errln("Fail: " + era + ":" + year + "/" + (month+1) + "/" + dayOfMonth +
179 " => " + d + ", expected " + D);
184 int e = cal.get(Calendar.ERA);
185 int y = cal.get(Calendar.YEAR);
186 if (y == year && e == era) {
187 logln("OK: " + D + " => " + cal.get(Calendar.ERA) + ":" +
188 cal.get(Calendar.YEAR) + "/" +
189 (cal.get(Calendar.MONTH)+1) + "/" + cal.get(Calendar.DATE));
191 logln("Fail: " + D + " => " + cal.get(Calendar.ERA) + ":" +
192 cal.get(Calendar.YEAR) + "/" +
193 (cal.get(Calendar.MONTH)+1) + "/" + cal.get(Calendar.DATE) +
194 ", expected " + era + ":" + year + "/" + (month+1) + "/" +
201 * Verify that BuddhistCalendar shifts years to Buddhist Era but otherwise
202 * behaves like GregorianCalendar.
204 public void TestBuddhist() {
205 quasiGregorianTest(new BuddhistCalendar(),
207 // BE 2542 == 1999 CE
208 0, 2542, 1999, Calendar.JUNE, 4
212 public void TestBuddhistCoverage() {
214 // new BuddhistCalendar(ULocale)
215 BuddhistCalendar cal = new BuddhistCalendar(ULocale.getDefault());
217 errln("could not create BuddhistCalendar with ULocale");
222 // new BuddhistCalendar(TimeZone,ULocale)
223 BuddhistCalendar cal = new BuddhistCalendar(TimeZone.getDefault(),ULocale.getDefault());
225 errln("could not create BuddhistCalendar with TimeZone ULocale");
230 // new BuddhistCalendar(TimeZone)
231 BuddhistCalendar cal = new BuddhistCalendar(TimeZone.getDefault());
233 errln("could not create BuddhistCalendar with TimeZone");
238 // new BuddhistCalendar(Locale)
239 BuddhistCalendar cal = new BuddhistCalendar(Locale.getDefault());
241 errln("could not create BuddhistCalendar with Locale");
246 // new BuddhistCalendar(TimeZone, Locale)
247 BuddhistCalendar cal = new BuddhistCalendar(TimeZone.getDefault(), Locale.getDefault());
249 errln("could not create BuddhistCalendar with TimeZone and Locale");
254 // new BuddhistCalendar(Date)
255 BuddhistCalendar cal = new BuddhistCalendar(new Date());
257 errln("could not create BuddhistCalendar with Date");
262 // new BuddhistCalendar(int year, int month, int date)
263 BuddhistCalendar cal = new BuddhistCalendar(2543, Calendar.MAY, 22);
265 errln("could not create BuddhistCalendar with year,month,data");
270 // new BuddhistCalendar(int year, int month, int date, int hour, int minute, int second)
271 BuddhistCalendar cal = new BuddhistCalendar(2543, Calendar.MAY, 22, 1, 1, 1);
273 errln("could not create BuddhistCalendar with year,month,date,hour,minute,second");
279 BuddhistCalendar cal = new BuddhistCalendar(2543, Calendar.MAY, 22);
280 Date time = cal.getTime();
282 String[] calendarLocales = {
286 String[] formatLocales = {
287 "en", "ar", "hu", "th"
290 for (int i = 0; i < calendarLocales.length; ++i) {
291 String calLocName = calendarLocales[i];
292 Locale calLocale = LocaleUtility.getLocaleFromName(calLocName);
293 cal = new BuddhistCalendar(calLocale);
295 for (int j = 0; j < formatLocales.length; ++j) {
296 String locName = formatLocales[j];
297 Locale formatLocale = LocaleUtility.getLocaleFromName(locName);
298 DateFormat format = DateFormat.getDateTimeInstance(cal, DateFormat.FULL, DateFormat.FULL, formatLocale);
299 logln(calLocName + "/" + locName + " --> " + format.format(time));
306 * Test limits of the Buddhist calendar.
308 public void TestBuddhistLimits() {
309 // Final parameter is either number of days, if > 0, or test
310 // duration in seconds, if < 0.
311 Calendar cal = Calendar.getInstance();
312 cal.set(2007, Calendar.JANUARY, 1);
313 BuddhistCalendar buddhist = new BuddhistCalendar();
314 doLimitsTest(buddhist, null, cal.getTime());
315 doTheoreticalLimitsTest(buddhist, false);
319 * Default calendar for Thai (Ticket#6302)
321 public void TestThaiDefault() {
322 // Buddhist calendar is used as the default calendar for
324 Calendar cal = Calendar.getInstance(new ULocale("th_TH"));
325 String type = cal.getType();
326 if (!type.equals("buddhist")) {
327 errln("FAIL: Buddhist calendar is not returned for locale " + cal.toString());
332 * Verify that TaiwanCalendar shifts years to Minguo Era but otherwise
333 * behaves like GregorianCalendar.
335 public void TestTaiwan() {
336 quasiGregorianTest(new TaiwanCalendar(),
338 TaiwanCalendar.BEFORE_MINGUO, 8, 1904, Calendar.FEBRUARY, 29,
339 TaiwanCalendar.MINGUO, 1, 1912, Calendar.JUNE, 4,
340 TaiwanCalendar.MINGUO, 3, 1914, Calendar.FEBRUARY, 12,
341 TaiwanCalendar.MINGUO, 96,2007, Calendar.FEBRUARY, 12,
346 * Test limits of the Taiwan calendar.
348 public void TestTaiwanLimits() {
349 // Final parameter is either number of days, if > 0, or test
350 // duration in seconds, if < 0.
351 Calendar cal = Calendar.getInstance();
352 cal.set(2007, Calendar.JANUARY, 1);
353 TaiwanCalendar taiwan = new TaiwanCalendar();
354 doLimitsTest(taiwan, null, cal.getTime());
355 doTheoreticalLimitsTest(taiwan, false);
358 public void TestTaiwanCoverage() {
360 // new TaiwanCalendar(ULocale)
361 TaiwanCalendar cal = new TaiwanCalendar(ULocale.getDefault());
363 errln("could not create TaiwanCalendar with ULocale");
368 // new TaiwanCalendar(TimeZone,ULocale)
369 TaiwanCalendar cal = new TaiwanCalendar(TimeZone.getDefault(),ULocale.getDefault());
371 errln("could not create TaiwanCalendar with TimeZone ULocale");
376 // new TaiwanCalendar(TimeZone)
377 TaiwanCalendar cal = new TaiwanCalendar(TimeZone.getDefault());
379 errln("could not create TaiwanCalendar with TimeZone");
384 // new TaiwanCalendar(Locale)
385 TaiwanCalendar cal = new TaiwanCalendar(Locale.getDefault());
387 errln("could not create TaiwanCalendar with Locale");
392 // new TaiwanCalendar(TimeZone, Locale)
393 TaiwanCalendar cal = new TaiwanCalendar(TimeZone.getDefault(), Locale.getDefault());
395 errln("could not create TaiwanCalendar with TimeZone and Locale");
400 // new TaiwanCalendar(Date)
401 TaiwanCalendar cal = new TaiwanCalendar(new Date());
403 errln("could not create TaiwanCalendar with Date");
408 // new TaiwanCalendar(int year, int month, int date)
409 TaiwanCalendar cal = new TaiwanCalendar(34, Calendar.MAY, 22);
411 errln("could not create TaiwanCalendar with year,month,data");
416 // new TaiwanCalendar(int year, int month, int date, int hour, int minute, int second)
417 TaiwanCalendar cal = new TaiwanCalendar(34, Calendar.MAY, 22, 1, 1, 1);
419 errln("could not create TaiwanCalendar with year,month,date,hour,minute,second");
425 TaiwanCalendar cal = new TaiwanCalendar(34, Calendar.MAY, 22);
426 Date time = cal.getTime();
428 String[] calendarLocales = {
432 String[] formatLocales = {
433 "en", "ar", "hu", "th"
436 for (int i = 0; i < calendarLocales.length; ++i) {
437 String calLocName = calendarLocales[i];
438 Locale calLocale = LocaleUtility.getLocaleFromName(calLocName);
439 cal = new TaiwanCalendar(calLocale);
441 for (int j = 0; j < formatLocales.length; ++j) {
442 String locName = formatLocales[j];
443 Locale formatLocale = LocaleUtility.getLocaleFromName(locName);
444 DateFormat format = DateFormat.getDateTimeInstance(cal, DateFormat.FULL, DateFormat.FULL, formatLocale);
445 logln(calLocName + "/" + locName + " --> " + format.format(time));
452 * Verify that JapaneseCalendar shifts years to Japanese Eras but otherwise
453 * behaves like GregorianCalendar.
455 public void TestJapanese() {
456 // First make sure this test works for GregorianCalendar
458 GregorianCalendar.AD, 1868, 1868, Calendar.SEPTEMBER, 8,
459 GregorianCalendar.AD, 1868, 1868, Calendar.SEPTEMBER, 9,
460 GregorianCalendar.AD, 1869, 1869, Calendar.JUNE, 4,
461 GregorianCalendar.AD, 1912, 1912, Calendar.JULY, 29,
462 GregorianCalendar.AD, 1912, 1912, Calendar.JULY, 30,
463 GregorianCalendar.AD, 1912, 1912, Calendar.AUGUST, 1,
465 quasiGregorianTest(new GregorianCalendar(), control);
468 JapaneseCalendar.MEIJI, 1, 1868, Calendar.SEPTEMBER, 8,
469 JapaneseCalendar.MEIJI, 1, 1868, Calendar.SEPTEMBER, 9,
470 JapaneseCalendar.MEIJI, 2, 1869, Calendar.JUNE, 4,
471 JapaneseCalendar.MEIJI, 45, 1912, Calendar.JULY, 29,
472 JapaneseCalendar.TAISHO, 1, 1912, Calendar.JULY, 30,
473 JapaneseCalendar.TAISHO, 1, 1912, Calendar.AUGUST, 1,
475 quasiGregorianTest(new JapaneseCalendar(), data);
479 * Test limits of the Gregorian calendar.
481 public void TestGregorianLimits() {
482 // Final parameter is either number of days, if > 0, or test
483 // duration in seconds, if < 0.
484 Calendar cal = Calendar.getInstance();
485 cal.set(2004, Calendar.JANUARY, 1);
486 GregorianCalendar gregorian = new GregorianCalendar();
487 doLimitsTest(gregorian, null, cal.getTime());
488 doTheoreticalLimitsTest(gregorian, false);
492 * Test behavior of fieldDifference around leap years. Also test a large
493 * field difference to check binary search.
495 public void TestLeapFieldDifference() {
496 Calendar cal = Calendar.getInstance();
497 cal.set(2004, Calendar.FEBRUARY, 29);
498 Date date2004 = cal.getTime();
499 cal.set(2000, Calendar.FEBRUARY, 29);
500 Date date2000 = cal.getTime();
501 int y = cal.fieldDifference(date2004, Calendar.YEAR);
502 int d = cal.fieldDifference(date2004, Calendar.DAY_OF_YEAR);
504 logln("Ok: 2004/Feb/29 - 2000/Feb/29 = " + y + " years, " + d + " days");
506 errln("FAIL: 2004/Feb/29 - 2000/Feb/29 = " + y + " years, " + d + " days");
508 cal.setTime(date2004);
509 y = cal.fieldDifference(date2000, Calendar.YEAR);
510 d = cal.fieldDifference(date2000, Calendar.DAY_OF_YEAR);
512 logln("Ok: 2000/Feb/29 - 2004/Feb/29 = " + y + " years, " + d + " days");
514 errln("FAIL: 2000/Feb/29 - 2004/Feb/29 = " + y + " years, " + d + " days");
516 // Test large difference
517 cal.set(2001, Calendar.APRIL, 5); // 2452005
518 Date ayl = cal.getTime();
519 cal.set(1964, Calendar.SEPTEMBER, 7); // 2438646
520 Date asl = cal.getTime();
521 d = cal.fieldDifference(ayl, Calendar.DAY_OF_MONTH);
523 int d2 = cal.fieldDifference(asl, Calendar.DAY_OF_MONTH);
524 if (d == -d2 && d == 13359) {
525 logln("Ok: large field difference symmetrical " + d);
527 logln("FAIL: large field difference incorrect " + d + ", " + d2 +
528 ", expect +/- 13359");
533 * Test ms_MY "Malay (Malaysia)" locale. Bug 1543.
535 public void TestMalaysianInstance() {
536 Locale loc = new Locale("ms", "MY"); // Malay (Malaysia)
537 Calendar cal = Calendar.getInstance(loc);
539 errln("could not create Malaysian instance");
544 * setFirstDayOfWeek and setMinimalDaysInFirstWeek may change the
545 * field <=> time mapping, since they affect the interpretation of
546 * the WEEK_OF_MONTH or WEEK_OF_YEAR fields.
548 public void TestWeekShift() {
549 Calendar cal = new GregorianCalendar(
550 TimeZone.getTimeZone("America/Los_Angeles"),
551 new Locale("en", "US"));
552 cal.setTime(new Date(997257600000L)); // Wed Aug 08 01:00:00 PDT 2001
553 // In pass one, change the first day of week so that the weeks
554 // shift in August 2001. In pass two, change the minimal days
555 // in the first week so that the weeks shift in August 2001.
557 // Su Mo Tu We Th Fr Sa
560 // 12 13 14 15 16 17 18
561 // 19 20 21 22 23 24 25
563 for (int pass=0; pass<2; ++pass) {
565 cal.setFirstDayOfWeek(Calendar.WEDNESDAY);
566 cal.setMinimalDaysInFirstWeek(4);
568 cal.setFirstDayOfWeek(Calendar.SUNDAY);
569 cal.setMinimalDaysInFirstWeek(4);
571 cal.add(Calendar.DATE, 1); // Force recalc
572 cal.add(Calendar.DATE, -1);
574 Date time1 = cal.getTime(); // Get time -- should not change
576 // Now change a week parameter and then force a recalc.
577 // The bug is that the recalc should not be necessary --
578 // calendar should do so automatically.
580 cal.setFirstDayOfWeek(Calendar.THURSDAY);
582 cal.setMinimalDaysInFirstWeek(5);
585 int woy1 = cal.get(Calendar.WEEK_OF_YEAR);
586 int wom1 = cal.get(Calendar.WEEK_OF_MONTH);
588 cal.add(Calendar.DATE, 1); // Force recalc
589 cal.add(Calendar.DATE, -1);
591 int woy2 = cal.get(Calendar.WEEK_OF_YEAR);
592 int wom2 = cal.get(Calendar.WEEK_OF_MONTH);
594 Date time2 = cal.getTime();
596 if (!time1.equals(time2)) {
597 errln("FAIL: shifting week should not alter time");
599 logln(time1.toString());
601 if (woy1 == woy2 && wom1 == wom2) {
602 logln("Ok: WEEK_OF_YEAR: " + woy1 +
603 ", WEEK_OF_MONTH: " + wom1);
605 errln("FAIL: WEEK_OF_YEAR: " + woy1 + " => " + woy2 +
606 ", WEEK_OF_MONTH: " + wom1 + " => " + wom2 +
607 " after week shift");
613 * Make sure that when adding a day, we actually wind up in a
614 * different day. The DST adjustments we use to keep the hour
615 * constant across DST changes can backfire and change the day.
617 public void TestTimeZoneTransitionAdd() {
618 Locale locale = Locale.US; // could also be CHINA
619 SimpleDateFormat dateFormat =
620 new SimpleDateFormat("MM/dd/yyyy HH:mm z", locale);
622 String tz[] = TimeZone.getAvailableIDs();
624 for (int z=0; z<tz.length; ++z) {
625 TimeZone t = TimeZone.getTimeZone(tz[z]);
626 dateFormat.setTimeZone(t);
628 Calendar cal = Calendar.getInstance(t, locale);
630 // Scan the year 2003, overlapping the edges of the year
631 cal.set(Calendar.YEAR, 2002);
632 cal.set(Calendar.MONTH, Calendar.DECEMBER);
633 cal.set(Calendar.DAY_OF_MONTH, 25);
635 for (int i=0; i<365+10; ++i) {
636 Date yesterday = cal.getTime();
637 int yesterday_day = cal.get(Calendar.DAY_OF_MONTH);
638 cal.add(Calendar.DAY_OF_MONTH, 1);
639 if (yesterday_day == cal.get(Calendar.DAY_OF_MONTH)) {
641 dateFormat.format(yesterday) + " +1d= " +
642 dateFormat.format(cal.getTime()));
648 public void TestJB1684() {
660 public TestData(int year, int month, int date,
661 int womyear, int wommon, int wom, int dow,
662 String data, String normalized) {
664 this.month = month-1;
666 this.womyear = womyear;
667 this.wommon = wommon-1;
670 this.data = data; // year, month, week of month, day
671 this.normalized = data;
672 if (normalized != null) this.normalized = normalized;
676 // July 2001 August 2001 January 2002
677 // Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
678 // 1 2 3 4 5 6 7 1 2 3 4 1 2 3 4 5
679 // 8 9 10 11 12 13 14 5 6 7 8 9 10 11 6 7 8 9 10 11 12
680 // 15 16 17 18 19 20 21 12 13 14 15 16 17 18 13 14 15 16 17 18 19
681 // 22 23 24 25 26 27 28 19 20 21 22 23 24 25 20 21 22 23 24 25 26
682 // 29 30 31 26 27 28 29 30 31 27 28 29 30 31
684 new TestData(2001, 8, 6, 2001,8,2,Calendar.MONDAY, "2001 08 02 Mon", null),
685 new TestData(2001, 8, 7, 2001,8,2,Calendar.TUESDAY, "2001 08 02 Tue", null),
686 new TestData(2001, 8, 5,/*12,*/ 2001,8,2,Calendar.SUNDAY, "2001 08 02 Sun", null),
687 new TestData(2001, 8,6, /*7, 30,*/ 2001,7,6,Calendar.MONDAY, "2001 07 06 Mon", "2001 08 02 Mon"),
688 new TestData(2001, 8,7, /*7, 31,*/ 2001,7,6,Calendar.TUESDAY, "2001 07 06 Tue", "2001 08 02 Tue"),
689 new TestData(2001, 8, 5, 2001,7,6,Calendar.SUNDAY, "2001 07 06 Sun", "2001 08 02 Sun"),
690 new TestData(2001, 7, 30, 2001,8,1,Calendar.MONDAY, "2001 08 01 Mon", "2001 07 05 Mon"),
691 new TestData(2001, 7, 31, 2001,8,1,Calendar.TUESDAY, "2001 08 01 Tue", "2001 07 05 Tue"),
692 new TestData(2001, 7,29, /*8, 5,*/ 2001,8,1,Calendar.SUNDAY, "2001 08 01 Sun", "2001 07 05 Sun"),
693 new TestData(2001, 12, 31, 2001,12,6,Calendar.MONDAY, "2001 12 06 Mon", null),
694 new TestData(2002, 1, 1, 2002,1,1,Calendar.TUESDAY, "2002 01 01 Tue", null),
695 new TestData(2002, 1, 2, 2002,1,1,Calendar.WEDNESDAY, "2002 01 01 Wed", null),
696 new TestData(2002, 1, 3, 2002,1,1,Calendar.THURSDAY, "2002 01 01 Thu", null),
697 new TestData(2002, 1, 4, 2002,1,1,Calendar.FRIDAY, "2002 01 01 Fri", null),
698 new TestData(2002, 1, 5, 2002,1,1,Calendar.SATURDAY, "2002 01 01 Sat", null),
699 new TestData(2001,12,30, /*2002, 1, 6,*/ 2002,1,1,Calendar.SUNDAY, "2002 01 01 Sun", "2001 12 06 Sun"),
702 int pass = 0, error = 0, warning = 0;
704 final String pattern = "yyyy MM WW EEE";
705 GregorianCalendar cal = new GregorianCalendar();
706 SimpleDateFormat sdf = new SimpleDateFormat(pattern);
707 sdf.setCalendar(cal);
709 cal.setFirstDayOfWeek(Calendar.SUNDAY);
710 cal.setMinimalDaysInFirstWeek(1);
712 for (int i = 0; i < tests.length; ++i) {
713 TestData test = tests[i];
714 log("\n-----\nTesting round trip of " + test.year +
715 " " + (test.month + 1) +
717 " (written as) " + test.data);
720 cal.set(test.year, test.month, test.date);
721 Date ms = cal.getTime();
724 cal.set(Calendar.YEAR, test.womyear);
725 cal.set(Calendar.MONTH, test.wommon);
726 cal.set(Calendar.WEEK_OF_MONTH, test.wom);
727 cal.set(Calendar.DAY_OF_WEEK, test.dow);
728 Date ms2 = cal.getTime();
730 if (!ms2.equals(ms)) {
731 log("\nError: GregorianCalendar.DOM gave " + ms +
732 "\n GregorianCalendar.WOM gave " + ms2);
740 ms2 = sdf.parse(test.data);
742 catch (ParseException e) {
743 errln("parse exception: " + e);
746 if (!ms2.equals(ms)) {
747 log("\nError: GregorianCalendar gave " + ms +
748 "\n SimpleDateFormat.parse gave " + ms2);
754 String result = sdf.format(ms);
755 if (!result.equals(test.normalized)) {
756 log("\nWarning: format of '" + test.data + "' gave" +
757 "\n '" + result + "'" +
758 "\n expected '" + test.normalized + "'");
766 ms3 = sdf.parse(result);
768 catch (ParseException e) {
769 errln("parse exception 2: " + e);
772 if (!ms3.equals(ms)) {
774 log("\nError: Re-parse of '" + result + "' gave time of " +
781 String info = "\nPassed: " + pass + ", Warnings: " + warning + ", Errors: " + error;
790 * Test the ZoneMeta API.
792 public void TestZoneMeta() {
793 // Test index by country API
795 // Format: {country, zone1, zone2, ..., zoneN}
796 String COUNTRY[][] = { {""},
797 {"US", "America/Los_Angeles", "PST"} };
798 StringBuffer buf = new StringBuffer();
799 for (int i=0; i<COUNTRY.length; ++i) {
800 Set<String> a = ZoneMeta.getAvailableIDs(SystemTimeZoneType.ANY, COUNTRY[i][0], null);
802 buf.append("Country \"" + COUNTRY[i][0] + "\": [");
803 // Use bitmask to track which of the expected zones we see
805 boolean first = true;
813 for (int k = 1; k < COUNTRY[i].length; ++k) {
814 if ((mask & (1 << k)) == 0 && z.equals(COUNTRY[i][k])) {
821 // Check bitmask to see if we saw all expected zones
822 if (mask == (1 << (COUNTRY[i].length-1))-1) {
823 logln(buf.toString());
825 errln(buf.toString());
829 // Test equivalent IDs API
831 int n = ZoneMeta.countEquivalentIDs("PST");
834 buf.append("Equivalent to PST: ");
835 for (int i=0; i<n; ++i) {
836 String id = ZoneMeta.getEquivalentID("PST", i);
837 if (id.equals("America/Los_Angeles")) {
840 if (i!=0) buf.append(", ");
844 logln(buf.toString());
846 errln(buf.toString());
850 public void TestComparable() {
851 GregorianCalendar c0 = new GregorianCalendar();
852 GregorianCalendar c1 = new GregorianCalendar();
853 c1.add(Calendar.DAY_OF_MONTH, 1);
854 if (c0.compareTo(c1) >= 0) {
855 errln("calendar " + c0 + " not < " + c1);
857 c0.add(Calendar.MONTH, 1);
858 if (c0.compareTo(c1) <= 0) {
859 errln("calendar " + c0 + " not > " + c1);
862 c0.setTimeInMillis(c1.getTimeInMillis());
863 if (c0.compareTo(c1) != 0) {
864 errln("calendar " + c0 + " not == " + c1);
870 * Miscellaneous tests to increase coverage.
872 public void TestCoverage() {
874 BuddhistCalendar bcal = new BuddhistCalendar();
875 /*int i =*/ bcal.getMinimum(Calendar.ERA);
876 bcal.add(Calendar.YEAR, 1);
877 bcal.add(Calendar.MONTH, 1);
878 /*Date d = */bcal.getTime();
880 // CalendarAstronomer
881 // (This class should probably be made package-private.)
882 CalendarAstronomer astro = new CalendarAstronomer();
883 /*String s = */astro.local(0);
886 ChineseCalendar ccal = new ChineseCalendar(TimeZone.getDefault(),
887 Locale.getDefault());
888 ccal.add(Calendar.MONTH, 1);
889 ccal.add(Calendar.YEAR, 1);
890 ccal.roll(Calendar.MONTH, 1);
891 ccal.roll(Calendar.YEAR, 1);
895 Calendar cal = Calendar.getInstance(Locale.US);
896 logln(cal.toString());
897 logln(cal.getDisplayName(Locale.US));
900 for (int i=Calendar.SUNDAY; i<=Calendar.SATURDAY; ++i) {
901 if (cal.getDayOfWeekType(i) == Calendar.WEEKEND_ONSET) {
904 if (cal.getDayOfWeekType(i) == Calendar.WEEKEND_CEASE) {
908 // can't call this unless we get a transition day (unusual),
909 // but make the call anyway for coverage reasons
911 /*int x=*/ cal.getWeekendTransition(weekendOnset);
912 /*int x=*/ cal.getWeekendTransition(weekendCease);
913 } catch (IllegalArgumentException e) {}
914 /*int x=*/ cal.isWeekend(new Date());
916 // new GregorianCalendar(ULocale)
917 GregorianCalendar gcal = new GregorianCalendar(ULocale.getDefault());
919 errln("could not create GregorianCalendar with ULocale");
921 logln("Calendar display name: " + gcal.getDisplayName(ULocale.getDefault()));
924 //cover getAvailableULocales
925 final ULocale[] locales = Calendar.getAvailableULocales();
926 long count = locales.length;
928 errln("getAvailableULocales return empty list");
929 logln("" + count + " available ulocales in Calendar.");
931 // Jitterbug 4451, for coverage
932 class StubCalendar extends Calendar{
936 private static final long serialVersionUID = -4558903444622684759L;
937 protected int handleGetLimit(int field, int limitType) {return 0;}
938 protected int handleComputeMonthStart(int eyear, int month, boolean useMonth) {return 0;}
939 protected int handleGetExtendedYear() {return 0;}
941 if (Calendar.gregorianPreviousMonthLength(2000,2) != 29){
942 errln("Year 2000 Feb should have 29 days.");
944 long millis = Calendar.julianDayToMillis(Calendar.MAX_JULIAN);
945 if(millis != Calendar.MAX_MILLIS){
946 errln("Did not get the expected value from julianDayToMillis. Got:" + millis);
948 DateFormat df = handleGetDateFormat("",Locale.getDefault());
949 if (!df.equals(handleGetDateFormat("",ULocale.getDefault()))){
950 errln ("Calendar.handleGetDateFormat(String, Locale) should delegate to ( ,ULocale)");
952 if (!getType().equals("unknown")){
953 errln ("Calendar.getType() should be 'unknown'");
957 StubCalendar stub = new StubCalendar();
962 public void TestJB4541() {
963 ULocale loc = new ULocale("en_US");
965 // !!! Shouldn't we have an api like this?
966 // !!! Question: should this reflect those actually available in this copy of ICU, or
967 // the list of types we assume is available?
968 // String[] calTypes = Calendar.getAvailableTypes();
969 final String[] calTypes = {
970 "buddhist", "chinese", "coptic", "ethiopic", "gregorian", "hebrew",
971 "islamic", "islamic-civil", "japanese", "roc"
974 // constructing a DateFormat with a locale indicating a calendar type should construct a
975 // date format appropriate to that calendar
976 final Date time = new Date();
977 for (int i = 0; i < calTypes.length; ++i) {
978 ULocale aLoc = loc.setKeywordValue("calendar", calTypes[i]);
979 logln("locale: " + aLoc);
981 DateFormat df = DateFormat.getDateTimeInstance(DateFormat.FULL,
985 logln("df type: " + df.getClass().getName() + " loc: " + df.getLocale(ULocale.VALID_LOCALE));
987 Calendar cal = df.getCalendar();
988 assertEquals("calendar types", cal.getType(), calTypes[i]);
989 DateFormat df2 = cal.getDateTimeFormat(DateFormat.FULL, DateFormat.FULL, ULocale.US);
990 logln("df2 type: " + df2.getClass().getName() + " loc: " + df2.getLocale(ULocale.VALID_LOCALE));
991 assertEquals("format results", df.format(time), df2.format(time));
994 // dateFormat.setCalendar should throw exception if wrong format for calendar
996 DateFormat df = DateFormat.getDateTimeInstance(DateFormat.FULL,
998 new ULocale("en_US@calendar=chinese"));
1000 logln("dateformat type: " + df.getClass().getName());
1002 Calendar cal = Calendar.getInstance(new ULocale("en_US@calendar=chinese"));
1004 logln("calendar type: " + cal.getClass().getName());
1008 public void TestTypes() {
1011 "en_US_VALLEYGIRL@collation=phonebook;calendar=japanese",
1012 "en_US_VALLEYGIRL@collation=phonebook;calendar=gregorian",
1013 "ja_JP@calendar=japanese",
1014 "th_TH@calendar=buddhist",
1015 "th-TH-u-ca-gregory",
1016 "ja_JP_TRADITIONAL",
1017 "th_TH_TRADITIONAL",
1018 "th_TH_TRADITIONAL@calendar=gregorian",
1020 "th_TH", // Default calendar for th_TH is buddhist
1021 "th", // th's default region is TH and buddhist is used as default for TH
1022 "en_TH", // Default calendar for any locales with region TH is buddhist
1023 "th_TH@calendar=iso8601", // iso8601 calendar type
1040 "gregorian", // iso8601 is a gregiran sub type
1043 for (int i = 0; i < locs.length; i++) {
1044 Calendar cal = Calendar.getInstance(new ULocale(locs[i]));
1045 if (!cal.getType().equals(types[i])) {
1046 errln(locs[i] + " Calendar type " + cal.getType() + " instead of " + types[i]);
1051 public void TestISO8601() {
1052 final ULocale[] TEST_LOCALES = {
1053 new ULocale("en_US@calendar=iso8601"),
1054 new ULocale("en_US@calendar=Iso8601"),
1055 new ULocale("th_TH@calendar=iso8601"),
1056 new ULocale("ar_EG@calendar=iso8601")
1059 final int[][] TEST_DATA = {
1060 // {<year>, <week# of Jan 1>, <week# year of Jan 1>}
1070 for (ULocale locale : TEST_LOCALES) {
1071 Calendar cal = Calendar.getInstance(locale);
1072 // No matter what locale is used, if calendar type is "iso8601",
1073 // calendar type must be Gregorian
1074 if (!cal.getType().equals("gregorian")) {
1075 errln("Error: Gregorian calendar is not used for locale: " + locale);
1078 for (int[] data : TEST_DATA) {
1079 cal.set(data[0], Calendar.JANUARY, 1);
1080 int weekNum = cal.get(Calendar.WEEK_OF_YEAR);
1081 int weekYear = cal.get(Calendar.YEAR_WOY);
1083 if (weekNum != data[1] || weekYear != data[2]) {
1084 errln("Error: Incorrect week of year on January 1st, " + data[0]
1085 + " for locale " + locale
1086 + ": Returned [weekNum=" + weekNum + ", weekYear=" + weekYear
1087 + "], Expected [weekNum=" + data[1] + ", weekYear=" + data[2] + "]");
1093 private static class CalFields {
1101 CalFields(int year, int month, int day, int hour, int min, int sec) {
1110 void setTo(Calendar cal) {
1112 cal.set(year, month - 1, day, hour, min, sec);
1115 public String toString() {
1116 return String.format("%04d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, min, sec);
1119 public boolean equals(Object other) {
1120 if (other instanceof CalFields) {
1121 CalFields otr = (CalFields)other;
1122 return (year == otr.year
1123 && month == otr.month
1132 static CalFields createFrom(Calendar cal) {
1133 int year = cal.get(Calendar.YEAR);
1134 int month = cal.get(Calendar.MONTH) + 1;
1135 int day = cal.get(Calendar.DAY_OF_MONTH);
1136 int hour = cal.get(Calendar.HOUR_OF_DAY);
1137 int min = cal.get(Calendar.MINUTE);
1138 int sec = cal.get(Calendar.SECOND);
1140 return new CalFields(year, month, day, hour, min, sec);
1144 public void TestAmbiguousWallTimeAPIs() {
1145 Calendar cal = Calendar.getInstance();
1147 assertEquals("Default repeated wall time option", cal.getRepeatedWallTimeOption(), Calendar.WALLTIME_LAST);
1148 assertEquals("Default skipped wall time option", cal.getSkippedWallTimeOption(), Calendar.WALLTIME_LAST);
1150 Calendar cal2 = (Calendar)cal.clone();
1152 assertTrue("Equality", cal2.equals(cal));
1153 assertTrue("Hash code", cal.hashCode() == cal2.hashCode());
1155 cal2.setRepeatedWallTimeOption(Calendar.WALLTIME_FIRST);
1156 cal2.setSkippedWallTimeOption(Calendar.WALLTIME_FIRST);
1158 assertFalse("Equality after mod", cal2.equals(cal));
1159 assertFalse("Hash code after mod", cal.hashCode() == cal2.hashCode());
1161 assertEquals("getRepeatedWallTimeOption after mod", cal2.getRepeatedWallTimeOption(), Calendar.WALLTIME_FIRST);
1162 assertEquals("getSkippedWallTimeOption after mod", cal2.getSkippedWallTimeOption(), Calendar.WALLTIME_FIRST);
1165 cal.setRepeatedWallTimeOption(Calendar.WALLTIME_NEXT_VALID);
1166 errln("IAE expected on setRepeatedWallTimeOption(WALLTIME_NEXT_VALID");
1167 } catch (IllegalArgumentException e) {
1172 public void TestRepeatedWallTime() {
1173 final Object[][] TESTDATA = {
1174 // Time zone Input wall time WALLTIME_LAST in GMT WALLTIME_FIRST in GMT
1175 {"America/New_York", new CalFields(2011,11,6,0,59,59), new CalFields(2011,11,6,4,59,59), new CalFields(2011,11,6,4,59,59)},
1176 {"America/New_York", new CalFields(2011,11,6,1,0,0), new CalFields(2011,11,6,6,0,0), new CalFields(2011,11,6,5,0,0)},
1177 {"America/New_York", new CalFields(2011,11,6,1,0,1), new CalFields(2011,11,6,6,0,1), new CalFields(2011,11,6,5,0,1)},
1178 {"America/New_York", new CalFields(2011,11,6,1,30,0), new CalFields(2011,11,6,6,30,0), new CalFields(2011,11,6,5,30,0)},
1179 {"America/New_York", new CalFields(2011,11,6,1,59,59), new CalFields(2011,11,6,6,59,59), new CalFields(2011,11,6,5,59,59)},
1180 {"America/New_York", new CalFields(2011,11,6,2,0,0), new CalFields(2011,11,6,7,0,0), new CalFields(2011,11,6,7,0,0)},
1181 {"America/New_York", new CalFields(2011,11,6,2,0,1), new CalFields(2011,11,6,7,0,1), new CalFields(2011,11,6,7,0,1)},
1183 {"Australia/Lord_Howe", new CalFields(2011,4,3,1,29,59), new CalFields(2011,4,2,14,29,59), new CalFields(2011,4,2,14,29,59)},
1184 {"Australia/Lord_Howe", new CalFields(2011,4,3,1,30,0), new CalFields(2011,4,2,15,0,0), new CalFields(2011,4,2,14,30,0)},
1185 {"Australia/Lord_Howe", new CalFields(2011,4,3,1,45,0), new CalFields(2011,4,2,15,15,0), new CalFields(2011,4,2,14,45,0)},
1186 {"Australia/Lord_Howe", new CalFields(2011,4,3,1,59,59), new CalFields(2011,4,2,15,29,59), new CalFields(2011,4,2,14,59,59)},
1187 {"Australia/Lord_Howe", new CalFields(2011,4,3,2,0,0), new CalFields(2011,4,2,15,30,0), new CalFields(2011,4,2,15,30,0)},
1188 {"Australia/Lord_Howe", new CalFields(2011,4,3,2,0,1), new CalFields(2011,4,2,15,30,1), new CalFields(2011,4,2,15,30,1)},
1191 Calendar calGMT = Calendar.getInstance(TimeZone.GMT_ZONE);
1193 Calendar calDefault = Calendar.getInstance();
1194 Calendar calLast = Calendar.getInstance();
1195 Calendar calFirst = Calendar.getInstance();
1197 calFirst.setRepeatedWallTimeOption(Calendar.WALLTIME_FIRST);
1198 calLast.setRepeatedWallTimeOption(Calendar.WALLTIME_LAST);
1200 for (Object[] test : TESTDATA) {
1201 String tzid = (String)test[0];
1202 TimeZone tz = TimeZone.getTimeZone(tzid);
1203 CalFields in = (CalFields)test[1];
1204 CalFields expLastGMT = (CalFields)test[2];
1205 CalFields expFirstGMT = (CalFields)test[3];
1208 calLast.setTimeZone(tz);
1210 calGMT.setTimeInMillis(calLast.getTimeInMillis());
1211 CalFields outLastGMT = CalFields.createFrom(calGMT);
1212 if (!outLastGMT.equals(expLastGMT)) {
1213 errln("Fail: WALLTIME_LAST " + in + "[" + tzid + "] is parsed as " + outLastGMT + "[GMT]. Expected: " + expLastGMT + "[GMT]");
1217 calDefault.setTimeZone(tz);
1218 in.setTo(calDefault);
1219 calGMT.setTimeInMillis(calDefault.getTimeInMillis());
1220 CalFields outDefGMT = CalFields.createFrom(calGMT);
1221 if (!outDefGMT.equals(expLastGMT)) {
1222 errln("Fail: (default) " + in + "[" + tzid + "] is parsed as " + outDefGMT + "[GMT]. Expected: " + expLastGMT + "[GMT]");
1226 calFirst.setTimeZone(tz);
1228 calGMT.setTimeInMillis(calFirst.getTimeInMillis());
1229 CalFields outFirstGMT = CalFields.createFrom(calGMT);
1230 if (!outFirstGMT.equals(expFirstGMT)) {
1231 errln("Fail: WALLTIME_FIRST " + in + "[" + tzid + "] is parsed as " + outFirstGMT + "[GMT]. Expected: " + expFirstGMT + "[GMT]");
1236 public void TestSkippedWallTime() {
1237 final Object[][] TESTDATA = {
1238 // Time zone Input wall time Valid wall time?
1239 {"America/New_York", new CalFields(2011,3,13,1,59,59), true,
1240 // WALLTIME_LAST in GMT WALLTIME_FIRST in GMT WALLTIME_NEXT_VALID in GMT
1241 new CalFields(2011,3,13,6,59,59), new CalFields(2011,3,13,6,59,59), new CalFields(2011,3,13,6,59,59)},
1243 {"America/New_York", new CalFields(2011,3,13,2,0,0), false,
1244 new CalFields(2011,3,13,7,0,0), new CalFields(2011,3,13,6,0,0), new CalFields(2011,3,13,7,0,0)},
1246 {"America/New_York", new CalFields(2011,3,13,2,1,0), false,
1247 new CalFields(2011,3,13,7,1,0), new CalFields(2011,3,13,6,1,0), new CalFields(2011,3,13,7,0,0)},
1249 {"America/New_York", new CalFields(2011,3,13,2,30,0), false,
1250 new CalFields(2011,3,13,7,30,0), new CalFields(2011,3,13,6,30,0), new CalFields(2011,3,13,7,0,0)},
1252 {"America/New_York", new CalFields(2011,3,13,2,59,59), false,
1253 new CalFields(2011,3,13,7,59,59), new CalFields(2011,3,13,6,59,59), new CalFields(2011,3,13,7,0,0)},
1255 {"America/New_York", new CalFields(2011,3,13,3,0,0), true,
1256 new CalFields(2011,3,13,7,0,0), new CalFields(2011,3,13,7,0,0), new CalFields(2011,3,13,7,0,0)},
1258 {"Pacific/Apia", new CalFields(2011,12,29,23,59,59), true,
1259 new CalFields(2011,12,30,9,59,59), new CalFields(2011,12,30,9,59,59), new CalFields(2011,12,30,9,59,59)},
1261 {"Pacific/Apia", new CalFields(2011,12,30,0,0,0), false,
1262 new CalFields(2011,12,30,10,0,0), new CalFields(2011,12,29,10,0,0), new CalFields(2011,12,30,10,0,0)},
1264 {"Pacific/Apia", new CalFields(2011,12,30,12,0,0), false,
1265 new CalFields(2011,12,30,22,0,0), new CalFields(2011,12,29,22,0,0), new CalFields(2011,12,30,10,0,0)},
1267 {"Pacific/Apia", new CalFields(2011,12,30,23,59,59), false,
1268 new CalFields(2011,12,31,9,59,59), new CalFields(2011,12,30,9,59,59), new CalFields(2011,12,30,10,0,0)},
1270 {"Pacific/Apia", new CalFields(2011,12,31,0,0,0), true,
1271 new CalFields(2011,12,30,10,0,0), new CalFields(2011,12,30,10,0,0), new CalFields(2011,12,30,10,0,0)},
1274 Calendar calGMT = Calendar.getInstance(TimeZone.GMT_ZONE);
1276 Calendar calDefault = Calendar.getInstance();
1277 Calendar calLast = Calendar.getInstance();
1278 Calendar calFirst = Calendar.getInstance();
1279 Calendar calNextAvail = Calendar.getInstance();
1281 calLast.setSkippedWallTimeOption(Calendar.WALLTIME_LAST);
1282 calFirst.setSkippedWallTimeOption(Calendar.WALLTIME_FIRST);
1283 calNextAvail.setSkippedWallTimeOption(Calendar.WALLTIME_NEXT_VALID);
1285 for (Object[] test : TESTDATA) {
1286 String tzid = (String)test[0];
1287 TimeZone tz = TimeZone.getTimeZone(tzid);
1288 CalFields in = (CalFields)test[1];
1289 boolean isValid = (Boolean)test[2];
1290 CalFields expLastGMT = (CalFields)test[3];
1291 CalFields expFirstGMT = (CalFields)test[4];
1292 CalFields expNextAvailGMT = (CalFields)test[5];
1294 for (int i = 0; i < 2; i++) {
1295 boolean bLenient = (i == 0);
1298 calLast.setLenient(bLenient);
1299 calLast.setTimeZone(tz);
1302 calGMT.setTimeInMillis(calLast.getTimeInMillis());
1303 CalFields outLastGMT = CalFields.createFrom(calGMT);
1304 if (!bLenient && !isValid) {
1305 errln("Fail: IllegalArgumentException expected - " + in + "[" + tzid + "] (WALLTIME_LAST)");
1306 } else if (!outLastGMT.equals(expLastGMT)) {
1307 errln("Fail: WALLTIME_LAST " + in + "[" + tzid + "] is parsed as " + outLastGMT + "[GMT]. Expected: " + expLastGMT + "[GMT]");
1309 } catch (IllegalArgumentException e) {
1310 if (bLenient || isValid) {
1311 errln("Fail: Unexpected IllegalArgumentException - " + in + "[" + tzid + "] (WALLTIME_LAST)");
1316 calDefault.setLenient(bLenient);
1317 calDefault.setTimeZone(tz);
1319 in.setTo(calDefault);
1320 calGMT.setTimeInMillis(calDefault.getTimeInMillis());
1321 CalFields outDefGMT = CalFields.createFrom(calGMT);
1322 if (!bLenient && !isValid) {
1323 errln("Fail: IllegalArgumentException expected - " + in + "[" + tzid + "] (default)");
1324 } else if (!outDefGMT.equals(expLastGMT)) {
1325 errln("Fail: (default) " + in + "[" + tzid + "] is parsed as " + outDefGMT + "[GMT]. Expected: " + expLastGMT + "[GMT]");
1327 } catch (IllegalArgumentException e) {
1328 if (bLenient || isValid) {
1329 errln("Fail: Unexpected IllegalArgumentException - " + in + "[" + tzid + "] (default)");
1334 calFirst.setLenient(bLenient);
1335 calFirst.setTimeZone(tz);
1338 calGMT.setTimeInMillis(calFirst.getTimeInMillis());
1339 CalFields outFirstGMT = CalFields.createFrom(calGMT);
1340 if (!bLenient && !isValid) {
1341 errln("Fail: IllegalArgumentException expected - " + in + "[" + tzid + "] (WALLTIME_FIRST)");
1342 } else if (!outFirstGMT.equals(expFirstGMT)) {
1343 errln("Fail: WALLTIME_FIRST " + in + "[" + tzid + "] is parsed as " + outFirstGMT + "[GMT]. Expected: " + expFirstGMT + "[GMT]");
1345 } catch (IllegalArgumentException e) {
1346 if (bLenient || isValid) {
1347 errln("Fail: Unexpected IllegalArgumentException - " + in + "[" + tzid + "] (WALLTIME_FIRST)");
1351 // WALLTIME_NEXT_VALID
1352 calNextAvail.setLenient(bLenient);
1353 calNextAvail.setTimeZone(tz);
1355 in.setTo(calNextAvail);
1356 calGMT.setTimeInMillis(calNextAvail.getTimeInMillis());
1357 CalFields outNextAvailGMT = CalFields.createFrom(calGMT);
1358 if (!bLenient && !isValid) {
1359 errln("Fail: IllegalArgumentException expected - " + in + "[" + tzid + "] (WALLTIME_NEXT_VALID)");
1360 } else if (!outNextAvailGMT.equals(expNextAvailGMT)) {
1361 errln("Fail: WALLTIME_NEXT_VALID " + in + "[" + tzid + "] is parsed as " + outNextAvailGMT + "[GMT]. Expected: " + expNextAvailGMT + "[GMT]");
1363 } catch (IllegalArgumentException e) {
1364 if (bLenient || isValid) {
1365 errln("Fail: Unexpected IllegalArgumentException - " + in + "[" + tzid + "] (WALLTIME_NEXT_VALID)");
1372 public void TestFieldDifference() {
1374 public String tzname;
1375 public String locale;
1378 public boolean progressive; // true to compute progressive difference for each field, false to reset calendar after each call
1384 int sDiff; // 0x7FFFFFFF indicates overflow error expected
1385 // Simple constructor
1386 public TFDItem(String tz, String loc, long st, long tg, boolean prg, int yD, int MD, int dD, int HD, int mD, int sD ) {
1400 final TFDItem[] tfdItems = {
1401 // timezobe locale start target prog yDf MDf dDf HDf mDf sDf
1402 // For these we compute the progressive difference for each field - not resetting the calendar after each call
1403 new TFDItem( "US/Pacific", "en_US", 1267459800000L, 1277772600000L, true, 0, 3, 27, 9, 40, 0 ), // 2010-Mar-01 08:10 -> 2010-Jun-28 17:50
1404 new TFDItem( "US/Pacific", "en_US", 1267459800000L, 1299089280000L, true, 1, 0, 1, 1, 58, 0 ), // 2010-Mar-01 08:10 -> 2011-Mar-02 10:08
1405 // For these we compute the total difference for each field - resetting the calendar after each call
1406 new TFDItem( "GMT", "en_US", 0, 1073692800000L, false, 34, 408, 12427, 298248, 17894880, 1073692800 ), // 1970-Jan-01 00:00 -> 2004-Jan-10 00:00
1407 new TFDItem( "GMT", "en_US", 0, 1073779200000L, false, 34, 408, 12428, 298272, 17896320, 1073779200 ), // 1970-Jan-01 00:00 -> 2004-Jan-11 00:00
1408 new TFDItem( "GMT", "en_US", 0, 2147472000000L, false, 68, 816, 24855, 596520, 35791200, 2147472000 ), // 1970-Jan-01 00:00 -> 2038-Jan-19 00:00
1409 // new TFDItem( "GMT", "en_US", 0, 2147558400000L, false, 68, 816, 24856, 596544, 35792640, 0x7FFFFFFF ), // 1970-Jan-01 00:00 -> 2038-Jan-20 00:00, seconds overflow => exception in ICU4J
1410 new TFDItem( "GMT", "en_US", 0, -1073692800000L, false, -34,-408,-12427,-298248,-17894880,-1073692800 ), // 1970-Jan-01 00:00 -> 1935-Dec-24 00:00
1411 new TFDItem( "GMT", "en_US", 0, -1073779200000L, false, -34,-408,-12428,-298272,-17896320,-1073779200 ), // 1970-Jan-01 00:00 -> 1935-Dec-23 00:00
1412 // check fwd/backward on either side of era boundary and across era boundary
1413 new TFDItem( "GMT", "en_US", -61978089600000L,-61820409600000L, false, 4, 59, 1825, 43800, 2628000, 157680000 ), // CE 5-Dec-31 00:00 -> CE 10-Dec-30 00:00
1414 new TFDItem( "GMT", "en_US", -61820409600000L,-61978089600000L, false, -4, -59, -1825, -43800, -2628000, -157680000 ), // CE 10-Dec-30 00:00 -> CE 5-Dec-31 00:00
1415 new TFDItem( "GMT", "en_US", -62451129600000L,-62293449600000L, false, 4, 59, 1825, 43800, 2628000, 157680000 ), // BCE 10-Jan-04 00:00 -> BCE 5-Jan-03 00:00
1416 new TFDItem( "GMT", "en_US", -62293449600000L,-62451129600000L, false, -4, -59, -1825, -43800, -2628000, -157680000 ), // BCE 5-Jan-03 00:00 -> BCE 10-Jan-04 00:00
1417 new TFDItem( "GMT", "en_US", -62293449600000L,-61978089600000L, false, 9, 119, 3650, 87600, 5256000, 315360000 ), // BCE 5-Jan-03 00:00 -> CE 5-Dec-31 00:00
1418 new TFDItem( "GMT", "en_US", -61978089600000L,-62293449600000L, false, -9,-119, -3650, -87600, -5256000, -315360000 ), // CE 5-Dec-31 00:00 -> BCE 5-Jan-03 00:00
1419 new TFDItem( "GMT", "en@calendar=roc", -1672704000000L, -1515024000000L, false, 4, 59, 1825, 43800, 2628000, 157680000 ), // MG 5-Dec-30 00:00 -> MG 10-Dec-29 00:00
1420 new TFDItem( "GMT", "en@calendar=roc", -1515024000000L, -1672704000000L, false, -4, -59, -1825, -43800, -2628000, -157680000 ), // MG 10-Dec-29 00:00 -> MG 5-Dec-30 00:00
1421 new TFDItem( "GMT", "en@calendar=roc", -2145744000000L, -1988064000000L, false, 4, 59, 1825, 43800, 2628000, 157680000 ), // BMG 10-Jan-03 00:00 -> BMG 5-Jan-02 00:00
1422 new TFDItem( "GMT", "en@calendar=roc", -1988064000000L, -2145744000000L, false, -4, -59, -1825, -43800, -2628000, -157680000 ), // BMG 5-Jan-02 00:00 -> BMG 10-Jan-03 00:00
1423 new TFDItem( "GMT", "en@calendar=roc", -1988064000000L, -1672704000000L, false, 9, 119, 3650, 87600, 5256000, 315360000 ), // BMG 5-Jan-02 00:00 -> MG 5-Dec-30 00:00
1424 new TFDItem( "GMT", "en@calendar=roc", -1672704000000L, -1988064000000L, false, -9,-119, -3650, -87600, -5256000, -315360000 ), // MG 5-Dec-30 00:00 -> BMG 5-Jan-02 00:00
1425 new TFDItem( "GMT", "en@calendar=coptic",-53026531200000L,-52868851200000L, false, 4, 64, 1825, 43800, 2628000, 157680000 ), // Er1 5-Nas-05 00:00 -> Er1 10-Nas-04 00:00
1426 new TFDItem( "GMT", "en@calendar=coptic",-52868851200000L,-53026531200000L, false, -4, -64, -1825, -43800, -2628000, -157680000 ), // Er1 10-Nas-04 00:00 -> Er1 5-Nas-05 00:00
1427 new TFDItem( "GMT", "en@calendar=coptic",-53499571200000L,-53341891200000L, false, 4, 64, 1825, 43800, 2628000, 157680000 ), // Er0 10-Tou-04 00:00 -> Er0 5-Tou-02 00:00
1428 new TFDItem( "GMT", "en@calendar=coptic",-53341891200000L,-53499571200000L, false, -4, -64, -1825, -43800, -2628000, -157680000 ), // Er0 5-Tou-02 00:00 -> Er0 10-Tou-04 00:00
1429 new TFDItem( "GMT", "en@calendar=coptic",-53341891200000L,-53026531200000L, false, 9, 129, 3650, 87600, 5256000, 315360000 ), // Er0 5-Tou-02 00:00 -> Er1 5-Nas-05 00:00
1430 new TFDItem( "GMT", "en@calendar=coptic",-53026531200000L,-53341891200000L, false, -9,-129, -3650, -87600, -5256000, -315360000 ), // Er1 5-Nas-05 00:00 -> Er0 5-Tou-02 00:00
1432 for (TFDItem tfdItem: tfdItems) {
1433 TimeZone timezone = TimeZone.getFrozenTimeZone(tfdItem.tzname);
1434 Calendar ucal = Calendar.getInstance(timezone, new ULocale(tfdItem.locale));
1435 ucal.setTimeInMillis(tfdItem.target);
1436 Date targetDate = ucal.getTime();
1437 int yDf, MDf, dDf, HDf, mDf, sDf;
1438 if (tfdItem.progressive) {
1439 ucal.setTimeInMillis(tfdItem.start);
1440 yDf = ucal.fieldDifference(targetDate, YEAR);
1441 MDf = ucal.fieldDifference(targetDate, MONTH);
1442 dDf = ucal.fieldDifference(targetDate, DATE);
1443 HDf = ucal.fieldDifference(targetDate, HOUR);
1444 mDf = ucal.fieldDifference(targetDate, MINUTE);
1445 sDf = ucal.fieldDifference(targetDate, SECOND);
1446 if ( yDf != tfdItem.yDiff || MDf != tfdItem.MDiff || dDf != tfdItem.dDiff || HDf != tfdItem.HDiff || mDf != tfdItem.mDiff || sDf != tfdItem.sDiff ) {
1447 errln("Fail: for locale \"" + tfdItem.locale + "\", start " + tfdItem.start + ", target " + tfdItem.target + ", expected y-M-d-H-m-s progressive diffs " +
1448 tfdItem.yDiff +","+ tfdItem.MDiff +","+ tfdItem.dDiff +","+ tfdItem.HDiff +","+ tfdItem.mDiff +","+ tfdItem.sDiff + ", got " +
1449 yDf +","+ MDf +","+ dDf +","+ HDf +","+ mDf +","+ sDf);
1452 ucal.setTimeInMillis(tfdItem.start);
1453 yDf = ucal.fieldDifference(targetDate, YEAR);
1454 ucal.setTimeInMillis(tfdItem.start);
1455 MDf = ucal.fieldDifference(targetDate, MONTH);
1456 ucal.setTimeInMillis(tfdItem.start);
1457 dDf = ucal.fieldDifference(targetDate, DATE);
1458 ucal.setTimeInMillis(tfdItem.start);
1459 HDf = ucal.fieldDifference(targetDate, HOUR);
1460 ucal.setTimeInMillis(tfdItem.start);
1461 mDf = ucal.fieldDifference(targetDate, MINUTE);
1462 if ( yDf != tfdItem.yDiff || MDf != tfdItem.MDiff || dDf != tfdItem.dDiff || HDf != tfdItem.HDiff || mDf != tfdItem.mDiff ) {
1463 errln("Fail: for locale \"" + tfdItem.locale + "\", start " + tfdItem.start + ", target " + tfdItem.target + ", expected y-M-d-H-m total diffs " +
1464 tfdItem.yDiff +","+ tfdItem.MDiff +","+ tfdItem.dDiff +","+ tfdItem.HDiff +","+ tfdItem.mDiff + ", got " +
1465 yDf +","+ MDf +","+ dDf +","+ HDf +","+ mDf);
1467 ucal.setTimeInMillis(tfdItem.start);
1468 sDf = ucal.fieldDifference(targetDate, SECOND);
1469 if ( sDf != 0x7FFFFFFF && sDf != tfdItem.sDiff ) {
1470 errln("Fail: for locale \"" + tfdItem.locale + "\", start " + tfdItem.start + ", target " + tfdItem.target + ", expected seconds total diffs " +
1471 tfdItem.sDiff + ", got " + sDf);
1477 public void TestAddRollEra0AndEraBounds() {
1478 final String[] localeIDs = {
1479 // calendars with non-modern era 0 that goes backwards, max era == 1
1480 "en@calendar=gregorian",
1482 "en@calendar=coptic",
1483 // calendars with non-modern era 0 that goes forwards, max era > 1
1484 "en@calendar=japanese",
1485 "en@calendar=chinese",
1486 // calendars with non-modern era 0 that goes forwards, max era == 1
1487 "en@calendar=ethiopic",
1488 // calendars with only one era = 0, forwards
1489 "en@calendar=buddhist",
1490 "en@calendar=hebrew",
1491 "en@calendar=islamic",
1492 "en@calendar=indian",
1493 //"en@calendar=persian", // no persian calendar in ICU4J yet
1494 "en@calendar=ethiopic-amete-alem",
1496 TimeZone zoneGMT = TimeZone.getFrozenTimeZone("GMT");
1497 for (String localeID : localeIDs) {
1498 Calendar ucalTest = Calendar.getInstance(zoneGMT, new ULocale(localeID));
1499 String calType = ucalTest.getType();
1500 boolean era0YearsGoBackwards = (calType.equals("gregorian") || calType.equals("roc") || calType.equals("coptic"));
1501 int yrBefore, yrAfter, yrMax, eraAfter, eraMax, eraNow;
1504 ucalTest.set(Calendar.YEAR, 2);
1505 ucalTest.set(Calendar.ERA, 0);
1506 yrBefore = ucalTest.get(Calendar.YEAR);
1507 ucalTest.add(Calendar.YEAR, 1);
1508 yrAfter = ucalTest.get(Calendar.YEAR);
1509 if ( (era0YearsGoBackwards && yrAfter>yrBefore) || (!era0YearsGoBackwards && yrAfter<yrBefore) ) {
1510 errln("Fail: era 0 add 1 year does not move forward in time for " + localeID);
1514 ucalTest.set(Calendar.YEAR, 2);
1515 ucalTest.set(Calendar.ERA, 0);
1516 yrBefore = ucalTest.get(Calendar.YEAR);
1517 ucalTest.roll(Calendar.YEAR, 1);
1518 yrAfter = ucalTest.get(Calendar.YEAR);
1519 if ( (era0YearsGoBackwards && yrAfter>yrBefore) || (!era0YearsGoBackwards && yrAfter<yrBefore) ) {
1520 errln("Fail: era 0 roll 1 year does not move forward in time for " + localeID);
1524 ucalTest.set(Calendar.YEAR, 1);
1525 ucalTest.set(Calendar.ERA, 0);
1526 if (era0YearsGoBackwards) {
1527 ucalTest.roll(Calendar.YEAR, 1);
1528 yrAfter = ucalTest.get(Calendar.YEAR);
1529 eraAfter = ucalTest.get(Calendar.ERA);
1530 if (eraAfter != 0 || yrAfter != 1) {
1531 errln("Fail: era 0 roll 1 year from year 1 does not stay within era or pin to year 1 for "
1532 + localeID + " (get era " + eraAfter + " year " + yrAfter + ")");
1535 // roll backward in time to where era 0 years go negative, except for the Chinese
1536 // calendar, which uses negative eras instead of having years outside the range 1-60
1537 ucalTest.roll(Calendar.YEAR, -2);
1538 yrAfter = ucalTest.get(Calendar.YEAR);
1539 eraAfter = ucalTest.get(Calendar.ERA);
1540 if ( !calType.equals("chinese") && (eraAfter != 0 || yrAfter != -1) ) {
1541 errln("Fail: era 0 roll -2 years from year 1 does not stay within era or produce year -1 for "
1542 + localeID + " (get era " + eraAfter + " year " + yrAfter + ")");
1548 int eraMin = ucalTest.getMinimum(Calendar.ERA);
1549 if (eraMin != 0 && calType.compareTo("chinese") != 0) {
1550 errln("Fail: getMinimum returns minimum era " + eraMin + " (should be 0) for calType " + calType);
1555 ucalTest.set(Calendar.YEAR, 1);
1556 ucalTest.set(Calendar.ERA, 0);
1557 eraMax = ucalTest.getMaximum(Calendar.ERA);
1559 // try similar tests for era 1 (if calendar has it), in which years always go forward
1562 ucalTest.set(Calendar.YEAR, 2);
1563 ucalTest.set(Calendar.ERA, 1);
1564 yrBefore = ucalTest.get(Calendar.YEAR);
1565 ucalTest.add(Calendar.YEAR, 1);
1566 yrAfter = ucalTest.get(Calendar.YEAR);
1567 if ( yrAfter<yrBefore ) {
1568 errln("Fail: era 1 add 1 year does not move forward in time for " + localeID);
1572 ucalTest.set(Calendar.YEAR, 2);
1573 ucalTest.set(Calendar.ERA, 1);
1574 yrBefore = ucalTest.get(Calendar.YEAR);
1575 ucalTest.roll(Calendar.YEAR, 1);
1576 yrAfter = ucalTest.get(Calendar.YEAR);
1577 if ( yrAfter<yrBefore ) {
1578 errln("Fail: era 1 roll 1 year does not move forward in time for " + localeID);
1582 ucalTest.set(Calendar.YEAR, 1);
1583 ucalTest.set(Calendar.ERA, 1);
1584 yrMax = ucalTest.getActualMaximum(Calendar.YEAR);
1585 ucalTest.roll(Calendar.YEAR, -1); // roll down which should pin or wrap to end
1586 yrAfter = ucalTest.get(Calendar.YEAR);
1587 eraAfter = ucalTest.get(Calendar.ERA);
1588 // if yrMax is reasonable we should wrap to that, else we should pin at yr 1
1589 if (yrMax >= 32768) {
1590 if (eraAfter != 1 || yrAfter != 1) {
1591 errln("Fail: era 1 roll -1 year from year 1 does not stay within era or pin to year 1 for "
1592 + localeID + " (get era " + eraAfter + " year " + yrAfter + ")");
1594 } else if (eraAfter != 1 || yrAfter != yrMax) {
1595 errln("Fail: era 1 roll -1 year from year 1 does not stay within era or wrap to year "
1596 + yrMax + " for " + localeID + " (get era " + eraAfter + " year " + yrAfter + ")");
1598 ucalTest.roll(Calendar.YEAR, 1); // now roll up which should wrap to beginning
1599 yrAfter = ucalTest.get(Calendar.YEAR);
1600 eraAfter = ucalTest.get(Calendar.ERA);
1601 if (eraAfter != 1 || yrAfter != 1) {
1602 errln("Fail: era 1 roll 1 year from year " + yrMax +
1603 " does not stay within era or wrap to year 1 for "
1604 + localeID + " (get era " + eraAfter + " year " + yrAfter + ")");
1608 // if current era > 1, try the same roll tests for current era
1609 ucalTest.setTime(new Date());
1610 eraNow = ucalTest.get(Calendar.ERA);
1613 ucalTest.set(Calendar.YEAR, 1);
1614 ucalTest.set(Calendar.ERA, eraNow);
1615 yrMax = ucalTest.getActualMaximum(Calendar.YEAR); // max year value for this era
1616 ucalTest.roll(Calendar.YEAR, -1);
1617 yrAfter = ucalTest.get(Calendar.YEAR);
1618 eraAfter = ucalTest.get(Calendar.ERA);
1619 // if yrMax is reasonable we should wrap to that, else we should pin at yr 1
1620 if (yrMax >= 32768) {
1621 if (eraAfter != eraNow || yrAfter != 1) {
1622 errln("Fail: era " + eraNow +
1623 " roll -1 year from year 1 does not stay within era or pin to year 1 for "
1624 + localeID + " (get era " + eraAfter + " year " + yrAfter + ")");
1626 } else if (eraAfter != eraNow || yrAfter != yrMax) {
1627 errln("Fail: era " + eraNow +
1628 " roll -1 year from year 1 does not stay within era or wrap to year " + yrMax
1629 + " for " + localeID + " (get era " + eraAfter + " year " + yrAfter + ")");
1631 ucalTest.roll(Calendar.YEAR, 1); // now roll up which should wrap to beginning
1632 yrAfter = ucalTest.get(Calendar.YEAR);
1633 eraAfter = ucalTest.get(Calendar.ERA);
1634 if (eraAfter != eraNow || yrAfter != 1) {
1635 errln("Fail: era " + eraNow + " roll 1 year from year " + yrMax +
1636 " does not stay within era or wrap to year 1 for "
1637 + localeID + " (get era " + eraAfter + " year " + yrAfter + ")");