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