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
escape(const UnicodeString & src)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
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)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
TestTypes()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 */
quasiGregorianTest(Calendar & cal,const Locale & gcl,const int32_t * data)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
TestGregorian()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 */
TestBuddhist()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 */
TestTaiwan()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 */
TestJapanese()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
TestBuddhistFormat()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
TestJapaneseFormat()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
TestJapanese3860()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
TestJapaneseHeiseiToReiwa()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 */
TestPersian()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
TestPersianFormat()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
simpleTest(const Locale & loc,const UnicodeString & expect,UDate expectDate,UErrorCode & status)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