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