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