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