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