]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_2_1-src/src/com/ibm/icu/dev/test/calendar/IBMCalendarTest.java
icu4jsrc
[Dictionary.git] / jars / icu4j-4_2_1-src / src / com / ibm / icu / dev / test / calendar / IBMCalendarTest.java
1 /*\r
2  *******************************************************************************\r
3  * Copyright (C) 2000-2009, International Business Machines Corporation and\r
4  * others. All Rights Reserved.\r
5  *******************************************************************************\r
6  */\r
7 package com.ibm.icu.dev.test.calendar;\r
8 \r
9 import java.util.Date;\r
10 import java.util.Locale;\r
11 import java.text.ParseException;\r
12 \r
13 import com.ibm.icu.impl.LocaleUtility;\r
14 import com.ibm.icu.impl.ZoneMeta;\r
15 import com.ibm.icu.impl.CalendarAstronomer;\r
16 import com.ibm.icu.text.DateFormat;\r
17 import com.ibm.icu.text.SimpleDateFormat;\r
18 import com.ibm.icu.util.*;\r
19 \r
20 /**\r
21  * @summary Tests of new functionality in IBMCalendar\r
22  */\r
23 public class IBMCalendarTest extends CalendarTest {\r
24 \r
25     public static void main(String[] args) throws Exception {\r
26         new IBMCalendarTest().run(args);\r
27     }\r
28 \r
29     /**\r
30      * Test weekend support in IBMCalendar.\r
31      *\r
32      * NOTE: This test will have to be updated when the isWeekend() etc.\r
33      *       API is finalized later.\r
34      *\r
35      *       In particular, the test will have to be rewritten to instantiate\r
36      *       a Calendar in the given locale (using getInstance()) and call\r
37      *       that Calendar's isWeekend() etc. methods.\r
38      */\r
39     public void TestWeekend() {\r
40         SimpleDateFormat fmt = new SimpleDateFormat("EEE MMM dd yyyy G HH:mm:ss.SSS");\r
41 \r
42         // NOTE\r
43         // This test tests for specific locale data.  This is probably okay\r
44         // as far as US data is concerned, but if the Arabic/Yemen data\r
45         // changes, this test will have to be updated.\r
46 \r
47         // Test specific days\r
48         Object[] DATA1 = {\r
49             Locale.US, new int[] { // Saturday:Sunday\r
50                 2000, Calendar.MARCH, 17, 23,  0, 0, // Fri 23:00\r
51                 2000, Calendar.MARCH, 18,  0, -1, 0, // Fri 23:59:59.999\r
52                 2000, Calendar.MARCH, 18,  0,  0, 1, // Sat 00:00\r
53                 2000, Calendar.MARCH, 18, 15,  0, 1, // Sat 15:00\r
54                 2000, Calendar.MARCH, 19, 23,  0, 1, // Sun 23:00\r
55                 2000, Calendar.MARCH, 20,  0, -1, 1, // Sun 23:59:59.999\r
56                 2000, Calendar.MARCH, 20,  0,  0, 0, // Mon 00:00\r
57                 2000, Calendar.MARCH, 20,  8,  0, 0, // Mon 08:00\r
58             },\r
59             new Locale("ar", "YE"), new int[] { // Thursday:Friday\r
60                 2000, Calendar.MARCH, 15, 23,  0, 0, // Wed 23:00\r
61                 2000, Calendar.MARCH, 16,  0, -1, 0, // Wed 23:59:59.999\r
62                 2000, Calendar.MARCH, 16,  0,  0, 1, // Thu 00:00\r
63                 2000, Calendar.MARCH, 16, 15,  0, 1, // Thu 15:00\r
64                 2000, Calendar.MARCH, 17, 23,  0, 1, // Fri 23:00\r
65                 2000, Calendar.MARCH, 18,  0, -1, 1, // Fri 23:59:59.999\r
66                 2000, Calendar.MARCH, 18,  0,  0, 0, // Sat 00:00\r
67                 2000, Calendar.MARCH, 18,  8,  0, 0, // Sat 08:00\r
68             },\r
69         };\r
70 \r
71         // Test days of the week\r
72         Object[] DATA2 = {\r
73             Locale.US, new int[] {\r
74                 Calendar.MONDAY,   Calendar.WEEKDAY,\r
75                 Calendar.FRIDAY,   Calendar.WEEKDAY,\r
76                 Calendar.SATURDAY, Calendar.WEEKEND,\r
77                 Calendar.SUNDAY,   Calendar.WEEKEND_CEASE,\r
78             },\r
79             new Locale("ar", "YE"), new int[] { // Thursday:Friday\r
80                 Calendar.WEDNESDAY,Calendar.WEEKDAY,\r
81                 Calendar.SATURDAY, Calendar.WEEKDAY,\r
82                 Calendar.THURSDAY, Calendar.WEEKEND,\r
83                 Calendar.FRIDAY,   Calendar.WEEKEND_CEASE,\r
84             },\r
85         };\r
86 \r
87         // We only test the getDayOfWeekType() and isWeekend() APIs.\r
88         // The getWeekendTransition() API is tested indirectly via the\r
89         // isWeekend() API, which calls it.\r
90 \r
91         for (int i1=0; i1<DATA1.length; i1+=2) {\r
92             Locale loc = (Locale)DATA1[i1];\r
93             int[] data = (int[]) DATA1[i1+1];\r
94             Calendar cal = Calendar.getInstance(loc);\r
95             logln("Locale: " + loc);\r
96             for (int i=0; i<data.length; i+=6) {\r
97                 cal.clear();\r
98                 cal.set(data[i], data[i+1], data[i+2], data[i+3], 0, 0);\r
99                 if (data[i+4] != 0) {\r
100                     cal.setTime(new Date(cal.getTime().getTime() + data[i+4]));\r
101                 }\r
102                 boolean isWeekend = cal.isWeekend();\r
103                 boolean ok = isWeekend == (data[i+5] != 0);\r
104                 if (ok) {\r
105                     logln("Ok:   " + fmt.format(cal.getTime()) + " isWeekend=" + isWeekend);\r
106                 } else {\r
107                     errln("FAIL: " + fmt.format(cal.getTime()) + " isWeekend=" + isWeekend +\r
108                           ", expected=" + (!isWeekend));\r
109                 }\r
110             }\r
111         }\r
112 \r
113         for (int i2=0; i2<DATA2.length; i2+=2) {\r
114             Locale loc = (Locale)DATA2[i2];\r
115             int[] data = (int[]) DATA2[i2+1];\r
116             logln("Locale: " + loc);\r
117             Calendar cal = Calendar.getInstance(loc);\r
118             for (int i=0; i<data.length; i+=2) {\r
119                 int type = cal.getDayOfWeekType(data[i]);\r
120                 int exp  = data[i+1];\r
121                 if (type == exp) {\r
122                     logln("Ok:   DOW " + data[i] + " type=" + type);\r
123                 } else {\r
124                     errln("FAIL: DOW " + data[i] + " type=" + type +\r
125                           ", expected=" + exp);\r
126                 }\r
127             }\r
128         }\r
129     }\r
130 \r
131     /**\r
132      * Run a test of a quasi-Gregorian calendar.  This is a calendar\r
133      * that behaves like a Gregorian but has different year/era mappings.\r
134      * The int[] data array should have the format:\r
135      *\r
136      * { era, year, gregorianYear, month, dayOfMonth, ... }\r
137      */\r
138     void quasiGregorianTest(Calendar cal, int[] data) {\r
139         // As of JDK 1.4.1_01, using the Sun JDK GregorianCalendar as\r
140         // a reference throws us off by one hour.  This is most likely\r
141         // due to the JDK 1.4 incorporation of historical time zones.\r
142         //java.util.Calendar grego = java.util.Calendar.getInstance();\r
143         Calendar grego = Calendar.getInstance();\r
144         for (int i=0; i<data.length; ) {\r
145             int era = data[i++];\r
146             int year = data[i++];\r
147             int gregorianYear = data[i++];\r
148             int month = data[i++];\r
149             int dayOfMonth = data[i++];\r
150 \r
151             grego.clear();\r
152             grego.set(gregorianYear, month, dayOfMonth);\r
153             Date D = grego.getTime();\r
154 \r
155             cal.clear();\r
156             cal.set(Calendar.ERA, era);\r
157             cal.set(year, month, dayOfMonth);\r
158             Date d = cal.getTime();\r
159             if (d.equals(D)) {\r
160                 logln("OK: " + era + ":" + year + "/" + (month+1) + "/" + dayOfMonth +\r
161                       " => " + d);\r
162             } else {\r
163                 errln("Fail: " + era + ":" + year + "/" + (month+1) + "/" + dayOfMonth +\r
164                       " => " + d + ", expected " + D);\r
165             }\r
166 \r
167             cal.clear();\r
168             cal.setTime(D);\r
169             int e = cal.get(Calendar.ERA);\r
170             int y = cal.get(Calendar.YEAR);\r
171             if (y == year && e == era) {\r
172                 logln("OK: " + D + " => " + cal.get(Calendar.ERA) + ":" +\r
173                       cal.get(Calendar.YEAR) + "/" +\r
174                       (cal.get(Calendar.MONTH)+1) + "/" + cal.get(Calendar.DATE));\r
175             } else {\r
176                 logln("Fail: " + D + " => " + cal.get(Calendar.ERA) + ":" +\r
177                       cal.get(Calendar.YEAR) + "/" +\r
178                       (cal.get(Calendar.MONTH)+1) + "/" + cal.get(Calendar.DATE) +\r
179                       ", expected " + era + ":" + year + "/" + (month+1) + "/" +\r
180                       dayOfMonth);\r
181             }\r
182         }\r
183     }\r
184 \r
185     /**\r
186      * Verify that BuddhistCalendar shifts years to Buddhist Era but otherwise\r
187      * behaves like GregorianCalendar.\r
188      */\r
189     public void TestBuddhist() {\r
190         quasiGregorianTest(new BuddhistCalendar(),\r
191                            new int[] {\r
192                                // BE 2542 == 1999 CE\r
193                                0, 2542, 1999, Calendar.JUNE, 4\r
194                            });\r
195     }\r
196 \r
197     public void TestBuddhistCoverage() {\r
198     {\r
199         // new BuddhistCalendar(ULocale)\r
200         BuddhistCalendar cal = new BuddhistCalendar(ULocale.getDefault());\r
201         if(cal == null){\r
202             errln("could not create BuddhistCalendar with ULocale");\r
203         }\r
204     }\r
205 \r
206     {\r
207         // new BuddhistCalendar(TimeZone,ULocale)\r
208         BuddhistCalendar cal = new BuddhistCalendar(TimeZone.getDefault(),ULocale.getDefault());\r
209         if(cal == null){\r
210             errln("could not create BuddhistCalendar with TimeZone ULocale");\r
211         }\r
212     }\r
213 \r
214     {\r
215         // new BuddhistCalendar(TimeZone)\r
216         BuddhistCalendar cal = new BuddhistCalendar(TimeZone.getDefault());\r
217         if(cal == null){\r
218             errln("could not create BuddhistCalendar with TimeZone");\r
219         }\r
220     }\r
221 \r
222     {\r
223         // new BuddhistCalendar(Locale)\r
224         BuddhistCalendar cal = new BuddhistCalendar(Locale.getDefault());\r
225         if(cal == null){\r
226             errln("could not create BuddhistCalendar with Locale");\r
227         }\r
228     }\r
229 \r
230     {\r
231         // new BuddhistCalendar(TimeZone, Locale)\r
232         BuddhistCalendar cal = new BuddhistCalendar(TimeZone.getDefault(), Locale.getDefault());\r
233         if(cal == null){\r
234             errln("could not create BuddhistCalendar with TimeZone and Locale");\r
235         }\r
236     }\r
237 \r
238     {\r
239         // new BuddhistCalendar(Date)\r
240         BuddhistCalendar cal = new BuddhistCalendar(new Date());\r
241         if(cal == null){\r
242             errln("could not create BuddhistCalendar with Date");\r
243         }\r
244     }\r
245 \r
246     {\r
247         // new BuddhistCalendar(int year, int month, int date)\r
248         BuddhistCalendar cal = new BuddhistCalendar(2543, Calendar.MAY, 22);\r
249         if(cal == null){\r
250             errln("could not create BuddhistCalendar with year,month,data");\r
251         }\r
252     }\r
253 \r
254     {\r
255         // new BuddhistCalendar(int year, int month, int date, int hour, int minute, int second)\r
256         BuddhistCalendar cal = new BuddhistCalendar(2543, Calendar.MAY, 22, 1, 1, 1);\r
257         if(cal == null){\r
258             errln("could not create BuddhistCalendar with year,month,date,hour,minute,second");\r
259         }\r
260     }\r
261 \r
262     {\r
263         // data\r
264         BuddhistCalendar cal = new BuddhistCalendar(2543, Calendar.MAY, 22);\r
265         Date time = cal.getTime();\r
266 \r
267         String[] calendarLocales = {\r
268         "th_TH"\r
269         };\r
270 \r
271         String[] formatLocales = {\r
272         "en", "ar", "hu", "th"\r
273         };\r
274 \r
275         for (int i = 0; i < calendarLocales.length; ++i) {\r
276         String calLocName = calendarLocales[i];\r
277         Locale calLocale = LocaleUtility.getLocaleFromName(calLocName);\r
278         cal = new BuddhistCalendar(calLocale);\r
279 \r
280         for (int j = 0; j < formatLocales.length; ++j) {\r
281             String locName = formatLocales[j];\r
282             Locale formatLocale = LocaleUtility.getLocaleFromName(locName);\r
283             DateFormat format = DateFormat.getDateTimeInstance(cal, DateFormat.FULL, DateFormat.FULL, formatLocale);\r
284             logln(calLocName + "/" + locName + " --> " + format.format(time));\r
285         }\r
286         }\r
287     }\r
288     }\r
289 \r
290     /**\r
291      * Test limits of the Buddhist calendar.\r
292      */\r
293     public void TestBuddhistLimits() {\r
294         // Final parameter is either number of days, if > 0, or test\r
295         // duration in seconds, if < 0.\r
296         Calendar cal = Calendar.getInstance();\r
297         cal.set(2007, Calendar.JANUARY, 1);\r
298         BuddhistCalendar buddhist = new BuddhistCalendar();\r
299         doLimitsTest(buddhist, null, cal.getTime());\r
300         doTheoreticalLimitsTest(buddhist, false);\r
301     }\r
302 \r
303     /**\r
304      * Default calendar for Thai (Ticket#6302)\r
305      */\r
306     public void TestThaiDefault() {\r
307         // Buddhist calendar is used as the default calendar for\r
308         // Thai locale\r
309         Calendar cal = Calendar.getInstance(new ULocale("th_TH"));\r
310         String type = cal.getType();\r
311         if (!type.equals("buddhist")) {\r
312             errln("FAIL: Buddhist calendar is not returned for locale " + cal.toString());\r
313         }\r
314     }\r
315     \r
316     /**\r
317      * Verify that TaiwanCalendar shifts years to Minguo Era but otherwise\r
318      * behaves like GregorianCalendar.\r
319      */\r
320     public void TestTaiwan() {\r
321         quasiGregorianTest(new TaiwanCalendar(),\r
322                            new int[] {\r
323                                TaiwanCalendar.BEFORE_MINGUO, 8, 1904, Calendar.FEBRUARY, 29,\r
324                                TaiwanCalendar.MINGUO, 1, 1912, Calendar.JUNE, 4,\r
325                                TaiwanCalendar.MINGUO, 3, 1914, Calendar.FEBRUARY, 12,\r
326                                TaiwanCalendar.MINGUO, 96,2007, Calendar.FEBRUARY, 12,\r
327                            });\r
328     }\r
329 \r
330     /**\r
331      * Test limits of the Taiwan calendar.\r
332      */\r
333     public void TestTaiwanLimits() {\r
334         // Final parameter is either number of days, if > 0, or test\r
335         // duration in seconds, if < 0.\r
336         Calendar cal = Calendar.getInstance();\r
337         cal.set(2007, Calendar.JANUARY, 1);\r
338         TaiwanCalendar taiwan = new TaiwanCalendar();\r
339         doLimitsTest(taiwan, null, cal.getTime());\r
340         doTheoreticalLimitsTest(taiwan, false);\r
341     }\r
342 \r
343     public void TestTaiwanCoverage() {\r
344     {\r
345         // new TaiwanCalendar(ULocale)\r
346         TaiwanCalendar cal = new TaiwanCalendar(ULocale.getDefault());\r
347         if(cal == null){\r
348             errln("could not create TaiwanCalendar with ULocale");\r
349         }\r
350     }\r
351 \r
352     {\r
353         // new TaiwanCalendar(TimeZone,ULocale)\r
354         TaiwanCalendar cal = new TaiwanCalendar(TimeZone.getDefault(),ULocale.getDefault());\r
355         if(cal == null){\r
356             errln("could not create TaiwanCalendar with TimeZone ULocale");\r
357         }\r
358     }\r
359 \r
360     {\r
361         // new TaiwanCalendar(TimeZone)\r
362         TaiwanCalendar cal = new TaiwanCalendar(TimeZone.getDefault());\r
363         if(cal == null){\r
364             errln("could not create TaiwanCalendar with TimeZone");\r
365         }\r
366     }\r
367 \r
368     {\r
369         // new TaiwanCalendar(Locale)\r
370         TaiwanCalendar cal = new TaiwanCalendar(Locale.getDefault());\r
371         if(cal == null){\r
372             errln("could not create TaiwanCalendar with Locale");\r
373         }\r
374     }\r
375 \r
376     {\r
377         // new TaiwanCalendar(TimeZone, Locale)\r
378         TaiwanCalendar cal = new TaiwanCalendar(TimeZone.getDefault(), Locale.getDefault());\r
379         if(cal == null){\r
380             errln("could not create TaiwanCalendar with TimeZone and Locale");\r
381         }\r
382     }\r
383 \r
384     {\r
385         // new TaiwanCalendar(Date)\r
386         TaiwanCalendar cal = new TaiwanCalendar(new Date());\r
387         if(cal == null){\r
388             errln("could not create TaiwanCalendar with Date");\r
389         }\r
390     }\r
391 \r
392     {\r
393         // new TaiwanCalendar(int year, int month, int date)\r
394         TaiwanCalendar cal = new TaiwanCalendar(34, Calendar.MAY, 22);\r
395         if(cal == null){\r
396             errln("could not create TaiwanCalendar with year,month,data");\r
397         }\r
398     }\r
399 \r
400     {\r
401         // new TaiwanCalendar(int year, int month, int date, int hour, int minute, int second)\r
402         TaiwanCalendar cal = new TaiwanCalendar(34, Calendar.MAY, 22, 1, 1, 1);\r
403         if(cal == null){\r
404             errln("could not create TaiwanCalendar with year,month,date,hour,minute,second");\r
405         }\r
406     }\r
407 \r
408     {\r
409         // data\r
410         TaiwanCalendar cal = new TaiwanCalendar(34, Calendar.MAY, 22);\r
411         Date time = cal.getTime();\r
412 \r
413         String[] calendarLocales = {\r
414         "en","zh"\r
415         };\r
416 \r
417         String[] formatLocales = {\r
418         "en", "ar", "hu", "th"\r
419         };\r
420 \r
421         for (int i = 0; i < calendarLocales.length; ++i) {\r
422         String calLocName = calendarLocales[i];\r
423         Locale calLocale = LocaleUtility.getLocaleFromName(calLocName);\r
424         cal = new TaiwanCalendar(calLocale);\r
425 \r
426         for (int j = 0; j < formatLocales.length; ++j) {\r
427             String locName = formatLocales[j];\r
428             Locale formatLocale = LocaleUtility.getLocaleFromName(locName);\r
429             DateFormat format = DateFormat.getDateTimeInstance(cal, DateFormat.FULL, DateFormat.FULL, formatLocale);\r
430             logln(calLocName + "/" + locName + " --> " + format.format(time));\r
431         }\r
432         }\r
433     }\r
434     }\r
435 \r
436     /**\r
437      * Verify that JapaneseCalendar shifts years to Japanese Eras but otherwise\r
438      * behaves like GregorianCalendar.\r
439      */\r
440     public void TestJapanese() {\r
441         // First make sure this test works for GregorianCalendar\r
442         int[] control = {\r
443             GregorianCalendar.AD, 1868, 1868, Calendar.SEPTEMBER, 8,\r
444             GregorianCalendar.AD, 1868, 1868, Calendar.SEPTEMBER, 9,\r
445             GregorianCalendar.AD, 1869, 1869, Calendar.JUNE, 4,\r
446             GregorianCalendar.AD, 1912, 1912, Calendar.JULY, 29,\r
447             GregorianCalendar.AD, 1912, 1912, Calendar.JULY, 30,\r
448             GregorianCalendar.AD, 1912, 1912, Calendar.AUGUST, 1,\r
449         };\r
450         quasiGregorianTest(new GregorianCalendar(), control);\r
451 \r
452         int[] data = {\r
453             JapaneseCalendar.MEIJI, 1, 1868, Calendar.SEPTEMBER, 8,\r
454             JapaneseCalendar.MEIJI, 1, 1868, Calendar.SEPTEMBER, 9,\r
455             JapaneseCalendar.MEIJI, 2, 1869, Calendar.JUNE, 4,\r
456             JapaneseCalendar.MEIJI, 45, 1912, Calendar.JULY, 29,\r
457             JapaneseCalendar.TAISHO, 1, 1912, Calendar.JULY, 30,\r
458             JapaneseCalendar.TAISHO, 1, 1912, Calendar.AUGUST, 1,\r
459         };\r
460         quasiGregorianTest(new JapaneseCalendar(), data);\r
461     }\r
462 \r
463     /**\r
464      * Test limits of the Gregorian calendar.\r
465      */\r
466     public void TestGregorianLimits() {\r
467         // Final parameter is either number of days, if > 0, or test\r
468         // duration in seconds, if < 0.\r
469         Calendar cal = Calendar.getInstance();\r
470         cal.set(2004, Calendar.JANUARY, 1);\r
471         GregorianCalendar gregorian = new GregorianCalendar();\r
472         doLimitsTest(gregorian, null, cal.getTime());\r
473         doTheoreticalLimitsTest(gregorian, false);\r
474     }\r
475 \r
476     /**\r
477      * Test behavior of fieldDifference around leap years.  Also test a large\r
478      * field difference to check binary search.\r
479      */\r
480     public void TestLeapFieldDifference() {\r
481         Calendar cal = Calendar.getInstance();\r
482         cal.set(2004, Calendar.FEBRUARY, 29);\r
483         Date date2004 = cal.getTime();\r
484         cal.set(2000, Calendar.FEBRUARY, 29);\r
485         Date date2000 = cal.getTime();\r
486         int y = cal.fieldDifference(date2004, Calendar.YEAR);\r
487         int d = cal.fieldDifference(date2004, Calendar.DAY_OF_YEAR);\r
488         if (d == 0) {\r
489             logln("Ok: 2004/Feb/29 - 2000/Feb/29 = " + y + " years, " + d + " days");\r
490         } else {\r
491             errln("FAIL: 2004/Feb/29 - 2000/Feb/29 = " + y + " years, " + d + " days");\r
492         }\r
493         cal.setTime(date2004);\r
494         y = cal.fieldDifference(date2000, Calendar.YEAR);\r
495         d = cal.fieldDifference(date2000, Calendar.DAY_OF_YEAR);\r
496         if (d == 0) {\r
497             logln("Ok: 2000/Feb/29 - 2004/Feb/29 = " + y + " years, " + d + " days");\r
498         } else {\r
499             errln("FAIL: 2000/Feb/29 - 2004/Feb/29 = " + y + " years, " + d + " days");\r
500         }\r
501         // Test large difference\r
502         cal.set(2001, Calendar.APRIL, 5); // 2452005\r
503         Date ayl = cal.getTime();\r
504         cal.set(1964, Calendar.SEPTEMBER, 7); // 2438646\r
505         Date asl = cal.getTime();\r
506         d = cal.fieldDifference(ayl, Calendar.DAY_OF_MONTH);\r
507         cal.setTime(ayl);\r
508         int d2 = cal.fieldDifference(asl, Calendar.DAY_OF_MONTH);\r
509         if (d == -d2 && d == 13359) {\r
510             logln("Ok: large field difference symmetrical " + d);\r
511         } else {\r
512             logln("FAIL: large field difference incorrect " + d + ", " + d2 +\r
513                   ", expect +/- 13359");\r
514         }\r
515     }\r
516 \r
517     /**\r
518      * Test ms_MY "Malay (Malaysia)" locale.  Bug 1543.\r
519      */\r
520     public void TestMalaysianInstance() {\r
521         Locale loc = new Locale("ms", "MY");  // Malay (Malaysia)\r
522         Calendar cal = Calendar.getInstance(loc);\r
523         if(cal == null){\r
524             errln("could not create Malaysian instance");\r
525         }\r
526     }\r
527 \r
528     /**\r
529      * setFirstDayOfWeek and setMinimalDaysInFirstWeek may change the\r
530      * field <=> time mapping, since they affect the interpretation of\r
531      * the WEEK_OF_MONTH or WEEK_OF_YEAR fields.\r
532      */\r
533     public void TestWeekShift() {\r
534         Calendar cal = new GregorianCalendar(\r
535                              TimeZone.getTimeZone("America/Los_Angeles"),\r
536                              new Locale("en", "US"));\r
537         cal.setTime(new Date(997257600000L)); // Wed Aug 08 01:00:00 PDT 2001\r
538         // In pass one, change the first day of week so that the weeks\r
539         // shift in August 2001.  In pass two, change the minimal days\r
540         // in the first week so that the weeks shift in August 2001.\r
541         //     August 2001\r
542         // Su Mo Tu We Th Fr Sa\r
543         //           1  2  3  4\r
544         //  5  6  7  8  9 10 11\r
545         // 12 13 14 15 16 17 18\r
546         // 19 20 21 22 23 24 25\r
547         // 26 27 28 29 30 31\r
548         for (int pass=0; pass<2; ++pass) {\r
549             if (pass==0) {\r
550                 cal.setFirstDayOfWeek(Calendar.WEDNESDAY);\r
551                 cal.setMinimalDaysInFirstWeek(4);\r
552             } else {\r
553                 cal.setFirstDayOfWeek(Calendar.SUNDAY);\r
554                 cal.setMinimalDaysInFirstWeek(4);\r
555             }\r
556             cal.add(Calendar.DATE, 1); // Force recalc\r
557             cal.add(Calendar.DATE, -1);\r
558 \r
559             Date time1 = cal.getTime(); // Get time -- should not change\r
560 \r
561             // Now change a week parameter and then force a recalc.\r
562             // The bug is that the recalc should not be necessary --\r
563             // calendar should do so automatically.\r
564             if (pass==0) {\r
565                 cal.setFirstDayOfWeek(Calendar.THURSDAY);\r
566             } else {\r
567                 cal.setMinimalDaysInFirstWeek(5);\r
568             }\r
569 \r
570             int woy1 = cal.get(Calendar.WEEK_OF_YEAR);\r
571             int wom1 = cal.get(Calendar.WEEK_OF_MONTH);\r
572 \r
573             cal.add(Calendar.DATE, 1); // Force recalc\r
574             cal.add(Calendar.DATE, -1);\r
575 \r
576             int woy2 = cal.get(Calendar.WEEK_OF_YEAR);\r
577             int wom2 = cal.get(Calendar.WEEK_OF_MONTH);\r
578 \r
579             Date time2 = cal.getTime();\r
580 \r
581             if (!time1.equals(time2)) {\r
582                 errln("FAIL: shifting week should not alter time");\r
583             } else {\r
584                 logln(time1.toString());\r
585             }\r
586             if (woy1 == woy2 && wom1 == wom2) {\r
587                 logln("Ok: WEEK_OF_YEAR: " + woy1 +\r
588                       ", WEEK_OF_MONTH: " + wom1);\r
589             } else {\r
590                 errln("FAIL: WEEK_OF_YEAR: " + woy1 + " => " + woy2 +\r
591                       ", WEEK_OF_MONTH: " + wom1 + " => " + wom2 +\r
592                       " after week shift");\r
593             }\r
594         }\r
595     }\r
596 \r
597     /**\r
598      * Make sure that when adding a day, we actually wind up in a\r
599      * different day.  The DST adjustments we use to keep the hour\r
600      * constant across DST changes can backfire and change the day.\r
601      */\r
602     public void TestTimeZoneTransitionAdd() {\r
603         Locale locale = Locale.US; // could also be CHINA\r
604         SimpleDateFormat dateFormat =\r
605             new SimpleDateFormat("MM/dd/yyyy HH:mm z", locale);\r
606 \r
607         String tz[] = TimeZone.getAvailableIDs();\r
608 \r
609         for (int z=0; z<tz.length; ++z) {\r
610             TimeZone t = TimeZone.getTimeZone(tz[z]);\r
611             dateFormat.setTimeZone(t);\r
612 \r
613             Calendar cal = Calendar.getInstance(t, locale);\r
614             cal.clear();\r
615             // Scan the year 2003, overlapping the edges of the year\r
616             cal.set(Calendar.YEAR, 2002);\r
617             cal.set(Calendar.MONTH, Calendar.DECEMBER);\r
618             cal.set(Calendar.DAY_OF_MONTH, 25);\r
619 \r
620             for (int i=0; i<365+10; ++i) {\r
621                 Date yesterday = cal.getTime();\r
622                 int yesterday_day = cal.get(Calendar.DAY_OF_MONTH);\r
623                 cal.add(Calendar.DAY_OF_MONTH, 1);\r
624                 if (yesterday_day == cal.get(Calendar.DAY_OF_MONTH)) {\r
625                     errln(tz[z] + " " +\r
626                           dateFormat.format(yesterday) + " +1d= " +\r
627                           dateFormat.format(cal.getTime()));\r
628                 }\r
629             }\r
630         }\r
631     }\r
632 \r
633     public void TestJB1684() {\r
634         class TestData {\r
635             int year;\r
636             int month;\r
637             int date;\r
638             int womyear;\r
639             int wommon;\r
640             int wom;\r
641             int dow;\r
642             String data;\r
643             String normalized;\r
644 \r
645             public TestData(int year, int month, int date,\r
646                             int womyear, int wommon, int wom, int dow,\r
647                             String data, String normalized) {\r
648                 this.year = year;\r
649                 this.month = month-1;\r
650                 this.date = date;\r
651                 this.womyear = womyear;\r
652                 this.wommon = wommon-1;\r
653                 this.wom = wom;\r
654                 this.dow = dow;\r
655                 this.data = data; // year, month, week of month, day\r
656                 this.normalized = data;\r
657                 if (normalized != null) this.normalized = normalized;\r
658             }\r
659         }\r
660 \r
661         //      July 2001            August 2001           January 2002\r
662         // Su Mo Tu We Th Fr Sa  Su Mo Tu We Th Fr Sa  Su Mo Tu We Th Fr Sa\r
663         //  1  2  3  4  5  6  7            1  2  3  4         1  2  3  4  5\r
664         //  8  9 10 11 12 13 14   5  6  7  8  9 10 11   6  7  8  9 10 11 12\r
665         // 15 16 17 18 19 20 21  12 13 14 15 16 17 18  13 14 15 16 17 18 19\r
666         // 22 23 24 25 26 27 28  19 20 21 22 23 24 25  20 21 22 23 24 25 26\r
667         // 29 30 31              26 27 28 29 30 31     27 28 29 30 31\r
668         TestData[] tests = {\r
669             new TestData(2001, 8,  6,  2001,8,2,Calendar.MONDAY,    "2001 08 02 Mon", null),\r
670             new TestData(2001, 8,  7,  2001,8,2,Calendar.TUESDAY,   "2001 08 02 Tue", null),\r
671             new TestData(2001, 8,  5,/*12,*/ 2001,8,2,Calendar.SUNDAY,    "2001 08 02 Sun", null),\r
672             new TestData(2001, 8,6, /*7,  30,*/ 2001,7,6,Calendar.MONDAY,    "2001 07 06 Mon", "2001 08 02 Mon"),\r
673             new TestData(2001, 8,7, /*7,  31,*/ 2001,7,6,Calendar.TUESDAY,   "2001 07 06 Tue", "2001 08 02 Tue"),\r
674             new TestData(2001, 8,  5,  2001,7,6,Calendar.SUNDAY,    "2001 07 06 Sun", "2001 08 02 Sun"),\r
675             new TestData(2001, 7,  30, 2001,8,1,Calendar.MONDAY,    "2001 08 01 Mon", "2001 07 05 Mon"),\r
676             new TestData(2001, 7,  31, 2001,8,1,Calendar.TUESDAY,   "2001 08 01 Tue", "2001 07 05 Tue"),\r
677             new TestData(2001, 7,29, /*8,  5,*/  2001,8,1,Calendar.SUNDAY,    "2001 08 01 Sun", "2001 07 05 Sun"),\r
678             new TestData(2001, 12, 31, 2001,12,6,Calendar.MONDAY,   "2001 12 06 Mon", null),\r
679             new TestData(2002, 1,  1,  2002,1,1,Calendar.TUESDAY,   "2002 01 01 Tue", null),\r
680             new TestData(2002, 1,  2,  2002,1,1,Calendar.WEDNESDAY, "2002 01 01 Wed", null),\r
681             new TestData(2002, 1,  3,  2002,1,1,Calendar.THURSDAY,  "2002 01 01 Thu", null),\r
682             new TestData(2002, 1,  4,  2002,1,1,Calendar.FRIDAY,    "2002 01 01 Fri", null),\r
683             new TestData(2002, 1,  5,  2002,1,1,Calendar.SATURDAY,  "2002 01 01 Sat", null),\r
684             new TestData(2001,12,30, /*2002, 1,  6,*/  2002,1,1,Calendar.SUNDAY,    "2002 01 01 Sun", "2001 12 06 Sun"),\r
685         };\r
686 \r
687         int pass = 0, error = 0, warning = 0;\r
688 \r
689         final String pattern = "yyyy MM WW EEE";\r
690         GregorianCalendar cal = new GregorianCalendar();\r
691         SimpleDateFormat sdf = new SimpleDateFormat(pattern);\r
692         sdf.setCalendar(cal);\r
693 \r
694         cal.setFirstDayOfWeek(Calendar.SUNDAY);\r
695         cal.setMinimalDaysInFirstWeek(1);\r
696 \r
697         for (int i = 0; i < tests.length; ++i) {\r
698             TestData test = tests[i];\r
699             log("\n-----\nTesting round trip of " + test.year +\r
700                   " " + (test.month + 1) +\r
701                   " " + test.date +\r
702                   " (written as) " + test.data);\r
703 \r
704             cal.clear();\r
705             cal.set(test.year, test.month, test.date);\r
706             Date ms = cal.getTime();\r
707 \r
708             cal.clear();\r
709             cal.set(Calendar.YEAR, test.womyear);\r
710             cal.set(Calendar.MONTH, test.wommon);\r
711             cal.set(Calendar.WEEK_OF_MONTH, test.wom);\r
712             cal.set(Calendar.DAY_OF_WEEK, test.dow);\r
713             Date ms2 = cal.getTime();\r
714 \r
715             if (!ms2.equals(ms)) {\r
716                 log("\nError: GregorianCalendar.DOM gave " + ms +\r
717                     "\n       GregorianCalendar.WOM gave " + ms2);\r
718                 error++;\r
719             } else {\r
720                 pass++;\r
721             }\r
722 \r
723             ms2 = null;\r
724             try {\r
725                 ms2 = sdf.parse(test.data);\r
726             }\r
727             catch (ParseException e) {\r
728                 errln("parse exception: " + e);\r
729             }\r
730 \r
731             if (!ms2.equals(ms)) {\r
732                 log("\nError: GregorianCalendar gave      " + ms +\r
733                     "\n       SimpleDateFormat.parse gave " + ms2);\r
734                 error++;\r
735             } else {\r
736                 pass++;\r
737             }\r
738 \r
739             String result = sdf.format(ms);\r
740             if (!result.equals(test.normalized)) {\r
741                 log("\nWarning: format of '" + test.data + "' gave" +\r
742                     "\n                   '" + result + "'" +\r
743                     "\n          expected '" + test.normalized + "'");\r
744                 warning++;\r
745             } else {\r
746                 pass++;\r
747             }\r
748 \r
749             Date ms3 = null;\r
750             try {\r
751                 ms3 = sdf.parse(result);\r
752             }\r
753             catch (ParseException e) {\r
754                 errln("parse exception 2: " + e);\r
755             }\r
756 \r
757             if (!ms3.equals(ms)) {\r
758                 error++;\r
759                 log("\nError: Re-parse of '" + result + "' gave time of " +\r
760                     "\n        " + ms3 +\r
761                     "\n    not " + ms);\r
762             } else {\r
763                 pass++;\r
764             }\r
765         }\r
766         String info = "\nPassed: " + pass + ", Warnings: " + warning + ", Errors: " + error;\r
767         if (error > 0) {\r
768             errln(info);\r
769         } else {\r
770             logln(info);\r
771         }\r
772     }\r
773 \r
774     /**\r
775      * Test the ZoneMeta API.\r
776      */\r
777     public void TestZoneMeta() {\r
778         // Test index by country API\r
779 \r
780         // Format: {country, zone1, zone2, ..., zoneN}\r
781         String COUNTRY[][] = { {""},\r
782                                {"US", "America/Los_Angeles", "PST"} };\r
783         StringBuffer buf = new StringBuffer();\r
784         for (int i=0; i<COUNTRY.length; ++i) {\r
785             String[] a = ZoneMeta.getAvailableIDs(COUNTRY[i][0]);\r
786             buf.setLength(0);\r
787             buf.append("Country \"" + COUNTRY[i][0] + "\": [");\r
788             // Use bitmask to track which of the expected zones we see\r
789             int mask = 0;\r
790             for (int j=0; j<a.length; ++j) {\r
791                 if (j!=0) buf.append(", ");\r
792                 buf.append(a[j]);\r
793                 for (int k=1; k<COUNTRY[i].length; ++k) {\r
794                     if ((mask & (1<<k)) == 0 &&\r
795                         a[j].equals(COUNTRY[i][k])) {\r
796                         mask |= (1<<k);\r
797                     }\r
798                 }\r
799             }\r
800             buf.append("]");\r
801             mask >>= 1;\r
802             // Check bitmask to see if we saw all expected zones\r
803             if (mask == (1 << (COUNTRY[i].length-1))-1) {\r
804                 logln(buf.toString());\r
805             } else {\r
806                 errln(buf.toString());\r
807             }\r
808         }\r
809 \r
810         // Test equivalent IDs API\r
811 \r
812         int n = ZoneMeta.countEquivalentIDs("PST");\r
813         boolean ok = false;\r
814         buf.setLength(0);\r
815         buf.append("Equivalent to PST: ");\r
816         for (int i=0; i<n; ++i) {\r
817             String id = ZoneMeta.getEquivalentID("PST", i);\r
818             if (id.equals("America/Los_Angeles")) {\r
819                 ok = true;\r
820             }\r
821             if (i!=0) buf.append(", ");\r
822             buf.append(id);\r
823         }\r
824         if (ok) {\r
825             logln(buf.toString());\r
826         } else {\r
827             errln(buf.toString());\r
828         }\r
829     }\r
830 \r
831     public void TestComparable() {\r
832     GregorianCalendar c0 = new GregorianCalendar();\r
833     GregorianCalendar c1 = new GregorianCalendar();\r
834     c1.add(Calendar.DAY_OF_MONTH, 1);\r
835     if (c0.compareTo(c1) >= 0) {\r
836         errln("calendar " + c0 + " not < " + c1);\r
837     }\r
838     c0.add(Calendar.MONTH, 1);\r
839     if (c0.compareTo(c1) <= 0) {\r
840         errln("calendar " + c0 + " not > " + c1);\r
841     }\r
842 \r
843     c0.setTimeInMillis(c1.getTimeInMillis());\r
844     if (c0.compareTo(c1) != 0) {\r
845         errln("calendar " + c0 + " not == " + c1);\r
846     }\r
847 \r
848     // coverage\r
849     try {\r
850         c0.compareTo((Object)null);\r
851         errln("calendar.compareTo didn't object to null arg");\r
852     }\r
853     catch (NullPointerException npe) {\r
854         logln("PASS: calendar.compareTo objected to null arg");\r
855     }\r
856     }\r
857 \r
858     /**\r
859      * Miscellaneous tests to increase coverage.\r
860      */\r
861     public void TestCoverage() {\r
862         // BuddhistCalendar\r
863         BuddhistCalendar bcal = new BuddhistCalendar();\r
864         /*int i =*/ bcal.getMinimum(Calendar.ERA);\r
865         bcal.add(Calendar.YEAR, 1);\r
866         bcal.add(Calendar.MONTH, 1);\r
867         /*Date d = */bcal.getTime();\r
868 \r
869         // CalendarAstronomer\r
870         // (This class should probably be made package-private.)\r
871         CalendarAstronomer astro = new CalendarAstronomer();\r
872         /*String s = */astro.local(0);\r
873 \r
874         // ChineseCalendar\r
875         ChineseCalendar ccal = new ChineseCalendar(TimeZone.getDefault(),\r
876                                                    Locale.getDefault());\r
877         ccal.add(Calendar.MONTH, 1);\r
878         ccal.add(Calendar.YEAR, 1);\r
879         ccal.roll(Calendar.MONTH, 1);\r
880         ccal.roll(Calendar.YEAR, 1);\r
881         ccal.getTime();\r
882 \r
883         // ICU 2.6\r
884         Calendar cal = Calendar.getInstance(Locale.US);\r
885         logln(cal.toString());\r
886         logln(cal.getDisplayName(Locale.US));\r
887         int weekendOnset=-1;\r
888         int weekendCease=-1;\r
889         for (int i=Calendar.SUNDAY; i<=Calendar.SATURDAY; ++i) {\r
890             if (cal.getDayOfWeekType(i) == Calendar.WEEKEND_ONSET) {\r
891                 weekendOnset = i;\r
892             }\r
893             if (cal.getDayOfWeekType(i) == Calendar.WEEKEND_CEASE) {\r
894                 weekendCease = i;\r
895             }\r
896         }\r
897         // can't call this unless we get a transition day (unusual),\r
898         // but make the call anyway for coverage reasons\r
899         try {\r
900             /*int x=*/ cal.getWeekendTransition(weekendOnset);\r
901             /*int x=*/ cal.getWeekendTransition(weekendCease);\r
902         } catch (IllegalArgumentException e) {}\r
903         /*int x=*/ cal.isWeekend(new Date());\r
904 \r
905         // new GregorianCalendar(ULocale)\r
906         GregorianCalendar gcal = new GregorianCalendar(ULocale.getDefault());\r
907         if(gcal==null){\r
908             errln("could not create GregorianCalendar with ULocale");\r
909         } else {\r
910             logln("Calendar display name: " + gcal.getDisplayName(ULocale.getDefault()));\r
911         }\r
912 \r
913         //cover getAvailableULocales\r
914         final ULocale[] locales = Calendar.getAvailableULocales();\r
915         long count = locales.length;\r
916         if (count == 0)\r
917             errln("getAvailableULocales return empty list");\r
918         logln("" + count + " available ulocales in Calendar.");\r
919 \r
920         // Jitterbug 4451, for coverage\r
921         class StubCalendar extends Calendar{\r
922             /**\r
923              * For serialization\r
924              */\r
925             private static final long serialVersionUID = -4558903444622684759L;\r
926             protected int handleGetLimit(int field, int limitType) {return 0;}\r
927             protected int handleComputeMonthStart(int eyear, int month, boolean useMonth) {return 0;}\r
928             protected int handleGetExtendedYear() {return 0;}\r
929             public void run(){\r
930                 if (Calendar.gregorianPreviousMonthLength(2000,2) != 29){\r
931                     errln("Year 2000 Feb should have 29 days.");\r
932                 }\r
933                 long millis = Calendar.julianDayToMillis(Calendar.MAX_JULIAN);\r
934                 if(millis != Calendar.MAX_MILLIS){\r
935                     errln("Did not get the expected value from julianDayToMillis. Got:" + millis);\r
936                 }\r
937                 DateFormat df = handleGetDateFormat("",Locale.getDefault());\r
938                 if (!df.equals(handleGetDateFormat("",ULocale.getDefault()))){\r
939                     errln ("Calendar.handleGetDateFormat(String, Locale) should delegate to ( ,ULocale)");\r
940                 }\r
941                 if (!getType().equals("gregorian")){\r
942                     errln ("Calendar.getType() should be 'gregorian'");\r
943                 }\r
944             }\r
945         }\r
946         StubCalendar stub = new StubCalendar();\r
947         stub.run();\r
948     }\r
949 \r
950     // Tests for jb 4541\r
951     public void TestJB4541() {\r
952         ULocale loc = new ULocale("en_US");\r
953 \r
954         // !!! Shouldn't we have an api like this?\r
955         // !!! Question: should this reflect those actually available in this copy of ICU, or \r
956         // the list of types we assume is available?\r
957         // String[] calTypes = Calendar.getAvailableTypes();\r
958         final String[] calTypes = {\r
959             "buddhist", "chinese", "coptic", "ethiopic", "gregorian", "hebrew", \r
960             "islamic", "islamic-civil", "japanese", "roc"\r
961         };\r
962         \r
963         // constructing a DateFormat with a locale indicating a calendar type should construct a\r
964         // date format appropriate to that calendar\r
965         final Date time = new Date();\r
966         for (int i = 0; i < calTypes.length; ++i) {\r
967             ULocale aLoc = loc.setKeywordValue("calendar", calTypes[i]);\r
968             logln("locale: " + aLoc);\r
969 \r
970             DateFormat df = DateFormat.getDateTimeInstance(DateFormat.FULL,\r
971                                                            DateFormat.FULL,\r
972                                                            aLoc);\r
973 \r
974             logln("df type: " + df.getClass().getName() + " loc: " + df.getLocale(ULocale.VALID_LOCALE));\r
975 \r
976             Calendar cal = df.getCalendar();\r
977             // todo, what about variants of calendars, we have a type for islamic-civil, should we also have a type\r
978             // for variants of other calendars?\r
979             assertEquals("calendar types", cal.getType(), calTypes[i].equals("islamic-civil") ? "islamic" : calTypes[i]);\r
980             DateFormat df2 = cal.getDateTimeFormat(DateFormat.FULL, DateFormat.FULL, ULocale.US);\r
981             logln("df2 type: " + df2.getClass().getName() + " loc: " + df2.getLocale(ULocale.VALID_LOCALE));\r
982             assertEquals("format results", df.format(time), df2.format(time));\r
983         }\r
984 \r
985         // dateFormat.setCalendar should throw exception if wrong format for calendar\r
986         if (false) {\r
987             DateFormat df = DateFormat.getDateTimeInstance(DateFormat.FULL, \r
988                                                            DateFormat.FULL, \r
989                                                            new ULocale("en_US@calendar=chinese"));\r
990 \r
991             logln("dateformat type: " + df.getClass().getName());\r
992 \r
993             Calendar cal = Calendar.getInstance(new ULocale("en_US@calendar=chinese"));\r
994                                                 \r
995             logln("calendar type: " + cal.getClass().getName());\r
996         }\r
997     }\r
998 \r
999     public void TestTypes() {\r
1000         String[] locs = {\r
1001                 "en_US_VALLEYGIRL",\r
1002                 "en_US_VALLEYGIRL@collation=phonebook;calendar=japanese",\r
1003                 "en_US_VALLEYGIRL@collation=phonebook;calendar=gregorian",\r
1004                 "ja_JP@calendar=japanese",\r
1005                 "th_TH@calendar=buddhist",\r
1006                 "ja_JP_TRADITIONAL",\r
1007                 "th_TH_TRADITIONAL",\r
1008                 "th_TH_TRADITIONAL@calendar=gregorian",\r
1009                 "en_US",\r
1010                 "th_TH",    // Default calendar for th_TH is buddhist\r
1011                 "th",       // th's default region is TH and buddhist is used as default for TH\r
1012 // FIXME: ICU Service canonicalize en_TH to en, so TH is ignored in Calendar instantiation.  See #6816.\r
1013 //                "en_TH",    // Default calendar for any locales with region TH is buddhist\r
1014         };\r
1015 \r
1016         String[] types = {\r
1017                 "gregorian",\r
1018                 "japanese",\r
1019                 "gregorian",\r
1020                 "japanese",\r
1021                 "buddhist",\r
1022                 "japanese",\r
1023                 "buddhist",\r
1024                 "gregorian",\r
1025                 "gregorian",\r
1026                 "buddhist",\r
1027                 "buddhist",\r
1028 // FIXME: ICU Service canonicalize en_TH to en, so TH is ignored in Calendar instantiation.  See #6816.\r
1029 //                "buddhist",\r
1030         };\r
1031 \r
1032         for (int i = 0; i < locs.length; i++) {\r
1033             Calendar cal = Calendar.getInstance(new ULocale(locs[i]));\r
1034             if (!cal.getType().equals(types[i])) {\r
1035                 errln(locs[i] + " Calendar type " + cal.getType() + " instead of " + types[i]);\r
1036             }\r
1037         }\r
1038     }\r
1039 }\r