]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-52_1/main/tests/core/src/com/ibm/icu/dev/test/calendar/ChineseTest.java
Upgrade ICU4J.
[Dictionary.git] / jars / icu4j-52_1 / main / tests / core / src / com / ibm / icu / dev / test / calendar / ChineseTest.java
1 /*********************************************************************
2  * Copyright (C) 2000-2013, International Business Machines Corporation and
3  * others. All Rights Reserved.
4  *********************************************************************
5  */
6 package com.ibm.icu.dev.test.calendar;
7 import java.util.Date;
8 import java.util.Locale;
9
10 import com.ibm.icu.text.ChineseDateFormat;
11 import com.ibm.icu.text.DateFormat;
12 import com.ibm.icu.text.DateFormatSymbols;
13 import com.ibm.icu.text.SimpleDateFormat;
14 import com.ibm.icu.util.Calendar;
15 import com.ibm.icu.util.ChineseCalendar;
16 import com.ibm.icu.util.GregorianCalendar;
17 import com.ibm.icu.util.TimeZone;
18 import com.ibm.icu.util.ULocale;
19
20 /**
21  * Test of ChineseCalendar.
22  *
23  * Leap months in this century:
24  * Wed May 23 2001 = 4638-04*-01, Year 18, Cycle 78
25  * Sun Mar 21 2004 = 4641-02*-01, Year 21, Cycle 78
26  * Thu Aug 24 2006 = 4643-07*-01, Year 23, Cycle 78
27  * Tue Jun 23 2009 = 4646-05*-01, Year 26, Cycle 78
28  * Mon May 21 2012 = 4649-04*-01, Year 29, Cycle 78
29  * Fri Oct 24 2014 = 4651-09*-01, Year 31, Cycle 78
30  * Sun Jul 23 2017 = 4654-06*-01, Year 34, Cycle 78
31  * Sat May 23 2020 = 4657-04*-01, Year 37, Cycle 78
32  * Wed Mar 22 2023 = 4660-02*-01, Year 40, Cycle 78
33  * Fri Jul 25 2025 = 4662-06*-01, Year 42, Cycle 78
34  * Fri Jun 23 2028 = 4665-05*-01, Year 45, Cycle 78
35  * Tue Apr 22 2031 = 4668-03*-01, Year 48, Cycle 78
36  * Thu Dec 22 2033 = 4670-11*-01, Year 50, Cycle 78
37  * Wed Jul 23 2036 = 4673-06*-01, Year 53, Cycle 78
38  * Wed Jun 22 2039 = 4676-05*-01, Year 56, Cycle 78
39  * Sat Mar 22 2042 = 4679-02*-01, Year 59, Cycle 78
40  * Tue Aug 23 2044 = 4681-07*-01, Year 01, Cycle 79
41  * Sun Jun 23 2047 = 4684-05*-01, Year 04, Cycle 79
42  * Thu Apr 21 2050 = 4687-03*-01, Year 07, Cycle 79
43  * Mon Sep 23 2052 = 4689-08*-01, Year 09, Cycle 79
44  * Sat Jul 24 2055 = 4692-06*-01, Year 12, Cycle 79
45  * Wed May 22 2058 = 4695-04*-01, Year 15, Cycle 79
46  * Wed Apr 20 2061 = 4698-03*-01, Year 18, Cycle 79
47  * Fri Aug 24 2063 = 4700-07*-01, Year 20, Cycle 79
48  * Wed Jun 23 2066 = 4703-05*-01, Year 23, Cycle 79
49  * Tue May 21 2069 = 4706-04*-01, Year 26, Cycle 79
50  * Thu Sep 24 2071 = 4708-08*-01, Year 28, Cycle 79
51  * Tue Jul 24 2074 = 4711-06*-01, Year 31, Cycle 79
52  * Sat May 22 2077 = 4714-04*-01, Year 34, Cycle 79
53  * Sat Apr 20 2080 = 4717-03*-01, Year 37, Cycle 79
54  * Mon Aug 24 2082 = 4719-07*-01, Year 39, Cycle 79
55  * Fri Jun 22 2085 = 4722-05*-01, Year 42, Cycle 79
56  * Fri May 21 2088 = 4725-04*-01, Year 45, Cycle 79
57  * Sun Sep 24 2090 = 4727-08*-01, Year 47, Cycle 79
58  * Thu Jul 23 2093 = 4730-06*-01, Year 50, Cycle 79
59  * Tue May 22 2096 = 4733-04*-01, Year 53, Cycle 79
60  * Sun Mar 22 2099 = 4736-02*-01, Year 56, Cycle 79
61  */
62 public class ChineseTest extends CalendarTest {
63
64     public static void main(String args[]) throws Exception {
65         new ChineseTest().run(args);
66     }
67
68     /**
69      * Test basic mapping to and from Gregorian.
70      */
71     public void TestMapping() {
72
73         final int[] DATA = {
74             // (Note: months are 1-based)
75             // Gregorian    Chinese
76             1964,  9,  4,   4601,  7,0, 28,
77             1964,  9,  5,   4601,  7,0, 29,
78             1964,  9,  6,   4601,  8,0,  1,
79             1964,  9,  7,   4601,  8,0,  2,
80             1961, 12, 25,   4598, 11,0, 18,
81             1999,  6,  4,   4636,  4,0, 21,
82             
83             1990,  5, 23,   4627,  4,0, 29,
84             1990,  5, 24,   4627,  5,0,  1,
85             1990,  6, 22,   4627,  5,0, 30,
86             1990,  6, 23,   4627,  5,1,  1,
87             1990,  7, 20,   4627,  5,1, 28,
88             1990,  7, 21,   4627,  5,1, 29,
89             1990,  7, 22,   4627,  6,0,  1,
90         };
91
92         ChineseCalendar cal = new ChineseCalendar();
93         StringBuffer buf = new StringBuffer();
94
95         logln("Gregorian -> Chinese");
96         //java.util.Calendar grego = java.util.Calendar.getInstance();
97         Calendar grego = Calendar.getInstance();
98         grego.clear();
99         for (int i=0; i<DATA.length; ) {
100             grego.set(DATA[i++], DATA[i++]-1, DATA[i++]);
101             Date date = grego.getTime();
102             cal.setTime(date);
103             int y = cal.get(Calendar.EXTENDED_YEAR);
104             int m = cal.get(Calendar.MONTH)+1; // 0-based -> 1-based
105             int L = cal.get(Calendar.IS_LEAP_MONTH);
106             int d = cal.get(Calendar.DAY_OF_MONTH);
107             int yE = DATA[i++]; // Expected y, m, isLeapMonth, d
108             int mE = DATA[i++]; // 1-based
109             int LE = DATA[i++];
110             int dE = DATA[i++];
111             buf.setLength(0);
112             buf.append(date + " -> ");
113             buf.append(y + "/" + m + (L==1?"(leap)":"") + "/" + d);
114             if (y == yE && m == mE && L == LE && d == dE) {
115                 logln("OK: " + buf.toString());
116             } else {
117                 errln("Fail: " + buf.toString() + ", expected " +
118                       yE + "/" + mE + (LE==1?"(leap)":"") + "/" + dE);
119             }
120         }
121
122         logln("Chinese -> Gregorian");
123         for (int i=0; i<DATA.length; ) {
124             grego.set(DATA[i++], DATA[i++]-1, DATA[i++]);
125             Date dexp = grego.getTime();
126             int cyear = DATA[i++];
127             int cmonth = DATA[i++];
128             int cisleapmonth = DATA[i++];
129             int cdayofmonth = DATA[i++];
130             cal.clear();
131             cal.set(Calendar.EXTENDED_YEAR, cyear);
132             cal.set(Calendar.MONTH, cmonth-1);
133             cal.set(Calendar.IS_LEAP_MONTH, cisleapmonth);
134             cal.set(Calendar.DAY_OF_MONTH, cdayofmonth);
135             Date date = cal.getTime();
136             buf.setLength(0);
137             buf.append(cyear + "/" + cmonth +
138                        (cisleapmonth==1?"(leap)":"") + "/" + cdayofmonth);
139             buf.append(" -> " + date);
140             if (date.equals(dexp)) {
141                 logln("OK: " + buf.toString());
142             } else {
143                 errln("Fail: " + buf.toString() + ", expected " + dexp);
144             }
145         }
146     }
147
148     /**
149      * Make sure no Gregorian dates map to Chinese 1-based day of
150      * month zero.  This was a problem with some of the astronomical
151      * new moon determinations.
152      */
153     public void TestZeroDOM() {
154         ChineseCalendar cal = new ChineseCalendar();
155         GregorianCalendar greg = new GregorianCalendar(1989, Calendar.SEPTEMBER, 1);
156         logln("Start: " + greg.getTime());
157         for (int i=0; i<1000; ++i) {
158             cal.setTimeInMillis(greg.getTimeInMillis());
159             if (cal.get(Calendar.DAY_OF_MONTH) == 0) {
160                 errln("Fail: " + greg.getTime() + " -> " +
161                       cal.get(Calendar.EXTENDED_YEAR) + "/" +
162                       cal.get(Calendar.MONTH) +
163                       (cal.get(Calendar.IS_LEAP_MONTH)==1?"(leap)":"") +
164                       "/" + cal.get(Calendar.DAY_OF_MONTH));
165             }
166             greg.add(Calendar.DAY_OF_YEAR, 1);
167         }
168         logln("End: " + greg.getTime());
169     }
170
171     /**
172      * Test minimum and maximum functions.
173      */
174     public void TestLimits() {
175         // The number of days and the start date can be adjusted
176         // arbitrarily to either speed up the test or make it more
177         // thorough, but try to test at least a full year, preferably a
178         // full non-leap and a full leap year.
179
180         // Final parameter is either number of days, if > 0, or test
181         // duration in seconds, if < 0.
182         java.util.Calendar tempcal = java.util.Calendar.getInstance();
183         tempcal.clear();
184         tempcal.set(1989, Calendar.NOVEMBER, 1);
185         ChineseCalendar chinese = new ChineseCalendar();
186         doLimitsTest(chinese, null, tempcal.getTime());
187         doTheoreticalLimitsTest(chinese, true);
188     }
189
190     /**
191      * Run through several standard tests from Dershowitz & Reingold.
192      */
193     public void TestJulianDayMapping() {
194
195         final TestCase[] tests = {
196             //
197             // From Dershowitz & Reingold, "Calendrical Calculations".
198             //
199             // The months in this table are 1-based rather than 0-based.
200             //
201             // * Failing fields->millis
202             // ** Millis->fields gives 0-based month -1
203             // These failures were fixed by changing the start search date
204             // for the winter solstice from Dec 15 to Dec 1.
205             // 
206             //                  Julian Day   Era  Year Month  Leap   DOM WkDay
207             new ChineseTestCase(1507231.5,   35,   11,    6, false,   12,  SUN),
208             new ChineseTestCase(1660037.5,   42,    9,   10, false,   27,  WED),
209             new ChineseTestCase(1746893.5,   46,    7,    8, false,    4,  WED),
210             new ChineseTestCase(1770641.5,   47,   12,    8, false,    9,  SUN),
211             new ChineseTestCase(1892731.5,   52,   46,   11, false,   20,  WED),
212             new ChineseTestCase(1931579.5,   54,   33,    4, false,    5,  MON),
213             new ChineseTestCase(1974851.5,   56,   31,   10, false,   15,  SAT),
214             new ChineseTestCase(2091164.5,   61,   50,    3, false,    7,  SUN),
215             new ChineseTestCase(2121509.5,   63,   13,    4, false,   24,  SUN),
216             new ChineseTestCase(2155779.5,   64,   47,    2, false,    9,  FRI),
217             new ChineseTestCase(2174029.5,   65,   37,    2, false,    9,  SAT),
218             new ChineseTestCase(2191584.5,   66,   25,    2, false,   23,  FRI),
219             new ChineseTestCase(2195261.5,   66,   35,    3, false,    9,  SUN), //*
220             new ChineseTestCase(2229274.5,   68,    8,    5, false,    2,  SUN), //*
221             new ChineseTestCase(2245580.5,   68,   53,    1, false,    8,  WED), //**
222             new ChineseTestCase(2266100.5,   69,   49,    3, false,    4,  SAT), 
223             new ChineseTestCase(2288542.5,   70,   50,    8, false,    2,  SAT), //*
224             new ChineseTestCase(2290901.5,   70,   57,    1, false,   29,  SAT), //*
225             new ChineseTestCase(2323140.5,   72,   25,    4,  true,   20,  WED), //*
226             new ChineseTestCase(2334848.5,   72,   57,    6, false,    5,  SUN),
227             new ChineseTestCase(2348020.5,   73,   33,    6, false,    6,  FRI),
228             new ChineseTestCase(2366978.5,   74,   25,    5, false,    5,  SUN),
229             new ChineseTestCase(2385648.5,   75,   16,    6, false,   12,  MON),
230             new ChineseTestCase(2392825.5,   75,   36,    2, false,   13,  WED),
231             new ChineseTestCase(2416223.5,   76,   40,    3, false,   22,  SUN),
232             new ChineseTestCase(2425848.5,   77,    6,    7, false,   21,  SUN),
233             new ChineseTestCase(2430266.5,   77,   18,    8, false,    9,  MON),
234             new ChineseTestCase(2430833.5,   77,   20,    3, false,   15,  MON),
235             new ChineseTestCase(2431004.5,   77,   20,    9, false,    9,  THU),
236             new ChineseTestCase(2448698.5,   78,    9,    2, false,   14,  TUE),
237             new ChineseTestCase(2450138.5,   78,   13,    1, false,    7,  SUN),
238             new ChineseTestCase(2465737.5,   78,   55,   10, false,   14,  WED),
239             new ChineseTestCase(2486076.5,   79,   51,    6, false,    7,  SUN),
240
241             // Additional tests not from D&R
242             new ChineseTestCase(2467496.5,   78,   60,    8, false,    2,  FRI), // year 60
243         };
244
245         ChineseCalendar cal = new ChineseCalendar();
246         cal.setLenient(true);
247         doTestCases(tests, cal);
248     }
249
250     /**
251      * Test formatting.
252      * Q: Why is this in Calendar tests instead of Format tests?
253      * Note: This test assumes that Chinese calendar formatted dates can be parsed
254      * unambiguously to recover the original Date that was formatted. This is not
255      * currently true since Chinese calendar formatted dates do not include an era.
256      * To address this will require formatting/parsing of fields from some other
257      * associated calendar, as per ICU ticket #9043. This test should be timebombed
258      * until that ticket is addressed.
259      */
260     public void TestFormat() {
261         ChineseCalendar cal = new ChineseCalendar();
262         DateFormat fmt = DateFormat.getDateTimeInstance(cal,
263                                     DateFormat.DEFAULT, DateFormat.DEFAULT);
264
265         java.util.Calendar tempcal = java.util.Calendar.getInstance();
266         tempcal.clear();
267         
268         Date[] DATA = new Date[2];
269         tempcal.set(2001, Calendar.MAY, 22);
270         DATA[0] = tempcal.getTime();
271         tempcal.set(2001, Calendar.MAY, 23);
272         DATA[1] = tempcal.getTime();
273         // Wed May 23 2001 = Month 4(leap), Day 1, Year 18, Cycle 78
274         
275         for (int i=0; i<DATA.length; ++i) {
276             String s = fmt.format(DATA[i]);
277             try {
278                 Date e = fmt.parse(s);
279                 if (e.equals(DATA[i])) {
280                     logln("Ok: " + DATA[i] + " -> " + s + " -> " + e);
281                 } else if (logKnownIssue("9043", "Ambiguous Chinese era parsing")) {
282                     logln("Ambiguous parse fails: " + DATA[i] + " -> " + s + " -> " + e);
283                 } else {
284                     errln("FAIL: " + DATA[i] + " -> " + s + " -> " + e);
285                 }
286             } catch (java.text.ParseException e) {
287                 errln("Fail: " + s + " -> parse failure at " + e.getErrorOffset());
288                 errln(e.toString());
289             }
290         }
291     }
292
293     /**
294      * Make sure IS_LEAP_MONTH participates in field resolution.
295      */
296     public void TestResolution() {
297         ChineseCalendar cal = new ChineseCalendar();
298         DateFormat fmt = DateFormat.getDateInstance(cal, DateFormat.DEFAULT);
299
300         // May 22 2001 = y4638 m4 d30 doy119
301         // May 23 2001 = y4638 m4* d1 doy120
302
303         final int THE_YEAR = 4638;
304         final int END = -1;
305
306         int[] DATA = {
307             // Format:
308             // (field, value)+, END, exp.month, exp.isLeapMonth, exp.DOM
309             // Note: exp.month is ONE-BASED
310
311             // If we set DAY_OF_YEAR only, that should be used
312             Calendar.DAY_OF_YEAR, 1,
313             END,
314             1,0,1, // Expect 1-1
315             
316             // If we set MONTH only, that should be used
317             Calendar.IS_LEAP_MONTH, 1,
318             Calendar.DAY_OF_MONTH, 1,
319             Calendar.MONTH, 3,
320             END,
321             4,1,1, // Expect 4*-1
322             
323             // If we set the DOY last, that should take precedence
324             Calendar.MONTH, 1, // Should ignore
325             Calendar.IS_LEAP_MONTH, 1, // Should ignore
326             Calendar.DAY_OF_MONTH, 1, // Should ignore
327             Calendar.DAY_OF_YEAR, 121,
328             END,
329             4,1,2, // Expect 4*-2
330             
331             // I've disabled this test because it doesn't work this way,
332             // not even with a GregorianCalendar!  MONTH alone isn't enough
333             // to supersede DAY_OF_YEAR.  Some other month-related field is
334             // also required. - Liu 11/28/00
335             //! // If we set MONTH last, that should take precedence
336             //! ChineseCalendar.IS_LEAP_MONTH, 1,
337             //! Calendar.DAY_OF_MONTH, 1,
338             //! Calendar.DAY_OF_YEAR, 5, // Should ignore
339             //! Calendar.MONTH, 3,
340             //! END,
341             //! 4,1,1, // Expect 4*-1
342             
343             // If we set IS_LEAP_MONTH last, that should take precedence
344             Calendar.MONTH, 3,
345             Calendar.DAY_OF_MONTH, 1,
346             Calendar.DAY_OF_YEAR, 5, // Should ignore
347             Calendar.IS_LEAP_MONTH, 1,
348             END,
349             4,1,1, // Expect 4*-1
350         };
351
352         StringBuffer buf = new StringBuffer();
353         for (int i=0; i<DATA.length; ) {
354             cal.clear();
355             cal.set(Calendar.EXTENDED_YEAR, THE_YEAR);
356             buf.setLength(0);
357             buf.append("EXTENDED_YEAR=" + THE_YEAR);
358             while (DATA[i] != END) {
359                 cal.set(DATA[i++], DATA[i++]);
360                 buf.append(" " + fieldName(DATA[i-2]) + "=" + DATA[i-1]);
361             }
362             ++i; // Skip over END mark
363             int expMonth = DATA[i++]-1;
364             int expIsLeapMonth = DATA[i++];
365             int expDOM = DATA[i++];
366             int month = cal.get(Calendar.MONTH);
367             int isLeapMonth = cal.get(Calendar.IS_LEAP_MONTH);
368             int dom = cal.get(Calendar.DAY_OF_MONTH);
369             if (expMonth == month && expIsLeapMonth == isLeapMonth &&
370                 dom == expDOM) {
371                 logln("OK: " + buf + " => " + fmt.format(cal.getTime()));
372             } else {
373                 String s = fmt.format(cal.getTime());
374                 cal.clear();
375                 cal.set(Calendar.EXTENDED_YEAR, THE_YEAR);
376                 cal.set(Calendar.MONTH, expMonth);
377                 cal.set(Calendar.IS_LEAP_MONTH, expIsLeapMonth);
378                 cal.set(Calendar.DAY_OF_MONTH, expDOM);
379                 errln("Fail: " + buf + " => " + s +
380                       "=" + (month+1) + "," + isLeapMonth + "," + dom +
381                       ", expected " + fmt.format(cal.getTime()) +
382                       "=" + (expMonth+1) + "," + expIsLeapMonth + "," + expDOM);
383             }
384         }
385     }
386
387     /**
388      * Test the behavior of fields that are out of range.
389      */
390     public void TestOutOfRange() {
391         int[] DATA = new int[] {
392             // Input       Output
393             4638, 13,  1,   4639,  1,  1,
394             4638, 18,  1,   4639,  6,  1,
395             4639,  0,  1,   4638, 12,  1,
396             4639, -6,  1,   4638,  6,  1,
397             4638,  1, 32,   4638,  2,  2, // 1-4638 has 30 days
398             4638,  2, -1,   4638,  1, 29,
399         };
400         ChineseCalendar cal = new ChineseCalendar();
401         for (int i=0; i<DATA.length; ) {
402             int y1 = DATA[i++];
403             int m1 = DATA[i++]-1;
404             int d1 = DATA[i++];
405             int y2 = DATA[i++];
406             int m2 = DATA[i++]-1;
407             int d2 = DATA[i++];
408             cal.clear();
409             cal.set(Calendar.EXTENDED_YEAR, y1);
410             cal.set(MONTH, m1);
411             cal.set(DATE, d1);
412             int y = cal.get(Calendar.EXTENDED_YEAR);
413             int m = cal.get(MONTH);
414             int d = cal.get(DATE);
415             if (y!=y2 || m!=m2 || d!=d2) {
416                 errln("Fail: " + y1 + "/" + (m1+1) + "/" + d1 + " resolves to " +
417                       y + "/" + (m+1) + "/" + d + ", expected " +
418                       y2 + "/" + (m2+1) + "/" + d2);
419             } else  if (isVerbose()) {
420                 logln("OK: " + y1 + "/" + (m1+1) + "/" + d1 + " resolves to " +
421                       y + "/" + (m+1) + "/" + d);
422             }
423         }
424     }
425
426     /**
427      * Test the behavior of ChineseCalendar.add().  The only real
428      * nastiness with roll is the MONTH field around leap months.
429      */
430     public void TestAdd() {
431         int[][] tests = new int[][] {
432             // MONTHS ARE 1-BASED HERE
433             // input               add           output
434             // year  mon    day    field amount  year  mon    day
435             {  4642,   3,0,  15,   MONTH,   3,   4642,   6,0,  15 }, // normal
436             {  4639,  12,0,  15,   MONTH,   1,   4640,   1,0,  15 }, // across year
437             {  4640,   1,0,  15,   MONTH,  -1,   4639,  12,0,  15 }, // across year
438             {  4638,   3,0,  15,   MONTH,   3,   4638,   5,0,  15 }, // 4=leap
439             {  4638,   3,0,  15,   MONTH,   2,   4638,   4,1,  15 }, // 4=leap
440             {  4638,   4,0,  15,   MONTH,   1,   4638,   4,1,  15 }, // 4=leap
441             {  4638,   4,1,  15,   MONTH,   1,   4638,   5,0,  15 }, // 4=leap
442             {  4638,   4,0,  30,   MONTH,   1,   4638,   4,1,  29 }, // dom should pin
443             {  4638,   4,0,  30,   MONTH,   2,   4638,   5,0,  30 }, // no dom pin
444             {  4638,   4,0,  30,   MONTH,   3,   4638,   6,0,  29 }, // dom should pin
445         };
446        
447         ChineseCalendar cal = new ChineseCalendar();
448         doRollAdd(ADD, cal, tests);
449     }
450
451     /**
452      * Test the behavior of ChineseCalendar.roll().  The only real
453      * nastiness with roll is the MONTH field around leap months.
454      */
455     public void TestRoll() {
456         int[][] tests = new int[][] {
457             // MONTHS ARE 1-BASED HERE
458             // input               add           output
459             // year  mon    day    field amount  year  mon    day
460             {  4642,   3,0,  15,   MONTH,   3,   4642,   6,0,  15 }, // normal
461             {  4642,   3,0,  15,   MONTH,  11,   4642,   2,0,  15 }, // normal
462             {  4639,  12,0,  15,   MONTH,   1,   4639,   1,0,  15 }, // across year
463             {  4640,   1,0,  15,   MONTH,  -1,   4640,  12,0,  15 }, // across year
464             {  4638,   3,0,  15,   MONTH,   3,   4638,   5,0,  15 }, // 4=leap
465             {  4638,   3,0,  15,   MONTH,  16,   4638,   5,0,  15 }, // 4=leap
466             {  4638,   3,0,  15,   MONTH,   2,   4638,   4,1,  15 }, // 4=leap
467             {  4638,   3,0,  15,   MONTH,  28,   4638,   4,1,  15 }, // 4=leap
468             {  4638,   4,0,  15,   MONTH,   1,   4638,   4,1,  15 }, // 4=leap
469             {  4638,   4,0,  15,   MONTH, -12,   4638,   4,1,  15 }, // 4=leap
470             {  4638,   4,1,  15,   MONTH,   1,   4638,   5,0,  15 }, // 4=leap
471             {  4638,   4,1,  15,   MONTH, -25,   4638,   5,0,  15 }, // 4=leap
472             {  4638,   4,0,  30,   MONTH,   1,   4638,   4,1,  29 }, // dom should pin
473             {  4638,   4,0,  30,   MONTH,  14,   4638,   4,1,  29 }, // dom should pin
474             {  4638,   4,0,  30,   MONTH,  15,   4638,   5,0,  30 }, // no dom pin
475             {  4638,   4,0,  30,   MONTH, -10,   4638,   6,0,  29 }, // dom should pin
476         };
477        
478         ChineseCalendar cal = new ChineseCalendar();
479         doRollAdd(ROLL, cal, tests);
480     }
481     
482     void doRollAdd(boolean roll, ChineseCalendar cal, int[][] tests) {
483         String name = roll ? "rolling" : "adding";
484         
485         for (int i = 0; i < tests.length; i++) {
486             int[] test = tests[i];
487
488             cal.clear();
489                 cal.set(Calendar.EXTENDED_YEAR, test[0]);
490                 cal.set(Calendar.MONTH, test[1]-1);
491                 cal.set(Calendar.IS_LEAP_MONTH, test[2]);
492                 cal.set(Calendar.DAY_OF_MONTH, test[3]);
493             if (roll) {
494                 cal.roll(test[4], test[5]);
495             } else {
496                 cal.add(test[4], test[5]);
497             }
498             if (cal.get(Calendar.EXTENDED_YEAR) != test[6] ||
499                 cal.get(MONTH) != (test[7]-1) ||
500                 cal.get(Calendar.IS_LEAP_MONTH) != test[8] ||
501                 cal.get(DATE) != test[9]) {
502                 errln("Fail: " + name + " " +
503                       ymdToString(test[0], test[1]-1, test[2], test[3])
504                       + " " + fieldName(test[4]) + " by " + test[5]
505                       + ": expected " +
506                       ymdToString(test[6], test[7]-1, test[8], test[9])
507                       + ", got " + ymdToString(cal));
508             } else if (isVerbose()) {
509                 logln("OK: " + name + " " +
510                       ymdToString(test[0], test[1]-1, test[2], test[3])
511                     + " " + fieldName(test[4]) + " by " + test[5]
512                     + ": got " + ymdToString(cal));
513             }
514         }
515     }
516
517     /**
518      * Convert year,month,day values to the form "year/month/day".
519      * On input the month value is zero-based, but in the result string it is one-based.
520      */
521     static public String ymdToString(int year, int month, int isLeapMonth, int day) {
522         return "" + year + "/" + (month+1) +
523             ((isLeapMonth!=0)?"(leap)":"") +
524             "/" + day;
525     }
526
527 //    public void TestFindLeapMonths() {
528 //        ChineseCalendar cal = new ChineseCalendar();
529 //        cal.setTime(new Date(2000-1900, Calendar.JANUARY, 1));
530 //        long end = new Date(2100-1900, Calendar.JANUARY, 1).getTime();
531 //        ChineseDateFormat fmt = (ChineseDateFormat) DateFormat.getInstance(cal);
532 //        fmt.applyPattern("u-MMl-dd, 'Year' y, 'Cycle' G");
533 //        while (cal.getTimeInMillis() < end) {
534 //            if (cal.get(ChineseCalendar.IS_LEAP_MONTH) != 0) {
535 //                cal.set(Calendar.DAY_OF_MONTH, 1);
536 //                logln(cal.getTime() + " = " + fmt.format(cal.getTime()));
537 //                cal.set(Calendar.DAY_OF_MONTH, 29);
538 //            }
539 //            cal.add(Calendar.DAY_OF_YEAR, 25);
540 //        }
541 //    }
542
543     public void TestCoverage() {
544         // Coverage for constructors
545         {
546             // new ChineseCalendar(Date)
547             ChineseCalendar cal = new ChineseCalendar(new Date());
548             if(cal == null){
549                 errln("could not create ChineseCalendar with Date");
550             }
551         }
552
553         {
554             // new ChineseCalendar(int year, int month, int isLeapMonth, int date)
555             ChineseCalendar cal = new ChineseCalendar(23, Calendar.JULY, 1, 2);
556             if(cal == null){
557                 errln("could not create ChineseCalendar with year,month,isLeapMonth,date");
558             }
559             // Make sure the given values are properly set
560             if (cal.get(Calendar.YEAR) != 23 || cal.get(Calendar.MONTH) != Calendar.JULY
561                     || cal.get(Calendar.IS_LEAP_MONTH) != 1 || cal.get(Calendar.DATE) != 2
562                     || cal.get(Calendar.MILLISECONDS_IN_DAY) != 0) {
563                 errln("ChineseCalendar was initialized incorrectly with year,month,isLeapMonth,date");
564             }
565         }
566
567         {
568             // new ChineseCalendar(int year, int month, int isLeapMonth, int date, int hour, int minute, int second)
569             ChineseCalendar cal = new ChineseCalendar(23, Calendar.JULY, 1, 2, 12, 34, 56);
570             if(cal == null){
571                 errln("could not create ChineseCalendar with year,month,isLeapMonth,date,hour,minute,second");
572             }
573             // Make sure the given values are properly set
574             if (cal.get(Calendar.YEAR) != 23 || cal.get(Calendar.MONTH) != Calendar.JULY
575                     || cal.get(Calendar.IS_LEAP_MONTH) != 1 || cal.get(Calendar.DATE) != 2
576                     || cal.get(Calendar.HOUR_OF_DAY) != 12 || cal.get(Calendar.MINUTE) != 34
577                     || cal.get(Calendar.SECOND) != 56 || cal.get(Calendar.MILLISECOND) != 0) {
578                 errln("ChineseCalendar was initialized incorrectly with year,month,isLeapMonth,date,hour,minute,second");
579             }
580         }
581
582         {
583             // new ChineseCalendar(Locale)
584             ChineseCalendar cal = new ChineseCalendar(Locale.getDefault());
585             if(cal == null){
586                 errln("could not create ChineseCalendar with Locale");
587             }
588         }
589
590         {
591             // new ChineseCalendar(ULocale)
592             ChineseCalendar cal = new ChineseCalendar(ULocale.getDefault());
593             if(cal == null){
594                 errln("could not create ChineseCalendar with ULocale");
595             }
596         }
597         
598
599         {
600             // new ChineseCalendar(TimeZone)
601             ChineseCalendar cal = new ChineseCalendar(TimeZone.getDefault()); 
602             if(cal == null){
603                 errln("could not create ChineseCalendar with TimeZone");
604             }
605         }
606
607         {
608             // new ChineseCalendar(TimeZone, Locale)
609             ChineseCalendar cal = new ChineseCalendar(TimeZone.getDefault(), Locale.getDefault());
610             if(cal == null){
611                 errln("could not create ChineseCalendar with TimeZone,Locale");
612             }
613         }
614
615         {
616             // new ChineseCalendar(TimeZone, ULocale)
617             ChineseCalendar cal = new ChineseCalendar(TimeZone.getDefault(), ULocale.getDefault());
618             if(cal == null){
619                 errln("could not create ChineseCalendar with TimeZone,ULocale");
620             }
621         }
622
623         // Note: ICU 50 or later versions, DateFormat.getInstance(ChineseCalendar) no longer
624         // returns an instance of ChineseDateFormat. Chinese calendar formatting support was
625         // changed and integrated into SimpleDateFormat since ICU 49. Also, ChineseDateFormat
626         // specific pattern letter "l" is no longer used by the new implementation.
627
628 //        ChineseCalendar cal = new ChineseCalendar();
629 //        DateFormat format = DateFormat.getInstance(cal);
630 //        if(!(format instanceof ChineseDateFormat)){
631 //            errln("DateFormat.getInstance("+cal+") did not return a ChineseDateFormat");
632 //        }
633 //        ChineseDateFormat fmt = (ChineseDateFormat)format;
634 //        fmt.applyPattern("llyyll");
635 //        Date time = getDate(2100, Calendar.JANUARY, 1);
636 //        String str = fmt.format(time);
637 //        try {
638 //            Date e = fmt.parse(str);
639 //            logln("chinese calendar time: " + time + " result: " + str + " --> " + e);
640 //        } catch (java.text.ParseException ex) {
641 //            logln(ex.getMessage()); // chinese calendar can't parse this, no error for now
642 //        }
643
644         //new ChineseCalendar(TimeZone,ULocale)
645         ChineseCalendar ccal2 = new ChineseCalendar(TimeZone.getDefault(),
646                                                    ULocale.CHINA);
647         if(ccal2==null){
648             errln("could not create ChineseCalendar with TimeZone ULocale");
649         } else {
650             DateFormat fmt2 = DateFormat.getDateInstance(ccal2, DateFormat.DEFAULT, ULocale.CHINA);
651             Date time2 = getDate(2001, Calendar.MAY, 23);
652             String str2 = fmt2.format(time2);
653             logln("Chinese calendar time: " + time2 + " result: " + str2);
654         }
655     }
656     public void TestScratch(){
657         String[] strMonths = {"Januari", "Pebruari", "Maret", "April", "Mei", "Juni",
658                 "Juli", "Agustus", "September", "Oktober", "Nopember", "Desember"};
659         String[] strShortMonths = {"Jan", "Peb", "Mar", "Apr", "Mei", "Jun",
660                      "Jul", "Agt", "Sep", "Okt", "Nop", "Des"};
661         String[] strWeeks = {"", "Minggu", "Senin", "Selasa", "Rabu", "Kamis", "Jumat", "Sabtu"};
662         DateFormatSymbols dfsDate = new DateFormatSymbols(new Locale("id", "ID"));
663         dfsDate.setMonths(strMonths);
664         dfsDate.setShortMonths(strShortMonths);
665         dfsDate.setWeekdays(strWeeks);
666         ULocale uloInd = dfsDate.getLocale(ULocale.ACTUAL_LOCALE);
667         if(uloInd==null){
668             errln("did not get the expected ULocale");
669         }
670         logln(uloInd.toString());
671         Locale locInd = uloInd.toLocale();
672         if(locInd==null){
673             errln("did not get the expected result");
674         }
675         logln(locInd.toString());
676     }
677
678     public void TestInitWithCurrentTime() {
679         // jb4555
680         // if the chinese calendar current millis isn't called, the default year is wrong.
681         // this test is assuming the 'year' is the current cycle
682         // so when we cross a cycle boundary, the target will need to change
683         // that shouldn't be for awhile yet... 
684
685         ChineseCalendar cc = new ChineseCalendar();
686         cc.set(Calendar.YEAR, 22);
687         cc.set(Calendar.MONTH, 0);
688          // need to set leap month flag off, otherwise, the test case always fails when
689          // current time is in a leap month
690         cc.set(Calendar.IS_LEAP_MONTH, 0);
691         cc.set(Calendar.DATE, 19);
692         cc.set(Calendar.HOUR_OF_DAY, 0);
693         cc.set(Calendar.MINUTE, 0);
694         cc.set(Calendar.SECOND, 0);
695         cc.set(Calendar.MILLISECOND, 0);
696
697         cc.add(Calendar.DATE, 1);
698  
699         Calendar cal = new GregorianCalendar(2005, Calendar.FEBRUARY, 28);
700         Date target = cal.getTime();
701         Date result = cc.getTime();
702
703         assertEquals("chinese and gregorian date should match", target, result);
704     }
705
706     public void Test6510() 
707     { 
708         Calendar gregorianCalendar; 
709         ChineseCalendar chineseCalendar, chineseCalendar2; 
710         ChineseDateFormat dateFormat; 
711         SimpleDateFormat simpleDateFormat; 
712  
713         simpleDateFormat = new com.ibm.icu.text.SimpleDateFormat("MM/dd/yyyy G 'at' HH:mm:ss vvvv", Locale.US); 
714         dateFormat = new com.ibm.icu.text.ChineseDateFormat("MM/dd/yyyy(G) HH:mm:ss", Locale.CHINA); 
715  
716         // lunar to gregorian 
717         chineseCalendar = new ChineseCalendar(77, 26, Calendar.JANUARY, 0, 6, 0, 0, 0); 
718         gregorianCalendar = Calendar.getInstance(Locale.US); 
719         gregorianCalendar.setTime(chineseCalendar.getTime()); 
720  
721         // gregorian to lunar 
722         chineseCalendar2 = new ChineseCalendar(); 
723         chineseCalendar2.setTimeInMillis(gregorianCalendar.getTimeInMillis()); 
724
725         // validate roundtrip 
726         if (chineseCalendar.getTimeInMillis() != chineseCalendar2.getTimeInMillis()) 
727         { 
728             errln("time1: " + chineseCalendar.getTimeInMillis()); 
729             errln("time2: " + chineseCalendar2.getTimeInMillis()); 
730             errln("Lunar [MM/dd/y(G) HH:mm:ss] " + dateFormat.format(chineseCalendar)); 
731             errln("**PROBLEM Grego [MM/dd/y(G) HH:mm:ss] " + simpleDateFormat.format(gregorianCalendar)); 
732             errln("Grego [MM/dd/y(G) HH:mm:ss] " + simpleDateFormat.format(gregorianCalendar)); 
733             errln("Lunar [MM/dd/y(G) HH:mm:ss] " + dateFormat.format(chineseCalendar2)); 
734         } 
735     }         
736 }