• 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 "cmemory.h"
13 #include "string.h"
14 #include "unicode/locid.h"
15 #include "japancal.h"
16 #include "unicode/localpointer.h"
17 #include "unicode/datefmt.h"
18 #include "unicode/smpdtfmt.h"
19 #include "unicode/dtptngen.h"
20 
21 #if !UCONFIG_NO_FORMATTING
22 
23 #include <stdio.h>
24 #include "caltest.h"
25 
26 #define CHECK(status, msg) UPRV_BLOCK_MACRO_BEGIN { \
27     if (U_FAILURE(status)) { \
28         dataerrln((UnicodeString(u_errorName(status)) + UnicodeString(" : " ) )+ msg); \
29         return; \
30     } \
31 } UPRV_BLOCK_MACRO_END
32 
33 
escape(const UnicodeString & src)34 static UnicodeString escape( const UnicodeString&src)
35 {
36   UnicodeString dst;
37     dst.remove();
38     for (int32_t i = 0; i < src.length(); ++i) {
39         char16_t c = src[i];
40         if(c < 0x0080)
41             dst += c;
42         else {
43             dst += UnicodeString("[");
44             char buf [8];
45             snprintf(buf, sizeof(buf), "%#x", c);
46             dst += UnicodeString(buf);
47             dst += UnicodeString("]");
48         }
49     }
50 
51     return dst;
52 }
53 
54 
55 #include "incaltst.h"
56 #include "unicode/gregocal.h"
57 #include "unicode/smpdtfmt.h"
58 #include "unicode/simpletz.h"
59 
60 // *****************************************************************************
61 // class IntlCalendarTest
62 // *****************************************************************************
63 //--- move to CalendarTest?
64 
65 // Turn this on to dump the calendar fields
66 #define U_DEBUG_DUMPCALS
67 
68 
69 #define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break
70 
71 
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)72 void IntlCalendarTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
73 {
74     if (exec) logln("TestSuite IntlCalendarTest");
75     TESTCASE_AUTO_BEGIN;
76     TESTCASE_AUTO(TestTypes);
77     TESTCASE_AUTO(TestGregorian);
78     TESTCASE_AUTO(TestBuddhist);
79     TESTCASE_AUTO(TestBug21043Indian);
80     TESTCASE_AUTO(TestBug21044Hebrew);
81     TESTCASE_AUTO(TestBug21045Islamic);
82     TESTCASE_AUTO(TestBug21046IslamicUmalqura);
83     TESTCASE_AUTO(TestJapanese);
84     TESTCASE_AUTO(TestBuddhistFormat);
85     TESTCASE_AUTO(TestJapaneseFormat);
86     TESTCASE_AUTO(TestJapanese3860);
87     TESTCASE_AUTO(TestForceGannenNumbering);
88     TESTCASE_AUTO(TestPersian);
89     TESTCASE_AUTO(TestPersianFormat);
90     TESTCASE_AUTO(TestTaiwan);
91     TESTCASE_AUTO(TestConsistencyGregorian);
92     TESTCASE_AUTO(TestConsistencyCoptic);
93     TESTCASE_AUTO(TestConsistencyEthiopic);
94     TESTCASE_AUTO(TestConsistencyROC);
95     TESTCASE_AUTO(TestConsistencyChinese);
96     TESTCASE_AUTO(TestConsistencyDangi);
97     TESTCASE_AUTO(TestConsistencyBuddhist);
98     TESTCASE_AUTO(TestConsistencyEthiopicAmeteAlem);
99     TESTCASE_AUTO(TestConsistencyHebrew);
100     TESTCASE_AUTO(TestConsistencyIndian);
101     TESTCASE_AUTO(TestConsistencyIslamic);
102     TESTCASE_AUTO(TestConsistencyIslamicCivil);
103     TESTCASE_AUTO(TestConsistencyIslamicRGSA);
104     TESTCASE_AUTO(TestConsistencyIslamicTBLA);
105     TESTCASE_AUTO(TestConsistencyIslamicUmalqura);
106     TESTCASE_AUTO(TestConsistencyPersian);
107     TESTCASE_AUTO(TestConsistencyJapanese);
108     TESTCASE_AUTO(TestIslamicUmalquraCalendarSlow);
109     TESTCASE_AUTO(TestJapaneseLargeEra);
110     TESTCASE_AUTO_END;
111 }
112 
113 #undef CASE
114 
115 // ---------------------------------------------------------------------------------
116 
117 
118 /**
119  * Test various API methods for API completeness.
120  */
121 void
TestTypes()122 IntlCalendarTest::TestTypes()
123 {
124   Calendar *c = nullptr;
125   UErrorCode status = U_ZERO_ERROR;
126   int j;
127   const char *locs [40] = { "en_US_VALLEYGIRL",
128                             "en_US_VALLEYGIRL@collation=phonebook;calendar=japanese",
129                             "en_US_VALLEYGIRL@collation=phonebook;calendar=gregorian",
130                             "ja_JP@calendar=japanese",
131                             "th_TH@calendar=buddhist",
132                             "th_TH_TRADITIONAL",
133                             "th_TH_TRADITIONAL@calendar=gregorian",
134                             "en_US",
135                             "th_TH",    // Default calendar for th_TH is buddhist
136                             "th",       // th's default region is TH and buddhist is used as default for TH
137                             "en_TH",    // Default calendar for any locales with region TH is buddhist
138                             "en-TH-u-ca-gregory",
139                             nullptr };
140   const char *types[40] = { "gregorian",
141                             "japanese",
142                             "gregorian",
143                             "japanese",
144                             "buddhist",
145                             "buddhist",
146                             "gregorian",
147                             "gregorian",
148                             "gregorian",  // android-changed.  "buddhist",
149                             "gregorian",  // android-changed.  "buddhist",
150                             "gregorian",  // android-changed.  "buddhist",
151                             "gregorian",
152                             nullptr };
153 
154   for(j=0;locs[j];j++) {
155     logln(UnicodeString("Creating calendar of locale ")  + locs[j]);
156     status = U_ZERO_ERROR;
157     c = Calendar::createInstance(locs[j], status);
158     CHECK(status, "creating '" + UnicodeString(locs[j]) + "' calendar");
159     if(U_SUCCESS(status)) {
160       logln(UnicodeString(" type is ") + c->getType());
161       if(strcmp(c->getType(), types[j])) {
162         dataerrln(UnicodeString(locs[j]) + UnicodeString("Calendar type ") + c->getType() + " instead of " + types[j]);
163       }
164     }
165     delete c;
166   }
167 }
168 
169 
170 
171 /**
172  * Run a test of a quasi-Gregorian calendar.  This is a calendar
173  * that behaves like a Gregorian but has different year/era mappings.
174  * The int[] data array should have the format:
175  *
176  * { era, year, gregorianYear, month, dayOfMonth, ...  ... , -1 }
177  */
quasiGregorianTest(Calendar & cal,const Locale & gcl,const int32_t * data)178 void IntlCalendarTest::quasiGregorianTest(Calendar& cal, const Locale& gcl, const int32_t *data) {
179   UErrorCode status = U_ZERO_ERROR;
180   // As of JDK 1.4.1_01, using the Sun JDK GregorianCalendar as
181   // a reference throws us off by one hour.  This is most likely
182   // due to the JDK 1.4 incorporation of historical time zones.
183   //java.util.Calendar grego = java.util.Calendar.getInstance();
184   Calendar *grego = Calendar::createInstance(gcl, status);
185   if (U_FAILURE(status)) {
186     dataerrln("Error calling Calendar::createInstance");
187     return;
188   }
189 
190   int32_t tz1 = cal.get(UCAL_ZONE_OFFSET,status);
191   int32_t tz2 = grego -> get (UCAL_ZONE_OFFSET, status);
192   if(tz1 != tz2) {
193     errln((UnicodeString)"cal's tz " + tz1 + " != grego's tz " + tz2);
194   }
195 
196   for (int32_t i=0; data[i]!=-1; ) {
197     int32_t era = data[i++];
198     int32_t year = data[i++];
199     int32_t gregorianYear = data[i++];
200     int32_t month = data[i++];
201     int32_t dayOfMonth = data[i++];
202 
203     grego->clear();
204     grego->set(gregorianYear, month, dayOfMonth);
205     UDate D = grego->getTime(status);
206 
207     cal.clear();
208     cal.set(UCAL_ERA, era);
209     cal.set(year, month, dayOfMonth);
210     UDate d = cal.getTime(status);
211 #ifdef U_DEBUG_DUMPCALS
212     logln((UnicodeString)"cal  : " + CalendarTest::calToStr(cal));
213     logln((UnicodeString)"grego: " + CalendarTest::calToStr(*grego));
214 #endif
215     if (d == D) {
216       logln(UnicodeString("OK: ") + era + ":" + year + "/" + (month+1) + "/" + dayOfMonth +
217             " => " + d + " (" + UnicodeString(cal.getType()) + ")");
218     } else {
219       errln(UnicodeString("Fail: (fields to millis)") + era + ":" + year + "/" + (month+1) + "/" + dayOfMonth +
220             " => " + d + ", expected " + D + " (" + UnicodeString(cal.getType()) + "Off by: " + (d-D));
221     }
222 
223     // Now, set the gregorian millis on the other calendar
224     cal.clear();
225     cal.setTime(D, status);
226     int e = cal.get(UCAL_ERA, status);
227     int y = cal.get(UCAL_YEAR, status);
228 #ifdef U_DEBUG_DUMPCALS
229     logln((UnicodeString)"cal  : " + CalendarTest::calToStr(cal));
230     logln((UnicodeString)"grego: " + CalendarTest::calToStr(*grego));
231 #endif
232     if (y == year && e == era) {
233       logln((UnicodeString)"OK: " + D + " => " + cal.get(UCAL_ERA, status) + ":" +
234             cal.get(UCAL_YEAR, status) + "/" +
235             (cal.get(UCAL_MONTH, status)+1) + "/" + cal.get(UCAL_DATE, status) +  " (" + UnicodeString(cal.getType()) + ")");
236     } else {
237       errln((UnicodeString)"Fail: (millis to fields)" + D + " => " + cal.get(UCAL_ERA, status) + ":" +
238             cal.get(UCAL_YEAR, status) + "/" +
239             (cal.get(UCAL_MONTH, status)+1) + "/" + cal.get(UCAL_DATE, status) +
240             ", expected " + era + ":" + year + "/" + (month+1) + "/" +
241             dayOfMonth +  " (" + UnicodeString(cal.getType()));
242     }
243   }
244   delete grego;
245   CHECK(status, "err during quasiGregorianTest()");
246 }
247 
248 // Verify that Gregorian works like Gregorian
TestGregorian()249 void IntlCalendarTest::TestGregorian() {
250     UDate timeA = Calendar::getNow();
251     int32_t data[] = {
252         GregorianCalendar::AD, 1868, 1868, UCAL_SEPTEMBER, 8,
253         GregorianCalendar::AD, 1868, 1868, UCAL_SEPTEMBER, 9,
254         GregorianCalendar::AD, 1869, 1869, UCAL_JUNE, 4,
255         GregorianCalendar::AD, 1912, 1912, UCAL_JULY, 29,
256         GregorianCalendar::AD, 1912, 1912, UCAL_JULY, 30,
257         GregorianCalendar::AD, 1912, 1912, UCAL_AUGUST, 1,
258         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
259     };
260 
261     Calendar *cal;
262     UErrorCode status = U_ZERO_ERROR;
263     cal = Calendar::createInstance(/*"de_DE", */ status);
264     CHECK(status, UnicodeString("Creating de_CH calendar"));
265     // Sanity check the calendar
266     UDate timeB = Calendar::getNow();
267     UDate timeCal = cal->getTime(status);
268 
269     if(!(timeA <= timeCal) || !(timeCal <= timeB)) {
270       errln((UnicodeString)"Error: Calendar time " + timeCal +
271             " is not within sampled times [" + timeA + " to " + timeB + "]!");
272     }
273     // end sanity check
274 
275     // Note, the following is a good way to test the sanity of the constructed calendars,
276     // using Collation as a delay-loop:
277     //
278     // $ intltest  format/IntlCalendarTest  collate/G7CollationTest format/IntlCalendarTest
279 
280     quasiGregorianTest(*cal,Locale("fr_FR"),data);
281     delete cal;
282 }
283 
284 /**
285  * Verify that BuddhistCalendar shifts years to Buddhist Era but otherwise
286  * behaves like GregorianCalendar.
287  */
TestBuddhist()288 void IntlCalendarTest::TestBuddhist() {
289     // BE 2542 == 1999 CE
290     UDate timeA = Calendar::getNow();
291 
292     int32_t data[] = {
293         0,           // B. era   [928479600000]
294         2542,        // B. year
295         1999,        // G. year
296         UCAL_JUNE,   // month
297         4,           // day
298 
299         0,           // B. era   [-79204842000000]
300         3,           // B. year
301         -540,        // G. year
302         UCAL_FEBRUARY, // month
303         12,          // day
304 
305         0,           // test month calculation:  4795 BE = 4252 AD is a leap year, but 4795 AD is not.
306         4795,        // BE [72018057600000]
307         4252,        // AD
308         UCAL_FEBRUARY,
309         29,
310 
311         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1
312     };
313     Calendar *cal;
314     UErrorCode status = U_ZERO_ERROR;
315     cal = Calendar::createInstance("th_TH@calendar=buddhist", status);
316     CHECK(status, UnicodeString("Creating th_TH@calendar=buddhist calendar"));
317 
318     // Sanity check the calendar
319     UDate timeB = Calendar::getNow();
320     UDate timeCal = cal->getTime(status);
321 
322     if(!(timeA <= timeCal) || !(timeCal <= timeB)) {
323       errln((UnicodeString)"Error: Calendar time " + timeCal +
324             " is not within sampled times [" + timeA + " to " + timeB + "]!");
325     }
326     // end sanity check
327 
328 
329     quasiGregorianTest(*cal,Locale("th_TH@calendar=gregorian"),data);
330     delete cal;
331 }
332 
333 
334 /**
335  * Verify that TaiWanCalendar shifts years to Minguo Era but otherwise
336  * behaves like GregorianCalendar.
337  */
TestTaiwan()338 void IntlCalendarTest::TestTaiwan() {
339     // MG 1 == 1912 AD
340     UDate timeA = Calendar::getNow();
341 
342     // TODO port these to the data items
343     int32_t data[] = {
344         1,           // B. era   [928479600000]
345         1,        // B. year
346         1912,        // G. year
347         UCAL_JUNE,   // month
348         4,           // day
349 
350         1,           // B. era   [-79204842000000]
351         3,           // B. year
352         1914,        // G. year
353         UCAL_FEBRUARY, // month
354         12,          // day
355 
356         1,           // B. era   [-79204842000000]
357         96,           // B. year
358         2007,        // G. year
359         UCAL_FEBRUARY, // month
360         12,          // day
361 
362         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1
363     };
364     Calendar *cal;
365     UErrorCode status = U_ZERO_ERROR;
366     cal = Calendar::createInstance("en_US@calendar=roc", status);
367     CHECK(status, UnicodeString("Creating en_US@calendar=roc calendar"));
368 
369     // Sanity check the calendar
370     UDate timeB = Calendar::getNow();
371     UDate timeCal = cal->getTime(status);
372 
373     if(!(timeA <= timeCal) || !(timeCal <= timeB)) {
374       errln((UnicodeString)"Error: Calendar time " + timeCal +
375             " is not within sampled times [" + timeA + " to " + timeB + "]!");
376     }
377     // end sanity check
378 
379 
380     quasiGregorianTest(*cal,Locale("en_US"),data);
381     delete cal;
382 }
383 
384 
385 
386 /**
387  * Verify that JapaneseCalendar shifts years to Japanese Eras but otherwise
388  * behaves like GregorianCalendar.
389  */
TestJapanese()390 void IntlCalendarTest::TestJapanese() {
391     UDate timeA = Calendar::getNow();
392 
393     /* Sorry.. japancal.h is private! */
394 #define JapaneseCalendar_MEIJI  232
395 #define JapaneseCalendar_TAISHO 233
396 #define JapaneseCalendar_SHOWA  234
397 #define JapaneseCalendar_HEISEI 235
398 
399     // BE 2542 == 1999 CE
400     int32_t data[] = {
401         //       Jera         Jyr  Gyear   m             d
402         JapaneseCalendar_MEIJI, 1, 1868, UCAL_SEPTEMBER, 8,
403         JapaneseCalendar_MEIJI, 1, 1868, UCAL_SEPTEMBER, 9,
404         JapaneseCalendar_MEIJI, 2, 1869, UCAL_JUNE, 4,
405         JapaneseCalendar_MEIJI, 45, 1912, UCAL_JULY, 29,
406         JapaneseCalendar_TAISHO, 1, 1912, UCAL_JULY, 30,
407         JapaneseCalendar_TAISHO, 1, 1912, UCAL_AUGUST, 1,
408 
409         // new tests (not in java)
410         JapaneseCalendar_SHOWA,     64,   1989,  UCAL_JANUARY, 7,  // Test current era transition (different code path than others)
411         JapaneseCalendar_HEISEI,    1,   1989,  UCAL_JANUARY, 8,
412         JapaneseCalendar_HEISEI,    1,   1989,  UCAL_JANUARY, 9,
413         JapaneseCalendar_HEISEI,    1,   1989,  UCAL_DECEMBER, 20,
414         JapaneseCalendar_HEISEI,  15,  2003,  UCAL_MAY, 22,
415         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1
416     };
417 
418     Calendar *cal;
419     UErrorCode status = U_ZERO_ERROR;
420     cal = Calendar::createInstance("ja_JP@calendar=japanese", status);
421     CHECK(status, UnicodeString("Creating ja_JP@calendar=japanese calendar"));
422     // Sanity check the calendar
423     UDate timeB = Calendar::getNow();
424     UDate timeCal = cal->getTime(status);
425 
426     if(!(timeA <= timeCal) || !(timeCal <= timeB)) {
427       errln((UnicodeString)"Error: Calendar time " + timeCal +
428             " is not within sampled times [" + timeA + " to " + timeB + "]!");
429     }
430     // end sanity check
431     quasiGregorianTest(*cal,Locale("ja_JP"),data);
432     delete cal;
433 }
434 
435 
436 
TestBuddhistFormat()437 void IntlCalendarTest::TestBuddhistFormat() {
438     UErrorCode status = U_ZERO_ERROR;
439 
440     // Test simple parse/format with adopt
441 
442     // First, a contrived English test..
443     UDate aDate = 999932400000.0;
444     SimpleDateFormat fmt(UnicodeString("MMMM d, yyyy G"), Locale("en_US@calendar=buddhist"), status);
445     CHECK(status, "creating date format instance");
446     SimpleDateFormat fmt2(UnicodeString("MMMM d, yyyy G"), Locale("en_US@calendar=gregorian"), status);
447     CHECK(status, "creating gregorian date format instance");
448     UnicodeString str;
449     fmt2.format(aDate, str);
450     logln(UnicodeString() + "Test Date: " + str);
451     str.remove();
452     fmt.format(aDate, str);
453     logln(UnicodeString() + "as Buddhist Calendar: " + escape(str));
454     UnicodeString expected("September 8, 2544 BE");
455     if(str != expected) {
456         errln("Expected " + escape(expected) + " but got " + escape(str));
457     }
458     UDate otherDate = fmt.parse(expected, status);
459     if(otherDate != aDate) {
460         UnicodeString str3;
461         fmt.format(otherDate, str3);
462         errln("Parse incorrect of " + escape(expected) + " - wanted " + aDate + " but got " +  otherDate + ", " + escape(str3));
463     } else {
464         logln("Parsed OK: " + expected);
465     }
466 
467     CHECK(status, "Error occurred testing Buddhist Calendar in English ");
468 
469     status = U_ZERO_ERROR;
470     // Now, try in Thai
471     {
472         UnicodeString expect = CharsToUnicodeString("\\u0E27\\u0E31\\u0E19\\u0E40\\u0E2A\\u0E32\\u0E23\\u0E4C\\u0E17\\u0E35\\u0E48"
473             " 8 \\u0E01\\u0E31\\u0e19\\u0e22\\u0e32\\u0e22\\u0e19 \\u0e1e.\\u0e28. 2544");
474         UDate         expectDate = 999932400000.0;
475         // Android-changed: Default calendar on Android is Gregorian.
476         // Locale        loc("th_TH_TRADITIONAL"); // legacy
477         Locale        loc("th_TH_TRADITIONAL@calendar=buddhist"); // legacy
478 
479         simpleTest(loc, expect, expectDate, status);
480     }
481     status = U_ZERO_ERROR;
482     {
483         UnicodeString expect = CharsToUnicodeString("\\u0E27\\u0E31\\u0E19\\u0E40\\u0E2A\\u0E32\\u0E23\\u0E4C\\u0E17\\u0E35\\u0E48"
484             " 8 \\u0E01\\u0E31\\u0e19\\u0e22\\u0e32\\u0e22\\u0e19 \\u0e1e.\\u0e28. 2544");
485         UDate         expectDate = 999932400000.0;
486         Locale        loc("th_TH@calendar=buddhist");
487 
488         simpleTest(loc, expect, expectDate, status);
489     }
490     status = U_ZERO_ERROR;
491     {
492         UnicodeString expect = CharsToUnicodeString("\\u0E27\\u0E31\\u0E19\\u0E40\\u0E2A\\u0E32\\u0E23\\u0E4C\\u0E17\\u0E35\\u0E48"
493             " 8 \\u0E01\\u0E31\\u0e19\\u0e22\\u0e32\\u0e22\\u0e19 \\u0e04.\\u0e28. 2001");
494         UDate         expectDate = 999932400000.0;
495         Locale        loc("th_TH@calendar=gregorian");
496 
497         simpleTest(loc, expect, expectDate, status);
498     }
499     status = U_ZERO_ERROR;
500     {
501         UnicodeString expect = CharsToUnicodeString("\\u0E27\\u0E31\\u0E19\\u0E40\\u0E2A\\u0E32\\u0E23\\u0E4C\\u0E17\\u0E35\\u0E48"
502             " 8 \\u0E01\\u0E31\\u0e19\\u0e22\\u0e32\\u0e22\\u0e19 \\u0e04.\\u0e28. 2001");
503         UDate         expectDate = 999932400000.0;
504         Locale        loc("th_TH_TRADITIONAL@calendar=gregorian");
505 
506         simpleTest(loc, expect, expectDate, status);
507     }
508 }
509 
510 // TaiwanFormat has been moved to testdata/format.txt
511 
512 
TestJapaneseFormat()513 void IntlCalendarTest::TestJapaneseFormat() {
514     LocalPointer<Calendar> cal;
515     UErrorCode status = U_ZERO_ERROR;
516     cal.adoptInstead(Calendar::createInstance("ja_JP@calendar=japanese", status));
517     CHECK(status, UnicodeString("Creating ja_JP@calendar=japanese calendar"));
518 
519     LocalPointer<Calendar> cal2(cal->clone());
520     cal.adoptInstead(nullptr);
521 
522     // Test simple parse/format with adopt
523 
524     UDate aDate = 999932400000.0;
525     SimpleDateFormat fmt(UnicodeString("MMMM d, yy G"), Locale("en_US@calendar=japanese"), status);
526     SimpleDateFormat fmt2(UnicodeString("MMMM d, yyyy G"), Locale("en_US@calendar=gregorian"), status);
527     CHECK(status, "creating date format instance");
528     UnicodeString str;
529     fmt2.format(aDate, str);
530     logln(UnicodeString() + "Test Date: " + str);
531     str.remove();
532     fmt.format(aDate, str);
533     logln(UnicodeString() + "as Japanese Calendar: " + str);
534     UnicodeString expected("September 8, 13 Heisei");
535     if(str != expected) {
536         errln("Expected " + expected + " but got " + str);
537     }
538     UDate otherDate = fmt.parse(expected, status);
539     if(otherDate != aDate) {
540         UnicodeString str3;
541         ParsePosition pp;
542         fmt.parse(expected, *cal2, pp);
543         fmt.format(otherDate, str3);
544         errln("Parse incorrect of " + expected + " - wanted " + aDate + " but got " +  " = " +   otherDate + ", " + str3 + " = " + CalendarTest::calToStr(*cal2) );
545 
546     } else {
547         logln("Parsed OK: " + expected);
548     }
549 
550     // Test parse with incomplete information
551     SimpleDateFormat fmti(UnicodeString("G y"), Locale("en_US@calendar=japanese"), status);
552     aDate = -3197117222000.0;
553     CHECK(status, "creating date format instance");
554     str.remove();
555     fmt2.format(aDate, str);
556     logln(UnicodeString() + "Test Date: " + str);
557     str.remove();
558     fmti.format(aDate, str);
559     logln(UnicodeString() + "as Japanese Calendar: " + str);
560     expected = u"Meiji 1";
561     if(str != expected) {
562         errln("Expected " + expected + " but got " + str);
563     }
564     otherDate = fmti.parse(expected, status);
565     if(otherDate != aDate) {
566         UnicodeString str3;
567         ParsePosition pp;
568         fmti.parse(expected, *cal2, pp);
569         fmti.format(otherDate, str3);
570         errln("Parse incorrect of " + expected + " - wanted " + aDate + " but got " +  " = " +
571                 otherDate + ", " + str3 + " = " + CalendarTest::calToStr(*cal2) );
572     } else {
573         logln("Parsed OK: " + expected);
574     }
575 
576     CHECK(status, "Error occurred");
577 
578     // Now, try in Japanese
579     {
580         UnicodeString expect = CharsToUnicodeString("\\u5e73\\u621013\\u5e749\\u67088\\u65e5\\u571f\\u66dc\\u65e5");
581         UDate         expectDate = 999932400000.0; // Testing a recent date
582         Locale        loc("ja_JP@calendar=japanese");
583 
584         status = U_ZERO_ERROR;
585         simpleTest(loc, expect, expectDate, status);
586     }
587     {
588         UnicodeString expect = CharsToUnicodeString("\\u5e73\\u621013\\u5e749\\u67088\\u65e5\\u571f\\u66dc\\u65e5");
589         UDate         expectDate = 999932400000.0; // Testing a recent date
590         Locale        loc("ja_JP@calendar=japanese");
591 
592         status = U_ZERO_ERROR;
593         simpleTest(loc, expect, expectDate, status);
594     }
595     {
596         UnicodeString expect = CharsToUnicodeString("\\u5b89\\u6c385\\u5e747\\u67084\\u65e5\\u6728\\u66dc\\u65e5");
597         UDate         expectDate = -6106032422000.0; // 1776-07-04T00:00:00Z-075258
598         Locale        loc("ja_JP@calendar=japanese");
599 
600         status = U_ZERO_ERROR;
601         simpleTest(loc, expect, expectDate, status);
602 
603     }
604     {   // Jitterbug 1869 - this is an ambiguous era. (Showa 64 = Jan 6 1989, but Showa could be 2 other eras) )
605         UnicodeString expect = CharsToUnicodeString("\\u662d\\u548c64\\u5e741\\u67086\\u65e5\\u91d1\\u66dc\\u65e5");
606         UDate         expectDate = 600076800000.0;
607         Locale        loc("ja_JP@calendar=japanese");
608 
609         status = U_ZERO_ERROR;
610         simpleTest(loc, expect, expectDate, status);
611 
612     }
613     {   // 1989 Jan 9 Monday = Heisei 1; full is Gy年M月d日EEEE => 平成元年1月9日月曜日
614         UnicodeString expect = CharsToUnicodeString("\\u5E73\\u6210\\u5143\\u5E741\\u67089\\u65E5\\u6708\\u66DC\\u65E5");
615         UDate         expectDate = 600336000000.0;
616         Locale        loc("ja_JP@calendar=japanese");
617 
618         status = U_ZERO_ERROR;
619         simpleTest(loc, expect, expectDate, status);
620 
621     }
622     {   // This Feb 29th falls on a leap year by gregorian year, but not by Japanese year.
623         UnicodeString expect = CharsToUnicodeString("\\u5EB7\\u6B632\\u5e742\\u670829\\u65e5\\u65e5\\u66dc\\u65e5");
624         UDate         expectDate =  -16214400422000.0;  // 1456-03-09T00:00Z-075258
625         Locale        loc("ja_JP@calendar=japanese");
626 
627         status = U_ZERO_ERROR;
628         simpleTest(loc, expect, expectDate, status);
629 
630     }
631 }
632 
TestJapanese3860()633 void IntlCalendarTest::TestJapanese3860()
634 {
635     LocalPointer<Calendar> cal;
636     UErrorCode status = U_ZERO_ERROR;
637     cal.adoptInstead(Calendar::createInstance("ja_JP@calendar=japanese", status));
638     CHECK(status, UnicodeString("Creating ja_JP@calendar=japanese calendar"));
639     LocalPointer<Calendar> cal2(cal->clone());
640     SimpleDateFormat fmt2(UnicodeString("HH:mm:ss.S MMMM d, yyyy G"), Locale("en_US@calendar=gregorian"), status);
641     UnicodeString str;
642 
643     {
644         // Test simple parse/format with adopt
645         UDate aDate = 0;
646 
647         // Test parse with missing era (should default to current era, heisei)
648         // Test parse with incomplete information
649         logln("Testing parse w/ missing era...");
650         SimpleDateFormat fmt(UnicodeString("y/M/d"), Locale("ja_JP@calendar=japanese"), status);
651         CHECK(status, "creating date format instance");
652         UErrorCode s2 = U_ZERO_ERROR;
653         cal2->clear();
654         UnicodeString samplestr("1/5/9");
655         logln(UnicodeString() + "Test Year: " + samplestr);
656         aDate = fmt.parse(samplestr, s2);
657         ParsePosition pp=0;
658         fmt.parse(samplestr, *cal2, pp);
659         CHECK(s2, "parsing the 1/5/9 string");
660         logln("*cal2 after 159 parse:");
661         str.remove();
662         fmt2.format(aDate, str);
663         logln(UnicodeString() + "as Gregorian Calendar: " + str);
664 
665         cal2->setTime(aDate, s2);
666         int32_t gotYear = cal2->get(UCAL_YEAR, s2);
667         int32_t gotEra = cal2->get(UCAL_ERA, s2);
668         int32_t expectYear = 1;
669         int32_t expectEra = JapaneseCalendar::getCurrentEra();
670         if((gotYear!=1) || (gotEra != expectEra)) {
671             errln(UnicodeString("parse "+samplestr+" of 'y/M/d' as Japanese Calendar, expected year ") + expectYear +
672                     UnicodeString(" and era ") + expectEra +", but got year " + gotYear + " and era " + gotEra + " (Gregorian:" + str +")");
673         } else {
674             logln(UnicodeString() + " year: " + gotYear + ", era: " + gotEra);
675         }
676     }
677 
678     {
679         // Test simple parse/format with adopt
680         UDate aDate = 0;
681 
682         // Test parse with missing era (should default to current era, heisei)
683         // Test parse with incomplete information
684         logln("Testing parse w/ just year...");
685         SimpleDateFormat fmt(UnicodeString("y"), Locale("ja_JP@calendar=japanese"), status);
686         CHECK(status, "creating date format instance");
687         UErrorCode s2 = U_ZERO_ERROR;
688         cal2->clear();
689         UnicodeString samplestr("1");
690         logln(UnicodeString() + "Test Year: " + samplestr);
691         aDate = fmt.parse(samplestr, s2);
692         ParsePosition pp=0;
693         fmt.parse(samplestr, *cal2, pp);
694         CHECK(s2, "parsing the 1 string");
695         logln("*cal2 after 1 parse:");
696         str.remove();
697         fmt2.format(aDate, str);
698         logln(UnicodeString() + "as Gregorian Calendar: " + str);
699 
700         cal2->setTime(aDate, s2);
701         int32_t gotYear = cal2->get(UCAL_YEAR, s2);
702         int32_t gotEra = cal2->get(UCAL_ERA, s2);
703         int32_t expectYear = 1;
704         int32_t expectEra = JapaneseCalendar::getCurrentEra();
705         if((gotYear!=1) || (gotEra != expectEra)) {
706             errln(UnicodeString("parse "+samplestr+" of 'y' as Japanese Calendar, expected year ") + expectYear +
707                     UnicodeString(" and era ") + expectEra +", but got year " + gotYear + " and era " + gotEra + " (Gregorian:" + str +")");
708         } else {
709             logln(UnicodeString() + " year: " + gotYear + ", era: " + gotEra);
710         }
711     }
712 }
713 
TestForceGannenNumbering()714 void IntlCalendarTest::TestForceGannenNumbering()
715 {
716     UErrorCode status;
717     const char* locID = "ja_JP@calendar=japanese";
718     Locale loc(locID);
719     UDate refDate = 600336000000.0; // 1989 Jan 9 Monday = Heisei 1
720     UnicodeString patText(u"Gy年M月d日",-1);
721     UnicodeString patNumr(u"GGGGGy/MM/dd",-1);
722     UnicodeString skelText(u"yMMMM",-1);
723 
724     // Test Gannen year forcing
725     status = U_ZERO_ERROR;
726     LocalPointer<SimpleDateFormat> testFmt1(new SimpleDateFormat(patText, loc, status));
727     LocalPointer<SimpleDateFormat> testFmt2(new SimpleDateFormat(patNumr, loc, status));
728     if (U_FAILURE(status)) {
729         dataerrln("Fail in new SimpleDateFormat locale %s: %s", locID, u_errorName(status));
730     } else {
731         UnicodeString testString1, testString2;
732         testString1 = testFmt1->format(refDate, testString1);
733         if (testString1.length() < 3 || testString1.charAt(2) != 0x5143) {
734             errln(UnicodeString("Formatting year 1 in created text style, got " + testString1 + " but expected 3rd char to be 0x5143"));
735         }
736         testString2 = testFmt2->format(refDate, testString2);
737         if (testString2.length() < 2 || testString2.charAt(1) != 0x0031) {
738             errln(UnicodeString("Formatting year 1 in created numeric style, got " + testString2 + " but expected 2nd char to be 1"));
739         }
740         // Now switch the patterns and verify that Gannen use follows the pattern
741         testFmt1->applyPattern(patNumr);
742         testString1.remove();
743         testString1 = testFmt1->format(refDate, testString1);
744         if (testString1.length() < 2 || testString1.charAt(1) != 0x0031) {
745             errln(UnicodeString("Formatting year 1 in applied numeric style, got " + testString1 + " but expected 2nd char to be 1"));
746         }
747         testFmt2->applyPattern(patText);
748         testString2.remove();
749         testString2 = testFmt2->format(refDate, testString2);
750         if (testString2.length() < 3 || testString2.charAt(2) != 0x5143) {
751             errln(UnicodeString("Formatting year 1 in applied text style, got " + testString2 + " but expected 3rd char to be 0x5143"));
752         }
753     }
754 
755     // Test disabling of Gannen year forcing
756     status = U_ZERO_ERROR;
757     LocalPointer<DateTimePatternGenerator> dtpgen(DateTimePatternGenerator::createInstance(loc, status));
758     if (U_FAILURE(status)) {
759         dataerrln("Fail in DateTimePatternGenerator::createInstance locale %s: %s", locID, u_errorName(status));
760     } else {
761         UnicodeString pattern = dtpgen->getBestPattern(skelText, status);
762         if (U_FAILURE(status)) {
763             dataerrln("Fail in DateTimePatternGenerator::getBestPattern locale %s: %s", locID, u_errorName(status));
764         } else  {
765             // Use override string of ""
766             LocalPointer<SimpleDateFormat> testFmt3(new SimpleDateFormat(pattern, UnicodeString(""), loc, status));
767             if (U_FAILURE(status)) {
768                 dataerrln("Fail in new SimpleDateFormat locale %s: %s", locID, u_errorName(status));
769             } else {
770                 UnicodeString testString3;
771                 testString3 = testFmt3->format(refDate, testString3);
772                 if (testString3.length() < 3 || testString3.charAt(2) != 0x0031) {
773                     errln(UnicodeString("Formatting year 1 with Gannen disabled, got " + testString3 + " but expected 3rd char to be 1"));
774                 }
775             }
776         }
777     }
778 }
779 
780 /**
781  * Verify the Persian Calendar.
782  */
TestPersian()783 void IntlCalendarTest::TestPersian() {
784     UDate timeA = Calendar::getNow();
785 
786     Calendar *cal;
787     UErrorCode status = U_ZERO_ERROR;
788     cal = Calendar::createInstance("fa_IR@calendar=persian", status);
789     CHECK(status, UnicodeString("Creating fa_IR@calendar=persian calendar"));
790     // Sanity check the calendar
791     UDate timeB = Calendar::getNow();
792     UDate timeCal = cal->getTime(status);
793 
794     if(!(timeA <= timeCal) || !(timeCal <= timeB)) {
795       errln((UnicodeString)"Error: Calendar time " + timeCal +
796             " is not within sampled times [" + timeA + " to " + timeB + "]!");
797     }
798     // end sanity check
799 
800     // Test various dates to be sure of validity
801     int32_t data[] = {
802         1925, 4, 24, 1304, 2, 4,
803         2011, 1, 11, 1389, 10, 21,
804         1986, 2, 25, 1364, 12, 6,
805         1934, 3, 14, 1312, 12, 23,
806 
807         2090, 3, 19, 1468, 12, 29,
808         2007, 2, 22, 1385, 12, 3,
809         1969, 12, 31, 1348, 10, 10,
810         1945, 11, 12, 1324, 8, 21,
811         1925, 3, 31, 1304, 1, 11,
812 
813         1996, 3, 19, 1374, 12, 29,
814         1996, 3, 20, 1375, 1, 1,
815         1997, 3, 20, 1375, 12, 30,
816         1997, 3, 21, 1376, 1, 1,
817 
818         2008, 3, 19, 1386, 12, 29,
819         2008, 3, 20, 1387, 1, 1,
820         2004, 3, 19, 1382, 12, 29,
821         2004, 3, 20, 1383, 1, 1,
822 
823         2006, 3, 20, 1384, 12, 29,
824         2006, 3, 21, 1385, 1, 1,
825 
826         2005, 4, 20, 1384, 1, 31,
827         2005, 4, 21, 1384, 2, 1,
828         2005, 5, 21, 1384, 2, 31,
829         2005, 5, 22, 1384, 3, 1,
830         2005, 6, 21, 1384, 3, 31,
831         2005, 6, 22, 1384, 4, 1,
832         2005, 7, 22, 1384, 4, 31,
833         2005, 7, 23, 1384, 5, 1,
834         2005, 8, 22, 1384, 5, 31,
835         2005, 8, 23, 1384, 6, 1,
836         2005, 9, 22, 1384, 6, 31,
837         2005, 9, 23, 1384, 7, 1,
838         2005, 10, 22, 1384, 7, 30,
839         2005, 10, 23, 1384, 8, 1,
840         2005, 11, 21, 1384, 8, 30,
841         2005, 11, 22, 1384, 9, 1,
842         2005, 12, 21, 1384, 9, 30,
843         2005, 12, 22, 1384, 10, 1,
844         2006, 1, 20, 1384, 10, 30,
845         2006, 1, 21, 1384, 11, 1,
846         2006, 2, 19, 1384, 11, 30,
847         2006, 2, 20, 1384, 12, 1,
848         2006, 3, 20, 1384, 12, 29,
849         2006, 3, 21, 1385, 1, 1,
850 
851         // The 2820-year cycle arithmetical algorithm would fail this one.
852         2025, 3, 21, 1404, 1, 1,
853 
854         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1
855     };
856 
857     Calendar *grego = Calendar::createInstance("fa_IR@calendar=gregorian", status);
858     for (int32_t i=0; data[i]!=-1; ) {
859         int32_t gregYear = data[i++];
860         int32_t gregMonth = data[i++]-1;
861         int32_t gregDay = data[i++];
862         int32_t persYear = data[i++];
863         int32_t persMonth = data[i++]-1;
864         int32_t persDay = data[i++];
865 
866         // Test conversion from Persian dates
867         grego->clear();
868         grego->set(gregYear, gregMonth, gregDay);
869 
870         cal->clear();
871         cal->set(persYear, persMonth, persDay);
872 
873         UDate persTime = cal->getTime(status);
874         UDate gregTime = grego->getTime(status);
875 
876         if (persTime != gregTime) {
877           errln(UnicodeString("Expected ") + gregTime + " but got " + persTime);
878         }
879 
880         // Test conversion to Persian dates
881         cal->clear();
882         cal->setTime(gregTime, status);
883 
884         int32_t computedYear = cal->get(UCAL_YEAR, status);
885         int32_t computedMonth = cal->get(UCAL_MONTH, status);
886         int32_t computedDay = cal->get(UCAL_DATE, status);
887 
888         if ((persYear != computedYear) ||
889             (persMonth != computedMonth) ||
890             (persDay != computedDay)) {
891           errln(UnicodeString("Expected ") + persYear + "/" + (persMonth+1) + "/" + persDay +
892                 " but got " +  computedYear + "/" + (computedMonth+1) + "/" + computedDay);
893         }
894 
895     }
896 
897     delete cal;
898     delete grego;
899 }
900 
TestPersianFormat()901 void IntlCalendarTest::TestPersianFormat() {
902     UErrorCode status = U_ZERO_ERROR;
903     SimpleDateFormat fmt(UnicodeString("MMMM d, yyyy G"), Locale(" en_US@calendar=persian"), status);
904     CHECK(status, "creating date format instance");
905     SimpleDateFormat fmt2(UnicodeString("MMMM d, yyyy G"), Locale("en_US@calendar=gregorian"), status);
906     CHECK(status, "creating gregorian date format instance");
907     UnicodeString gregorianDate("January 18, 2007 AD");
908     UDate aDate = fmt2.parse(gregorianDate, status);
909     UnicodeString str;
910     fmt.format(aDate, str);
911     logln(UnicodeString() + "as Persian Calendar: " + escape(str));
912     UnicodeString expected("Dey 28, 1385 AP");
913     if(str != expected) {
914         errln("Expected " + escape(expected) + " but got " + escape(str));
915     }
916     UDate otherDate = fmt.parse(expected, status);
917     if(otherDate != aDate) {
918         UnicodeString str3;
919         fmt.format(otherDate, str3);
920         errln("Parse incorrect of " + escape(expected) + " - wanted " + aDate + " but got " +  otherDate + ", " + escape(str3));
921     } else {
922         logln("Parsed OK: " + expected);
923     }
924     // Two digit year parsing problem #4732
925     fmt.applyPattern("yy-MM-dd");
926     str.remove();
927     fmt.format(aDate, str);
928     expected.setTo("85-10-28");
929     if(str != expected) {
930         errln("Expected " + escape(expected) + " but got " + escape(str));
931     }
932     otherDate = fmt.parse(expected, status);
933     if (otherDate != aDate) {
934         errln("Parse incorrect of " + escape(expected) + " - wanted " + aDate + " but got " + otherDate);
935     } else {
936         logln("Parsed OK: " + expected);
937     }
938 
939     CHECK(status, "Error occurred testing Persian Calendar in English ");
940 }
941 
TestConsistencyGregorian()942 void IntlCalendarTest::TestConsistencyGregorian() {
943     checkConsistency("en@calendar=gregorian");
944 }
TestConsistencyIndian()945 void IntlCalendarTest::TestConsistencyIndian() {
946     checkConsistency("en@calendar=indian");
947 }
TestConsistencyHebrew()948 void IntlCalendarTest::TestConsistencyHebrew() {
949     checkConsistency("en@calendar=hebrew");
950 }
TestConsistencyIslamic()951 void IntlCalendarTest::TestConsistencyIslamic() {
952     checkConsistency("en@calendar=islamic");
953 }
TestConsistencyIslamicRGSA()954 void IntlCalendarTest::TestConsistencyIslamicRGSA() {
955     checkConsistency("en@calendar=islamic-rgsa");
956 }
TestConsistencyIslamicTBLA()957 void IntlCalendarTest::TestConsistencyIslamicTBLA() {
958     checkConsistency("en@calendar=islamic-tbla");
959 }
TestConsistencyIslamicUmalqura()960 void IntlCalendarTest::TestConsistencyIslamicUmalqura() {
961     checkConsistency("en@calendar=islamic-umalqura");
962 }
TestConsistencyIslamicCivil()963 void IntlCalendarTest::TestConsistencyIslamicCivil() {
964     checkConsistency("en@calendar=islamic-civil");
965 }
TestConsistencyCoptic()966 void IntlCalendarTest::TestConsistencyCoptic() {
967     checkConsistency("en@calendar=coptic");
968 }
TestConsistencyEthiopic()969 void IntlCalendarTest::TestConsistencyEthiopic() {
970     checkConsistency("en@calendar=ethiopic");
971 }
TestConsistencyROC()972 void IntlCalendarTest::TestConsistencyROC() {
973     checkConsistency("en@calendar=roc");
974 }
TestConsistencyChinese()975 void IntlCalendarTest::TestConsistencyChinese() {
976     checkConsistency("en@calendar=chinese");
977 }
TestConsistencyDangi()978 void IntlCalendarTest::TestConsistencyDangi() {
979     checkConsistency("en@calendar=dangi");
980 }
TestConsistencyPersian()981 void IntlCalendarTest::TestConsistencyPersian() {
982     checkConsistency("en@calendar=persian");
983 }
TestConsistencyBuddhist()984 void IntlCalendarTest::TestConsistencyBuddhist() {
985     checkConsistency("en@calendar=buddhist");
986 }
TestConsistencyJapanese()987 void IntlCalendarTest::TestConsistencyJapanese() {
988     checkConsistency("en@calendar=japanese");
989 }
TestConsistencyEthiopicAmeteAlem()990 void IntlCalendarTest::TestConsistencyEthiopicAmeteAlem() {
991     checkConsistency("en@calendar=ethiopic-amete-alem");
992 }
checkConsistency(const char * locale)993 void IntlCalendarTest::checkConsistency(const char* locale) {
994     // Check 2.5 years in quick mode and 6000 years in exhaustive mode.
995     int32_t numOfDaysToTest = static_cast<int32_t>((quick ? 2.5 : 6000) * 365);
996     constexpr int32_t msInADay = 1000*60*60*24;
997     std::string msg("TestConsistency");
998     IcuTestErrorCode status(*this, (msg + locale).c_str());
999     // g is just for debugging messages.
1000     std::unique_ptr<Calendar> g(Calendar::createInstance("en", status));
1001     g->setTimeZone(*(TimeZone::getGMT()));
1002     std::unique_ptr<Calendar> base(Calendar::createInstance(locale, status));
1003     if (status.errIfFailureAndReset("Cannot create calendar %s", locale)) {
1004         return;
1005     }
1006     const char* type = base->getType();
1007     // Do not ignore in quick mode
1008     bool ignoreOrdinaryMonth12Bug = (!quick) && (strcmp("chinese", type) == 0 || strcmp("dangi", type) == 0);
1009     UDate test = Calendar::getNow();
1010     base->setTimeZone(*(TimeZone::getGMT()));
1011     int32_t j;
1012     int lastDay = 1;
1013     std::unique_ptr<Calendar> r(base->clone());
1014     for (j = 0; j < numOfDaysToTest; j++, test -= msInADay) {
1015         status.errIfFailureAndReset();
1016         g->setTime(test, status);
1017         if (status.errIfFailureAndReset("Cannot set time")) {
1018             return;
1019         }
1020         base->clear();
1021         base->setTime(test, status);
1022         if (status.errIfFailureAndReset("Cannot set time")) {
1023             return;
1024         }
1025         // First, we verify the date from base is decrease one day from the
1026         // last day unless the last day is 1.
1027         int32_t cday = base->get(UCAL_DATE, status);
1028         if (U_FAILURE(status)) {
1029            UErrorCode localStatus = U_ZERO_ERROR;
1030            if (status.errIfFailureAndReset(
1031                "Cannot get the %dth date for %f %d %d/%d/%d\n",
1032                j,
1033                test,
1034                g->get(UCAL_ERA, localStatus),
1035                g->get(UCAL_YEAR, localStatus),
1036                (g->get(UCAL_MONTH, localStatus) + 1),
1037                g->get(UCAL_DATE, localStatus))) {
1038                return;
1039            }
1040         }
1041         if (lastDay == 1) {
1042             lastDay = cday;
1043         } else {
1044             if (cday != lastDay-1) {
1045                 // Ignore if it is the last day before Gregorian Calendar switch on
1046                 // 1582 Oct 4
1047                 if (g->get(UCAL_YEAR, status) == 1582 &&
1048                     (g->get(UCAL_MONTH, status) + 1) == 10 &&
1049                     g->get(UCAL_DATE, status) == 4) {
1050                     lastDay = 5;
1051                 } else {
1052                     errln((UnicodeString)
1053                         "Day is not one less from previous date for "
1054                         "Gregorian(e=" + g->get(UCAL_ERA, status) + " " +
1055                         g->get(UCAL_YEAR, status) + "/" +
1056                         (g->get(UCAL_MONTH, status) + 1) + "/" +
1057                         g->get(UCAL_DATE, status) + ") " + locale + "(" +
1058                         base->get(UCAL_ERA, status) + " " +
1059                         base->get(UCAL_YEAR, status) + "/" +
1060                         (base->get(UCAL_MONTH, status) + 1 ) + "/" +
1061                         base->get(UCAL_DATE, status) + ")");
1062                     status.errIfFailureAndReset();
1063                     return;
1064                 }
1065             }
1066             lastDay--;
1067         }
1068         // Second, we verify the month is in reasonale range.
1069         int32_t cmonth = base->get(UCAL_MONTH, status);
1070         if (cmonth < 0 || cmonth > 13) {
1071             errln((UnicodeString)
1072                 "Month is out of range Gregorian(e=" +
1073                 g->get(UCAL_ERA, status) + " " +
1074                 g->get(UCAL_YEAR, status) + "/" +
1075                 (g->get(UCAL_MONTH, status) + 1) + "/" +
1076                 g->get(UCAL_DATE, status) + ") " + locale + "(" +
1077                 base->get(UCAL_ERA, status) + " " +
1078                 base->get(UCAL_YEAR, status) + "/" +
1079                 (base->get(UCAL_MONTH, status) + 1 ) + "/" +
1080                 base->get(UCAL_DATE, status) + ")");
1081             status.errIfFailureAndReset();
1082             return;
1083         }
1084         // Third, we verify the set function can round trip the time back.
1085         r->clear();
1086         for (int32_t f = 0; f < UCAL_FIELD_COUNT; f++) {
1087             UCalendarDateFields ut = (UCalendarDateFields)f;
1088             r->set(ut, base->get(ut, status));
1089         }
1090         UDate result = r->getTime(status);
1091         if (status.errIfFailureAndReset("Cannot get time %s", locale)) {
1092             return;
1093         }
1094         if (test != result) {
1095             if (ignoreOrdinaryMonth12Bug &&
1096                 base->get(UCAL_ORDINAL_MONTH, status) == 12) {
1097                 logKnownIssue("ICU-22230", "Problem December in Leap Year");
1098                 status.reset();
1099                 continue;
1100             }
1101             int32_t year = base->get(UCAL_YEAR, status);
1102             int32_t month = base->get(UCAL_MONTH, status) + 1;
1103             int32_t date = base->get(UCAL_DATE, status);
1104 
1105             errln((UnicodeString)"Round trip conversion produces different "
1106                   "time from " + test + " to  " + result + " delta: " +
1107                   (result - test) +
1108                   " Gregorian(e=" + g->get(UCAL_ERA, status) + " " +
1109                   g->get(UCAL_YEAR, status) + "/" +
1110                   (g->get(UCAL_MONTH, status) + 1) + "/" +
1111                   g->get(UCAL_DATE, status) + ") \n" +
1112                   " Calendar[" + base->getType() +
1113                   "](e=" + base->get(UCAL_ERA, status) + " " +
1114                   year + "/" + month + "/" + date +
1115                   ") ordinalMonth=" +
1116                   base->get(UCAL_ORDINAL_MONTH, status));
1117             status.errIfFailureAndReset();
1118         }
1119     }
1120 }
1121 
TestIslamicUmalquraCalendarSlow()1122 void IntlCalendarTest::TestIslamicUmalquraCalendarSlow() {
1123     IcuTestErrorCode status(*this, "TestIslamicUmalquraCalendarSlow");
1124     Locale l("th@calendar=islamic-umalqura");
1125     std::unique_ptr<Calendar> cal(
1126         Calendar::createInstance(l, status));
1127     cal->add(UCAL_YEAR, 1229080905, status);
1128     cal->roll(UCAL_WEEK_OF_MONTH, 1499050699, status);
1129     cal->fieldDifference(0.000000, UCAL_YEAR_WOY, status);
1130     // Ignore the error
1131     status.reset();
1132 }
1133 
TestJapaneseLargeEra()1134 void IntlCalendarTest::TestJapaneseLargeEra() {
1135     IcuTestErrorCode status(*this, "TestJapaneseLargeEra");
1136     Locale l("ja@calendar=japanese");
1137     std::unique_ptr<Calendar> cal(
1138         Calendar::createInstance(l, status));
1139     cal->clear();
1140     cal->set(UCAL_ERA, 2139062143);
1141     cal->add(UCAL_YEAR, 1229539657, status);
1142     status.expectErrorAndReset(U_ILLEGAL_ARGUMENT_ERROR);
1143 }
1144 
simpleTest(const Locale & loc,const UnicodeString & expect,UDate expectDate,UErrorCode & status)1145 void IntlCalendarTest::simpleTest(const Locale& loc, const UnicodeString& expect, UDate expectDate, UErrorCode& status)
1146 {
1147     UnicodeString tmp;
1148     UDate         d;
1149     DateFormat *fmt0 = DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull);
1150 
1151     logln("Try format/parse of " + (UnicodeString)loc.getName());
1152     DateFormat *fmt2 = DateFormat::createDateInstance(DateFormat::kFull, loc);
1153     if(fmt2) {
1154         fmt2->format(expectDate, tmp);
1155         logln(escape(tmp) + " ( in locale " + loc.getName() + ")");
1156         if(tmp != expect) {
1157             errln(UnicodeString("Failed to format " ) + loc.getName() + " expected " + escape(expect) + " got " + escape(tmp) );
1158         }
1159 
1160         d = fmt2->parse(expect,status);
1161         CHECK(status, "Error occurred parsing " + UnicodeString(loc.getName()));
1162         if(d != expectDate) {
1163             fmt2->format(d,tmp);
1164             errln(UnicodeString("Failed to parse " ) + escape(expect) + ", " + loc.getName() + " expect " + (double)expectDate + " got " + (double)d  + " " + escape(tmp));
1165             logln( "wanted " + escape(fmt0->format(expectDate,tmp.remove())) + " but got " + escape(fmt0->format(d,tmp.remove())));
1166         }
1167         delete fmt2;
1168     } else {
1169         errln((UnicodeString)"Can't create " + loc.getName() + " date instance");
1170     }
1171     delete fmt0;
1172 }
1173 
TestBug21043Indian()1174 void IntlCalendarTest::TestBug21043Indian() {
1175     IcuTestErrorCode status(*this, "TestBug21043Indian");
1176     std::unique_ptr<Calendar> cal(
1177         Calendar::createInstance("en@calendar=indian", status));
1178     std::unique_ptr<Calendar> g(
1179         Calendar::createInstance("en@calendar=gregorian", status));
1180     // set to 10 BC
1181     g->set(UCAL_ERA, 0);
1182     g->set(UCAL_YEAR, 10);
1183     g->set(UCAL_MONTH, 1);
1184     g->set(UCAL_DATE, 1);
1185     cal->setTime(g->getTime(status), status);
1186     int32_t m = cal->get(UCAL_MONTH, status);
1187     if (m < 0 || m > 11) {
1188         errln(
1189               u"Month should be between 0 and 11 in India calendar");
1190     }
1191 }
1192 
TestBug21044Hebrew()1193 void IntlCalendarTest::TestBug21044Hebrew() {
1194     IcuTestErrorCode status(*this, "TestBug21044Hebrew");
1195     std::unique_ptr<Calendar> cal(
1196         Calendar::createInstance("en@calendar=hebrew", status));
1197     std::unique_ptr<Calendar> g(
1198         Calendar::createInstance("en@calendar=gregorian", status));
1199     // set to 3771/10/27 BC which is before 3760 BC.
1200     g->set(UCAL_ERA, 0);
1201     g->set(UCAL_YEAR, 3771);
1202     g->set(UCAL_MONTH, 9);
1203     g->set(UCAL_DATE, 27);
1204     cal->setTime(g->getTime(status), status);
1205 
1206     if (status.errIfFailureAndReset(
1207         "Cannot set date. Got error %s", u_errorName(status))) {
1208         return;
1209     }
1210     int32_t y = cal->get(UCAL_YEAR, status);
1211     int32_t m = cal->get(UCAL_MONTH, status);
1212     int32_t d = cal->get(UCAL_DATE, status);
1213     if (status.errIfFailureAndReset(
1214         "Cannot get date. Got error %s", u_errorName(status))) {
1215         return;
1216    }
1217     if (y > 0 || m < 0 || m > 12 || d < 0 || d > 32) {
1218         errln((UnicodeString)"Out of rage!\nYear " +  y + " should be " +
1219               "negative number before 1AD.\nMonth " + m + " should " +
1220               "be between 0 and 12 in Hebrew calendar.\nDate " + d +
1221               " should be between 0 and 32 in Islamic calendar.");
1222     }
1223 }
1224 
TestBug21045Islamic()1225 void IntlCalendarTest::TestBug21045Islamic() {
1226     IcuTestErrorCode status(*this, "TestBug21045Islamic");
1227     std::unique_ptr<Calendar> cal(
1228         Calendar::createInstance("en@calendar=islamic", status));
1229     std::unique_ptr<Calendar> g(
1230         Calendar::createInstance("en@calendar=gregorian", status));
1231     // set to 500 AD before 622 AD.
1232     g->set(UCAL_ERA, 1);
1233     g->set(UCAL_YEAR, 500);
1234     g->set(UCAL_MONTH, 1);
1235     g->set(UCAL_DATE, 1);
1236     cal->setTime(g->getTime(status), status);
1237     int32_t m = cal->get(UCAL_MONTH, status);
1238     if (m < 0 || m > 11) {
1239         errln(u"Month should be between 1 and 12 in Islamic calendar");
1240     }
1241 }
1242 
TestBug21046IslamicUmalqura()1243 void IntlCalendarTest::TestBug21046IslamicUmalqura() {
1244     IcuTestErrorCode status(*this, "TestBug21046IslamicUmalqura");
1245     std::unique_ptr<Calendar> cal(
1246         Calendar::createInstance("en@calendar=islamic-umalqura", status));
1247     std::unique_ptr<Calendar> g(
1248         Calendar::createInstance("en@calendar=gregorian", status));
1249     // set to 195366 BC
1250     g->set(UCAL_ERA, 0);
1251     g->set(UCAL_YEAR, 195366);
1252     g->set(UCAL_MONTH, 1);
1253     g->set(UCAL_DATE, 1);
1254     cal->setTime(g->getTime(status), status);
1255     int32_t y = cal->get(UCAL_YEAR, status);
1256     int32_t m = cal->get(UCAL_MONTH, status);
1257     int32_t d = cal->get(UCAL_DATE, status);
1258     if (y > 0 || m < 0 || m > 11 || d < 0 || d > 32) {
1259         errln((UnicodeString)"Out of rage!\nYear " +  y + " should be " +
1260               "negative number before 1AD.\nMonth " + m + " should " +
1261               "be between 0 and 11 in Islamic calendar.\nDate " + d +
1262               " should be between 0 and 32 in Islamic calendar.");
1263     }
1264 }
1265 #undef CHECK
1266 
1267 #endif /* #if !UCONFIG_NO_FORMATTING */
1268 
1269 //eof
1270