• 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                             "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