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