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