• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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                             "buddhist",
126                             "buddhist",
127                             "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     UErrorCode status = U_ZERO_ERROR;
416 
417     // Test simple parse/format with adopt
418 
419     // First, a contrived English test..
420     UDate aDate = 999932400000.0;
421     SimpleDateFormat fmt(UnicodeString("MMMM d, yyyy G"), Locale("en_US@calendar=buddhist"), status);
422     CHECK(status, "creating date format instance");
423     SimpleDateFormat fmt2(UnicodeString("MMMM d, yyyy G"), Locale("en_US@calendar=gregorian"), status);
424     CHECK(status, "creating gregorian date format instance");
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 
444     CHECK(status, "Error occurred testing Buddhist Calendar in English ");
445 
446     status = U_ZERO_ERROR;
447     // Now, try in Thai
448     {
449         UnicodeString expect = CharsToUnicodeString("\\u0E27\\u0E31\\u0E19\\u0E40\\u0E2A\\u0E32\\u0E23\\u0E4C\\u0E17\\u0E35\\u0E48"
450             " 8 \\u0E01\\u0E31\\u0e19\\u0e22\\u0e32\\u0e22\\u0e19 \\u0e1e.\\u0e28. 2544");
451         UDate         expectDate = 999932400000.0;
452         Locale        loc("th_TH_TRADITIONAL"); // legacy
453 
454         simpleTest(loc, expect, expectDate, status);
455     }
456     status = U_ZERO_ERROR;
457     {
458         UnicodeString expect = CharsToUnicodeString("\\u0E27\\u0E31\\u0E19\\u0E40\\u0E2A\\u0E32\\u0E23\\u0E4C\\u0E17\\u0E35\\u0E48"
459             " 8 \\u0E01\\u0E31\\u0e19\\u0e22\\u0e32\\u0e22\\u0e19 \\u0e1e.\\u0e28. 2544");
460         UDate         expectDate = 999932400000.0;
461         Locale        loc("th_TH@calendar=buddhist");
462 
463         simpleTest(loc, expect, expectDate, status);
464     }
465     status = U_ZERO_ERROR;
466     {
467         UnicodeString expect = CharsToUnicodeString("\\u0E27\\u0E31\\u0E19\\u0E40\\u0E2A\\u0E32\\u0E23\\u0E4C\\u0E17\\u0E35\\u0E48"
468             " 8 \\u0E01\\u0E31\\u0e19\\u0e22\\u0e32\\u0e22\\u0e19 \\u0e04.\\u0e28. 2001");
469         UDate         expectDate = 999932400000.0;
470         Locale        loc("th_TH@calendar=gregorian");
471 
472         simpleTest(loc, expect, expectDate, status);
473     }
474     status = U_ZERO_ERROR;
475     {
476         UnicodeString expect = CharsToUnicodeString("\\u0E27\\u0E31\\u0E19\\u0E40\\u0E2A\\u0E32\\u0E23\\u0E4C\\u0E17\\u0E35\\u0E48"
477             " 8 \\u0E01\\u0E31\\u0e19\\u0e22\\u0e32\\u0e22\\u0e19 \\u0e04.\\u0e28. 2001");
478         UDate         expectDate = 999932400000.0;
479         Locale        loc("th_TH_TRADITIONAL@calendar=gregorian");
480 
481         simpleTest(loc, expect, expectDate, status);
482     }
483 }
484 
485 // TaiwanFormat has been moved to testdata/format.txt
486 
487 
TestJapaneseFormat()488 void IntlCalendarTest::TestJapaneseFormat() {
489     LocalPointer<Calendar> cal;
490     UErrorCode status = U_ZERO_ERROR;
491     cal.adoptInstead(Calendar::createInstance("ja_JP@calendar=japanese", status));
492     CHECK(status, UnicodeString("Creating ja_JP@calendar=japanese calendar"));
493 
494     LocalPointer<Calendar> cal2(cal->clone());
495     cal.adoptInstead(nullptr);
496 
497     // Test simple parse/format with adopt
498 
499     UDate aDate = 999932400000.0;
500     SimpleDateFormat fmt(UnicodeString("MMMM d, yy G"), Locale("en_US@calendar=japanese"), status);
501     SimpleDateFormat fmt2(UnicodeString("MMMM d, yyyy G"), Locale("en_US@calendar=gregorian"), status);
502     CHECK(status, "creating date format instance");
503     UnicodeString str;
504     fmt2.format(aDate, str);
505     logln(UnicodeString() + "Test Date: " + str);
506     str.remove();
507     fmt.format(aDate, str);
508     logln(UnicodeString() + "as Japanese Calendar: " + str);
509     UnicodeString expected("September 8, 13 Heisei");
510     if(str != expected) {
511         errln("Expected " + expected + " but got " + str);
512     }
513     UDate otherDate = fmt.parse(expected, status);
514     if(otherDate != aDate) {
515         UnicodeString str3;
516         ParsePosition pp;
517         fmt.parse(expected, *cal2, pp);
518         fmt.format(otherDate, str3);
519         errln("Parse incorrect of " + expected + " - wanted " + aDate + " but got " +  " = " +   otherDate + ", " + str3 + " = " + CalendarTest::calToStr(*cal2) );
520 
521     } else {
522         logln("Parsed OK: " + expected);
523     }
524 
525     // Test parse with incomplete information
526     SimpleDateFormat fmti(UnicodeString("G y"), Locale("en_US@calendar=japanese"), status);
527     aDate = -3197117222000.0;
528     CHECK(status, "creating date format instance");
529     str.remove();
530     fmt2.format(aDate, str);
531     logln(UnicodeString() + "Test Date: " + str);
532     str.remove();
533     fmti.format(aDate, str);
534     logln(UnicodeString() + "as Japanese Calendar: " + str);
535     expected = u"Meiji 1";
536     if(str != expected) {
537         errln("Expected " + expected + " but got " + str);
538     }
539     otherDate = fmti.parse(expected, status);
540     if(otherDate != aDate) {
541         UnicodeString str3;
542         ParsePosition pp;
543         fmti.parse(expected, *cal2, pp);
544         fmti.format(otherDate, str3);
545         errln("Parse incorrect of " + expected + " - wanted " + aDate + " but got " +  " = " +
546                 otherDate + ", " + str3 + " = " + CalendarTest::calToStr(*cal2) );
547     } else {
548         logln("Parsed OK: " + expected);
549     }
550 
551     CHECK(status, "Error occurred");
552 
553     // Now, try in Japanese
554     {
555         UnicodeString expect = CharsToUnicodeString("\\u5e73\\u621013\\u5e749\\u67088\\u65e5\\u571f\\u66dc\\u65e5");
556         UDate         expectDate = 999932400000.0; // Testing a recent date
557         Locale        loc("ja_JP@calendar=japanese");
558 
559         status = U_ZERO_ERROR;
560         simpleTest(loc, expect, expectDate, status);
561     }
562     {
563         UnicodeString expect = CharsToUnicodeString("\\u5e73\\u621013\\u5e749\\u67088\\u65e5\\u571f\\u66dc\\u65e5");
564         UDate         expectDate = 999932400000.0; // Testing a recent date
565         Locale        loc("ja_JP@calendar=japanese");
566 
567         status = U_ZERO_ERROR;
568         simpleTest(loc, expect, expectDate, status);
569     }
570     {
571         UnicodeString expect = CharsToUnicodeString("\\u5b89\\u6c385\\u5e747\\u67084\\u65e5\\u6728\\u66dc\\u65e5");
572         UDate         expectDate = -6106032422000.0; // 1776-07-04T00:00:00Z-075258
573         Locale        loc("ja_JP@calendar=japanese");
574 
575         status = U_ZERO_ERROR;
576         simpleTest(loc, expect, expectDate, status);
577 
578     }
579     {   // Jitterbug 1869 - this is an ambiguous era. (Showa 64 = Jan 6 1989, but Showa could be 2 other eras) )
580         UnicodeString expect = CharsToUnicodeString("\\u662d\\u548c64\\u5e741\\u67086\\u65e5\\u91d1\\u66dc\\u65e5");
581         UDate         expectDate = 600076800000.0;
582         Locale        loc("ja_JP@calendar=japanese");
583 
584         status = U_ZERO_ERROR;
585         simpleTest(loc, expect, expectDate, status);
586 
587     }
588     {   // 1989 Jan 9 Monday = Heisei 1; full is Gy年M月d日EEEE => 平成元年1月9日月曜日
589         UnicodeString expect = CharsToUnicodeString("\\u5E73\\u6210\\u5143\\u5E741\\u67089\\u65E5\\u6708\\u66DC\\u65E5");
590         UDate         expectDate = 600336000000.0;
591         Locale        loc("ja_JP@calendar=japanese");
592 
593         status = U_ZERO_ERROR;
594         simpleTest(loc, expect, expectDate, status);
595 
596     }
597     {   // This Feb 29th falls on a leap year by gregorian year, but not by Japanese year.
598         UnicodeString expect = CharsToUnicodeString("\\u5EB7\\u6B632\\u5e742\\u670829\\u65e5\\u65e5\\u66dc\\u65e5");
599         UDate         expectDate =  -16214400422000.0;  // 1456-03-09T00:00Z-075258
600         Locale        loc("ja_JP@calendar=japanese");
601 
602         status = U_ZERO_ERROR;
603         simpleTest(loc, expect, expectDate, status);
604 
605     }
606 }
607 
TestJapanese3860()608 void IntlCalendarTest::TestJapanese3860()
609 {
610     LocalPointer<Calendar> cal;
611     UErrorCode status = U_ZERO_ERROR;
612     cal.adoptInstead(Calendar::createInstance("ja_JP@calendar=japanese", status));
613     CHECK(status, UnicodeString("Creating ja_JP@calendar=japanese calendar"));
614     LocalPointer<Calendar> cal2(cal->clone());
615     SimpleDateFormat fmt2(UnicodeString("HH:mm:ss.S MMMM d, yyyy G"), Locale("en_US@calendar=gregorian"), status);
616     UnicodeString str;
617 
618     {
619         // Test simple parse/format with adopt
620         UDate aDate = 0;
621 
622         // Test parse with missing era (should default to current era, heisei)
623         // Test parse with incomplete information
624         logln("Testing parse w/ missing era...");
625         SimpleDateFormat fmt(UnicodeString("y/M/d"), Locale("ja_JP@calendar=japanese"), status);
626         CHECK(status, "creating date format instance");
627         UErrorCode s2 = U_ZERO_ERROR;
628         cal2->clear();
629         UnicodeString samplestr("1/5/9");
630         logln(UnicodeString() + "Test Year: " + samplestr);
631         aDate = fmt.parse(samplestr, s2);
632         ParsePosition pp=0;
633         fmt.parse(samplestr, *cal2, pp);
634         CHECK(s2, "parsing the 1/5/9 string");
635         logln("*cal2 after 159 parse:");
636         str.remove();
637         fmt2.format(aDate, str);
638         logln(UnicodeString() + "as Gregorian Calendar: " + str);
639 
640         cal2->setTime(aDate, s2);
641         int32_t gotYear = cal2->get(UCAL_YEAR, s2);
642         int32_t gotEra = cal2->get(UCAL_ERA, s2);
643         int32_t expectYear = 1;
644         int32_t expectEra = JapaneseCalendar::getCurrentEra();
645         if((gotYear!=1) || (gotEra != expectEra)) {
646             errln(UnicodeString("parse "+samplestr+" of 'y/M/d' as Japanese Calendar, expected year ") + expectYear +
647                     UnicodeString(" and era ") + expectEra +", but got year " + gotYear + " and era " + gotEra + " (Gregorian:" + str +")");
648         } else {
649             logln(UnicodeString() + " year: " + gotYear + ", era: " + gotEra);
650         }
651     }
652 
653     {
654         // Test simple parse/format with adopt
655         UDate aDate = 0;
656 
657         // Test parse with missing era (should default to current era, heisei)
658         // Test parse with incomplete information
659         logln("Testing parse w/ just year...");
660         SimpleDateFormat fmt(UnicodeString("y"), Locale("ja_JP@calendar=japanese"), status);
661         CHECK(status, "creating date format instance");
662         UErrorCode s2 = U_ZERO_ERROR;
663         cal2->clear();
664         UnicodeString samplestr("1");
665         logln(UnicodeString() + "Test Year: " + samplestr);
666         aDate = fmt.parse(samplestr, s2);
667         ParsePosition pp=0;
668         fmt.parse(samplestr, *cal2, pp);
669         CHECK(s2, "parsing the 1 string");
670         logln("*cal2 after 1 parse:");
671         str.remove();
672         fmt2.format(aDate, str);
673         logln(UnicodeString() + "as Gregorian Calendar: " + str);
674 
675         cal2->setTime(aDate, s2);
676         int32_t gotYear = cal2->get(UCAL_YEAR, s2);
677         int32_t gotEra = cal2->get(UCAL_ERA, s2);
678         int32_t expectYear = 1;
679         int32_t expectEra = JapaneseCalendar::getCurrentEra();
680         if((gotYear!=1) || (gotEra != expectEra)) {
681             errln(UnicodeString("parse "+samplestr+" of 'y' as Japanese Calendar, expected year ") + expectYear +
682                     UnicodeString(" and era ") + expectEra +", but got year " + gotYear + " and era " + gotEra + " (Gregorian:" + str +")");
683         } else {
684             logln(UnicodeString() + " year: " + gotYear + ", era: " + gotEra);
685         }
686     }
687 }
688 
TestForceGannenNumbering()689 void IntlCalendarTest::TestForceGannenNumbering()
690 {
691     UErrorCode status;
692     const char* locID = "ja_JP@calendar=japanese";
693     Locale loc(locID);
694     UDate refDate = 600336000000.0; // 1989 Jan 9 Monday = Heisei 1
695     UnicodeString patText(u"Gy年M月d日",-1);
696     UnicodeString patNumr(u"GGGGGy/MM/dd",-1);
697     UnicodeString skelText(u"yMMMM",-1);
698 
699     // Test Gannen year forcing
700     status = U_ZERO_ERROR;
701     LocalPointer<SimpleDateFormat> testFmt1(new SimpleDateFormat(patText, loc, status));
702     LocalPointer<SimpleDateFormat> testFmt2(new SimpleDateFormat(patNumr, loc, status));
703     if (U_FAILURE(status)) {
704         dataerrln("Fail in new SimpleDateFormat locale %s: %s", locID, u_errorName(status));
705     } else {
706         UnicodeString testString1, testString2;
707         testString1 = testFmt1->format(refDate, testString1);
708         if (testString1.length() < 3 || testString1.charAt(2) != 0x5143) {
709             errln(UnicodeString("Formatting year 1 in created text style, got " + testString1 + " but expected 3rd char to be 0x5143"));
710         }
711         testString2 = testFmt2->format(refDate, testString2);
712         if (testString2.length() < 2 || testString2.charAt(1) != 0x0031) {
713             errln(UnicodeString("Formatting year 1 in created numeric style, got " + testString2 + " but expected 2nd char to be 1"));
714         }
715         // Now switch the patterns and verify that Gannen use follows the pattern
716         testFmt1->applyPattern(patNumr);
717         testString1.remove();
718         testString1 = testFmt1->format(refDate, testString1);
719         if (testString1.length() < 2 || testString1.charAt(1) != 0x0031) {
720             errln(UnicodeString("Formatting year 1 in applied numeric style, got " + testString1 + " but expected 2nd char to be 1"));
721         }
722         testFmt2->applyPattern(patText);
723         testString2.remove();
724         testString2 = testFmt2->format(refDate, testString2);
725         if (testString2.length() < 3 || testString2.charAt(2) != 0x5143) {
726             errln(UnicodeString("Formatting year 1 in applied text style, got " + testString2 + " but expected 3rd char to be 0x5143"));
727         }
728     }
729 
730     // Test disabling of Gannen year forcing
731     status = U_ZERO_ERROR;
732     LocalPointer<DateTimePatternGenerator> dtpgen(DateTimePatternGenerator::createInstance(loc, status));
733     if (U_FAILURE(status)) {
734         dataerrln("Fail in DateTimePatternGenerator::createInstance locale %s: %s", locID, u_errorName(status));
735     } else {
736         UnicodeString pattern = dtpgen->getBestPattern(skelText, status);
737         if (U_FAILURE(status)) {
738             dataerrln("Fail in DateTimePatternGenerator::getBestPattern locale %s: %s", locID, u_errorName(status));
739         } else  {
740             // Use override string of ""
741             LocalPointer<SimpleDateFormat> testFmt3(new SimpleDateFormat(pattern, UnicodeString(""), loc, status));
742             if (U_FAILURE(status)) {
743                 dataerrln("Fail in new SimpleDateFormat locale %s: %s", locID, u_errorName(status));
744             } else {
745                 UnicodeString testString3;
746                 testString3 = testFmt3->format(refDate, testString3);
747                 if (testString3.length() < 3 || testString3.charAt(2) != 0x0031) {
748                     errln(UnicodeString("Formatting year 1 with Gannen disabled, got " + testString3 + " but expected 3rd char to be 1"));
749                 }
750             }
751         }
752     }
753 }
754 
755 /**
756  * Verify the Persian Calendar.
757  */
TestPersian()758 void IntlCalendarTest::TestPersian() {
759     UDate timeA = Calendar::getNow();
760 
761     Calendar *cal;
762     UErrorCode status = U_ZERO_ERROR;
763     cal = Calendar::createInstance("fa_IR@calendar=persian", status);
764     CHECK(status, UnicodeString("Creating fa_IR@calendar=persian calendar"));
765     // Sanity check the calendar
766     UDate timeB = Calendar::getNow();
767     UDate timeCal = cal->getTime(status);
768 
769     if(!(timeA <= timeCal) || !(timeCal <= timeB)) {
770       errln((UnicodeString)"Error: Calendar time " + timeCal +
771             " is not within sampled times [" + timeA + " to " + timeB + "]!");
772     }
773     // end sanity check
774 
775     // Test various dates to be sure of validity
776     int32_t data[] = {
777         1925, 4, 24, 1304, 2, 4,
778         2011, 1, 11, 1389, 10, 21,
779         1986, 2, 25, 1364, 12, 6,
780         1934, 3, 14, 1312, 12, 23,
781 
782         2090, 3, 19, 1468, 12, 29,
783         2007, 2, 22, 1385, 12, 3,
784         1969, 12, 31, 1348, 10, 10,
785         1945, 11, 12, 1324, 8, 21,
786         1925, 3, 31, 1304, 1, 11,
787 
788         1996, 3, 19, 1374, 12, 29,
789         1996, 3, 20, 1375, 1, 1,
790         1997, 3, 20, 1375, 12, 30,
791         1997, 3, 21, 1376, 1, 1,
792 
793         2008, 3, 19, 1386, 12, 29,
794         2008, 3, 20, 1387, 1, 1,
795         2004, 3, 19, 1382, 12, 29,
796         2004, 3, 20, 1383, 1, 1,
797 
798         2006, 3, 20, 1384, 12, 29,
799         2006, 3, 21, 1385, 1, 1,
800 
801         2005, 4, 20, 1384, 1, 31,
802         2005, 4, 21, 1384, 2, 1,
803         2005, 5, 21, 1384, 2, 31,
804         2005, 5, 22, 1384, 3, 1,
805         2005, 6, 21, 1384, 3, 31,
806         2005, 6, 22, 1384, 4, 1,
807         2005, 7, 22, 1384, 4, 31,
808         2005, 7, 23, 1384, 5, 1,
809         2005, 8, 22, 1384, 5, 31,
810         2005, 8, 23, 1384, 6, 1,
811         2005, 9, 22, 1384, 6, 31,
812         2005, 9, 23, 1384, 7, 1,
813         2005, 10, 22, 1384, 7, 30,
814         2005, 10, 23, 1384, 8, 1,
815         2005, 11, 21, 1384, 8, 30,
816         2005, 11, 22, 1384, 9, 1,
817         2005, 12, 21, 1384, 9, 30,
818         2005, 12, 22, 1384, 10, 1,
819         2006, 1, 20, 1384, 10, 30,
820         2006, 1, 21, 1384, 11, 1,
821         2006, 2, 19, 1384, 11, 30,
822         2006, 2, 20, 1384, 12, 1,
823         2006, 3, 20, 1384, 12, 29,
824         2006, 3, 21, 1385, 1, 1,
825 
826         // The 2820-year cycle arithmetical algorithm would fail this one.
827         2025, 3, 21, 1404, 1, 1,
828 
829         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1
830     };
831 
832     Calendar *grego = Calendar::createInstance("fa_IR@calendar=gregorian", status);
833     for (int32_t i=0; data[i]!=-1; ) {
834         int32_t gregYear = data[i++];
835         int32_t gregMonth = data[i++]-1;
836         int32_t gregDay = data[i++];
837         int32_t persYear = data[i++];
838         int32_t persMonth = data[i++]-1;
839         int32_t persDay = data[i++];
840 
841         // Test conversion from Persian dates
842         grego->clear();
843         grego->set(gregYear, gregMonth, gregDay);
844 
845         cal->clear();
846         cal->set(persYear, persMonth, persDay);
847 
848         UDate persTime = cal->getTime(status);
849         UDate gregTime = grego->getTime(status);
850 
851         if (persTime != gregTime) {
852           errln(UnicodeString("Expected ") + gregTime + " but got " + persTime);
853         }
854 
855         // Test conversion to Persian dates
856         cal->clear();
857         cal->setTime(gregTime, status);
858 
859         int32_t computedYear = cal->get(UCAL_YEAR, status);
860         int32_t computedMonth = cal->get(UCAL_MONTH, status);
861         int32_t computedDay = cal->get(UCAL_DATE, status);
862 
863         if ((persYear != computedYear) ||
864             (persMonth != computedMonth) ||
865             (persDay != computedDay)) {
866           errln(UnicodeString("Expected ") + persYear + "/" + (persMonth+1) + "/" + persDay +
867                 " but got " +  computedYear + "/" + (computedMonth+1) + "/" + computedDay);
868         }
869 
870     }
871 
872     delete cal;
873     delete grego;
874 }
875 
TestPersianFormat()876 void IntlCalendarTest::TestPersianFormat() {
877     UErrorCode status = U_ZERO_ERROR;
878     SimpleDateFormat fmt(UnicodeString("MMMM d, yyyy G"), Locale(" en_US@calendar=persian"), status);
879     CHECK(status, "creating date format instance");
880     SimpleDateFormat fmt2(UnicodeString("MMMM d, yyyy G"), Locale("en_US@calendar=gregorian"), status);
881     CHECK(status, "creating gregorian date format instance");
882     UnicodeString gregorianDate("January 18, 2007 AD");
883     UDate aDate = fmt2.parse(gregorianDate, status);
884     UnicodeString str;
885     fmt.format(aDate, str);
886     logln(UnicodeString() + "as Persian Calendar: " + escape(str));
887     UnicodeString expected("Dey 28, 1385 AP");
888     if(str != expected) {
889         errln("Expected " + escape(expected) + " but got " + escape(str));
890     }
891     UDate otherDate = fmt.parse(expected, status);
892     if(otherDate != aDate) {
893         UnicodeString str3;
894         fmt.format(otherDate, str3);
895         errln("Parse incorrect of " + escape(expected) + " - wanted " + aDate + " but got " +  otherDate + ", " + escape(str3));
896     } else {
897         logln("Parsed OK: " + expected);
898     }
899     // Two digit year parsing problem #4732
900     fmt.applyPattern("yy-MM-dd");
901     str.remove();
902     fmt.format(aDate, str);
903     expected.setTo("85-10-28");
904     if(str != expected) {
905         errln("Expected " + escape(expected) + " but got " + escape(str));
906     }
907     otherDate = fmt.parse(expected, status);
908     if (otherDate != aDate) {
909         errln("Parse incorrect of " + escape(expected) + " - wanted " + aDate + " but got " + otherDate);
910     } else {
911         logln("Parsed OK: " + expected);
912     }
913 
914     CHECK(status, "Error occured testing Persian Calendar in English ");
915 }
916 
917 
simpleTest(const Locale & loc,const UnicodeString & expect,UDate expectDate,UErrorCode & status)918 void IntlCalendarTest::simpleTest(const Locale& loc, const UnicodeString& expect, UDate expectDate, UErrorCode& status)
919 {
920     UnicodeString tmp;
921     UDate         d;
922     DateFormat *fmt0 = DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull);
923 
924     logln("Try format/parse of " + (UnicodeString)loc.getName());
925     DateFormat *fmt2 = DateFormat::createDateInstance(DateFormat::kFull, loc);
926     if(fmt2) {
927         fmt2->format(expectDate, tmp);
928         logln(escape(tmp) + " ( in locale " + loc.getName() + ")");
929         if(tmp != expect) {
930             errln(UnicodeString("Failed to format " ) + loc.getName() + " expected " + escape(expect) + " got " + escape(tmp) );
931         }
932 
933         d = fmt2->parse(expect,status);
934         CHECK(status, "Error occurred parsing " + UnicodeString(loc.getName()));
935         if(d != expectDate) {
936             fmt2->format(d,tmp);
937             errln(UnicodeString("Failed to parse " ) + escape(expect) + ", " + loc.getName() + " expect " + (double)expectDate + " got " + (double)d  + " " + escape(tmp));
938             logln( "wanted " + escape(fmt0->format(expectDate,tmp.remove())) + " but got " + escape(fmt0->format(d,tmp.remove())));
939         }
940         delete fmt2;
941     } else {
942         errln((UnicodeString)"Can't create " + loc.getName() + " date instance");
943     }
944     delete fmt0;
945 }
946 
947 #undef CHECK
948 
949 #endif /* #if !UCONFIG_NO_FORMATTING */
950 
951 //eof
952