1 /***********************************************************************
2  * COPYRIGHT:
3  * Copyright (c) 1997-2014, International Business Machines Corporation
4  * and others. All Rights Reserved.
5  ***********************************************************************/
6 
7 /* Test Internationalized Calendars for C++ */
8 
9 #include "unicode/utypes.h"
10 #include "string.h"
11 #include "unicode/locid.h"
12 #include "japancal.h"
13 
14 #if !UCONFIG_NO_FORMATTING
15 
16 #include <stdio.h>
17 #include "caltest.h"
18 
19 #define CHECK(status, msg) \
20     if (U_FAILURE(status)) { \
21       dataerrln((UnicodeString(u_errorName(status)) + UnicodeString(" : " ) )+ msg); \
22         return; \
23     }
24 
25 
escape(const UnicodeString & src)26 static UnicodeString escape( const UnicodeString&src)
27 {
28   UnicodeString dst;
29     dst.remove();
30     for (int32_t i = 0; i < src.length(); ++i) {
31         UChar c = src[i];
32         if(c < 0x0080)
33             dst += c;
34         else {
35             dst += UnicodeString("[");
36             char buf [8];
37             sprintf(buf, "%#x", c);
38             dst += UnicodeString(buf);
39             dst += UnicodeString("]");
40         }
41     }
42 
43     return dst;
44 }
45 
46 
47 #include "incaltst.h"
48 #include "unicode/gregocal.h"
49 #include "unicode/smpdtfmt.h"
50 #include "unicode/simpletz.h"
51 
52 // *****************************************************************************
53 // class IntlCalendarTest
54 // *****************************************************************************
55 //--- move to CalendarTest?
56 
57 // Turn this on to dump the calendar fields
58 #define U_DEBUG_DUMPCALS
59 
60 
61 #define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break
62 
63 
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)64 void IntlCalendarTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
65 {
66     if (exec) logln("TestSuite IntlCalendarTest");
67     switch (index) {
68     CASE(0,TestTypes);
69     CASE(1,TestGregorian);
70     CASE(2,TestBuddhist);
71     CASE(3,TestJapanese);
72     CASE(4,TestBuddhistFormat);
73     CASE(5,TestJapaneseFormat);
74     CASE(6,TestJapanese3860);
75     CASE(7,TestPersian);
76     CASE(8,TestPersianFormat);
77     CASE(9,TestTaiwan);
78     default: name = ""; break;
79     }
80 }
81 
82 #undef CASE
83 
84 // ---------------------------------------------------------------------------------
85 
86 
87 /**
88  * Test various API methods for API completeness.
89  */
90 void
TestTypes()91 IntlCalendarTest::TestTypes()
92 {
93   Calendar *c = NULL;
94   UErrorCode status = U_ZERO_ERROR;
95   int j;
96   const char *locs [40] = { "en_US_VALLEYGIRL",
97                             "en_US_VALLEYGIRL@collation=phonebook;calendar=japanese",
98                             "en_US_VALLEYGIRL@collation=phonebook;calendar=gregorian",
99                             "ja_JP@calendar=japanese",
100                             "th_TH@calendar=buddhist",
101                             "ja_JP_TRADITIONAL",
102                             "th_TH_TRADITIONAL",
103                             "th_TH_TRADITIONAL@calendar=gregorian",
104                             "en_US",
105                             "th_TH",    // Default calendar for th_TH is buddhist
106                             "th",       // th's default region is TH and buddhist is used as default for TH
107                             "en_TH",    // Default calendar for any locales with region TH is buddhist
108                             "en-TH-u-ca-gregory",
109                             NULL };
110   const char *types[40] = { "gregorian",
111                             "japanese",
112                             "gregorian",
113                             "japanese",
114                             "buddhist",
115                             "japanese",
116                             "buddhist",
117                             "gregorian",
118                             "gregorian",
119                             "gregorian",  // android-changed.  "buddhist",
120                             "gregorian",  // android-changed.  "buddhist",
121                             "gregorian",  // android-changed.  "buddhist",
122                             "gregorian",
123                             NULL };
124 
125   for(j=0;locs[j];j++) {
126     logln(UnicodeString("Creating calendar of locale ")  + locs[j]);
127     status = U_ZERO_ERROR;
128     c = Calendar::createInstance(locs[j], status);
129     CHECK(status, "creating '" + UnicodeString(locs[j]) + "' calendar");
130     if(U_SUCCESS(status)) {
131       logln(UnicodeString(" type is ") + c->getType());
132       if(strcmp(c->getType(), types[j])) {
133         dataerrln(UnicodeString(locs[j]) + UnicodeString("Calendar type ") + c->getType() + " instead of " + types[j]);
134       }
135     }
136     delete c;
137   }
138 }
139 
140 
141 
142 /**
143  * Run a test of a quasi-Gregorian calendar.  This is a calendar
144  * that behaves like a Gregorian but has different year/era mappings.
145  * The int[] data array should have the format:
146  *
147  * { era, year, gregorianYear, month, dayOfMonth, ...  ... , -1 }
148  */
quasiGregorianTest(Calendar & cal,const Locale & gcl,const int32_t * data)149 void IntlCalendarTest::quasiGregorianTest(Calendar& cal, const Locale& gcl, const int32_t *data) {
150   UErrorCode status = U_ZERO_ERROR;
151   // As of JDK 1.4.1_01, using the Sun JDK GregorianCalendar as
152   // a reference throws us off by one hour.  This is most likely
153   // due to the JDK 1.4 incorporation of historical time zones.
154   //java.util.Calendar grego = java.util.Calendar.getInstance();
155   Calendar *grego = Calendar::createInstance(gcl, status);
156   if (U_FAILURE(status)) {
157     dataerrln("Error calling Calendar::createInstance");
158     return;
159   }
160 
161   int32_t tz1 = cal.get(UCAL_ZONE_OFFSET,status);
162   int32_t tz2 = grego -> get (UCAL_ZONE_OFFSET, status);
163   if(tz1 != tz2) {
164     errln((UnicodeString)"cal's tz " + tz1 + " != grego's tz " + tz2);
165   }
166 
167   for (int32_t i=0; data[i]!=-1; ) {
168     int32_t era = data[i++];
169     int32_t year = data[i++];
170     int32_t gregorianYear = data[i++];
171     int32_t month = data[i++];
172     int32_t dayOfMonth = data[i++];
173 
174     grego->clear();
175     grego->set(gregorianYear, month, dayOfMonth);
176     UDate D = grego->getTime(status);
177 
178     cal.clear();
179     cal.set(UCAL_ERA, era);
180     cal.set(year, month, dayOfMonth);
181     UDate d = cal.getTime(status);
182 #ifdef U_DEBUG_DUMPCALS
183     logln((UnicodeString)"cal  : " + CalendarTest::calToStr(cal));
184     logln((UnicodeString)"grego: " + CalendarTest::calToStr(*grego));
185 #endif
186     if (d == D) {
187       logln(UnicodeString("OK: ") + era + ":" + year + "/" + (month+1) + "/" + dayOfMonth +
188             " => " + d + " (" + UnicodeString(cal.getType()) + ")");
189     } else {
190       errln(UnicodeString("Fail: (fields to millis)") + era + ":" + year + "/" + (month+1) + "/" + dayOfMonth +
191             " => " + d + ", expected " + D + " (" + UnicodeString(cal.getType()) + "Off by: " + (d-D));
192     }
193 
194     // Now, set the gregorian millis on the other calendar
195     cal.clear();
196     cal.setTime(D, status);
197     int e = cal.get(UCAL_ERA, status);
198     int y = cal.get(UCAL_YEAR, status);
199 #ifdef U_DEBUG_DUMPCALS
200     logln((UnicodeString)"cal  : " + CalendarTest::calToStr(cal));
201     logln((UnicodeString)"grego: " + CalendarTest::calToStr(*grego));
202 #endif
203     if (y == year && e == era) {
204       logln((UnicodeString)"OK: " + D + " => " + cal.get(UCAL_ERA, status) + ":" +
205             cal.get(UCAL_YEAR, status) + "/" +
206             (cal.get(UCAL_MONTH, status)+1) + "/" + cal.get(UCAL_DATE, status) +  " (" + UnicodeString(cal.getType()) + ")");
207     } else {
208       errln((UnicodeString)"Fail: (millis to fields)" + D + " => " + cal.get(UCAL_ERA, status) + ":" +
209             cal.get(UCAL_YEAR, status) + "/" +
210             (cal.get(UCAL_MONTH, status)+1) + "/" + cal.get(UCAL_DATE, status) +
211             ", expected " + era + ":" + year + "/" + (month+1) + "/" +
212             dayOfMonth +  " (" + UnicodeString(cal.getType()));
213     }
214   }
215   delete grego;
216   CHECK(status, "err during quasiGregorianTest()");
217 }
218 
219 // Verify that Gregorian works like Gregorian
TestGregorian()220 void IntlCalendarTest::TestGregorian() {
221     UDate timeA = Calendar::getNow();
222     int32_t data[] = {
223         GregorianCalendar::AD, 1868, 1868, UCAL_SEPTEMBER, 8,
224         GregorianCalendar::AD, 1868, 1868, UCAL_SEPTEMBER, 9,
225         GregorianCalendar::AD, 1869, 1869, UCAL_JUNE, 4,
226         GregorianCalendar::AD, 1912, 1912, UCAL_JULY, 29,
227         GregorianCalendar::AD, 1912, 1912, UCAL_JULY, 30,
228         GregorianCalendar::AD, 1912, 1912, UCAL_AUGUST, 1,
229         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
230     };
231 
232     Calendar *cal;
233     UErrorCode status = U_ZERO_ERROR;
234     cal = Calendar::createInstance(/*"de_DE", */ status);
235     CHECK(status, UnicodeString("Creating de_CH calendar"));
236     // Sanity check the calendar
237     UDate timeB = Calendar::getNow();
238     UDate timeCal = cal->getTime(status);
239 
240     if(!(timeA <= timeCal) || !(timeCal <= timeB)) {
241       errln((UnicodeString)"Error: Calendar time " + timeCal +
242             " is not within sampled times [" + timeA + " to " + timeB + "]!");
243     }
244     // end sanity check
245 
246     // Note, the following is a good way to test the sanity of the constructed calendars,
247     // using Collation as a delay-loop:
248     //
249     // $ intltest  format/IntlCalendarTest  collate/G7CollationTest format/IntlCalendarTest
250 
251     quasiGregorianTest(*cal,Locale("fr_FR"),data);
252     delete cal;
253 }
254 
255 /**
256  * Verify that BuddhistCalendar shifts years to Buddhist Era but otherwise
257  * behaves like GregorianCalendar.
258  */
TestBuddhist()259 void IntlCalendarTest::TestBuddhist() {
260     // BE 2542 == 1999 CE
261     UDate timeA = Calendar::getNow();
262 
263     int32_t data[] = {
264         0,           // B. era   [928479600000]
265         2542,        // B. year
266         1999,        // G. year
267         UCAL_JUNE,   // month
268         4,           // day
269 
270         0,           // B. era   [-79204842000000]
271         3,           // B. year
272         -540,        // G. year
273         UCAL_FEBRUARY, // month
274         12,          // day
275 
276         0,           // test month calculation:  4795 BE = 4252 AD is a leap year, but 4795 AD is not.
277         4795,        // BE [72018057600000]
278         4252,        // AD
279         UCAL_FEBRUARY,
280         29,
281 
282         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1
283     };
284     Calendar *cal;
285     UErrorCode status = U_ZERO_ERROR;
286     cal = Calendar::createInstance("th_TH@calendar=buddhist", status);
287     CHECK(status, UnicodeString("Creating th_TH@calendar=buddhist calendar"));
288 
289     // Sanity check the calendar
290     UDate timeB = Calendar::getNow();
291     UDate timeCal = cal->getTime(status);
292 
293     if(!(timeA <= timeCal) || !(timeCal <= timeB)) {
294       errln((UnicodeString)"Error: Calendar time " + timeCal +
295             " is not within sampled times [" + timeA + " to " + timeB + "]!");
296     }
297     // end sanity check
298 
299 
300     quasiGregorianTest(*cal,Locale("th_TH@calendar=gregorian"),data);
301     delete cal;
302 }
303 
304 
305 /**
306  * Verify that TaiWanCalendar shifts years to Minguo Era but otherwise
307  * behaves like GregorianCalendar.
308  */
TestTaiwan()309 void IntlCalendarTest::TestTaiwan() {
310     // MG 1 == 1912 AD
311     UDate timeA = Calendar::getNow();
312 
313     // TODO port these to the data items
314     int32_t data[] = {
315         1,           // B. era   [928479600000]
316         1,        // B. year
317         1912,        // G. year
318         UCAL_JUNE,   // month
319         4,           // day
320 
321         1,           // B. era   [-79204842000000]
322         3,           // B. year
323         1914,        // G. year
324         UCAL_FEBRUARY, // month
325         12,          // day
326 
327         1,           // B. era   [-79204842000000]
328         96,           // B. year
329         2007,        // G. year
330         UCAL_FEBRUARY, // month
331         12,          // day
332 
333         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1
334     };
335     Calendar *cal;
336     UErrorCode status = U_ZERO_ERROR;
337     cal = Calendar::createInstance("en_US@calendar=roc", status);
338     CHECK(status, UnicodeString("Creating en_US@calendar=roc calendar"));
339 
340     // Sanity check the calendar
341     UDate timeB = Calendar::getNow();
342     UDate timeCal = cal->getTime(status);
343 
344     if(!(timeA <= timeCal) || !(timeCal <= timeB)) {
345       errln((UnicodeString)"Error: Calendar time " + timeCal +
346             " is not within sampled times [" + timeA + " to " + timeB + "]!");
347     }
348     // end sanity check
349 
350 
351     quasiGregorianTest(*cal,Locale("en_US"),data);
352     delete cal;
353 }
354 
355 
356 
357 /**
358  * Verify that JapaneseCalendar shifts years to Japanese Eras but otherwise
359  * behaves like GregorianCalendar.
360  */
TestJapanese()361 void IntlCalendarTest::TestJapanese() {
362     UDate timeA = Calendar::getNow();
363 
364     /* Sorry.. japancal.h is private! */
365 #define JapaneseCalendar_MEIJI  232
366 #define JapaneseCalendar_TAISHO 233
367 #define JapaneseCalendar_SHOWA  234
368 #define JapaneseCalendar_HEISEI 235
369 
370     // BE 2542 == 1999 CE
371     int32_t data[] = {
372         //       Jera         Jyr  Gyear   m             d
373         JapaneseCalendar_MEIJI, 1, 1868, UCAL_SEPTEMBER, 8,
374         JapaneseCalendar_MEIJI, 1, 1868, UCAL_SEPTEMBER, 9,
375         JapaneseCalendar_MEIJI, 2, 1869, UCAL_JUNE, 4,
376         JapaneseCalendar_MEIJI, 45, 1912, UCAL_JULY, 29,
377         JapaneseCalendar_TAISHO, 1, 1912, UCAL_JULY, 30,
378         JapaneseCalendar_TAISHO, 1, 1912, UCAL_AUGUST, 1,
379 
380         // new tests (not in java)
381         JapaneseCalendar_SHOWA,     64,   1989,  UCAL_JANUARY, 7,  // Test current era transition (different code path than others)
382         JapaneseCalendar_HEISEI,    1,   1989,  UCAL_JANUARY, 8,
383         JapaneseCalendar_HEISEI,    1,   1989,  UCAL_JANUARY, 9,
384         JapaneseCalendar_HEISEI,    1,   1989,  UCAL_DECEMBER, 20,
385         JapaneseCalendar_HEISEI,  15,  2003,  UCAL_MAY, 22,
386         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1
387     };
388 
389     Calendar *cal;
390     UErrorCode status = U_ZERO_ERROR;
391     cal = Calendar::createInstance("ja_JP@calendar=japanese", status);
392     CHECK(status, UnicodeString("Creating ja_JP@calendar=japanese calendar"));
393     // Sanity check the calendar
394     UDate timeB = Calendar::getNow();
395     UDate timeCal = cal->getTime(status);
396 
397     if(!(timeA <= timeCal) || !(timeCal <= timeB)) {
398       errln((UnicodeString)"Error: Calendar time " + timeCal +
399             " is not within sampled times [" + timeA + " to " + timeB + "]!");
400     }
401     // end sanity check
402     quasiGregorianTest(*cal,Locale("ja_JP"),data);
403     delete cal;
404 }
405 
406 
407 
TestBuddhistFormat()408 void IntlCalendarTest::TestBuddhistFormat() {
409     UErrorCode status = U_ZERO_ERROR;
410 
411     // Test simple parse/format with adopt
412 
413     // First, a contrived english test..
414     UDate aDate = 999932400000.0;
415     SimpleDateFormat *fmt = new SimpleDateFormat(UnicodeString("MMMM d, yyyy G"), Locale("en_US@calendar=buddhist"), status);
416     CHECK(status, "creating date format instance");
417     SimpleDateFormat *fmt2 = new SimpleDateFormat(UnicodeString("MMMM d, yyyy G"), Locale("en_US@calendar=gregorian"), status);
418     CHECK(status, "creating gregorian date format instance");
419     if(!fmt) {
420         errln("Coudln't create en_US instance");
421     } else {
422         UnicodeString str;
423         fmt2->format(aDate, str);
424         logln(UnicodeString() + "Test Date: " + str);
425         str.remove();
426         fmt->format(aDate, str);
427         logln(UnicodeString() + "as Buddhist Calendar: " + escape(str));
428         UnicodeString expected("September 8, 2544 BE");
429         if(str != expected) {
430             errln("Expected " + escape(expected) + " but got " + escape(str));
431         }
432         UDate otherDate = fmt->parse(expected, status);
433         if(otherDate != aDate) {
434             UnicodeString str3;
435             fmt->format(otherDate, str3);
436             errln("Parse incorrect of " + escape(expected) + " - wanted " + aDate + " but got " +  otherDate + ", " + escape(str3));
437         } else {
438             logln("Parsed OK: " + expected);
439         }
440         delete fmt;
441     }
442     delete fmt2;
443 
444     CHECK(status, "Error occured testing Buddhist Calendar in English ");
445 
446     status = U_ZERO_ERROR;
447     // Now, try in Thai
448     {
449         UnicodeString expect = CharsToUnicodeString("\\u0E27\\u0E31\\u0E19\\u0E40\\u0E2A\\u0E32\\u0E23\\u0E4C\\u0E17\\u0E35\\u0E48"
450             " 8 \\u0E01\\u0E31\\u0e19\\u0e22\\u0e32\\u0e22\\u0e19 \\u0e1e.\\u0e28. 2544");
451         UDate         expectDate = 999932400000.0;
452         Locale        loc("th_TH_TRADITIONAL"); // legacy
453 
454         simpleTest(loc, expect, expectDate, status);
455     }
456     status = U_ZERO_ERROR;
457     {
458         UnicodeString expect = CharsToUnicodeString("\\u0E27\\u0E31\\u0E19\\u0E40\\u0E2A\\u0E32\\u0E23\\u0E4C\\u0E17\\u0E35\\u0E48"
459             " 8 \\u0E01\\u0E31\\u0e19\\u0e22\\u0e32\\u0e22\\u0e19 \\u0e1e.\\u0e28. 2544");
460         UDate         expectDate = 999932400000.0;
461         Locale        loc("th_TH@calendar=buddhist");
462 
463         simpleTest(loc, expect, expectDate, status);
464     }
465     status = U_ZERO_ERROR;
466     {
467         UnicodeString expect = CharsToUnicodeString("\\u0E27\\u0E31\\u0E19\\u0E40\\u0E2A\\u0E32\\u0E23\\u0E4C\\u0E17\\u0E35\\u0E48"
468             " 8 \\u0E01\\u0E31\\u0e19\\u0e22\\u0e32\\u0e22\\u0e19 \\u0e04.\\u0e28. 2001");
469         UDate         expectDate = 999932400000.0;
470         Locale        loc("th_TH@calendar=gregorian");
471 
472         simpleTest(loc, expect, expectDate, status);
473     }
474     status = U_ZERO_ERROR;
475     {
476         UnicodeString expect = CharsToUnicodeString("\\u0E27\\u0E31\\u0E19\\u0E40\\u0E2A\\u0E32\\u0E23\\u0E4C\\u0E17\\u0E35\\u0E48"
477             " 8 \\u0E01\\u0E31\\u0e19\\u0e22\\u0e32\\u0e22\\u0e19 \\u0e04.\\u0e28. 2001");
478         UDate         expectDate = 999932400000.0;
479         Locale        loc("th_TH_TRADITIONAL@calendar=gregorian");
480 
481         simpleTest(loc, expect, expectDate, status);
482     }
483 }
484 
485 // TaiwanFormat has been moved to testdata/format.txt
486 
487 
TestJapaneseFormat()488 void IntlCalendarTest::TestJapaneseFormat() {
489     Calendar *cal;
490     UErrorCode status = U_ZERO_ERROR;
491     cal = Calendar::createInstance("ja_JP_TRADITIONAL", status);
492     CHECK(status, UnicodeString("Creating ja_JP_TRADITIONAL calendar"));
493 
494     Calendar *cal2 = cal->clone();
495     delete cal;
496     cal = NULL;
497 
498     // Test simple parse/format with adopt
499 
500     UDate aDate = 999932400000.0;
501     SimpleDateFormat *fmt = new SimpleDateFormat(UnicodeString("MMMM d, yy G"), Locale("en_US@calendar=japanese"), status);
502     SimpleDateFormat *fmt2 = new SimpleDateFormat(UnicodeString("MMMM d, yyyy G"), Locale("en_US@calendar=gregorian"), status);
503     CHECK(status, "creating date format instance");
504     if(!fmt) {
505         errln("Coudln't create en_US instance");
506     } else {
507         UnicodeString str;
508         fmt2->format(aDate, str);
509         logln(UnicodeString() + "Test Date: " + str);
510         str.remove();
511         fmt->format(aDate, str);
512         logln(UnicodeString() + "as Japanese Calendar: " + str);
513         UnicodeString expected("September 8, 13 Heisei");
514         if(str != expected) {
515             errln("Expected " + expected + " but got " + str);
516         }
517         UDate otherDate = fmt->parse(expected, status);
518         if(otherDate != aDate) {
519             UnicodeString str3;
520             ParsePosition pp;
521             fmt->parse(expected, *cal2, pp);
522             fmt->format(otherDate, str3);
523             errln("Parse incorrect of " + expected + " - wanted " + aDate + " but got " +  " = " +   otherDate + ", " + str3 + " = " + CalendarTest::calToStr(*cal2) );
524 
525         } else {
526             logln("Parsed OK: " + expected);
527         }
528         delete fmt;
529     }
530 
531     // Test parse with incomplete information
532     fmt = new SimpleDateFormat(UnicodeString("G y"), Locale("en_US@calendar=japanese"), status);
533     aDate = -3197117222000.0;
534     CHECK(status, "creating date format instance");
535     if(!fmt) {
536         errln("Coudln't create en_US instance");
537     } else {
538         UnicodeString str;
539         fmt2->format(aDate, str);
540         logln(UnicodeString() + "Test Date: " + str);
541         str.remove();
542         fmt->format(aDate, str);
543         logln(UnicodeString() + "as Japanese Calendar: " + str);
544         UnicodeString expected("Meiji 1");
545         if(str != expected) {
546             errln("Expected " + expected + " but got " + str);
547         }
548         UDate otherDate = fmt->parse(expected, status);
549         if(otherDate != aDate) {
550             UnicodeString str3;
551             ParsePosition pp;
552             fmt->parse(expected, *cal2, pp);
553             fmt->format(otherDate, str3);
554             errln("Parse incorrect of " + expected + " - wanted " + aDate + " but got " +  " = " +
555                 otherDate + ", " + str3 + " = " + CalendarTest::calToStr(*cal2) );
556         } else {
557             logln("Parsed OK: " + expected);
558         }
559         delete fmt;
560     }
561 
562     delete cal2;
563     delete fmt2;
564     CHECK(status, "Error occured");
565 
566     // Now, try in Japanese
567     {
568         UnicodeString expect = CharsToUnicodeString("\\u5e73\\u621013\\u5e749\\u67088\\u65e5\\u571f\\u66dc\\u65e5");
569         UDate         expectDate = 999932400000.0; // Testing a recent date
570         Locale        loc("ja_JP@calendar=japanese");
571 
572         status = U_ZERO_ERROR;
573         simpleTest(loc, expect, expectDate, status);
574     }
575     {
576         UnicodeString expect = CharsToUnicodeString("\\u5e73\\u621013\\u5e749\\u67088\\u65e5\\u571f\\u66dc\\u65e5");
577         UDate         expectDate = 999932400000.0; // Testing a recent date
578         Locale        loc("ja_JP_TRADITIONAL"); // legacy
579 
580         status = U_ZERO_ERROR;
581         simpleTest(loc, expect, expectDate, status);
582     }
583     {
584         UnicodeString expect = CharsToUnicodeString("\\u5b89\\u6c385\\u5e747\\u67084\\u65e5\\u6728\\u66dc\\u65e5");
585         UDate         expectDate = -6106032422000.0; // 1776-07-04T00:00:00Z-075258
586         Locale        loc("ja_JP@calendar=japanese");
587 
588         status = U_ZERO_ERROR;
589         simpleTest(loc, expect, expectDate, status);
590 
591     }
592     {   // Jitterbug 1869 - this is an ambiguous era. (Showa 64 = Jan 6 1989, but Showa could be 2 other eras) )
593         UnicodeString expect = CharsToUnicodeString("\\u662d\\u548c64\\u5e741\\u67086\\u65e5\\u91d1\\u66dc\\u65e5");
594         UDate         expectDate = 600076800000.0;
595         Locale        loc("ja_JP@calendar=japanese");
596 
597         status = U_ZERO_ERROR;
598         simpleTest(loc, expect, expectDate, status);
599 
600     }
601     {   // This Feb 29th falls on a leap year by gregorian year, but not by Japanese year.
602         UnicodeString expect = CharsToUnicodeString("\\u5EB7\\u6B632\\u5e742\\u670829\\u65e5\\u65e5\\u66dc\\u65e5");
603         UDate         expectDate =  -16214400422000.0;  // 1456-03-09T00:00Z-075258
604         Locale        loc("ja_JP@calendar=japanese");
605 
606         status = U_ZERO_ERROR;
607         simpleTest(loc, expect, expectDate, status);
608 
609     }
610 }
611 
TestJapanese3860()612 void IntlCalendarTest::TestJapanese3860()
613 {
614     Calendar *cal;
615     UErrorCode status = U_ZERO_ERROR;
616     cal = Calendar::createInstance("ja_JP@calendar=japanese", status);
617     CHECK(status, UnicodeString("Creating ja_JP@calendar=japanese calendar"));
618     Calendar *cal2 = cal->clone();
619     SimpleDateFormat *fmt2 = new SimpleDateFormat(UnicodeString("HH:mm:ss.S MMMM d, yyyy G"), Locale("en_US@calendar=gregorian"), status);
620     UnicodeString str;
621 
622 
623     {
624         // Test simple parse/format with adopt
625         UDate aDate = 0;
626 
627         // Test parse with missing era (should default to current era, heisei)
628         // Test parse with incomplete information
629         logln("Testing parse w/ missing era...");
630         SimpleDateFormat *fmt = new SimpleDateFormat(UnicodeString("y.M.d"), Locale("ja_JP@calendar=japanese"), status);
631         CHECK(status, "creating date format instance");
632         if(!fmt) {
633             errln("Coudln't create en_US instance");
634         } else {
635             UErrorCode s2 = U_ZERO_ERROR;
636             cal2->clear();
637             UnicodeString samplestr("1.1.9");
638             logln(UnicodeString() + "Test Year: " + samplestr);
639             aDate = fmt->parse(samplestr, s2);
640             ParsePosition pp=0;
641             fmt->parse(samplestr, *cal2, pp);
642             CHECK(s2, "parsing the 1.1.9 string");
643             logln("*cal2 after 119 parse:");
644             str.remove();
645             fmt2->format(aDate, str);
646             logln(UnicodeString() + "as Gregorian Calendar: " + str);
647 
648             cal2->setTime(aDate, s2);
649             int32_t gotYear = cal2->get(UCAL_YEAR, s2);
650             int32_t gotEra = cal2->get(UCAL_ERA, s2);
651             int32_t expectYear = 1;
652             int32_t expectEra = JapaneseCalendar::getCurrentEra();
653             if((gotYear!=1) || (gotEra != expectEra)) {
654                 errln(UnicodeString("parse "+samplestr+" of 'y.m.d' as Japanese Calendar, expected year ") + expectYear +
655                     UnicodeString(" and era ") + expectEra +", but got year " + gotYear + " and era " + gotEra + " (Gregorian:" + str +")");
656             } else {
657                 logln(UnicodeString() + " year: " + gotYear + ", era: " + gotEra);
658             }
659             delete fmt;
660         }
661     }
662 
663     {
664         // Test simple parse/format with adopt
665         UDate aDate = 0;
666 
667         // Test parse with missing era (should default to current era, heisei)
668         // Test parse with incomplete information
669         logln("Testing parse w/ just year...");
670         SimpleDateFormat *fmt = new SimpleDateFormat(UnicodeString("y"), Locale("ja_JP@calendar=japanese"), status);
671         CHECK(status, "creating date format instance");
672         if(!fmt) {
673             errln("Coudln't create en_US instance");
674         } else {
675             UErrorCode s2 = U_ZERO_ERROR;
676             cal2->clear();
677             UnicodeString samplestr("1");
678             logln(UnicodeString() + "Test Year: " + samplestr);
679             aDate = fmt->parse(samplestr, s2);
680             ParsePosition pp=0;
681             fmt->parse(samplestr, *cal2, pp);
682             CHECK(s2, "parsing the 1 string");
683             logln("*cal2 after 1 parse:");
684             str.remove();
685             fmt2->format(aDate, str);
686             logln(UnicodeString() + "as Gregorian Calendar: " + str);
687 
688             cal2->setTime(aDate, s2);
689             int32_t gotYear = cal2->get(UCAL_YEAR, s2);
690             int32_t gotEra = cal2->get(UCAL_ERA, s2);
691             int32_t expectYear = 1;
692             int32_t expectEra = 235; //JapaneseCalendar::kCurrentEra;
693             if((gotYear!=1) || (gotEra != expectEra)) {
694                 errln(UnicodeString("parse "+samplestr+" of 'y' as Japanese Calendar, expected year ") + expectYear +
695                     UnicodeString(" and era ") + expectEra +", but got year " + gotYear + " and era " + gotEra + " (Gregorian:" + str +")");
696             } else {
697                 logln(UnicodeString() + " year: " + gotYear + ", era: " + gotEra);
698             }
699             delete fmt;
700         }
701     }
702 
703     delete cal2;
704     delete cal;
705     delete fmt2;
706 }
707 
708 
709 
710 
711 /**
712  * Verify the Persian Calendar.
713  */
TestPersian()714 void IntlCalendarTest::TestPersian() {
715     UDate timeA = Calendar::getNow();
716 
717     Calendar *cal;
718     UErrorCode status = U_ZERO_ERROR;
719     cal = Calendar::createInstance("fa_IR@calendar=persian", status);
720     CHECK(status, UnicodeString("Creating fa_IR@calendar=persian calendar"));
721     // Sanity check the calendar
722     UDate timeB = Calendar::getNow();
723     UDate timeCal = cal->getTime(status);
724 
725     if(!(timeA <= timeCal) || !(timeCal <= timeB)) {
726       errln((UnicodeString)"Error: Calendar time " + timeCal +
727             " is not within sampled times [" + timeA + " to " + timeB + "]!");
728     }
729     // end sanity check
730 
731     // Test various dates to be sure of validity
732     int32_t data[] = {
733         1925, 4, 24, 1304, 2, 4,
734         2011, 1, 11, 1389, 10, 21,
735         1986, 2, 25, 1364, 12, 6,
736         1934, 3, 14, 1312, 12, 23,
737 
738         2090, 3, 19, 1468, 12, 29,
739         2007, 2, 22, 1385, 12, 3,
740         1969, 12, 31, 1348, 10, 10,
741         1945, 11, 12, 1324, 8, 21,
742         1925, 3, 31, 1304, 1, 11,
743 
744         1996, 3, 19, 1374, 12, 29,
745         1996, 3, 20, 1375, 1, 1,
746         1997, 3, 20, 1375, 12, 30,
747         1997, 3, 21, 1376, 1, 1,
748 
749         2008, 3, 19, 1386, 12, 29,
750         2008, 3, 20, 1387, 1, 1,
751         2004, 3, 19, 1382, 12, 29,
752         2004, 3, 20, 1383, 1, 1,
753 
754         2006, 3, 20, 1384, 12, 29,
755         2006, 3, 21, 1385, 1, 1,
756 
757         2005, 4, 20, 1384, 1, 31,
758         2005, 4, 21, 1384, 2, 1,
759         2005, 5, 21, 1384, 2, 31,
760         2005, 5, 22, 1384, 3, 1,
761         2005, 6, 21, 1384, 3, 31,
762         2005, 6, 22, 1384, 4, 1,
763         2005, 7, 22, 1384, 4, 31,
764         2005, 7, 23, 1384, 5, 1,
765         2005, 8, 22, 1384, 5, 31,
766         2005, 8, 23, 1384, 6, 1,
767         2005, 9, 22, 1384, 6, 31,
768         2005, 9, 23, 1384, 7, 1,
769         2005, 10, 22, 1384, 7, 30,
770         2005, 10, 23, 1384, 8, 1,
771         2005, 11, 21, 1384, 8, 30,
772         2005, 11, 22, 1384, 9, 1,
773         2005, 12, 21, 1384, 9, 30,
774         2005, 12, 22, 1384, 10, 1,
775         2006, 1, 20, 1384, 10, 30,
776         2006, 1, 21, 1384, 11, 1,
777         2006, 2, 19, 1384, 11, 30,
778         2006, 2, 20, 1384, 12, 1,
779         2006, 3, 20, 1384, 12, 29,
780         2006, 3, 21, 1385, 1, 1,
781 
782         // The 2820-year cycle arithmetical algorithm would fail this one.
783         2025, 3, 21, 1404, 1, 1,
784 
785         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1
786     };
787 
788     Calendar *grego = Calendar::createInstance("fa_IR@calendar=gregorian", status);
789     for (int32_t i=0; data[i]!=-1; ) {
790         int32_t gregYear = data[i++];
791         int32_t gregMonth = data[i++]-1;
792         int32_t gregDay = data[i++];
793         int32_t persYear = data[i++];
794         int32_t persMonth = data[i++]-1;
795         int32_t persDay = data[i++];
796 
797         // Test conversion from Persian dates
798         grego->clear();
799         grego->set(gregYear, gregMonth, gregDay);
800 
801         cal->clear();
802         cal->set(persYear, persMonth, persDay);
803 
804         UDate persTime = cal->getTime(status);
805         UDate gregTime = grego->getTime(status);
806 
807         if (persTime != gregTime) {
808           errln(UnicodeString("Expected ") + gregTime + " but got " + persTime);
809         }
810 
811         // Test conversion to Persian dates
812         cal->clear();
813         cal->setTime(gregTime, status);
814 
815         int32_t computedYear = cal->get(UCAL_YEAR, status);
816         int32_t computedMonth = cal->get(UCAL_MONTH, status);
817         int32_t computedDay = cal->get(UCAL_DATE, status);
818 
819         if ((persYear != computedYear) ||
820             (persMonth != computedMonth) ||
821             (persDay != computedDay)) {
822           errln(UnicodeString("Expected ") + persYear + "/" + (persMonth+1) + "/" + persDay +
823                 " but got " +  computedYear + "/" + (computedMonth+1) + "/" + computedDay);
824         }
825 
826     }
827 
828     delete cal;
829     delete grego;
830 }
831 
TestPersianFormat()832 void IntlCalendarTest::TestPersianFormat() {
833     UErrorCode status = U_ZERO_ERROR;
834     SimpleDateFormat *fmt = new SimpleDateFormat(UnicodeString("MMMM d, yyyy G"), Locale(" en_US@calendar=persian"), status);
835     CHECK(status, "creating date format instance");
836     SimpleDateFormat *fmt2 = new SimpleDateFormat(UnicodeString("MMMM d, yyyy G"), Locale("en_US@calendar=gregorian"), status);
837     CHECK(status, "creating gregorian date format instance");
838     UnicodeString gregorianDate("January 18, 2007 AD");
839     UDate aDate = fmt2->parse(gregorianDate, status);
840     if(!fmt) {
841         errln("Coudln't create en_US instance");
842     } else {
843         UnicodeString str;
844         fmt->format(aDate, str);
845         logln(UnicodeString() + "as Persian Calendar: " + escape(str));
846         UnicodeString expected("Dey 28, 1385 AP");
847         if(str != expected) {
848             errln("Expected " + escape(expected) + " but got " + escape(str));
849         }
850         UDate otherDate = fmt->parse(expected, status);
851         if(otherDate != aDate) {
852             UnicodeString str3;
853             fmt->format(otherDate, str3);
854             errln("Parse incorrect of " + escape(expected) + " - wanted " + aDate + " but got " +  otherDate + ", " + escape(str3));
855         } else {
856             logln("Parsed OK: " + expected);
857         }
858         // Two digit year parsing problem #4732
859         fmt->applyPattern("yy-MM-dd");
860         str.remove();
861         fmt->format(aDate, str);
862         expected.setTo("85-10-28");
863         if(str != expected) {
864             errln("Expected " + escape(expected) + " but got " + escape(str));
865         }
866         otherDate = fmt->parse(expected, status);
867         if (otherDate != aDate) {
868             errln("Parse incorrect of " + escape(expected) + " - wanted " + aDate + " but got " + otherDate);
869         } else {
870             logln("Parsed OK: " + expected);
871         }
872         delete fmt;
873     }
874     delete fmt2;
875 
876     CHECK(status, "Error occured testing Persian Calendar in English ");
877 }
878 
879 
simpleTest(const Locale & loc,const UnicodeString & expect,UDate expectDate,UErrorCode & status)880 void IntlCalendarTest::simpleTest(const Locale& loc, const UnicodeString& expect, UDate expectDate, UErrorCode& status)
881 {
882     UnicodeString tmp;
883     UDate         d;
884     DateFormat *fmt0 = DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull);
885 
886     logln("Try format/parse of " + (UnicodeString)loc.getName());
887     DateFormat *fmt2 = DateFormat::createDateInstance(DateFormat::kFull, loc);
888     if(fmt2) {
889         fmt2->format(expectDate, tmp);
890         logln(escape(tmp) + " ( in locale " + loc.getName() + ")");
891         if(tmp != expect) {
892             errln(UnicodeString("Failed to format " ) + loc.getName() + " expected " + escape(expect) + " got " + escape(tmp) );
893         }
894 
895         d = fmt2->parse(expect,status);
896         CHECK(status, "Error occured parsing " + UnicodeString(loc.getName()));
897         if(d != expectDate) {
898             fmt2->format(d,tmp);
899             errln(UnicodeString("Failed to parse " ) + escape(expect) + ", " + loc.getName() + " expect " + (double)expectDate + " got " + (double)d  + " " + escape(tmp));
900             logln( "wanted " + escape(fmt0->format(expectDate,tmp.remove())) + " but got " + escape(fmt0->format(d,tmp.remove())));
901         }
902         delete fmt2;
903     } else {
904         errln((UnicodeString)"Can't create " + loc.getName() + " date instance");
905     }
906     delete fmt0;
907 }
908 
909 #undef CHECK
910 
911 #endif /* #if !UCONFIG_NO_FORMATTING */
912 
913 //eof
914