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