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