• 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                             "buddhist",
147                             "buddhist",
148                             "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         Locale        loc("th_TH_TRADITIONAL"); // legacy
474 
475         simpleTest(loc, expect, expectDate, status);
476     }
477     status = U_ZERO_ERROR;
478     {
479         UnicodeString expect = CharsToUnicodeString("\\u0E27\\u0E31\\u0E19\\u0E40\\u0E2A\\u0E32\\u0E23\\u0E4C\\u0E17\\u0E35\\u0E48"
480             " 8 \\u0E01\\u0E31\\u0e19\\u0e22\\u0e32\\u0e22\\u0e19 \\u0e1e.\\u0e28. 2544");
481         UDate         expectDate = 999932400000.0;
482         Locale        loc("th_TH@calendar=buddhist");
483 
484         simpleTest(loc, expect, expectDate, status);
485     }
486     status = U_ZERO_ERROR;
487     {
488         UnicodeString expect = CharsToUnicodeString("\\u0E27\\u0E31\\u0E19\\u0E40\\u0E2A\\u0E32\\u0E23\\u0E4C\\u0E17\\u0E35\\u0E48"
489             " 8 \\u0E01\\u0E31\\u0e19\\u0e22\\u0e32\\u0e22\\u0e19 \\u0e04.\\u0e28. 2001");
490         UDate         expectDate = 999932400000.0;
491         Locale        loc("th_TH@calendar=gregorian");
492 
493         simpleTest(loc, expect, expectDate, status);
494     }
495     status = U_ZERO_ERROR;
496     {
497         UnicodeString expect = CharsToUnicodeString("\\u0E27\\u0E31\\u0E19\\u0E40\\u0E2A\\u0E32\\u0E23\\u0E4C\\u0E17\\u0E35\\u0E48"
498             " 8 \\u0E01\\u0E31\\u0e19\\u0e22\\u0e32\\u0e22\\u0e19 \\u0e04.\\u0e28. 2001");
499         UDate         expectDate = 999932400000.0;
500         Locale        loc("th_TH_TRADITIONAL@calendar=gregorian");
501 
502         simpleTest(loc, expect, expectDate, status);
503     }
504 }
505 
506 // TaiwanFormat has been moved to testdata/format.txt
507 
508 
TestJapaneseFormat()509 void IntlCalendarTest::TestJapaneseFormat() {
510     LocalPointer<Calendar> cal;
511     UErrorCode status = U_ZERO_ERROR;
512     cal.adoptInstead(Calendar::createInstance("ja_JP@calendar=japanese", status));
513     CHECK(status, UnicodeString("Creating ja_JP@calendar=japanese calendar"));
514 
515     LocalPointer<Calendar> cal2(cal->clone());
516     cal.adoptInstead(nullptr);
517 
518     // Test simple parse/format with adopt
519 
520     UDate aDate = 999932400000.0;
521     SimpleDateFormat fmt(UnicodeString("MMMM d, yy G"), Locale("en_US@calendar=japanese"), status);
522     SimpleDateFormat fmt2(UnicodeString("MMMM d, yyyy G"), Locale("en_US@calendar=gregorian"), status);
523     CHECK(status, "creating date format instance");
524     UnicodeString str;
525     fmt2.format(aDate, str);
526     logln(UnicodeString() + "Test Date: " + str);
527     str.remove();
528     fmt.format(aDate, str);
529     logln(UnicodeString() + "as Japanese Calendar: " + str);
530     UnicodeString expected("September 8, 13 Heisei");
531     if(str != expected) {
532         errln("Expected " + expected + " but got " + str);
533     }
534     UDate otherDate = fmt.parse(expected, status);
535     if(otherDate != aDate) {
536         UnicodeString str3;
537         ParsePosition pp;
538         fmt.parse(expected, *cal2, pp);
539         fmt.format(otherDate, str3);
540         errln("Parse incorrect of " + expected + " - wanted " + aDate + " but got " +  " = " +   otherDate + ", " + str3 + " = " + CalendarTest::calToStr(*cal2) );
541 
542     } else {
543         logln("Parsed OK: " + expected);
544     }
545 
546     // Test parse with incomplete information
547     SimpleDateFormat fmti(UnicodeString("G y"), Locale("en_US@calendar=japanese"), status);
548     aDate = -3197117222000.0;
549     CHECK(status, "creating date format instance");
550     str.remove();
551     fmt2.format(aDate, str);
552     logln(UnicodeString() + "Test Date: " + str);
553     str.remove();
554     fmti.format(aDate, str);
555     logln(UnicodeString() + "as Japanese Calendar: " + str);
556     expected = u"Meiji 1";
557     if(str != expected) {
558         errln("Expected " + expected + " but got " + str);
559     }
560     otherDate = fmti.parse(expected, status);
561     if(otherDate != aDate) {
562         UnicodeString str3;
563         ParsePosition pp;
564         fmti.parse(expected, *cal2, pp);
565         fmti.format(otherDate, str3);
566         errln("Parse incorrect of " + expected + " - wanted " + aDate + " but got " +  " = " +
567                 otherDate + ", " + str3 + " = " + CalendarTest::calToStr(*cal2) );
568     } else {
569         logln("Parsed OK: " + expected);
570     }
571 
572     CHECK(status, "Error occurred");
573 
574     // Now, try in Japanese
575     {
576         UnicodeString expect = CharsToUnicodeString("\\u5e73\\u621013\\u5e749\\u67088\\u65e5\\u571f\\u66dc\\u65e5");
577         UDate         expectDate = 999932400000.0; // Testing a recent date
578         Locale        loc("ja_JP@calendar=japanese");
579 
580         status = U_ZERO_ERROR;
581         simpleTest(loc, expect, expectDate, status);
582     }
583     {
584         UnicodeString expect = CharsToUnicodeString("\\u5e73\\u621013\\u5e749\\u67088\\u65e5\\u571f\\u66dc\\u65e5");
585         UDate         expectDate = 999932400000.0; // Testing a recent date
586         Locale        loc("ja_JP@calendar=japanese");
587 
588         status = U_ZERO_ERROR;
589         simpleTest(loc, expect, expectDate, status);
590     }
591     {
592         UnicodeString expect = CharsToUnicodeString("\\u5b89\\u6c385\\u5e747\\u67084\\u65e5\\u6728\\u66dc\\u65e5");
593         UDate         expectDate = -6106032422000.0; // 1776-07-04T00:00:00Z-075258
594         Locale        loc("ja_JP@calendar=japanese");
595 
596         status = U_ZERO_ERROR;
597         simpleTest(loc, expect, expectDate, status);
598 
599     }
600     {   // Jitterbug 1869 - this is an ambiguous era. (Showa 64 = Jan 6 1989, but Showa could be 2 other eras) )
601         UnicodeString expect = CharsToUnicodeString("\\u662d\\u548c64\\u5e741\\u67086\\u65e5\\u91d1\\u66dc\\u65e5");
602         UDate         expectDate = 600076800000.0;
603         Locale        loc("ja_JP@calendar=japanese");
604 
605         status = U_ZERO_ERROR;
606         simpleTest(loc, expect, expectDate, status);
607 
608     }
609     {   // 1989 Jan 9 Monday = Heisei 1; full is Gy年M月d日EEEE => 平成元年1月9日月曜日
610         UnicodeString expect = CharsToUnicodeString("\\u5E73\\u6210\\u5143\\u5E741\\u67089\\u65E5\\u6708\\u66DC\\u65E5");
611         UDate         expectDate = 600336000000.0;
612         Locale        loc("ja_JP@calendar=japanese");
613 
614         status = U_ZERO_ERROR;
615         simpleTest(loc, expect, expectDate, status);
616 
617     }
618     {   // This Feb 29th falls on a leap year by gregorian year, but not by Japanese year.
619         UnicodeString expect = CharsToUnicodeString("\\u5EB7\\u6B632\\u5e742\\u670829\\u65e5\\u65e5\\u66dc\\u65e5");
620         UDate         expectDate =  -16214400422000.0;  // 1456-03-09T00:00Z-075258
621         Locale        loc("ja_JP@calendar=japanese");
622 
623         status = U_ZERO_ERROR;
624         simpleTest(loc, expect, expectDate, status);
625 
626     }
627 }
628 
TestJapanese3860()629 void IntlCalendarTest::TestJapanese3860()
630 {
631     LocalPointer<Calendar> cal;
632     UErrorCode status = U_ZERO_ERROR;
633     cal.adoptInstead(Calendar::createInstance("ja_JP@calendar=japanese", status));
634     CHECK(status, UnicodeString("Creating ja_JP@calendar=japanese calendar"));
635     LocalPointer<Calendar> cal2(cal->clone());
636     SimpleDateFormat fmt2(UnicodeString("HH:mm:ss.S MMMM d, yyyy G"), Locale("en_US@calendar=gregorian"), status);
637     UnicodeString str;
638 
639     {
640         // Test simple parse/format with adopt
641         UDate aDate = 0;
642 
643         // Test parse with missing era (should default to current era, heisei)
644         // Test parse with incomplete information
645         logln("Testing parse w/ missing era...");
646         SimpleDateFormat fmt(UnicodeString("y/M/d"), Locale("ja_JP@calendar=japanese"), status);
647         CHECK(status, "creating date format instance");
648         UErrorCode s2 = U_ZERO_ERROR;
649         cal2->clear();
650         UnicodeString samplestr("1/5/9");
651         logln(UnicodeString() + "Test Year: " + samplestr);
652         aDate = fmt.parse(samplestr, s2);
653         ParsePosition pp=0;
654         fmt.parse(samplestr, *cal2, pp);
655         CHECK(s2, "parsing the 1/5/9 string");
656         logln("*cal2 after 159 parse:");
657         str.remove();
658         fmt2.format(aDate, str);
659         logln(UnicodeString() + "as Gregorian Calendar: " + str);
660 
661         cal2->setTime(aDate, s2);
662         int32_t gotYear = cal2->get(UCAL_YEAR, s2);
663         int32_t gotEra = cal2->get(UCAL_ERA, s2);
664         int32_t expectYear = 1;
665         int32_t expectEra = JapaneseCalendar::getCurrentEra();
666         if((gotYear!=1) || (gotEra != expectEra)) {
667             errln(UnicodeString("parse "+samplestr+" of 'y/M/d' as Japanese Calendar, expected year ") + expectYear +
668                     UnicodeString(" and era ") + expectEra +", but got year " + gotYear + " and era " + gotEra + " (Gregorian:" + str +")");
669         } else {
670             logln(UnicodeString() + " year: " + gotYear + ", era: " + gotEra);
671         }
672     }
673 
674     {
675         // Test simple parse/format with adopt
676         UDate aDate = 0;
677 
678         // Test parse with missing era (should default to current era, heisei)
679         // Test parse with incomplete information
680         logln("Testing parse w/ just year...");
681         SimpleDateFormat fmt(UnicodeString("y"), Locale("ja_JP@calendar=japanese"), status);
682         CHECK(status, "creating date format instance");
683         UErrorCode s2 = U_ZERO_ERROR;
684         cal2->clear();
685         UnicodeString samplestr("1");
686         logln(UnicodeString() + "Test Year: " + samplestr);
687         aDate = fmt.parse(samplestr, s2);
688         ParsePosition pp=0;
689         fmt.parse(samplestr, *cal2, pp);
690         CHECK(s2, "parsing the 1 string");
691         logln("*cal2 after 1 parse:");
692         str.remove();
693         fmt2.format(aDate, str);
694         logln(UnicodeString() + "as Gregorian Calendar: " + str);
695 
696         cal2->setTime(aDate, s2);
697         int32_t gotYear = cal2->get(UCAL_YEAR, s2);
698         int32_t gotEra = cal2->get(UCAL_ERA, s2);
699         int32_t expectYear = 1;
700         int32_t expectEra = JapaneseCalendar::getCurrentEra();
701         if((gotYear!=1) || (gotEra != expectEra)) {
702             errln(UnicodeString("parse "+samplestr+" of 'y' as Japanese Calendar, expected year ") + expectYear +
703                     UnicodeString(" and era ") + expectEra +", but got year " + gotYear + " and era " + gotEra + " (Gregorian:" + str +")");
704         } else {
705             logln(UnicodeString() + " year: " + gotYear + ", era: " + gotEra);
706         }
707     }
708 }
709 
TestForceGannenNumbering()710 void IntlCalendarTest::TestForceGannenNumbering()
711 {
712     UErrorCode status;
713     const char* locID = "ja_JP@calendar=japanese";
714     Locale loc(locID);
715     UDate refDate = 600336000000.0; // 1989 Jan 9 Monday = Heisei 1
716     UnicodeString patText(u"Gy年M月d日",-1);
717     UnicodeString patNumr(u"GGGGGy/MM/dd",-1);
718     UnicodeString skelText(u"yMMMM",-1);
719 
720     // Test Gannen year forcing
721     status = U_ZERO_ERROR;
722     LocalPointer<SimpleDateFormat> testFmt1(new SimpleDateFormat(patText, loc, status));
723     LocalPointer<SimpleDateFormat> testFmt2(new SimpleDateFormat(patNumr, loc, status));
724     if (U_FAILURE(status)) {
725         dataerrln("Fail in new SimpleDateFormat locale %s: %s", locID, u_errorName(status));
726     } else {
727         UnicodeString testString1, testString2;
728         testString1 = testFmt1->format(refDate, testString1);
729         if (testString1.length() < 3 || testString1.charAt(2) != 0x5143) {
730             errln(UnicodeString("Formatting year 1 in created text style, got " + testString1 + " but expected 3rd char to be 0x5143"));
731         }
732         testString2 = testFmt2->format(refDate, testString2);
733         if (testString2.length() < 2 || testString2.charAt(1) != 0x0031) {
734             errln(UnicodeString("Formatting year 1 in created numeric style, got " + testString2 + " but expected 2nd char to be 1"));
735         }
736         // Now switch the patterns and verify that Gannen use follows the pattern
737         testFmt1->applyPattern(patNumr);
738         testString1.remove();
739         testString1 = testFmt1->format(refDate, testString1);
740         if (testString1.length() < 2 || testString1.charAt(1) != 0x0031) {
741             errln(UnicodeString("Formatting year 1 in applied numeric style, got " + testString1 + " but expected 2nd char to be 1"));
742         }
743         testFmt2->applyPattern(patText);
744         testString2.remove();
745         testString2 = testFmt2->format(refDate, testString2);
746         if (testString2.length() < 3 || testString2.charAt(2) != 0x5143) {
747             errln(UnicodeString("Formatting year 1 in applied text style, got " + testString2 + " but expected 3rd char to be 0x5143"));
748         }
749     }
750 
751     // Test disabling of Gannen year forcing
752     status = U_ZERO_ERROR;
753     LocalPointer<DateTimePatternGenerator> dtpgen(DateTimePatternGenerator::createInstance(loc, status));
754     if (U_FAILURE(status)) {
755         dataerrln("Fail in DateTimePatternGenerator::createInstance locale %s: %s", locID, u_errorName(status));
756     } else {
757         UnicodeString pattern = dtpgen->getBestPattern(skelText, status);
758         if (U_FAILURE(status)) {
759             dataerrln("Fail in DateTimePatternGenerator::getBestPattern locale %s: %s", locID, u_errorName(status));
760         } else  {
761             // Use override string of ""
762             LocalPointer<SimpleDateFormat> testFmt3(new SimpleDateFormat(pattern, UnicodeString(""), loc, status));
763             if (U_FAILURE(status)) {
764                 dataerrln("Fail in new SimpleDateFormat locale %s: %s", locID, u_errorName(status));
765             } else {
766                 UnicodeString testString3;
767                 testString3 = testFmt3->format(refDate, testString3);
768                 if (testString3.length() < 3 || testString3.charAt(2) != 0x0031) {
769                     errln(UnicodeString("Formatting year 1 with Gannen disabled, got " + testString3 + " but expected 3rd char to be 1"));
770                 }
771             }
772         }
773     }
774 }
775 
776 /**
777  * Verify the Persian Calendar.
778  */
TestPersian()779 void IntlCalendarTest::TestPersian() {
780     UDate timeA = Calendar::getNow();
781 
782     Calendar *cal;
783     UErrorCode status = U_ZERO_ERROR;
784     cal = Calendar::createInstance("fa_IR@calendar=persian", status);
785     CHECK(status, UnicodeString("Creating fa_IR@calendar=persian calendar"));
786     // Sanity check the calendar
787     UDate timeB = Calendar::getNow();
788     UDate timeCal = cal->getTime(status);
789 
790     if(!(timeA <= timeCal) || !(timeCal <= timeB)) {
791       errln((UnicodeString)"Error: Calendar time " + timeCal +
792             " is not within sampled times [" + timeA + " to " + timeB + "]!");
793     }
794     // end sanity check
795 
796     // Test various dates to be sure of validity
797     int32_t data[] = {
798         1925, 4, 24, 1304, 2, 4,
799         2011, 1, 11, 1389, 10, 21,
800         1986, 2, 25, 1364, 12, 6,
801         1934, 3, 14, 1312, 12, 23,
802 
803         2090, 3, 19, 1468, 12, 29,
804         2007, 2, 22, 1385, 12, 3,
805         1969, 12, 31, 1348, 10, 10,
806         1945, 11, 12, 1324, 8, 21,
807         1925, 3, 31, 1304, 1, 11,
808 
809         1996, 3, 19, 1374, 12, 29,
810         1996, 3, 20, 1375, 1, 1,
811         1997, 3, 20, 1375, 12, 30,
812         1997, 3, 21, 1376, 1, 1,
813 
814         2008, 3, 19, 1386, 12, 29,
815         2008, 3, 20, 1387, 1, 1,
816         2004, 3, 19, 1382, 12, 29,
817         2004, 3, 20, 1383, 1, 1,
818 
819         2006, 3, 20, 1384, 12, 29,
820         2006, 3, 21, 1385, 1, 1,
821 
822         2005, 4, 20, 1384, 1, 31,
823         2005, 4, 21, 1384, 2, 1,
824         2005, 5, 21, 1384, 2, 31,
825         2005, 5, 22, 1384, 3, 1,
826         2005, 6, 21, 1384, 3, 31,
827         2005, 6, 22, 1384, 4, 1,
828         2005, 7, 22, 1384, 4, 31,
829         2005, 7, 23, 1384, 5, 1,
830         2005, 8, 22, 1384, 5, 31,
831         2005, 8, 23, 1384, 6, 1,
832         2005, 9, 22, 1384, 6, 31,
833         2005, 9, 23, 1384, 7, 1,
834         2005, 10, 22, 1384, 7, 30,
835         2005, 10, 23, 1384, 8, 1,
836         2005, 11, 21, 1384, 8, 30,
837         2005, 11, 22, 1384, 9, 1,
838         2005, 12, 21, 1384, 9, 30,
839         2005, 12, 22, 1384, 10, 1,
840         2006, 1, 20, 1384, 10, 30,
841         2006, 1, 21, 1384, 11, 1,
842         2006, 2, 19, 1384, 11, 30,
843         2006, 2, 20, 1384, 12, 1,
844         2006, 3, 20, 1384, 12, 29,
845         2006, 3, 21, 1385, 1, 1,
846 
847         // The 2820-year cycle arithmetical algorithm would fail this one.
848         2025, 3, 21, 1404, 1, 1,
849 
850         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1
851     };
852 
853     Calendar *grego = Calendar::createInstance("fa_IR@calendar=gregorian", status);
854     for (int32_t i=0; data[i]!=-1; ) {
855         int32_t gregYear = data[i++];
856         int32_t gregMonth = data[i++]-1;
857         int32_t gregDay = data[i++];
858         int32_t persYear = data[i++];
859         int32_t persMonth = data[i++]-1;
860         int32_t persDay = data[i++];
861 
862         // Test conversion from Persian dates
863         grego->clear();
864         grego->set(gregYear, gregMonth, gregDay);
865 
866         cal->clear();
867         cal->set(persYear, persMonth, persDay);
868 
869         UDate persTime = cal->getTime(status);
870         UDate gregTime = grego->getTime(status);
871 
872         if (persTime != gregTime) {
873           errln(UnicodeString("Expected ") + gregTime + " but got " + persTime);
874         }
875 
876         // Test conversion to Persian dates
877         cal->clear();
878         cal->setTime(gregTime, status);
879 
880         int32_t computedYear = cal->get(UCAL_YEAR, status);
881         int32_t computedMonth = cal->get(UCAL_MONTH, status);
882         int32_t computedDay = cal->get(UCAL_DATE, status);
883 
884         if ((persYear != computedYear) ||
885             (persMonth != computedMonth) ||
886             (persDay != computedDay)) {
887           errln(UnicodeString("Expected ") + persYear + "/" + (persMonth+1) + "/" + persDay +
888                 " but got " +  computedYear + "/" + (computedMonth+1) + "/" + computedDay);
889         }
890 
891     }
892 
893     delete cal;
894     delete grego;
895 }
896 
TestPersianFormat()897 void IntlCalendarTest::TestPersianFormat() {
898     UErrorCode status = U_ZERO_ERROR;
899     SimpleDateFormat fmt(UnicodeString("MMMM d, yyyy G"), Locale(" en_US@calendar=persian"), status);
900     CHECK(status, "creating date format instance");
901     SimpleDateFormat fmt2(UnicodeString("MMMM d, yyyy G"), Locale("en_US@calendar=gregorian"), status);
902     CHECK(status, "creating gregorian date format instance");
903     UnicodeString gregorianDate("January 18, 2007 AD");
904     UDate aDate = fmt2.parse(gregorianDate, status);
905     UnicodeString str;
906     fmt.format(aDate, str);
907     logln(UnicodeString() + "as Persian Calendar: " + escape(str));
908     UnicodeString expected("Dey 28, 1385 AP");
909     if(str != expected) {
910         errln("Expected " + escape(expected) + " but got " + escape(str));
911     }
912     UDate otherDate = fmt.parse(expected, status);
913     if(otherDate != aDate) {
914         UnicodeString str3;
915         fmt.format(otherDate, str3);
916         errln("Parse incorrect of " + escape(expected) + " - wanted " + aDate + " but got " +  otherDate + ", " + escape(str3));
917     } else {
918         logln("Parsed OK: " + expected);
919     }
920     // Two digit year parsing problem #4732
921     fmt.applyPattern("yy-MM-dd");
922     str.remove();
923     fmt.format(aDate, str);
924     expected.setTo("85-10-28");
925     if(str != expected) {
926         errln("Expected " + escape(expected) + " but got " + escape(str));
927     }
928     otherDate = fmt.parse(expected, status);
929     if (otherDate != aDate) {
930         errln("Parse incorrect of " + escape(expected) + " - wanted " + aDate + " but got " + otherDate);
931     } else {
932         logln("Parsed OK: " + expected);
933     }
934 
935     CHECK(status, "Error occurred testing Persian Calendar in English ");
936 }
937 
TestConsistencyGregorian()938 void IntlCalendarTest::TestConsistencyGregorian() {
939     checkConsistency("en@calendar=gregorian");
940 }
TestConsistencyIndian()941 void IntlCalendarTest::TestConsistencyIndian() {
942     checkConsistency("en@calendar=indian");
943 }
TestConsistencyHebrew()944 void IntlCalendarTest::TestConsistencyHebrew() {
945     checkConsistency("en@calendar=hebrew");
946 }
TestConsistencyIslamic()947 void IntlCalendarTest::TestConsistencyIslamic() {
948     checkConsistency("en@calendar=islamic");
949 }
TestConsistencyIslamicRGSA()950 void IntlCalendarTest::TestConsistencyIslamicRGSA() {
951     checkConsistency("en@calendar=islamic-rgsa");
952 }
TestConsistencyIslamicTBLA()953 void IntlCalendarTest::TestConsistencyIslamicTBLA() {
954     checkConsistency("en@calendar=islamic-tbla");
955 }
TestConsistencyIslamicUmalqura()956 void IntlCalendarTest::TestConsistencyIslamicUmalqura() {
957     checkConsistency("en@calendar=islamic-umalqura");
958 }
TestConsistencyIslamicCivil()959 void IntlCalendarTest::TestConsistencyIslamicCivil() {
960     checkConsistency("en@calendar=islamic-civil");
961 }
TestConsistencyCoptic()962 void IntlCalendarTest::TestConsistencyCoptic() {
963     checkConsistency("en@calendar=coptic");
964 }
TestConsistencyEthiopic()965 void IntlCalendarTest::TestConsistencyEthiopic() {
966     checkConsistency("en@calendar=ethiopic");
967 }
TestConsistencyROC()968 void IntlCalendarTest::TestConsistencyROC() {
969     checkConsistency("en@calendar=roc");
970 }
TestConsistencyChinese()971 void IntlCalendarTest::TestConsistencyChinese() {
972     checkConsistency("en@calendar=chinese");
973 }
TestConsistencyDangi()974 void IntlCalendarTest::TestConsistencyDangi() {
975     checkConsistency("en@calendar=dangi");
976 }
TestConsistencyPersian()977 void IntlCalendarTest::TestConsistencyPersian() {
978     checkConsistency("en@calendar=persian");
979 }
TestConsistencyBuddhist()980 void IntlCalendarTest::TestConsistencyBuddhist() {
981     checkConsistency("en@calendar=buddhist");
982 }
TestConsistencyJapanese()983 void IntlCalendarTest::TestConsistencyJapanese() {
984     checkConsistency("en@calendar=japanese");
985 }
TestConsistencyEthiopicAmeteAlem()986 void IntlCalendarTest::TestConsistencyEthiopicAmeteAlem() {
987     checkConsistency("en@calendar=ethiopic-amete-alem");
988 }
checkConsistency(const char * locale)989 void IntlCalendarTest::checkConsistency(const char* locale) {
990     // Check 2.5 years in quick mode and 8000 years in exhaustive mode.
991     int32_t numOfDaysToTest = static_cast<int32_t>((quick ? 2.5 : 8000) * 365);
992     constexpr int32_t msInADay = 1000*60*60*24;
993     std::string msg("TestConsistency");
994     IcuTestErrorCode status(*this, (msg + locale).c_str());
995     // g is just for debugging messages.
996     std::unique_ptr<Calendar> g(Calendar::createInstance("en", status));
997     g->setTimeZone(*(TimeZone::getGMT()));
998     std::unique_ptr<Calendar> base(Calendar::createInstance(locale, status));
999     if (status.errIfFailureAndReset("Cannot create calendar %s", locale)) {
1000         return;
1001     }
1002     UDate test = Calendar::getNow();
1003     base->setTimeZone(*(TimeZone::getGMT()));
1004     int32_t j;
1005     int lastDay = 1;
1006     std::unique_ptr<Calendar> r(base->clone());
1007     for (j = 0; j < numOfDaysToTest; j++, test -= msInADay) {
1008         status.errIfFailureAndReset();
1009         g->setTime(test, status);
1010         if (status.errIfFailureAndReset("Cannot set time")) {
1011             return;
1012         }
1013         base->clear();
1014         base->setTime(test, status);
1015         if (status.errIfFailureAndReset("Cannot set time")) {
1016             return;
1017         }
1018         // First, we verify the date from base is decrease one day from the
1019         // last day unless the last day is 1.
1020         int32_t cday = base->get(UCAL_DATE, status);
1021         if (U_FAILURE(status)) {
1022            UErrorCode localStatus = U_ZERO_ERROR;
1023            if (status.errIfFailureAndReset(
1024                "Cannot get the %dth date for %f %d %d/%d/%d\n",
1025                j,
1026                test,
1027                g->get(UCAL_ERA, localStatus),
1028                g->get(UCAL_YEAR, localStatus),
1029                (g->get(UCAL_MONTH, localStatus) + 1),
1030                g->get(UCAL_DATE, localStatus))) {
1031                return;
1032            }
1033         }
1034         if (lastDay == 1) {
1035             lastDay = cday;
1036         } else {
1037             if (cday != lastDay-1) {
1038                 // Ignore if it is the last day before Gregorian Calendar switch on
1039                 // 1582 Oct 4
1040                 if (g->get(UCAL_YEAR, status) == 1582 &&
1041                     (g->get(UCAL_MONTH, status) + 1) == 10 &&
1042                     g->get(UCAL_DATE, status) == 4) {
1043                     lastDay = 5;
1044                 } else {
1045                     errln((UnicodeString)
1046                         "Day is not one less from previous date for "
1047                         "Gregorian(e=" + g->get(UCAL_ERA, status) + " " +
1048                         g->get(UCAL_YEAR, status) + "/" +
1049                         (g->get(UCAL_MONTH, status) + 1) + "/" +
1050                         g->get(UCAL_DATE, status) + ") " + locale + "(" +
1051                         base->get(UCAL_ERA, status) + " " +
1052                         base->get(UCAL_YEAR, status) + "/" +
1053                         (base->get(UCAL_MONTH, status) + 1 ) + "/" +
1054                         base->get(UCAL_DATE, status) + ")");
1055                     status.errIfFailureAndReset();
1056                     return;
1057                 }
1058             }
1059             lastDay--;
1060         }
1061         // Second, we verify the month is in reasonale range.
1062         int32_t cmonth = base->get(UCAL_MONTH, status);
1063         if (cmonth < 0 || cmonth > 13) {
1064             errln((UnicodeString)
1065                 "Month is out of range Gregorian(e=" +
1066                 g->get(UCAL_ERA, status) + " " +
1067                 g->get(UCAL_YEAR, status) + "/" +
1068                 (g->get(UCAL_MONTH, status) + 1) + "/" +
1069                 g->get(UCAL_DATE, status) + ") " + locale + "(" +
1070                 base->get(UCAL_ERA, status) + " " +
1071                 base->get(UCAL_YEAR, status) + "/" +
1072                 (base->get(UCAL_MONTH, status) + 1 ) + "/" +
1073                 base->get(UCAL_DATE, status) + ")");
1074             status.errIfFailureAndReset();
1075             return;
1076         }
1077         // Third, we verify the set function can round trip the time back.
1078         r->clear();
1079         for (int32_t f = 0; f < UCAL_FIELD_COUNT; f++) {
1080             UCalendarDateFields ut = (UCalendarDateFields)f;
1081             r->set(ut, base->get(ut, status));
1082         }
1083         UDate result = r->getTime(status);
1084         if (status.errIfFailureAndReset("Cannot get time %s", locale)) {
1085             return;
1086         }
1087         if (test != result) {
1088             errln((UnicodeString)"Round trip conversion produces different "
1089                   "time from " + test + " to  " + result + " delta: " +
1090                   (result - test) +
1091                   " Gregorian(e=" + g->get(UCAL_ERA, status) + " " +
1092                   g->get(UCAL_YEAR, status) + "/" +
1093                   (g->get(UCAL_MONTH, status) + 1) + "/" +
1094                   g->get(UCAL_DATE, status) + ") ");
1095             status.errIfFailureAndReset();
1096             return;
1097         }
1098     }
1099     status.errIfFailureAndReset();
1100 }
1101 
simpleTest(const Locale & loc,const UnicodeString & expect,UDate expectDate,UErrorCode & status)1102 void IntlCalendarTest::simpleTest(const Locale& loc, const UnicodeString& expect, UDate expectDate, UErrorCode& status)
1103 {
1104     UnicodeString tmp;
1105     UDate         d;
1106     DateFormat *fmt0 = DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull);
1107 
1108     logln("Try format/parse of " + (UnicodeString)loc.getName());
1109     DateFormat *fmt2 = DateFormat::createDateInstance(DateFormat::kFull, loc);
1110     if(fmt2) {
1111         fmt2->format(expectDate, tmp);
1112         logln(escape(tmp) + " ( in locale " + loc.getName() + ")");
1113         if(tmp != expect) {
1114             errln(UnicodeString("Failed to format " ) + loc.getName() + " expected " + escape(expect) + " got " + escape(tmp) );
1115         }
1116 
1117         d = fmt2->parse(expect,status);
1118         CHECK(status, "Error occurred parsing " + UnicodeString(loc.getName()));
1119         if(d != expectDate) {
1120             fmt2->format(d,tmp);
1121             errln(UnicodeString("Failed to parse " ) + escape(expect) + ", " + loc.getName() + " expect " + (double)expectDate + " got " + (double)d  + " " + escape(tmp));
1122             logln( "wanted " + escape(fmt0->format(expectDate,tmp.remove())) + " but got " + escape(fmt0->format(d,tmp.remove())));
1123         }
1124         delete fmt2;
1125     } else {
1126         errln((UnicodeString)"Can't create " + loc.getName() + " date instance");
1127     }
1128     delete fmt0;
1129 }
1130 
TestBug21043Indian()1131 void IntlCalendarTest::TestBug21043Indian() {
1132     IcuTestErrorCode status(*this, "TestBug21043Indian");
1133     std::unique_ptr<Calendar> cal(
1134         Calendar::createInstance("en@calendar=indian", status));
1135     std::unique_ptr<Calendar> g(
1136         Calendar::createInstance("en@calendar=gregorian", status));
1137     // set to 10 BC
1138     g->set(UCAL_ERA, 0);
1139     g->set(UCAL_YEAR, 10);
1140     g->set(UCAL_MONTH, 1);
1141     g->set(UCAL_DATE, 1);
1142     cal->setTime(g->getTime(status), status);
1143     int32_t m = cal->get(UCAL_MONTH, status);
1144     if (m < 0 || m > 11) {
1145         errln(
1146               u"Month should be between 0 and 11 in India calendar");
1147     }
1148 }
1149 
TestBug21044Hebrew()1150 void IntlCalendarTest::TestBug21044Hebrew() {
1151     IcuTestErrorCode status(*this, "TestBug21044Hebrew");
1152     std::unique_ptr<Calendar> cal(
1153         Calendar::createInstance("en@calendar=hebrew", status));
1154     std::unique_ptr<Calendar> g(
1155         Calendar::createInstance("en@calendar=gregorian", status));
1156     // set to 3771/10/27 BC which is before 3760 BC.
1157     g->set(UCAL_ERA, 0);
1158     g->set(UCAL_YEAR, 3771);
1159     g->set(UCAL_MONTH, 9);
1160     g->set(UCAL_DATE, 27);
1161     cal->setTime(g->getTime(status), status);
1162 
1163     if (status.errIfFailureAndReset(
1164         "Cannot set date. Got error %s", u_errorName(status))) {
1165         return;
1166     }
1167     int32_t y = cal->get(UCAL_YEAR, status);
1168     int32_t m = cal->get(UCAL_MONTH, status);
1169     int32_t d = cal->get(UCAL_DATE, status);
1170     if (status.errIfFailureAndReset(
1171         "Cannot get date. Got error %s", u_errorName(status))) {
1172         return;
1173    }
1174     if (y > 0 || m < 0 || m > 12 || d < 0 || d > 32) {
1175         errln((UnicodeString)"Out of rage!\nYear " +  y + " should be " +
1176               "negative number before 1AD.\nMonth " + m + " should " +
1177               "be between 0 and 12 in Hebrew calendar.\nDate " + d +
1178               " should be between 0 and 32 in Islamic calendar.");
1179     }
1180 }
1181 
TestBug21045Islamic()1182 void IntlCalendarTest::TestBug21045Islamic() {
1183     IcuTestErrorCode status(*this, "TestBug21045Islamic");
1184     std::unique_ptr<Calendar> cal(
1185         Calendar::createInstance("en@calendar=islamic", status));
1186     std::unique_ptr<Calendar> g(
1187         Calendar::createInstance("en@calendar=gregorian", status));
1188     // set to 500 AD before 622 AD.
1189     g->set(UCAL_ERA, 1);
1190     g->set(UCAL_YEAR, 500);
1191     g->set(UCAL_MONTH, 1);
1192     g->set(UCAL_DATE, 1);
1193     cal->setTime(g->getTime(status), status);
1194     int32_t m = cal->get(UCAL_MONTH, status);
1195     if (m < 0 || m > 11) {
1196         errln(u"Month should be between 1 and 12 in Islamic calendar");
1197     }
1198 }
1199 
TestBug21046IslamicUmalqura()1200 void IntlCalendarTest::TestBug21046IslamicUmalqura() {
1201     IcuTestErrorCode status(*this, "TestBug21046IslamicUmalqura");
1202     std::unique_ptr<Calendar> cal(
1203         Calendar::createInstance("en@calendar=islamic-umalqura", status));
1204     std::unique_ptr<Calendar> g(
1205         Calendar::createInstance("en@calendar=gregorian", status));
1206     // set to 195366 BC
1207     g->set(UCAL_ERA, 0);
1208     g->set(UCAL_YEAR, 195366);
1209     g->set(UCAL_MONTH, 1);
1210     g->set(UCAL_DATE, 1);
1211     cal->setTime(g->getTime(status), status);
1212     int32_t y = cal->get(UCAL_YEAR, status);
1213     int32_t m = cal->get(UCAL_MONTH, status);
1214     int32_t d = cal->get(UCAL_DATE, status);
1215     if (y > 0 || m < 0 || m > 11 || d < 0 || d > 32) {
1216         errln((UnicodeString)"Out of rage!\nYear " +  y + " should be " +
1217               "negative number before 1AD.\nMonth " + m + " should " +
1218               "be between 0 and 11 in Islamic calendar.\nDate " + d +
1219               " should be between 0 and 32 in Islamic calendar.");
1220     }
1221 }
1222 #undef CHECK
1223 
1224 #endif /* #if !UCONFIG_NO_FORMATTING */
1225 
1226 //eof
1227