1/************************************************************************
2 * COPYRIGHT:
3 * Copyright (c) 1997-2014, International Business Machines Corporation
4 * and others. All Rights Reserved.
5 ************************************************************************/
6
7#include "unicode/utypes.h"
8
9#if !UCONFIG_NO_FORMATTING
10
11#include "caltest.h"
12#include "unicode/dtfmtsym.h"
13#include "unicode/gregocal.h"
14#include "unicode/localpointer.h"
15#include "hebrwcal.h"
16#include "unicode/smpdtfmt.h"
17#include "unicode/simpletz.h"
18#include "dbgutil.h"
19#include "unicode/udat.h"
20#include "unicode/ustring.h"
21#include "cstring.h"
22#include "unicode/localpointer.h"
23
24#define mkcstr(U) u_austrcpy(calloc(8, u_strlen(U) + 1), U)
25
26#define TEST_CHECK_STATUS {if (U_FAILURE(status)) {errln("%s:%d: Test failure.  status=%s", \
27                                                              __FILE__, __LINE__, u_errorName(status)); return;}}
28
29#define TEST_ASSERT(expr) {if ((expr)==FALSE) {errln("%s:%d: Test failure \n", __FILE__, __LINE__);};}
30
31// *****************************************************************************
32// class CalendarTest
33// *****************************************************************************
34
35UnicodeString CalendarTest::calToStr(const Calendar & cal)
36{
37  UnicodeString out;
38  UErrorCode status = U_ZERO_ERROR;
39  int i;
40  UDate d;
41  for(i = 0;i<UCAL_FIELD_COUNT;i++) {
42    out += (UnicodeString("") + fieldName((UCalendarDateFields)i) + "=" +  cal.get((UCalendarDateFields)i, status) + UnicodeString(" "));
43  }
44  out += "[" + UnicodeString(cal.getType()) + "]";
45
46  if(cal.inDaylightTime(status)) {
47    out += UnicodeString(" (in DST), zone=");
48  }
49  else {
50    out += UnicodeString(", zone=");
51  }
52
53  UnicodeString str2;
54  out += cal.getTimeZone().getDisplayName(str2);
55  d = cal.getTime(status);
56  out += UnicodeString(" :","") + d;
57
58  return out;
59}
60
61void CalendarTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
62{
63    if (exec) logln("TestSuite TestCalendar");
64    switch (index) {
65        case 0:
66            name = "TestDOW943";
67            if (exec) {
68                logln("TestDOW943---"); logln("");
69                TestDOW943();
70            }
71            break;
72        case 1:
73            name = "TestClonesUnique908";
74            if (exec) {
75                logln("TestClonesUnique908---"); logln("");
76                TestClonesUnique908();
77            }
78            break;
79        case 2:
80            name = "TestGregorianChange768";
81            if (exec) {
82                logln("TestGregorianChange768---"); logln("");
83                TestGregorianChange768();
84            }
85            break;
86        case 3:
87            name = "TestDisambiguation765";
88            if (exec) {
89                logln("TestDisambiguation765---"); logln("");
90                TestDisambiguation765();
91            }
92            break;
93        case 4:
94            name = "TestGMTvsLocal4064654";
95            if (exec) {
96                logln("TestGMTvsLocal4064654---"); logln("");
97                TestGMTvsLocal4064654();
98            }
99            break;
100        case 5:
101            name = "TestAddSetOrder621";
102            if (exec) {
103                logln("TestAddSetOrder621---"); logln("");
104                TestAddSetOrder621();
105            }
106            break;
107        case 6:
108            name = "TestAdd520";
109            if (exec) {
110                logln("TestAdd520---"); logln("");
111                TestAdd520();
112            }
113            break;
114        case 7:
115            name = "TestFieldSet4781";
116            if (exec) {
117                logln("TestFieldSet4781---"); logln("");
118                TestFieldSet4781();
119            }
120            break;
121        case 8:
122            name = "TestSerialize337";
123            if (exec) {
124                logln("TestSerialize337---"); logln("");
125            //  TestSerialize337();
126            }
127            break;
128        case 9:
129            name = "TestSecondsZero121";
130            if (exec) {
131                logln("TestSecondsZero121---"); logln("");
132                TestSecondsZero121();
133            }
134            break;
135        case 10:
136            name = "TestAddSetGet0610";
137            if (exec) {
138                logln("TestAddSetGet0610---"); logln("");
139                TestAddSetGet0610();
140            }
141            break;
142        case 11:
143            name = "TestFields060";
144            if (exec) {
145                logln("TestFields060---"); logln("");
146                TestFields060();
147            }
148            break;
149        case 12:
150            name = "TestEpochStartFields";
151            if (exec) {
152                logln("TestEpochStartFields---"); logln("");
153                TestEpochStartFields();
154            }
155            break;
156        case 13:
157            name = "TestDOWProgression";
158            if (exec) {
159                logln("TestDOWProgression---"); logln("");
160                TestDOWProgression();
161            }
162            break;
163        case 14:
164            name = "TestGenericAPI";
165            if (exec) {
166                logln("TestGenericAPI---"); logln("");
167                TestGenericAPI();
168            }
169            break;
170        case 15:
171            name = "TestAddRollExtensive";
172            if (exec) {
173                logln("TestAddRollExtensive---"); logln("");
174                TestAddRollExtensive();
175            }
176            break;
177        case 16:
178            name = "TestDOW_LOCALandYEAR_WOY";
179            if (exec) {
180                logln("TestDOW_LOCALandYEAR_WOY---"); logln("");
181                TestDOW_LOCALandYEAR_WOY();
182            }
183            break;
184        case 17:
185            name = "TestWOY";
186            if (exec) {
187                logln("TestWOY---"); logln("");
188                TestWOY();
189            }
190            break;
191        case 18:
192            name = "TestRog";
193            if (exec) {
194                logln("TestRog---"); logln("");
195                TestRog();
196            }
197            break;
198        case 19:
199           name = "TestYWOY";
200            if (exec) {
201                logln("TestYWOY---"); logln("");
202                TestYWOY();
203            }
204            break;
205        case 20:
206          name = "TestJD";
207          if(exec) {
208            logln("TestJD---"); logln("");
209            TestJD();
210          }
211          break;
212        case 21:
213          name = "TestDebug";
214          if(exec) {
215            logln("TestDebug---"); logln("");
216            TestDebug();
217          }
218          break;
219        case 22:
220          name = "Test6703";
221          if(exec) {
222            logln("Test6703---"); logln("");
223            Test6703();
224          }
225          break;
226        case 23:
227          name = "Test3785";
228          if(exec) {
229            logln("Test3785---"); logln("");
230            Test3785();
231          }
232          break;
233        case 24:
234          name = "Test1624";
235          if(exec) {
236            logln("Test1624---"); logln("");
237            Test1624();
238          }
239          break;
240        case 25:
241          name = "TestTimeStamp";
242          if(exec) {
243            logln("TestTimeStamp---"); logln("");
244            TestTimeStamp();
245          }
246          break;
247        case 26:
248          name = "TestISO8601";
249          if(exec) {
250            logln("TestISO8601---"); logln("");
251            TestISO8601();
252          }
253          break;
254        case 27:
255          name = "TestAmbiguousWallTimeAPIs";
256          if(exec) {
257            logln("TestAmbiguousWallTimeAPIs---"); logln("");
258            TestAmbiguousWallTimeAPIs();
259          }
260          break;
261        case 28:
262          name = "TestRepeatedWallTime";
263          if(exec) {
264            logln("TestRepeatedWallTime---"); logln("");
265            TestRepeatedWallTime();
266          }
267          break;
268        case 29:
269          name = "TestSkippedWallTime";
270          if(exec) {
271            logln("TestSkippedWallTime---"); logln("");
272            TestSkippedWallTime();
273          }
274          break;
275        case 30:
276          name = "TestCloneLocale";
277          if(exec) {
278            logln("TestCloneLocale---"); logln("");
279            TestCloneLocale();
280          }
281          break;
282        case 31:
283          name = "TestAddAcrossZoneTransition";
284          if(exec) {
285            logln("TestAddAcrossZoneTransition---"); logln("");
286            TestAddAcrossZoneTransition();
287          }
288          break;
289        default: name = ""; break;
290    }
291}
292
293// ---------------------------------------------------------------------------------
294
295UnicodeString CalendarTest::fieldName(UCalendarDateFields f) {
296    switch (f) {
297#define FIELD_NAME_STR(x) case x: return (#x+5)
298      FIELD_NAME_STR( UCAL_ERA );
299      FIELD_NAME_STR( UCAL_YEAR );
300      FIELD_NAME_STR( UCAL_MONTH );
301      FIELD_NAME_STR( UCAL_WEEK_OF_YEAR );
302      FIELD_NAME_STR( UCAL_WEEK_OF_MONTH );
303      FIELD_NAME_STR( UCAL_DATE );
304      FIELD_NAME_STR( UCAL_DAY_OF_YEAR );
305      FIELD_NAME_STR( UCAL_DAY_OF_WEEK );
306      FIELD_NAME_STR( UCAL_DAY_OF_WEEK_IN_MONTH );
307      FIELD_NAME_STR( UCAL_AM_PM );
308      FIELD_NAME_STR( UCAL_HOUR );
309      FIELD_NAME_STR( UCAL_HOUR_OF_DAY );
310      FIELD_NAME_STR( UCAL_MINUTE );
311      FIELD_NAME_STR( UCAL_SECOND );
312      FIELD_NAME_STR( UCAL_MILLISECOND );
313      FIELD_NAME_STR( UCAL_ZONE_OFFSET );
314      FIELD_NAME_STR( UCAL_DST_OFFSET );
315      FIELD_NAME_STR( UCAL_YEAR_WOY );
316      FIELD_NAME_STR( UCAL_DOW_LOCAL );
317      FIELD_NAME_STR( UCAL_EXTENDED_YEAR );
318      FIELD_NAME_STR( UCAL_JULIAN_DAY );
319      FIELD_NAME_STR( UCAL_MILLISECONDS_IN_DAY );
320#undef FIELD_NAME_STR
321    default:
322        return UnicodeString("") + ((int32_t)f);
323    }
324}
325
326/**
327 * Test various API methods for API completeness.
328 */
329void
330CalendarTest::TestGenericAPI()
331{
332    UErrorCode status = U_ZERO_ERROR;
333    UDate d;
334    UnicodeString str;
335    UBool eq = FALSE,b4 = FALSE,af = FALSE;
336
337    UDate when = date(90, UCAL_APRIL, 15);
338
339    UnicodeString tzid("TestZone");
340    int32_t tzoffset = 123400;
341
342    SimpleTimeZone *zone = new SimpleTimeZone(tzoffset, tzid);
343    Calendar *cal = Calendar::createInstance(zone->clone(), status);
344    if (failure(status, "Calendar::createInstance", TRUE)) return;
345
346    if (*zone != cal->getTimeZone()) errln("FAIL: Calendar::getTimeZone failed");
347
348    Calendar *cal2 = Calendar::createInstance(cal->getTimeZone(), status);
349    if (failure(status, "Calendar::createInstance")) return;
350    cal->setTime(when, status);
351    cal2->setTime(when, status);
352    if (failure(status, "Calendar::setTime")) return;
353
354    if (!(*cal == *cal2)) errln("FAIL: Calendar::operator== failed");
355    if ((*cal != *cal2))  errln("FAIL: Calendar::operator!= failed");
356    if (!cal->equals(*cal2, status) ||
357        cal->before(*cal2, status) ||
358        cal->after(*cal2, status) ||
359        U_FAILURE(status)) errln("FAIL: equals/before/after failed");
360
361    logln(UnicodeString("cal=")  +cal->getTime(status)  + UnicodeString(calToStr(*cal)));
362    logln(UnicodeString("cal2=")  +cal2->getTime(status)  + UnicodeString(calToStr(*cal2)));
363    logln("cal2->setTime(when+1000)");
364    cal2->setTime(when + 1000, status);
365    logln(UnicodeString("cal2=")  +cal2->getTime(status)  + UnicodeString(calToStr(*cal2)));
366
367    if (failure(status, "Calendar::setTime")) return;
368    if (cal->equals(*cal2, status) ||
369        cal2->before(*cal, status) ||
370        cal->after(*cal2, status) ||
371        U_FAILURE(status)) errln("FAIL: equals/before/after failed after setTime(+1000)");
372
373    logln("cal->roll(UCAL_SECOND)");
374    cal->roll(UCAL_SECOND, (UBool) TRUE, status);
375    logln(UnicodeString("cal=")  +cal->getTime(status)  + UnicodeString(calToStr(*cal)));
376    cal->roll(UCAL_SECOND, (int32_t)0, status);
377    logln(UnicodeString("cal=")  +cal->getTime(status)  + UnicodeString(calToStr(*cal)));
378    if (failure(status, "Calendar::roll")) return;
379
380    if (!(eq=cal->equals(*cal2, status)) ||
381        (b4=cal->before(*cal2, status)) ||
382        (af=cal->after(*cal2, status)) ||
383        U_FAILURE(status)) {
384      errln("FAIL: equals[%c]/before[%c]/after[%c] failed after roll 1 second [should be T/F/F]",
385            eq?'T':'F',
386            b4?'T':'F',
387            af?'T':'F');
388      logln(UnicodeString("cal=")  +cal->getTime(status)  + UnicodeString(calToStr(*cal)));
389      logln(UnicodeString("cal2=")  +cal2->getTime(status)  + UnicodeString(calToStr(*cal2)));
390    }
391
392    // Roll back to January
393    cal->roll(UCAL_MONTH, (int32_t)(1 + UCAL_DECEMBER - cal->get(UCAL_MONTH, status)), status);
394    if (failure(status, "Calendar::roll")) return;
395    if (cal->equals(*cal2, status) ||
396        cal2->before(*cal, status) ||
397        cal->after(*cal2, status) ||
398        U_FAILURE(status)) errln("FAIL: equals/before/after failed after rollback to January");
399
400    TimeZone *z = cal->orphanTimeZone();
401    if (z->getID(str) != tzid ||
402        z->getRawOffset() != tzoffset)
403        errln("FAIL: orphanTimeZone failed");
404
405    int32_t i;
406    for (i=0; i<2; ++i)
407    {
408        UBool lenient = ( i > 0 );
409        cal->setLenient(lenient);
410        if (lenient != cal->isLenient()) errln("FAIL: setLenient/isLenient failed");
411        // Later: Check for lenient behavior
412    }
413
414    for (i=UCAL_SUNDAY; i<=UCAL_SATURDAY; ++i)
415    {
416        cal->setFirstDayOfWeek((UCalendarDaysOfWeek)i);
417        if (cal->getFirstDayOfWeek() != i) errln("FAIL: set/getFirstDayOfWeek failed");
418        UErrorCode aStatus = U_ZERO_ERROR;
419        if (cal->getFirstDayOfWeek(aStatus) != i || U_FAILURE(aStatus)) errln("FAIL: getFirstDayOfWeek(status) failed");
420    }
421
422    for (i=1; i<=7; ++i)
423    {
424        cal->setMinimalDaysInFirstWeek((uint8_t)i);
425        if (cal->getMinimalDaysInFirstWeek() != i) errln("FAIL: set/getFirstDayOfWeek failed");
426    }
427
428    for (i=0; i<UCAL_FIELD_COUNT; ++i)
429    {
430        if (cal->getMinimum((UCalendarDateFields)i) > cal->getGreatestMinimum((UCalendarDateFields)i))
431            errln(UnicodeString("FAIL: getMinimum larger than getGreatestMinimum for field ") + i);
432        if (cal->getLeastMaximum((UCalendarDateFields)i) > cal->getMaximum((UCalendarDateFields)i))
433            errln(UnicodeString("FAIL: getLeastMaximum larger than getMaximum for field ") + i);
434        if (cal->getMinimum((UCalendarDateFields)i) >= cal->getMaximum((UCalendarDateFields)i))
435            errln(UnicodeString("FAIL: getMinimum not less than getMaximum for field ") + i);
436    }
437
438    cal->adoptTimeZone(TimeZone::createDefault());
439    cal->clear();
440    cal->set(1984, 5, 24);
441    if (cal->getTime(status) != date(84, 5, 24) || U_FAILURE(status))
442        errln("FAIL: Calendar::set(3 args) failed");
443
444    cal->clear();
445    cal->set(1985, 3, 2, 11, 49);
446    if (cal->getTime(status) != date(85, 3, 2, 11, 49) || U_FAILURE(status))
447        errln("FAIL: Calendar::set(5 args) failed");
448
449    cal->clear();
450    cal->set(1995, 9, 12, 1, 39, 55);
451    if (cal->getTime(status) != date(95, 9, 12, 1, 39, 55) || U_FAILURE(status))
452        errln("FAIL: Calendar::set(6 args) failed");
453
454    cal->getTime(status);
455    if (failure(status, "Calendar::getTime")) return;
456    for (i=0; i<UCAL_FIELD_COUNT; ++i)
457    {
458        switch(i) {
459            case UCAL_YEAR: case UCAL_MONTH: case UCAL_DATE:
460            case UCAL_HOUR_OF_DAY: case UCAL_MINUTE: case UCAL_SECOND:
461            case UCAL_EXTENDED_YEAR:
462              if (!cal->isSet((UCalendarDateFields)i)) errln("FAIL: Calendar::isSet F, should be T " + fieldName((UCalendarDateFields)i));
463                break;
464            default:
465              if (cal->isSet((UCalendarDateFields)i)) errln("FAIL: Calendar::isSet = T, should be F  " + fieldName((UCalendarDateFields)i));
466        }
467        cal->clear((UCalendarDateFields)i);
468        if (cal->isSet((UCalendarDateFields)i)) errln("FAIL: Calendar::clear/isSet failed " + fieldName((UCalendarDateFields)i));
469    }
470
471    if(cal->getActualMinimum(Calendar::SECOND, status) != 0){
472        errln("Calendar is suppose to return 0 for getActualMinimum");
473    }
474
475    Calendar *cal3 = Calendar::createInstance(status);
476    cal3->roll(Calendar::SECOND, (int32_t)0, status);
477    if (failure(status, "Calendar::roll(EDateFields, int32_t, UErrorCode)")) return;
478
479    delete cal;
480    delete cal2;
481    delete cal3;
482
483    int32_t count;
484    const Locale* loc = Calendar::getAvailableLocales(count);
485    if (count < 1 || loc == 0)
486    {
487        dataerrln("FAIL: getAvailableLocales failed");
488    }
489    else
490    {
491        for (i=0; i<count; ++i)
492        {
493            cal = Calendar::createInstance(loc[i], status);
494            if (failure(status, "Calendar::createInstance")) return;
495            delete cal;
496        }
497    }
498
499    cal = Calendar::createInstance(TimeZone::createDefault(), Locale::getEnglish(), status);
500    if (failure(status, "Calendar::createInstance")) return;
501    delete cal;
502
503    cal = Calendar::createInstance(*zone, Locale::getEnglish(), status);
504    if (failure(status, "Calendar::createInstance")) return;
505    delete cal;
506
507    GregorianCalendar *gc = new GregorianCalendar(*zone, status);
508    if (failure(status, "new GregorianCalendar")) return;
509    delete gc;
510
511    gc = new GregorianCalendar(Locale::getEnglish(), status);
512    if (failure(status, "new GregorianCalendar")) return;
513    delete gc;
514
515    gc = new GregorianCalendar(Locale::getEnglish(), status);
516    delete gc;
517
518    gc = new GregorianCalendar(*zone, Locale::getEnglish(), status);
519    if (failure(status, "new GregorianCalendar")) return;
520    delete gc;
521
522    gc = new GregorianCalendar(zone, status);
523    if (failure(status, "new GregorianCalendar")) return;
524    delete gc;
525
526    gc = new GregorianCalendar(1998, 10, 14, 21, 43, status);
527    if (gc->getTime(status) != (d =date(98, 10, 14, 21, 43) )|| U_FAILURE(status))
528      errln("FAIL: new GregorianCalendar(ymdhm) failed with " + UnicodeString(u_errorName(status)) + ",  cal="  + gc->getTime(status)  + UnicodeString(calToStr(*gc)) + ", d=" + d);
529    else
530      logln(UnicodeString("GOOD: cal=")  +gc->getTime(status)  + UnicodeString(calToStr(*gc)) + ", d=" + d);
531    delete gc;
532
533    gc = new GregorianCalendar(1998, 10, 14, 21, 43, 55, status);
534    if (gc->getTime(status) != (d=date(98, 10, 14, 21, 43, 55)) || U_FAILURE(status))
535      errln("FAIL: new GregorianCalendar(ymdhms) failed with " + UnicodeString(u_errorName(status)));
536
537    GregorianCalendar gc2(Locale::getEnglish(), status);
538    if (failure(status, "new GregorianCalendar")) return;
539    gc2 = *gc;
540    if (gc2 != *gc || !(gc2 == *gc)) errln("FAIL: GregorianCalendar assignment/operator==/operator!= failed");
541    delete gc;
542    delete z;
543
544    /* Code coverage for Calendar class. */
545    cal = Calendar::createInstance(status);
546    if (failure(status, "Calendar::createInstance")) {
547        return;
548    }else {
549        ((Calendar *)cal)->roll(UCAL_HOUR, (int32_t)100, status);
550        ((Calendar *)cal)->clear(UCAL_HOUR);
551#if !UCONFIG_NO_SERVICE
552        URegistryKey key = cal->registerFactory(NULL, status);
553        cal->unregister(key, status);
554#endif
555    }
556    delete cal;
557
558    status = U_ZERO_ERROR;
559    cal = Calendar::createInstance(Locale("he_IL@calendar=hebrew"), status);
560    if (failure(status, "Calendar::createInstance")) {
561        return;
562    } else {
563        cal->roll(Calendar::MONTH, (int32_t)100, status);
564    }
565
566    LocalPointer<StringEnumeration> values(
567        Calendar::getKeywordValuesForLocale("calendar", Locale("he"), FALSE, status));
568    if (values.isNull() || U_FAILURE(status)) {
569        dataerrln("FAIL: Calendar::getKeywordValuesForLocale(he): %s", u_errorName(status));
570    } else {
571        UBool containsHebrew = FALSE;
572        const char *charValue;
573        int32_t valueLength;
574        while ((charValue = values->next(&valueLength, status)) != NULL) {
575            if (valueLength == 6 && strcmp(charValue, "hebrew") == 0) {
576                containsHebrew = TRUE;
577            }
578        }
579        if (!containsHebrew) {
580            errln("Calendar::getKeywordValuesForLocale(he)->next() does not contain \"hebrew\"");
581        }
582
583        values->reset(status);
584        containsHebrew = FALSE;
585        UnicodeString hebrew = UNICODE_STRING_SIMPLE("hebrew");
586        const UChar *ucharValue;
587        while ((ucharValue = values->unext(&valueLength, status)) != NULL) {
588            UnicodeString value(FALSE, ucharValue, valueLength);
589            if (value == hebrew) {
590                containsHebrew = TRUE;
591            }
592        }
593        if (!containsHebrew) {
594            errln("Calendar::getKeywordValuesForLocale(he)->unext() does not contain \"hebrew\"");
595        }
596
597        values->reset(status);
598        containsHebrew = FALSE;
599        const UnicodeString *stringValue;
600        while ((stringValue = values->snext(status)) != NULL) {
601            if (*stringValue == hebrew) {
602                containsHebrew = TRUE;
603            }
604        }
605        if (!containsHebrew) {
606            errln("Calendar::getKeywordValuesForLocale(he)->snext() does not contain \"hebrew\"");
607        }
608    }
609    delete cal;
610}
611
612// -------------------------------------
613
614/**
615 * This test confirms the correct behavior of add when incrementing
616 * through subsequent days.
617 */
618void
619CalendarTest::TestRog()
620{
621    UErrorCode status = U_ZERO_ERROR;
622    GregorianCalendar* gc = new GregorianCalendar(status);
623    if (failure(status, "new GregorianCalendar", TRUE)) return;
624    int32_t year = 1997, month = UCAL_APRIL, date = 1;
625    gc->set(year, month, date);
626    gc->set(UCAL_HOUR_OF_DAY, 23);
627    gc->set(UCAL_MINUTE, 0);
628    gc->set(UCAL_SECOND, 0);
629    gc->set(UCAL_MILLISECOND, 0);
630    for (int32_t i = 0; i < 9; i++, gc->add(UCAL_DATE, 1, status)) {
631        if (U_FAILURE(status)) { errln("Calendar::add failed"); return; }
632        if (gc->get(UCAL_YEAR, status) != year ||
633            gc->get(UCAL_MONTH, status) != month ||
634            gc->get(UCAL_DATE, status) != (date + i)) errln("FAIL: Date wrong");
635        if (U_FAILURE(status)) { errln("Calendar::get failed"); return; }
636    }
637    delete gc;
638}
639
640// -------------------------------------
641
642/**
643 * Test the handling of the day of the week, checking for correctness and
644 * for correct minimum and maximum values.
645 */
646void
647CalendarTest::TestDOW943()
648{
649    dowTest(FALSE);
650    dowTest(TRUE);
651}
652
653void CalendarTest::dowTest(UBool lenient)
654{
655    UErrorCode status = U_ZERO_ERROR;
656    GregorianCalendar* cal = new GregorianCalendar(status);
657    if (failure(status, "new GregorianCalendar", TRUE)) return;
658    logln("cal - Aug 12, 1997\n");
659    cal->set(1997, UCAL_AUGUST, 12);
660    cal->getTime(status);
661    if (U_FAILURE(status)) { errln("Calendar::getTime failed"); return; }
662    logln((lenient?UnicodeString("LENIENT0: "):UnicodeString("nonlenient0: ")) + UnicodeString(calToStr(*cal)));
663    cal->setLenient(lenient);
664    logln("cal - Dec 1, 1996\n");
665    cal->set(1996, UCAL_DECEMBER, 1);
666    logln((lenient?UnicodeString("LENIENT: "):UnicodeString("nonlenient: ")) + UnicodeString(calToStr(*cal)));
667    int32_t dow = cal->get(UCAL_DAY_OF_WEEK, status);
668    if (U_FAILURE(status)) { errln("Calendar::get failed [%s]", u_errorName(status)); return; }
669    int32_t min = cal->getMinimum(UCAL_DAY_OF_WEEK);
670    int32_t max = cal->getMaximum(UCAL_DAY_OF_WEEK);
671    if (dow < min ||
672        dow > max) errln(UnicodeString("FAIL: Day of week ") + (int32_t)dow + " out of range");
673    if (dow != UCAL_SUNDAY) errln("FAIL: Day of week should be SUNDAY[%d] not %d", UCAL_SUNDAY, dow);
674    if (min != UCAL_SUNDAY ||
675        max != UCAL_SATURDAY) errln("FAIL: Min/max bad");
676    delete cal;
677}
678
679// -------------------------------------
680
681/**
682 * Confirm that cloned Calendar objects do not inadvertently share substructures.
683 */
684void
685CalendarTest::TestClonesUnique908()
686{
687    UErrorCode status = U_ZERO_ERROR;
688    Calendar *c = Calendar::createInstance(status);
689    if (failure(status, "Calendar::createInstance", TRUE)) return;
690    Calendar *d = (Calendar*) c->clone();
691    c->set(UCAL_MILLISECOND, 123);
692    d->set(UCAL_MILLISECOND, 456);
693    if (c->get(UCAL_MILLISECOND, status) != 123 ||
694        d->get(UCAL_MILLISECOND, status) != 456) {
695        errln("FAIL: Clones share fields");
696    }
697    if (U_FAILURE(status)) { errln("Calendar::get failed"); return; }
698    delete c;
699    delete d;
700}
701
702// -------------------------------------
703
704/**
705 * Confirm that the Gregorian cutoff value works as advertised.
706 */
707void
708CalendarTest::TestGregorianChange768()
709{
710    UBool b;
711    UErrorCode status = U_ZERO_ERROR;
712    UnicodeString str;
713    GregorianCalendar* c = new GregorianCalendar(status);
714    if (failure(status, "new GregorianCalendar", TRUE)) return;
715    logln(UnicodeString("With cutoff ") + dateToString(c->getGregorianChange(), str));
716    b = c->isLeapYear(1800);
717    logln(UnicodeString(" isLeapYear(1800) = ") + (b ? "true" : "false"));
718    logln(UnicodeString(" (should be FALSE)"));
719    if (b) errln("FAIL");
720    c->setGregorianChange(date(0, 0, 1), status);
721    if (U_FAILURE(status)) { errln("GregorianCalendar::setGregorianChange failed"); return; }
722    logln(UnicodeString("With cutoff ") + dateToString(c->getGregorianChange(), str));
723    b = c->isLeapYear(1800);
724    logln(UnicodeString(" isLeapYear(1800) = ") + (b ? "true" : "false"));
725    logln(UnicodeString(" (should be TRUE)"));
726    if (!b) errln("FAIL");
727    delete c;
728}
729
730// -------------------------------------
731
732/**
733 * Confirm the functioning of the field disambiguation algorithm.
734 */
735void
736CalendarTest::TestDisambiguation765()
737{
738    UErrorCode status = U_ZERO_ERROR;
739    Calendar *c = Calendar::createInstance("en_US", status);
740    if (failure(status, "Calendar::createInstance", TRUE)) return;
741    c->setLenient(FALSE);
742    c->clear();
743    c->set(UCAL_YEAR, 1997);
744    c->set(UCAL_MONTH, UCAL_JUNE);
745    c->set(UCAL_DATE, 3);
746    verify765("1997 third day of June = ", c, 1997, UCAL_JUNE, 3);
747    c->clear();
748    c->set(UCAL_YEAR, 1997);
749    c->set(UCAL_DAY_OF_WEEK, UCAL_TUESDAY);
750    c->set(UCAL_MONTH, UCAL_JUNE);
751    c->set(UCAL_DAY_OF_WEEK_IN_MONTH, 1);
752    verify765("1997 first Tuesday in June = ", c, 1997, UCAL_JUNE, 3);
753    c->clear();
754    c->set(UCAL_YEAR, 1997);
755    c->set(UCAL_DAY_OF_WEEK, UCAL_TUESDAY);
756    c->set(UCAL_MONTH, UCAL_JUNE);
757    c->set(UCAL_DAY_OF_WEEK_IN_MONTH, - 1);
758    verify765("1997 last Tuesday in June = ", c, 1997, UCAL_JUNE, 24);
759
760    status = U_ZERO_ERROR;
761    c->clear();
762    c->set(UCAL_YEAR, 1997);
763    c->set(UCAL_DAY_OF_WEEK, UCAL_TUESDAY);
764    c->set(UCAL_MONTH, UCAL_JUNE);
765    c->set(UCAL_DAY_OF_WEEK_IN_MONTH, 0);
766    c->getTime(status);
767    verify765("1997 zero-th Tuesday in June = ", status);
768
769    c->clear();
770    c->set(UCAL_YEAR, 1997);
771    c->set(UCAL_DAY_OF_WEEK, UCAL_TUESDAY);
772    c->set(UCAL_MONTH, UCAL_JUNE);
773    c->set(UCAL_WEEK_OF_MONTH, 1);
774    verify765("1997 Tuesday in week 1 of June = ", c, 1997, UCAL_JUNE, 3);
775    c->clear();
776    c->set(UCAL_YEAR, 1997);
777    c->set(UCAL_DAY_OF_WEEK, UCAL_TUESDAY);
778    c->set(UCAL_MONTH, UCAL_JUNE);
779    c->set(UCAL_WEEK_OF_MONTH, 5);
780    verify765("1997 Tuesday in week 5 of June = ", c, 1997, UCAL_JULY, 1);
781
782    status = U_ZERO_ERROR;
783    c->clear();
784    c->set(UCAL_YEAR, 1997);
785    c->set(UCAL_DAY_OF_WEEK, UCAL_TUESDAY);
786    c->set(UCAL_MONTH, UCAL_JUNE);
787    c->set(UCAL_WEEK_OF_MONTH, 0);
788    c->setMinimalDaysInFirstWeek(1);
789    c->getTime(status);
790    verify765("1997 Tuesday in week 0 of June = ", status);
791
792    /* Note: The following test used to expect YEAR 1997, WOY 1 to
793     * resolve to a date in Dec 1996; that is, to behave as if
794     * YEAR_WOY were 1997.  With the addition of a new explicit
795     * YEAR_WOY field, YEAR_WOY must itself be set if that is what is
796     * desired.  Using YEAR in combination with WOY is ambiguous, and
797     * results in the first WOY/DOW day of the year satisfying the
798     * given fields (there may be up to two such days). In this case,
799     * it propertly resolves to Tue Dec 30 1997, which has a WOY value
800     * of 1 (for YEAR_WOY 1998) and a DOW of Tuesday, and falls in the
801     * _calendar_ year 1997, as specified. - aliu */
802    c->clear();
803    c->set(UCAL_YEAR_WOY, 1997); // aliu
804    c->set(UCAL_DAY_OF_WEEK, UCAL_TUESDAY);
805    c->set(UCAL_WEEK_OF_YEAR, 1);
806    verify765("1997 Tuesday in week 1 of yearWOY = ", c, 1996, UCAL_DECEMBER, 31);
807    c->clear(); // - add test for YEAR
808    c->setMinimalDaysInFirstWeek(1);
809    c->set(UCAL_YEAR, 1997);
810    c->set(UCAL_DAY_OF_WEEK, UCAL_TUESDAY);
811    c->set(UCAL_WEEK_OF_YEAR, 1);
812    verify765("1997 Tuesday in week 1 of year = ", c, 1997, UCAL_DECEMBER, 30);
813    c->clear();
814    c->set(UCAL_YEAR, 1997);
815    c->set(UCAL_DAY_OF_WEEK, UCAL_TUESDAY);
816    c->set(UCAL_WEEK_OF_YEAR, 10);
817    verify765("1997 Tuesday in week 10 of year = ", c, 1997, UCAL_MARCH, 4);
818    //try {
819
820    // {sfb} week 0 is no longer a valid week of year
821    /*c->clear();
822    c->set(Calendar::YEAR, 1997);
823    c->set(Calendar::DAY_OF_WEEK, Calendar::TUESDAY);
824    //c->set(Calendar::WEEK_OF_YEAR, 0);
825    c->set(Calendar::WEEK_OF_YEAR, 1);
826    verify765("1997 Tuesday in week 0 of year = ", c, 1996, Calendar::DECEMBER, 24);*/
827
828    //}
829    //catch(IllegalArgumentException ex) {
830    //    errln("FAIL: Exception seen:");
831    //    ex.printStackTrace(log);
832    //}
833    delete c;
834}
835
836// -------------------------------------
837
838void
839CalendarTest::verify765(const UnicodeString& msg, Calendar* c, int32_t year, int32_t month, int32_t day)
840{
841    UnicodeString str;
842    UErrorCode status = U_ZERO_ERROR;
843    int32_t y = c->get(UCAL_YEAR, status);
844    int32_t m = c->get(UCAL_MONTH, status);
845    int32_t d = c->get(UCAL_DATE, status);
846    if ( y == year &&
847         m == month &&
848         d == day) {
849        if (U_FAILURE(status)) { errln("FAIL: Calendar::get failed"); return; }
850        logln("PASS: " + msg + dateToString(c->getTime(status), str));
851        if (U_FAILURE(status)) { errln("Calendar::getTime failed"); return; }
852    }
853    else {
854        errln("FAIL: " + msg + dateToString(c->getTime(status), str) + "; expected " + (int32_t)year + "/" + (int32_t)(month + 1) + "/" + (int32_t)day +
855            "; got " + (int32_t)y + "/" + (int32_t)(m + 1) + "/" + (int32_t)d + " for Locale: " + c->getLocaleID(ULOC_ACTUAL_LOCALE,status));
856        if (U_FAILURE(status)) { errln("Calendar::getTime failed"); return; }
857    }
858}
859
860// -------------------------------------
861
862void
863CalendarTest::verify765(const UnicodeString& msg/*, IllegalArgumentException e*/, UErrorCode status)
864{
865    if (status != U_ILLEGAL_ARGUMENT_ERROR) errln("FAIL: No IllegalArgumentException for " + msg);
866    else logln("PASS: " + msg + "IllegalArgument as expected");
867}
868
869// -------------------------------------
870
871/**
872 * Confirm that the offset between local time and GMT behaves as expected.
873 */
874void
875CalendarTest::TestGMTvsLocal4064654()
876{
877    test4064654(1997, 1, 1, 12, 0, 0);
878    test4064654(1997, 4, 16, 18, 30, 0);
879}
880
881// -------------------------------------
882
883void
884CalendarTest::test4064654(int32_t yr, int32_t mo, int32_t dt, int32_t hr, int32_t mn, int32_t sc)
885{
886    UDate date;
887    UErrorCode status = U_ZERO_ERROR;
888    UnicodeString str;
889    Calendar *gmtcal = Calendar::createInstance(status);
890    if (failure(status, "Calendar::createInstance", TRUE)) return;
891    gmtcal->adoptTimeZone(TimeZone::createTimeZone("Africa/Casablanca"));
892    gmtcal->set(yr, mo - 1, dt, hr, mn, sc);
893    gmtcal->set(UCAL_MILLISECOND, 0);
894    date = gmtcal->getTime(status);
895    if (U_FAILURE(status)) { errln("Calendar::getTime failed"); return; }
896    logln("date = " + dateToString(date, str));
897    Calendar *cal = Calendar::createInstance(status);
898    if (U_FAILURE(status)) { errln("Calendar::createInstance failed"); return; }
899    cal->setTime(date, status);
900    if (U_FAILURE(status)) { errln("Calendar::setTime failed"); return; }
901    int32_t offset = cal->getTimeZone().getOffset((uint8_t)cal->get(UCAL_ERA, status),
902                                                  cal->get(UCAL_YEAR, status),
903                                                  cal->get(UCAL_MONTH, status),
904                                                  cal->get(UCAL_DATE, status),
905                                                  (uint8_t)cal->get(UCAL_DAY_OF_WEEK, status),
906                                                  cal->get(UCAL_MILLISECOND, status), status);
907    if (U_FAILURE(status)) { errln("Calendar::get failed"); return; }
908    logln("offset for " + dateToString(date, str) + "= " + (offset / 1000 / 60 / 60.0) + "hr");
909    int32_t utc = ((cal->get(UCAL_HOUR_OF_DAY, status) * 60 +
910                    cal->get(UCAL_MINUTE, status)) * 60 +
911                   cal->get(UCAL_SECOND, status)) * 1000 +
912        cal->get(UCAL_MILLISECOND, status) - offset;
913    if (U_FAILURE(status)) { errln("Calendar::get failed"); return; }
914    int32_t expected = ((hr * 60 + mn) * 60 + sc) * 1000;
915    if (utc != expected) errln(UnicodeString("FAIL: Discrepancy of ") + (utc - expected) +
916                               " millis = " + ((utc - expected) / 1000 / 60 / 60.0) + " hr");
917    delete gmtcal;
918    delete cal;
919}
920
921// -------------------------------------
922
923/**
924 * The operations of adding and setting should not exhibit pathological
925 * dependence on the order of operations.  This test checks for this.
926 */
927void
928CalendarTest::TestAddSetOrder621()
929{
930    UDate d = date(97, 4, 14, 13, 23, 45);
931    UErrorCode status = U_ZERO_ERROR;
932    Calendar *cal = Calendar::createInstance(status);
933    if (failure(status, "Calendar::createInstance", TRUE)) return;
934
935    cal->setTime(d, status);
936    if (U_FAILURE(status)) {
937        errln("Calendar::setTime failed");
938        delete cal;
939        return;
940    }
941    cal->add(UCAL_DATE, - 5, status);
942    if (U_FAILURE(status)) {
943        errln("Calendar::add failed");
944        delete cal;
945        return;
946    }
947    cal->set(UCAL_HOUR_OF_DAY, 0);
948    cal->set(UCAL_MINUTE, 0);
949    cal->set(UCAL_SECOND, 0);
950    UnicodeString s;
951    dateToString(cal->getTime(status), s);
952    if (U_FAILURE(status)) {
953        errln("Calendar::getTime failed");
954        delete cal;
955        return;
956    }
957    delete cal;
958
959    cal = Calendar::createInstance(status);
960    if (U_FAILURE(status)) {
961        errln("Calendar::createInstance failed");
962        delete cal;
963        return;
964    }
965    cal->setTime(d, status);
966    if (U_FAILURE(status)) {
967        errln("Calendar::setTime failed");
968        delete cal;
969        return;
970    }
971    cal->set(UCAL_HOUR_OF_DAY, 0);
972    cal->set(UCAL_MINUTE, 0);
973    cal->set(UCAL_SECOND, 0);
974    cal->add(UCAL_DATE, - 5, status);
975    if (U_FAILURE(status)) {
976        errln("Calendar::add failed");
977        delete cal;
978        return;
979    }
980    UnicodeString s2;
981    dateToString(cal->getTime(status), s2);
982    if (U_FAILURE(status)) {
983        errln("Calendar::getTime failed");
984        delete cal;
985        return;
986    }
987    if (s == s2)
988        logln("Pass: " + s + " == " + s2);
989    else
990        errln("FAIL: " + s + " != " + s2);
991    delete cal;
992}
993
994// -------------------------------------
995
996/**
997 * Confirm that adding to various fields works.
998 */
999void
1000CalendarTest::TestAdd520()
1001{
1002    int32_t y = 1997, m = UCAL_FEBRUARY, d = 1;
1003    UErrorCode status = U_ZERO_ERROR;
1004    GregorianCalendar *temp = new GregorianCalendar(y, m, d, status);
1005    if (failure(status, "new GregorianCalendar", TRUE)) return;
1006    check520(temp, y, m, d);
1007    temp->add(UCAL_YEAR, 1, status);
1008    if (U_FAILURE(status)) { errln("Calendar::add failed"); return; }
1009    y++;
1010    check520(temp, y, m, d);
1011    temp->add(UCAL_MONTH, 1, status);
1012    if (U_FAILURE(status)) { errln("Calendar::add failed"); return; }
1013    m++;
1014    check520(temp, y, m, d);
1015    temp->add(UCAL_DATE, 1, status);
1016    if (U_FAILURE(status)) { errln("Calendar::add failed"); return; }
1017    d++;
1018    check520(temp, y, m, d);
1019    temp->add(UCAL_DATE, 2, status);
1020    if (U_FAILURE(status)) { errln("Calendar::add failed"); return; }
1021    d += 2;
1022    check520(temp, y, m, d);
1023    temp->add(UCAL_DATE, 28, status);
1024    if (U_FAILURE(status)) { errln("Calendar::add failed"); return; }
1025    d = 1;++m;
1026    check520(temp, y, m, d);
1027    delete temp;
1028}
1029
1030// -------------------------------------
1031
1032/**
1033 * Execute adding and rolling in GregorianCalendar extensively,
1034 */
1035void
1036CalendarTest::TestAddRollExtensive()
1037{
1038    int32_t maxlimit = 40;
1039    int32_t y = 1997, m = UCAL_FEBRUARY, d = 1, hr = 1, min = 1, sec = 0, ms = 0;
1040    UErrorCode status = U_ZERO_ERROR;
1041    GregorianCalendar *temp = new GregorianCalendar(y, m, d, status);
1042    if (failure(status, "new GregorianCalendar", TRUE)) return;
1043
1044    temp->set(UCAL_HOUR, hr);
1045    temp->set(UCAL_MINUTE, min);
1046    temp->set(UCAL_SECOND, sec);
1047    temp->set(UCAL_MILLISECOND, ms);
1048    temp->setMinimalDaysInFirstWeek(1);
1049
1050    UCalendarDateFields e;
1051
1052    logln("Testing GregorianCalendar add...");
1053    e = UCAL_YEAR;
1054    while (e < UCAL_FIELD_COUNT) {
1055        int32_t i;
1056        int32_t limit = maxlimit;
1057        status = U_ZERO_ERROR;
1058        for (i = 0; i < limit; i++) {
1059            temp->add(e, 1, status);
1060            if (U_FAILURE(status)) { limit = i; status = U_ZERO_ERROR; }
1061        }
1062        for (i = 0; i < limit; i++) {
1063            temp->add(e, -1, status);
1064            if (U_FAILURE(status)) { errln("GregorianCalendar::add -1 failed"); return; }
1065        }
1066        check520(temp, y, m, d, hr, min, sec, ms, e);
1067
1068        e = (UCalendarDateFields) ((int32_t) e + 1);
1069    }
1070
1071    logln("Testing GregorianCalendar roll...");
1072    e = UCAL_YEAR;
1073    while (e < UCAL_FIELD_COUNT) {
1074        int32_t i;
1075        int32_t limit = maxlimit;
1076        status = U_ZERO_ERROR;
1077        for (i = 0; i < limit; i++) {
1078            logln(calToStr(*temp) + UnicodeString("  " ) + fieldName(e) + UnicodeString("++") );
1079            temp->roll(e, 1, status);
1080            if (U_FAILURE(status)) {
1081              logln("caltest.cpp:%d e=%d, i=%d - roll(+) err %s\n",  __LINE__, (int) e, (int) i, u_errorName(status));
1082              logln(calToStr(*temp));
1083              limit = i; status = U_ZERO_ERROR;
1084            }
1085        }
1086        for (i = 0; i < limit; i++) {
1087            logln("caltest.cpp:%d e=%d, i=%d\n",  __LINE__, (int) e, (int) i);
1088            logln(calToStr(*temp) + UnicodeString("  " ) + fieldName(e) + UnicodeString("--") );
1089            temp->roll(e, -1, status);
1090            if (U_FAILURE(status)) { errln(UnicodeString("GregorianCalendar::roll ") + CalendarTest::fieldName(e) + " count=" + UnicodeString('@'+i) + " by -1 failed with " + u_errorName(status) ); return; }
1091        }
1092        check520(temp, y, m, d, hr, min, sec, ms, e);
1093
1094        e = (UCalendarDateFields) ((int32_t) e + 1);
1095    }
1096
1097    delete temp;
1098}
1099
1100// -------------------------------------
1101void
1102CalendarTest::check520(Calendar* c,
1103                        int32_t y, int32_t m, int32_t d,
1104                        int32_t hr, int32_t min, int32_t sec,
1105                        int32_t ms, UCalendarDateFields field)
1106
1107{
1108    UErrorCode status = U_ZERO_ERROR;
1109    if (c->get(UCAL_YEAR, status) != y ||
1110        c->get(UCAL_MONTH, status) != m ||
1111        c->get(UCAL_DATE, status) != d ||
1112        c->get(UCAL_HOUR, status) != hr ||
1113        c->get(UCAL_MINUTE, status) != min ||
1114        c->get(UCAL_SECOND, status) != sec ||
1115        c->get(UCAL_MILLISECOND, status) != ms) {
1116        errln(UnicodeString("U_FAILURE for field ") + (int32_t)field +
1117                ": Expected y/m/d h:m:s:ms of " +
1118                y + "/" + (m + 1) + "/" + d + " " +
1119              hr + ":" + min + ":" + sec + ":" + ms +
1120              "; got " + c->get(UCAL_YEAR, status) +
1121              "/" + (c->get(UCAL_MONTH, status) + 1) +
1122              "/" + c->get(UCAL_DATE, status) +
1123              " " + c->get(UCAL_HOUR, status) + ":" +
1124              c->get(UCAL_MINUTE, status) + ":" +
1125              c->get(UCAL_SECOND, status) + ":" +
1126              c->get(UCAL_MILLISECOND, status)
1127              );
1128
1129        if (U_FAILURE(status)) { errln("Calendar::get failed"); return; }
1130    }
1131    else
1132        logln(UnicodeString("Confirmed: ") + y + "/" +
1133                (m + 1) + "/" + d + " " +
1134                hr + ":" + min + ":" + sec + ":" + ms);
1135}
1136
1137// -------------------------------------
1138void
1139CalendarTest::check520(Calendar* c,
1140                        int32_t y, int32_t m, int32_t d)
1141
1142{
1143    UErrorCode status = U_ZERO_ERROR;
1144    if (c->get(UCAL_YEAR, status) != y ||
1145        c->get(UCAL_MONTH, status) != m ||
1146        c->get(UCAL_DATE, status) != d) {
1147        errln(UnicodeString("FAILURE: Expected y/m/d of ") +
1148              y + "/" + (m + 1) + "/" + d + " " +
1149              "; got " + c->get(UCAL_YEAR, status) +
1150              "/" + (c->get(UCAL_MONTH, status) + 1) +
1151              "/" + c->get(UCAL_DATE, status)
1152              );
1153
1154        if (U_FAILURE(status)) { errln("Calendar::get failed"); return; }
1155    }
1156    else
1157        logln(UnicodeString("Confirmed: ") + y + "/" +
1158                (m + 1) + "/" + d);
1159}
1160
1161// -------------------------------------
1162
1163/**
1164 * Test that setting of fields works.  In particular, make sure that all instances
1165 * of GregorianCalendar don't share a static instance of the fields array.
1166 */
1167void
1168CalendarTest::TestFieldSet4781()
1169{
1170    // try {
1171        UErrorCode status = U_ZERO_ERROR;
1172        GregorianCalendar *g = new GregorianCalendar(status);
1173        if (failure(status, "new GregorianCalendar", TRUE)) return;
1174        GregorianCalendar *g2 = new GregorianCalendar(status);
1175        if (U_FAILURE(status)) { errln("Couldn't create GregorianCalendar"); return; }
1176        g2->set(UCAL_HOUR, 12, status);
1177        g2->set(UCAL_MINUTE, 0, status);
1178        g2->set(UCAL_SECOND, 0, status);
1179        if (U_FAILURE(status)) { errln("Calendar::set failed"); return; }
1180        if (*g == *g2) logln("Same");
1181        else logln("Different");
1182    //}
1183        //catch(IllegalArgumentException e) {
1184        //errln("Unexpected exception seen: " + e);
1185    //}
1186        delete g;
1187        delete g2;
1188}
1189
1190// -------------------------------------
1191
1192/* We don't support serialization on C++
1193void
1194CalendarTest::TestSerialize337()
1195{
1196    Calendar cal = Calendar::getInstance();
1197    UBool ok = FALSE;
1198    try {
1199        FileOutputStream f = new FileOutputStream(FILENAME);
1200        ObjectOutput s = new ObjectOutputStream(f);
1201        s.writeObject(PREFIX);
1202        s.writeObject(cal);
1203        s.writeObject(POSTFIX);
1204        f.close();
1205        FileInputStream in = new FileInputStream(FILENAME);
1206        ObjectInputStream t = new ObjectInputStream(in);
1207        UnicodeString& pre = (UnicodeString&) t.readObject();
1208        Calendar c = (Calendar) t.readObject();
1209        UnicodeString& post = (UnicodeString&) t.readObject();
1210        in.close();
1211        ok = pre.equals(PREFIX) &&
1212            post.equals(POSTFIX) &&
1213            cal->equals(c);
1214        File fl = new File(FILENAME);
1215        fl.delete();
1216    }
1217    catch(IOException e) {
1218        errln("FAIL: Exception received:");
1219        e.printStackTrace(log);
1220    }
1221    catch(ClassNotFoundException e) {
1222        errln("FAIL: Exception received:");
1223        e.printStackTrace(log);
1224    }
1225    if (!ok) errln("Serialization of Calendar object failed.");
1226}
1227
1228UnicodeString& CalendarTest::PREFIX = "abc";
1229
1230UnicodeString& CalendarTest::POSTFIX = "def";
1231
1232UnicodeString& CalendarTest::FILENAME = "tmp337.bin";
1233 */
1234
1235// -------------------------------------
1236
1237/**
1238 * Verify that the seconds of a Calendar can be zeroed out through the
1239 * expected sequence of operations.
1240 */
1241void
1242CalendarTest::TestSecondsZero121()
1243{
1244    UErrorCode status = U_ZERO_ERROR;
1245    Calendar *cal = new GregorianCalendar(status);
1246    if (failure(status, "new GregorianCalendar", TRUE)) return;
1247    cal->setTime(Calendar::getNow(), status);
1248    if (U_FAILURE(status)) { errln("Calendar::setTime failed"); return; }
1249    cal->set(UCAL_SECOND, 0);
1250    if (U_FAILURE(status)) { errln("Calendar::set failed"); return; }
1251    UDate d = cal->getTime(status);
1252    if (U_FAILURE(status)) { errln("Calendar::getTime failed"); return; }
1253    UnicodeString s;
1254    dateToString(d, s);
1255    if (s.indexOf("DATE_FORMAT_FAILURE") >= 0) {
1256        dataerrln("Got: \"DATE_FORMAT_FAILURE\".");
1257    } else if (s.indexOf(":00 ") < 0) {
1258        errln("Expected to see :00 in " + s);
1259    }
1260    delete cal;
1261}
1262
1263// -------------------------------------
1264
1265/**
1266 * Verify that a specific sequence of adding and setting works as expected;
1267 * it should not vary depending on when and whether the get method is
1268 * called.
1269 */
1270void
1271CalendarTest::TestAddSetGet0610()
1272{
1273    UnicodeString EXPECTED_0610("1993/0/5", "");
1274    UErrorCode status = U_ZERO_ERROR;
1275    {
1276        Calendar *calendar = new GregorianCalendar(status);
1277        if (failure(status, "new GregorianCalendar", TRUE)) return;
1278        calendar->set(1993, UCAL_JANUARY, 4);
1279        logln("1A) " + value(calendar));
1280        calendar->add(UCAL_DATE, 1, status);
1281        if (U_FAILURE(status)) { errln("Calendar::add failed"); return; }
1282        UnicodeString v = value(calendar);
1283        logln("1B) " + v);
1284        logln("--) 1993/0/5");
1285        if (!(v == EXPECTED_0610)) errln("Expected " + EXPECTED_0610 + "; saw " + v);
1286        delete calendar;
1287    }
1288    {
1289        Calendar *calendar = new GregorianCalendar(1993, UCAL_JANUARY, 4, status);
1290        if (U_FAILURE(status)) { errln("Couldn't create GregorianCalendar"); return; }
1291        logln("2A) " + value(calendar));
1292        calendar->add(UCAL_DATE, 1, status);
1293        if (U_FAILURE(status)) { errln("Calendar::add failed"); return; }
1294        UnicodeString v = value(calendar);
1295        logln("2B) " + v);
1296        logln("--) 1993/0/5");
1297        if (!(v == EXPECTED_0610)) errln("Expected " + EXPECTED_0610 + "; saw " + v);
1298        delete calendar;
1299    }
1300    {
1301        Calendar *calendar = new GregorianCalendar(1993, UCAL_JANUARY, 4, status);
1302        if (U_FAILURE(status)) { errln("Couldn't create GregorianCalendar"); return; }
1303        logln("3A) " + value(calendar));
1304        calendar->getTime(status);
1305        if (U_FAILURE(status)) { errln("Calendar::getTime failed"); return; }
1306        calendar->add(UCAL_DATE, 1, status);
1307        if (U_FAILURE(status)) { errln("Calendar::add failed"); return; }
1308        UnicodeString v = value(calendar);
1309        logln("3B) " + v);
1310        logln("--) 1993/0/5");
1311        if (!(v == EXPECTED_0610)) errln("Expected " + EXPECTED_0610 + "; saw " + v);
1312        delete calendar;
1313    }
1314}
1315
1316// -------------------------------------
1317
1318UnicodeString
1319CalendarTest::value(Calendar* calendar)
1320{
1321    UErrorCode status = U_ZERO_ERROR;
1322    return UnicodeString("") + (int32_t)calendar->get(UCAL_YEAR, status) +
1323        "/" + (int32_t)calendar->get(UCAL_MONTH, status) +
1324        "/" + (int32_t)calendar->get(UCAL_DATE, status) +
1325        (U_FAILURE(status) ? " FAIL: Calendar::get failed" : "");
1326}
1327
1328
1329// -------------------------------------
1330
1331/**
1332 * Verify that various fields on a known date are set correctly.
1333 */
1334void
1335CalendarTest::TestFields060()
1336{
1337    UErrorCode status = U_ZERO_ERROR;
1338    int32_t year = 1997;
1339    int32_t month = UCAL_OCTOBER;
1340    int32_t dDate = 22;
1341    GregorianCalendar *calendar = 0;
1342    calendar = new GregorianCalendar(year, month, dDate, status);
1343    if (failure(status, "new GregorianCalendar", TRUE)) return;
1344    for (int32_t i = 0; i < EXPECTED_FIELDS_length;) {
1345        UCalendarDateFields field = (UCalendarDateFields)EXPECTED_FIELDS[i++];
1346        int32_t expected = EXPECTED_FIELDS[i++];
1347        if (calendar->get(field, status) != expected) {
1348            errln(UnicodeString("Expected field ") + (int32_t)field + " to have value " + (int32_t)expected +
1349                  "; received " + (int32_t)calendar->get(field, status) + " instead");
1350            if (U_FAILURE(status)) { errln("Calendar::get failed"); return; }
1351        }
1352    }
1353    delete calendar;
1354}
1355
1356int32_t CalendarTest::EXPECTED_FIELDS[] = {
1357    UCAL_YEAR, 1997,
1358    UCAL_MONTH, UCAL_OCTOBER,
1359    UCAL_DATE, 22,
1360    UCAL_DAY_OF_WEEK, UCAL_WEDNESDAY,
1361    UCAL_DAY_OF_WEEK_IN_MONTH, 4,
1362    UCAL_DAY_OF_YEAR, 295
1363};
1364
1365const int32_t CalendarTest::EXPECTED_FIELDS_length = (int32_t)(sizeof(CalendarTest::EXPECTED_FIELDS) /
1366    sizeof(CalendarTest::EXPECTED_FIELDS[0]));
1367
1368// -------------------------------------
1369
1370/**
1371 * Verify that various fields on a known date are set correctly.  In this
1372 * case, the start of the epoch (January 1 1970).
1373 */
1374void
1375CalendarTest::TestEpochStartFields()
1376{
1377    UErrorCode status = U_ZERO_ERROR;
1378    TimeZone *z = TimeZone::createDefault();
1379    Calendar *c = Calendar::createInstance(status);
1380    if (failure(status, "Calendar::createInstance", TRUE)) return;
1381    UDate d = - z->getRawOffset();
1382    GregorianCalendar *gc = new GregorianCalendar(status);
1383    if (U_FAILURE(status)) { errln("Couldn't create GregorianCalendar"); return; }
1384    gc->setTimeZone(*z);
1385    gc->setTime(d, status);
1386    if (U_FAILURE(status)) { errln("Calendar::setTime failed"); return; }
1387    UBool idt = gc->inDaylightTime(status);
1388    if (U_FAILURE(status)) { errln("GregorianCalendar::inDaylightTime failed"); return; }
1389    if (idt) {
1390        UnicodeString str;
1391        logln("Warning: Skipping test because " + dateToString(d, str) + " is in DST.");
1392    }
1393    else {
1394        c->setTime(d, status);
1395        if (U_FAILURE(status)) { errln("Calendar::setTime failed"); return; }
1396        for (int32_t i = 0; i < UCAL_ZONE_OFFSET;++i) {
1397            if (c->get((UCalendarDateFields)i, status) != EPOCH_FIELDS[i])
1398                dataerrln(UnicodeString("Expected field ") + i + " to have value " + EPOCH_FIELDS[i] +
1399                      "; saw " + c->get((UCalendarDateFields)i, status) + " instead");
1400            if (U_FAILURE(status)) { errln("Calendar::get failed"); return; }
1401        }
1402        if (c->get(UCAL_ZONE_OFFSET, status) != z->getRawOffset())
1403        {
1404            errln(UnicodeString("Expected field ZONE_OFFSET to have value ") + z->getRawOffset() +
1405                  "; saw " + c->get(UCAL_ZONE_OFFSET, status) + " instead");
1406            if (U_FAILURE(status)) { errln("Calendar::get failed"); return; }
1407        }
1408        if (c->get(UCAL_DST_OFFSET, status) != 0)
1409        {
1410            errln(UnicodeString("Expected field DST_OFFSET to have value 0") +
1411                  "; saw " + c->get(UCAL_DST_OFFSET, status) + " instead");
1412            if (U_FAILURE(status)) { errln("Calendar::get failed"); return; }
1413        }
1414    }
1415    delete c;
1416    delete z;
1417    delete gc;
1418}
1419
1420int32_t CalendarTest::EPOCH_FIELDS[] = {
1421    1, 1970, 0, 1, 1, 1, 1, 5, 1, 0, 0, 0, 0, 0, 0, - 28800000, 0
1422};
1423
1424// -------------------------------------
1425
1426/**
1427 * Test that the days of the week progress properly when add is called repeatedly
1428 * for increments of 24 days.
1429 */
1430void
1431CalendarTest::TestDOWProgression()
1432{
1433    UErrorCode status = U_ZERO_ERROR;
1434    Calendar *cal = new GregorianCalendar(1972, UCAL_OCTOBER, 26, status);
1435    if (failure(status, "new GregorianCalendar", TRUE)) return;
1436    marchByDelta(cal, 24);
1437    delete cal;
1438}
1439
1440// -------------------------------------
1441
1442void
1443CalendarTest::TestDOW_LOCALandYEAR_WOY()
1444{
1445    /* Note: I've commented out the loop_addroll tests for YEAR and
1446     * YEAR_WOY below because these two fields should NOT behave
1447     * identically when adding.  YEAR should keep the month/dom
1448     * invariant.  YEAR_WOY should keep the woy/dow invariant.  I've
1449     * added a new test that checks for this in place of the old call
1450     * to loop_addroll. - aliu */
1451    UErrorCode status = U_ZERO_ERROR;
1452    int32_t times = 20;
1453    Calendar *cal=Calendar::createInstance(Locale::getGermany(), status);
1454    if (failure(status, "Calendar::createInstance", TRUE)) return;
1455    SimpleDateFormat *sdf=new SimpleDateFormat(UnicodeString("YYYY'-W'ww-ee"), Locale::getGermany(), status);
1456    if (U_FAILURE(status)) { dataerrln("Couldn't create SimpleDateFormat - %s", u_errorName(status)); return; }
1457
1458    // ICU no longer use localized date-time pattern characters by default.
1459    // So we set pattern chars using 'J' instead of 'Y'.
1460    DateFormatSymbols *dfs = new DateFormatSymbols(Locale::getGermany(), status);
1461    dfs->setLocalPatternChars(UnicodeString("GyMdkHmsSEDFwWahKzJeugAZvcLQq"));
1462    sdf->adoptDateFormatSymbols(dfs);
1463    sdf->applyLocalizedPattern(UnicodeString("JJJJ'-W'ww-ee"), status);
1464    if (U_FAILURE(status)) { errln("Couldn't apply localized pattern"); return; }
1465
1466    cal->clear();
1467    cal->set(1997, UCAL_DECEMBER, 25);
1468    doYEAR_WOYLoop(cal, sdf, times, status);
1469    //loop_addroll(cal, /*sdf,*/ times, UCAL_YEAR_WOY, UCAL_YEAR,  status);
1470    yearAddTest(*cal, status); // aliu
1471    loop_addroll(cal, /*sdf,*/ times, UCAL_DOW_LOCAL, UCAL_DAY_OF_WEEK, status);
1472    if (U_FAILURE(status)) { errln("Error in parse/calculate test for 1997"); return; }
1473
1474    cal->clear();
1475    cal->set(1998, UCAL_DECEMBER, 25);
1476    doYEAR_WOYLoop(cal, sdf, times, status);
1477    //loop_addroll(cal, /*sdf,*/ times, UCAL_YEAR_WOY, UCAL_YEAR,  status);
1478    yearAddTest(*cal, status); // aliu
1479    loop_addroll(cal, /*sdf,*/ times, UCAL_DOW_LOCAL, UCAL_DAY_OF_WEEK, status);
1480    if (U_FAILURE(status)) { errln("Error in parse/calculate test for 1998"); return; }
1481
1482    cal->clear();
1483    cal->set(1582, UCAL_OCTOBER, 1);
1484    doYEAR_WOYLoop(cal, sdf, times, status);
1485    //loop_addroll(cal, /*sdf,*/ times, Calendar::YEAR_WOY, Calendar::YEAR,  status);
1486    yearAddTest(*cal, status); // aliu
1487    loop_addroll(cal, /*sdf,*/ times, UCAL_DOW_LOCAL, UCAL_DAY_OF_WEEK, status);
1488    if (U_FAILURE(status)) { errln("Error in parse/calculate test for 1582"); return; }
1489    delete sdf;
1490    delete cal;
1491
1492    return;
1493}
1494
1495/**
1496 * Confirm that adding a YEAR and adding a YEAR_WOY work properly for
1497 * the given Calendar at its current setting.
1498 */
1499void CalendarTest::yearAddTest(Calendar& cal, UErrorCode& status) {
1500    /**
1501     * When adding the YEAR, the month and day should remain constant.
1502     * When adding the YEAR_WOY, the WOY and DOW should remain constant. - aliu
1503     * Examples:
1504     *  Wed Jan 14 1998 / 1998-W03-03 Add(YEAR_WOY, 1) -> Wed Jan 20 1999 / 1999-W03-03
1505     *                                Add(YEAR, 1)     -> Thu Jan 14 1999 / 1999-W02-04
1506     *  Thu Jan 14 1999 / 1999-W02-04 Add(YEAR_WOY, 1) -> Thu Jan 13 2000 / 2000-W02-04
1507     *                                Add(YEAR, 1)     -> Fri Jan 14 2000 / 2000-W02-05
1508     *  Sun Oct 31 1582 / 1582-W42-07 Add(YEAR_WOY, 1) -> Sun Oct 23 1583 / 1583-W42-07
1509     *                                Add(YEAR, 1)     -> Mon Oct 31 1583 / 1583-W44-01
1510     */
1511    int32_t y   = cal.get(UCAL_YEAR, status);
1512    int32_t mon = cal.get(UCAL_MONTH, status);
1513    int32_t day = cal.get(UCAL_DATE, status);
1514    int32_t ywy = cal.get(UCAL_YEAR_WOY, status);
1515    int32_t woy = cal.get(UCAL_WEEK_OF_YEAR, status);
1516    int32_t dow = cal.get(UCAL_DOW_LOCAL, status);
1517    UDate t = cal.getTime(status);
1518
1519    if(U_FAILURE(status)){
1520        errln(UnicodeString("Failed to create Calendar for locale. Error: ") + UnicodeString(u_errorName(status)));
1521        return;
1522    }
1523    UnicodeString str, str2;
1524    SimpleDateFormat fmt(UnicodeString("EEE MMM dd yyyy / YYYY'-W'ww-ee"), status);
1525    fmt.setCalendar(cal);
1526
1527    fmt.format(t, str.remove());
1528    str += ".add(YEAR, 1)    =>";
1529    cal.add(UCAL_YEAR, 1, status);
1530    int32_t y2   = cal.get(UCAL_YEAR, status);
1531    int32_t mon2 = cal.get(UCAL_MONTH, status);
1532    int32_t day2 = cal.get(UCAL_DATE, status);
1533    fmt.format(cal.getTime(status), str);
1534    if (y2 != (y+1) || mon2 != mon || day2 != day) {
1535        str += (UnicodeString)", expected year " +
1536            (y+1) + ", month " + (mon+1) + ", day " + day;
1537        errln((UnicodeString)"FAIL: " + str);
1538        logln( UnicodeString(" -> ") + CalendarTest::calToStr(cal) );
1539    } else {
1540        logln(str);
1541    }
1542
1543    fmt.format(t, str.remove());
1544    str += ".add(YEAR_WOY, 1)=>";
1545    cal.setTime(t, status);
1546    logln( UnicodeString(" <- ") + CalendarTest::calToStr(cal) );
1547    cal.add(UCAL_YEAR_WOY, 1, status);
1548    int32_t ywy2 = cal.get(UCAL_YEAR_WOY, status);
1549    int32_t woy2 = cal.get(UCAL_WEEK_OF_YEAR, status);
1550    int32_t dow2 = cal.get(UCAL_DOW_LOCAL, status);
1551    fmt.format(cal.getTime(status), str);
1552    if (ywy2 != (ywy+1) || woy2 != woy || dow2 != dow) {
1553        str += (UnicodeString)", expected yearWOY " +
1554            (ywy+1) + ", woy " + woy + ", dowLocal " + dow;
1555        errln((UnicodeString)"FAIL: " + str);
1556        logln( UnicodeString(" -> ") + CalendarTest::calToStr(cal) );
1557    } else {
1558        logln(str);
1559    }
1560}
1561
1562// -------------------------------------
1563
1564void CalendarTest::loop_addroll(Calendar *cal, /*SimpleDateFormat *sdf,*/ int times, UCalendarDateFields field, UCalendarDateFields field2, UErrorCode& errorCode) {
1565    Calendar *calclone;
1566    SimpleDateFormat fmt(UnicodeString("EEE MMM dd yyyy / YYYY'-W'ww-ee"), errorCode);
1567    fmt.setCalendar(*cal);
1568    int i;
1569
1570    for(i = 0; i<times; i++) {
1571        calclone = cal->clone();
1572        UDate start = cal->getTime(errorCode);
1573        cal->add(field,1,errorCode);
1574        if (U_FAILURE(errorCode)) { errln("Error in add"); delete calclone; return; }
1575        calclone->add(field2,1,errorCode);
1576        if (U_FAILURE(errorCode)) { errln("Error in add"); delete calclone; return; }
1577        if(cal->getTime(errorCode) != calclone->getTime(errorCode)) {
1578            UnicodeString str("FAIL: Results of add differ. "), str2;
1579            str += fmt.format(start, str2) + " ";
1580            str += UnicodeString("Add(") + fieldName(field) + ", 1) -> " +
1581                fmt.format(cal->getTime(errorCode), str2.remove()) + "; ";
1582            str += UnicodeString("Add(") + fieldName(field2) + ", 1) -> " +
1583                fmt.format(calclone->getTime(errorCode), str2.remove());
1584            errln(str);
1585            delete calclone;
1586            return;
1587        }
1588        delete calclone;
1589    }
1590
1591    for(i = 0; i<times; i++) {
1592        calclone = cal->clone();
1593        cal->roll(field,(int32_t)1,errorCode);
1594        if (U_FAILURE(errorCode)) { errln("Error in roll"); delete calclone; return; }
1595        calclone->roll(field2,(int32_t)1,errorCode);
1596        if (U_FAILURE(errorCode)) { errln("Error in roll"); delete calclone; return; }
1597        if(cal->getTime(errorCode) != calclone->getTime(errorCode)) {
1598            delete calclone;
1599            errln("Results of roll differ!");
1600            return;
1601        }
1602        delete calclone;
1603    }
1604}
1605
1606// -------------------------------------
1607
1608void
1609CalendarTest::doYEAR_WOYLoop(Calendar *cal, SimpleDateFormat *sdf,
1610                                    int32_t times, UErrorCode& errorCode) {
1611
1612    UnicodeString us;
1613    UDate tst, original;
1614    Calendar *tstres = new GregorianCalendar(Locale::getGermany(), errorCode);
1615    for(int i=0; i<times; ++i) {
1616        sdf->format(Formattable(cal->getTime(errorCode),Formattable::kIsDate), us, errorCode);
1617        //logln("expected: "+us);
1618        if (U_FAILURE(errorCode)) { errln("Format error"); return; }
1619        tst=sdf->parse(us,errorCode);
1620        if (U_FAILURE(errorCode)) { errln("Parse error"); return; }
1621        tstres->clear();
1622        tstres->setTime(tst, errorCode);
1623        //logln((UnicodeString)"Parsed week of year is "+tstres->get(UCAL_WEEK_OF_YEAR, errorCode));
1624        if (U_FAILURE(errorCode)) { errln("Set time error"); return; }
1625        original = cal->getTime(errorCode);
1626        us.remove();
1627        sdf->format(Formattable(tst,Formattable::kIsDate), us, errorCode);
1628        //logln("got: "+us);
1629        if (U_FAILURE(errorCode)) { errln("Get time error"); return; }
1630        if(original!=tst) {
1631            us.remove();
1632            sdf->format(Formattable(original, Formattable::kIsDate), us, errorCode);
1633            errln("FAIL: Parsed time doesn't match with regular");
1634            logln("expected "+us + " " + calToStr(*cal));
1635            us.remove();
1636            sdf->format(Formattable(tst, Formattable::kIsDate), us, errorCode);
1637            logln("got "+us + " " + calToStr(*tstres));
1638        }
1639        tstres->clear();
1640        tstres->set(UCAL_YEAR_WOY, cal->get(UCAL_YEAR_WOY, errorCode));
1641        tstres->set(UCAL_WEEK_OF_YEAR, cal->get(UCAL_WEEK_OF_YEAR, errorCode));
1642        tstres->set(UCAL_DOW_LOCAL, cal->get(UCAL_DOW_LOCAL, errorCode));
1643        if(cal->get(UCAL_YEAR, errorCode) != tstres->get(UCAL_YEAR, errorCode)) {
1644            errln("FAIL: Different Year!");
1645            logln((UnicodeString)"Expected "+cal->get(UCAL_YEAR, errorCode));
1646            logln((UnicodeString)"Got "+tstres->get(UCAL_YEAR, errorCode));
1647            return;
1648        }
1649        if(cal->get(UCAL_DAY_OF_YEAR, errorCode) != tstres->get(UCAL_DAY_OF_YEAR, errorCode)) {
1650            errln("FAIL: Different Day Of Year!");
1651            logln((UnicodeString)"Expected "+cal->get(UCAL_DAY_OF_YEAR, errorCode));
1652            logln((UnicodeString)"Got "+tstres->get(UCAL_DAY_OF_YEAR, errorCode));
1653            return;
1654        }
1655        //logln(calToStr(*cal));
1656        cal->add(UCAL_DATE, 1, errorCode);
1657        if (U_FAILURE(errorCode)) { errln("Add error"); return; }
1658        us.remove();
1659    }
1660    delete (tstres);
1661}
1662// -------------------------------------
1663
1664void
1665CalendarTest::marchByDelta(Calendar* cal, int32_t delta)
1666{
1667    UErrorCode status = U_ZERO_ERROR;
1668    Calendar *cur = (Calendar*) cal->clone();
1669    int32_t initialDOW = cur->get(UCAL_DAY_OF_WEEK, status);
1670    if (U_FAILURE(status)) { errln("Calendar::get failed"); return; }
1671    int32_t DOW, newDOW = initialDOW;
1672    do {
1673        UnicodeString str;
1674        DOW = newDOW;
1675        logln(UnicodeString("DOW = ") + DOW + "  " + dateToString(cur->getTime(status), str));
1676        if (U_FAILURE(status)) { errln("Calendar::getTime failed"); return; }
1677        cur->add(UCAL_DAY_OF_WEEK, delta, status);
1678        if (U_FAILURE(status)) { errln("Calendar::add failed"); return; }
1679        newDOW = cur->get(UCAL_DAY_OF_WEEK, status);
1680        if (U_FAILURE(status)) { errln("Calendar::get failed"); return; }
1681        int32_t expectedDOW = 1 + (DOW + delta - 1) % 7;
1682        if (newDOW != expectedDOW) {
1683            errln(UnicodeString("Day of week should be ") + expectedDOW + " instead of " + newDOW +
1684                  " on " + dateToString(cur->getTime(status), str));
1685            if (U_FAILURE(status)) { errln("Calendar::getTime failed"); return; }
1686            return;
1687        }
1688    }
1689    while (newDOW != initialDOW);
1690    delete cur;
1691}
1692
1693#define CHECK(status, msg) \
1694    if (U_FAILURE(status)) { \
1695        errcheckln(status, msg); \
1696        return; \
1697    }
1698
1699void CalendarTest::TestWOY(void) {
1700    /*
1701      FDW = Mon, MDFW = 4:
1702         Sun Dec 26 1999, WOY 51
1703         Mon Dec 27 1999, WOY 52
1704         Tue Dec 28 1999, WOY 52
1705         Wed Dec 29 1999, WOY 52
1706         Thu Dec 30 1999, WOY 52
1707         Fri Dec 31 1999, WOY 52
1708         Sat Jan 01 2000, WOY 52 ***
1709         Sun Jan 02 2000, WOY 52 ***
1710         Mon Jan 03 2000, WOY 1
1711         Tue Jan 04 2000, WOY 1
1712         Wed Jan 05 2000, WOY 1
1713         Thu Jan 06 2000, WOY 1
1714         Fri Jan 07 2000, WOY 1
1715         Sat Jan 08 2000, WOY 1
1716         Sun Jan 09 2000, WOY 1
1717         Mon Jan 10 2000, WOY 2
1718
1719      FDW = Mon, MDFW = 2:
1720         Sun Dec 26 1999, WOY 52
1721         Mon Dec 27 1999, WOY 1  ***
1722         Tue Dec 28 1999, WOY 1  ***
1723         Wed Dec 29 1999, WOY 1  ***
1724         Thu Dec 30 1999, WOY 1  ***
1725         Fri Dec 31 1999, WOY 1  ***
1726         Sat Jan 01 2000, WOY 1
1727         Sun Jan 02 2000, WOY 1
1728         Mon Jan 03 2000, WOY 2
1729         Tue Jan 04 2000, WOY 2
1730         Wed Jan 05 2000, WOY 2
1731         Thu Jan 06 2000, WOY 2
1732         Fri Jan 07 2000, WOY 2
1733         Sat Jan 08 2000, WOY 2
1734         Sun Jan 09 2000, WOY 2
1735         Mon Jan 10 2000, WOY 3
1736    */
1737
1738    UnicodeString str;
1739    UErrorCode status = U_ZERO_ERROR;
1740    int32_t i;
1741
1742    GregorianCalendar cal(status);
1743    SimpleDateFormat fmt(UnicodeString("EEE MMM dd yyyy', WOY' w"), status);
1744    if (failure(status, "Cannot construct calendar/format", TRUE)) return;
1745
1746    UCalendarDaysOfWeek fdw = (UCalendarDaysOfWeek) 0;
1747
1748    //for (int8_t pass=2; pass<=2; ++pass) {
1749    for (int8_t pass=1; pass<=2; ++pass) {
1750        switch (pass) {
1751        case 1:
1752            fdw = UCAL_MONDAY;
1753            cal.setFirstDayOfWeek(fdw);
1754            cal.setMinimalDaysInFirstWeek(4);
1755            fmt.adoptCalendar(cal.clone());
1756            break;
1757        case 2:
1758            fdw = UCAL_MONDAY;
1759            cal.setFirstDayOfWeek(fdw);
1760            cal.setMinimalDaysInFirstWeek(2);
1761            fmt.adoptCalendar(cal.clone());
1762            break;
1763        }
1764
1765        //for (i=2; i<=6; ++i) {
1766        for (i=0; i<16; ++i) {
1767        UDate t, t2;
1768        int32_t t_y, t_woy, t_dow;
1769        cal.clear();
1770        cal.set(1999, UCAL_DECEMBER, 26 + i);
1771        fmt.format(t = cal.getTime(status), str.remove());
1772        CHECK(status, "Fail: getTime failed");
1773        logln(UnicodeString("* ") + str);
1774        int32_t dow = cal.get(UCAL_DAY_OF_WEEK, status);
1775        int32_t woy = cal.get(UCAL_WEEK_OF_YEAR, status);
1776        int32_t year = cal.get(UCAL_YEAR, status);
1777        int32_t mon = cal.get(UCAL_MONTH, status);
1778        logln(calToStr(cal));
1779        CHECK(status, "Fail: get failed");
1780        int32_t dowLocal = dow - fdw;
1781        if (dowLocal < 0) dowLocal += 7;
1782        dowLocal++;
1783        int32_t yearWoy = year;
1784        if (mon == UCAL_JANUARY) {
1785            if (woy >= 52) --yearWoy;
1786        } else {
1787            if (woy == 1) ++yearWoy;
1788        }
1789
1790        // Basic fields->time check y/woy/dow
1791        // Since Y/WOY is ambiguous, we do a check of the fields,
1792        // not of the specific time.
1793        cal.clear();
1794        cal.set(UCAL_YEAR, year);
1795        cal.set(UCAL_WEEK_OF_YEAR, woy);
1796        cal.set(UCAL_DAY_OF_WEEK, dow);
1797        t_y = cal.get(UCAL_YEAR, status);
1798        t_woy = cal.get(UCAL_WEEK_OF_YEAR, status);
1799        t_dow = cal.get(UCAL_DAY_OF_WEEK, status);
1800        CHECK(status, "Fail: get failed");
1801        if (t_y != year || t_woy != woy || t_dow != dow) {
1802            str = "Fail: y/woy/dow fields->time => ";
1803            fmt.format(cal.getTime(status), str);
1804            errln(str);
1805            logln(calToStr(cal));
1806            logln("[get!=set] Y%d!=%d || woy%d!=%d || dow%d!=%d\n",
1807                  t_y, year, t_woy, woy, t_dow, dow);
1808        } else {
1809          logln("y/woy/dow fields->time OK");
1810        }
1811
1812        // Basic fields->time check y/woy/dow_local
1813        // Since Y/WOY is ambiguous, we do a check of the fields,
1814        // not of the specific time.
1815        cal.clear();
1816        cal.set(UCAL_YEAR, year);
1817        cal.set(UCAL_WEEK_OF_YEAR, woy);
1818        cal.set(UCAL_DOW_LOCAL, dowLocal);
1819        t_y = cal.get(UCAL_YEAR, status);
1820        t_woy = cal.get(UCAL_WEEK_OF_YEAR, status);
1821        t_dow = cal.get(UCAL_DOW_LOCAL, status);
1822        CHECK(status, "Fail: get failed");
1823        if (t_y != year || t_woy != woy || t_dow != dowLocal) {
1824            str = "Fail: y/woy/dow_local fields->time => ";
1825            fmt.format(cal.getTime(status), str);
1826            errln(str);
1827        }
1828
1829        // Basic fields->time check y_woy/woy/dow
1830        cal.clear();
1831        cal.set(UCAL_YEAR_WOY, yearWoy);
1832        cal.set(UCAL_WEEK_OF_YEAR, woy);
1833        cal.set(UCAL_DAY_OF_WEEK, dow);
1834        t2 = cal.getTime(status);
1835        CHECK(status, "Fail: getTime failed");
1836        if (t != t2) {
1837            str = "Fail: y_woy/woy/dow fields->time => ";
1838            fmt.format(t2, str);
1839            errln(str);
1840            logln(calToStr(cal));
1841            logln("%.f != %.f\n", t, t2);
1842        } else {
1843          logln("y_woy/woy/dow OK");
1844        }
1845
1846        // Basic fields->time check y_woy/woy/dow_local
1847        cal.clear();
1848        cal.set(UCAL_YEAR_WOY, yearWoy);
1849        cal.set(UCAL_WEEK_OF_YEAR, woy);
1850        cal.set(UCAL_DOW_LOCAL, dowLocal);
1851        t2 = cal.getTime(status);
1852        CHECK(status, "Fail: getTime failed");
1853        if (t != t2) {
1854            str = "Fail: y_woy/woy/dow_local fields->time => ";
1855            fmt.format(t2, str);
1856            errln(str);
1857        }
1858
1859        logln("Testing DOW_LOCAL.. dow%d\n", dow);
1860        // Make sure DOW_LOCAL disambiguates over DOW
1861        int32_t wrongDow = dow - 3;
1862        if (wrongDow < 1) wrongDow += 7;
1863        cal.setTime(t, status);
1864        cal.set(UCAL_DAY_OF_WEEK, wrongDow);
1865        cal.set(UCAL_DOW_LOCAL, dowLocal);
1866        t2 = cal.getTime(status);
1867        CHECK(status, "Fail: set/getTime failed");
1868        if (t != t2) {
1869            str = "Fail: DOW_LOCAL fields->time => ";
1870            fmt.format(t2, str);
1871            errln(str);
1872            logln(calToStr(cal));
1873            logln("%.f :   DOW%d, DOW_LOCAL%d -> %.f\n",
1874                  t, wrongDow, dowLocal, t2);
1875        }
1876
1877        // Make sure DOW disambiguates over DOW_LOCAL
1878        int32_t wrongDowLocal = dowLocal - 3;
1879        if (wrongDowLocal < 1) wrongDowLocal += 7;
1880        cal.setTime(t, status);
1881        cal.set(UCAL_DOW_LOCAL, wrongDowLocal);
1882        cal.set(UCAL_DAY_OF_WEEK, dow);
1883        t2 = cal.getTime(status);
1884        CHECK(status, "Fail: set/getTime failed");
1885        if (t != t2) {
1886            str = "Fail: DOW       fields->time => ";
1887            fmt.format(t2, str);
1888            errln(str);
1889        }
1890
1891        // Make sure YEAR_WOY disambiguates over YEAR
1892        cal.setTime(t, status);
1893        cal.set(UCAL_YEAR, year - 2);
1894        cal.set(UCAL_YEAR_WOY, yearWoy);
1895        t2 = cal.getTime(status);
1896        CHECK(status, "Fail: set/getTime failed");
1897        if (t != t2) {
1898            str = "Fail: YEAR_WOY  fields->time => ";
1899            fmt.format(t2, str);
1900            errln(str);
1901        }
1902
1903        // Make sure YEAR disambiguates over YEAR_WOY
1904        cal.setTime(t, status);
1905        cal.set(UCAL_YEAR_WOY, yearWoy - 2);
1906        cal.set(UCAL_YEAR, year);
1907        t2 = cal.getTime(status);
1908        CHECK(status, "Fail: set/getTime failed");
1909        if (t != t2) {
1910            str = "Fail: YEAR      fields->time => ";
1911            fmt.format(t2, str);
1912            errln(str);
1913        }
1914    }
1915    }
1916
1917    /*
1918      FDW = Mon, MDFW = 4:
1919         Sun Dec 26 1999, WOY 51
1920         Mon Dec 27 1999, WOY 52
1921         Tue Dec 28 1999, WOY 52
1922         Wed Dec 29 1999, WOY 52
1923         Thu Dec 30 1999, WOY 52
1924         Fri Dec 31 1999, WOY 52
1925         Sat Jan 01 2000, WOY 52
1926         Sun Jan 02 2000, WOY 52
1927    */
1928
1929    // Roll the DOW_LOCAL within week 52
1930    for (i=27; i<=33; ++i) {
1931        int32_t amount;
1932        for (amount=-7; amount<=7; ++amount) {
1933            str = "roll(";
1934            cal.set(1999, UCAL_DECEMBER, i);
1935            UDate t, t2;
1936            fmt.format(cal.getTime(status), str);
1937            CHECK(status, "Fail: getTime failed");
1938            str += UnicodeString(", ") + amount + ") = ";
1939
1940            cal.roll(UCAL_DOW_LOCAL, amount, status);
1941            CHECK(status, "Fail: roll failed");
1942
1943            t = cal.getTime(status);
1944            int32_t newDom = i + amount;
1945            while (newDom < 27) newDom += 7;
1946            while (newDom > 33) newDom -= 7;
1947            cal.set(1999, UCAL_DECEMBER, newDom);
1948            t2 = cal.getTime(status);
1949            CHECK(status, "Fail: getTime failed");
1950            fmt.format(t, str);
1951
1952            if (t != t2) {
1953                str.append(", exp ");
1954                fmt.format(t2, str);
1955                errln(str);
1956            } else {
1957                logln(str);
1958            }
1959        }
1960    }
1961}
1962
1963void CalendarTest::TestYWOY()
1964{
1965   UnicodeString str;
1966   UErrorCode status = U_ZERO_ERROR;
1967
1968   GregorianCalendar cal(status);
1969   if (failure(status, "construct GregorianCalendar", TRUE)) return;
1970
1971   cal.setFirstDayOfWeek(UCAL_SUNDAY);
1972   cal.setMinimalDaysInFirstWeek(1);
1973
1974   logln("Setting:  ywoy=2004, woy=1, dow=MONDAY");
1975   cal.clear();
1976   cal.set(UCAL_YEAR_WOY,2004);
1977   cal.set(UCAL_WEEK_OF_YEAR,1);
1978   cal.set(UCAL_DAY_OF_WEEK, UCAL_MONDAY);
1979
1980   logln(calToStr(cal));
1981   if(cal.get(UCAL_YEAR, status) != 2003) {
1982     errln("year not 2003");
1983   }
1984
1985   logln("+ setting DOW to THURSDAY");
1986   cal.clear();
1987   cal.set(UCAL_YEAR_WOY,2004);
1988   cal.set(UCAL_WEEK_OF_YEAR,1);
1989   cal.set(UCAL_DAY_OF_WEEK, UCAL_THURSDAY);
1990
1991   logln(calToStr(cal));
1992   if(cal.get(UCAL_YEAR, status) != 2004) {
1993     errln("year not 2004");
1994   }
1995
1996   logln("+ setting DOW_LOCAL to 1");
1997   cal.clear();
1998   cal.set(UCAL_YEAR_WOY,2004);
1999   cal.set(UCAL_WEEK_OF_YEAR,1);
2000   cal.set(UCAL_DAY_OF_WEEK, UCAL_THURSDAY);
2001   cal.set(UCAL_DOW_LOCAL, 1);
2002
2003   logln(calToStr(cal));
2004   if(cal.get(UCAL_YEAR, status) != 2003) {
2005     errln("year not 2003");
2006   }
2007
2008   cal.setFirstDayOfWeek(UCAL_MONDAY);
2009   cal.setMinimalDaysInFirstWeek(4);
2010   UDate t = 946713600000.;
2011   cal.setTime(t, status);
2012   cal.set(UCAL_DAY_OF_WEEK, 4);
2013   cal.set(UCAL_DOW_LOCAL, 6);
2014   if(cal.getTime(status) != t) {
2015     logln(calToStr(cal));
2016     errln("FAIL:  DOW_LOCAL did not take precedence");
2017   }
2018
2019}
2020
2021void CalendarTest::TestJD()
2022{
2023  int32_t jd;
2024  static const int32_t kEpochStartAsJulianDay = 2440588;
2025  UErrorCode status = U_ZERO_ERROR;
2026  GregorianCalendar cal(status);
2027  if (failure(status, "construct GregorianCalendar", TRUE)) return;
2028  cal.setTimeZone(*TimeZone::getGMT());
2029  cal.clear();
2030  jd = cal.get(UCAL_JULIAN_DAY, status);
2031  if(jd != kEpochStartAsJulianDay) {
2032    errln("Wanted JD of %d at time=0, [epoch 1970] but got %d\n", kEpochStartAsJulianDay, jd);
2033  } else {
2034    logln("Wanted JD of %d at time=0, [epoch 1970], got %d\n", kEpochStartAsJulianDay, jd);
2035  }
2036
2037  cal.setTime(Calendar::getNow(), status);
2038  cal.clear();
2039  cal.set(UCAL_JULIAN_DAY, kEpochStartAsJulianDay);
2040  UDate epochTime = cal.getTime(status);
2041  if(epochTime != 0) {
2042    errln("Wanted time of 0 at jd=%d, got %.1lf\n", kEpochStartAsJulianDay, epochTime);
2043  } else {
2044    logln("Wanted time of 0 at jd=%d, got %.1lf\n", kEpochStartAsJulianDay, epochTime);
2045  }
2046
2047}
2048
2049// make sure the ctestfw utilities are in sync with the Calendar
2050void CalendarTest::TestDebug()
2051{
2052    for(int32_t  t=0;t<=UDBG_ENUM_COUNT;t++) {
2053        int32_t count = udbg_enumCount((UDebugEnumType)t);
2054        if(count == -1) {
2055            logln("enumCount(%d) returned -1", count);
2056            continue;
2057        }
2058        for(int32_t i=0;i<=count;i++) {
2059            if(t<=UDBG_HIGHEST_CONTIGUOUS_ENUM && i<count) {
2060                if( i!=udbg_enumArrayValue((UDebugEnumType)t, i)) {
2061                    errln("FAIL: udbg_enumArrayValue(%d,%d) returned %d, expected %d", t, i, udbg_enumArrayValue((UDebugEnumType)t,i), i);
2062                }
2063            } else {
2064                logln("Testing count+1:");
2065            }
2066                  const char *name = udbg_enumName((UDebugEnumType)t,i);
2067                  if(name==NULL) {
2068                          if(i==count || t>UDBG_HIGHEST_CONTIGUOUS_ENUM  ) {
2069                                logln(" null name - expected.\n");
2070                          } else {
2071                                errln("FAIL: udbg_enumName(%d,%d) returned NULL", t, i);
2072                          }
2073                          name = "(null)";
2074                  }
2075          logln("udbg_enumArrayValue(%d,%d) = %s, returned %d", t, i,
2076                      name, udbg_enumArrayValue((UDebugEnumType)t,i));
2077            logln("udbg_enumString = " + udbg_enumString((UDebugEnumType)t,i));
2078        }
2079        if(udbg_enumExpectedCount((UDebugEnumType)t) != count && t<=UDBG_HIGHEST_CONTIGUOUS_ENUM) {
2080            errln("FAIL: udbg_enumExpectedCount(%d): %d, != UCAL_FIELD_COUNT=%d ", t, udbg_enumExpectedCount((UDebugEnumType)t), count);
2081        } else {
2082            logln("udbg_ucal_fieldCount: %d, UCAL_FIELD_COUNT=udbg_enumCount %d ", udbg_enumExpectedCount((UDebugEnumType)t), count);
2083        }
2084    }
2085}
2086
2087
2088#undef CHECK
2089
2090// List of interesting locales
2091const char *CalendarTest::testLocaleID(int32_t i)
2092{
2093  switch(i) {
2094  case 0: return "he_IL@calendar=hebrew";
2095  case 1: return "en_US@calendar=hebrew";
2096  case 2: return "fr_FR@calendar=hebrew";
2097  case 3: return "fi_FI@calendar=hebrew";
2098  case 4: return "nl_NL@calendar=hebrew";
2099  case 5: return "hu_HU@calendar=hebrew";
2100  case 6: return "nl_BE@currency=MTL;calendar=islamic";
2101  case 7: return "th_TH_TRADITIONAL@calendar=gregorian";
2102  case 8: return "ar_JO@calendar=islamic-civil";
2103  case 9: return "fi_FI@calendar=islamic";
2104  case 10: return "fr_CH@calendar=islamic-civil";
2105  case 11: return "he_IL@calendar=islamic-civil";
2106  case 12: return "hu_HU@calendar=buddhist";
2107  case 13: return "hu_HU@calendar=islamic";
2108  case 14: return "en_US@calendar=japanese";
2109  default: return NULL;
2110  }
2111}
2112
2113int32_t CalendarTest::testLocaleCount()
2114{
2115  static int32_t gLocaleCount = -1;
2116  if(gLocaleCount < 0) {
2117    int32_t i;
2118    for(i=0;testLocaleID(i) != NULL;i++) {
2119      ;
2120    }
2121    gLocaleCount = i;
2122  }
2123  return gLocaleCount;
2124}
2125
2126static UDate doMinDateOfCalendar(Calendar* adopt, UBool &isGregorian, UErrorCode& status) {
2127  if(U_FAILURE(status)) return 0.0;
2128
2129  adopt->clear();
2130  adopt->set(UCAL_EXTENDED_YEAR, adopt->getActualMinimum(UCAL_EXTENDED_YEAR, status));
2131  UDate ret = adopt->getTime(status);
2132  isGregorian = dynamic_cast<GregorianCalendar*>(adopt) != NULL;
2133  delete adopt;
2134  return ret;
2135}
2136
2137UDate CalendarTest::minDateOfCalendar(const Locale& locale, UBool &isGregorian, UErrorCode& status) {
2138  if(U_FAILURE(status)) return 0.0;
2139  return doMinDateOfCalendar(Calendar::createInstance(locale, status), isGregorian, status);
2140}
2141
2142UDate CalendarTest::minDateOfCalendar(const Calendar& cal, UBool &isGregorian, UErrorCode& status) {
2143  if(U_FAILURE(status)) return 0.0;
2144  return doMinDateOfCalendar(cal.clone(), isGregorian, status);
2145}
2146
2147void CalendarTest::Test6703()
2148{
2149    UErrorCode status = U_ZERO_ERROR;
2150    Calendar *cal;
2151
2152    Locale loc1("en@calendar=fubar");
2153    cal = Calendar::createInstance(loc1, status);
2154    if (failure(status, "Calendar::createInstance", TRUE)) return;
2155    delete cal;
2156
2157    status = U_ZERO_ERROR;
2158    Locale loc2("en");
2159    cal = Calendar::createInstance(loc2, status);
2160    if (failure(status, "Calendar::createInstance")) return;
2161    delete cal;
2162
2163    status = U_ZERO_ERROR;
2164    Locale loc3("en@calendar=roc");
2165    cal = Calendar::createInstance(loc3, status);
2166    if (failure(status, "Calendar::createInstance")) return;
2167    delete cal;
2168
2169    return;
2170}
2171
2172void CalendarTest::Test3785()
2173{
2174    UErrorCode status = U_ZERO_ERROR;
2175    UnicodeString uzone = UNICODE_STRING_SIMPLE("Europe/Paris");
2176    UnicodeString exp1 = UNICODE_STRING_SIMPLE("Mon 30 Jumada II 1433 AH, 01:47:03");
2177    UnicodeString exp2 = UNICODE_STRING_SIMPLE("Mon 1 Rajab 1433 AH, 01:47:04");
2178
2179    LocalUDateFormatPointer df(udat_open(UDAT_NONE, UDAT_NONE, "en@calendar=islamic", uzone.getTerminatedBuffer(),
2180                                         uzone.length(), NULL, 0, &status));
2181    if (df.isNull() || U_FAILURE(status)) return;
2182
2183    UChar upattern[64];
2184    u_uastrcpy(upattern, "EEE d MMMM y G, HH:mm:ss");
2185    udat_applyPattern(df.getAlias(), FALSE, upattern, u_strlen(upattern));
2186
2187    UChar ubuffer[1024];
2188    UDate ud0 = 1337557623000.0;
2189
2190    status = U_ZERO_ERROR;
2191    udat_format(df.getAlias(), ud0, ubuffer, 1024, NULL, &status);
2192    if (U_FAILURE(status)) {
2193        errln("Error formatting date 1\n");
2194        return;
2195    }
2196    //printf("formatted: '%s'\n", mkcstr(ubuffer));
2197
2198    UnicodeString act1(ubuffer);
2199    if ( act1 != exp1 ) {
2200        errln("Unexpected result from date 1 format\n");
2201    }
2202    ud0 += 1000.0; // add one second
2203
2204    status = U_ZERO_ERROR;
2205    udat_format(df.getAlias(), ud0, ubuffer, 1024, NULL, &status);
2206    if (U_FAILURE(status)) {
2207        errln("Error formatting date 2\n");
2208        return;
2209    }
2210    //printf("formatted: '%s'\n", mkcstr(ubuffer));
2211    UnicodeString act2(ubuffer);
2212    if ( act2 != exp2 ) {
2213        errln("Unexpected result from date 2 format\n");
2214    }
2215
2216    return;
2217}
2218
2219void CalendarTest::Test1624() {
2220    UErrorCode status = U_ZERO_ERROR;
2221    Locale loc("he_IL@calendar=hebrew");
2222    HebrewCalendar hc(loc,status);
2223
2224    for (int32_t year = 5600; year < 5800; year++ ) {
2225
2226        for (int32_t month = HebrewCalendar::TISHRI; month <= HebrewCalendar::ELUL; month++) {
2227            // skip the adar 1 month if year is not a leap year
2228            if (HebrewCalendar::isLeapYear(year) == FALSE && month == HebrewCalendar::ADAR_1) {
2229                continue;
2230            }
2231            int32_t day = 15;
2232            hc.set(year,month,day);
2233            int32_t dayHC = hc.get(UCAL_DATE,status);
2234            int32_t monthHC = hc.get(UCAL_MONTH,status);
2235            int32_t yearHC = hc.get(UCAL_YEAR,status);
2236
2237            if (failure(status, "HebrewCalendar.get()", TRUE)) continue;
2238
2239            if (dayHC != day) {
2240                errln(" ==> day %d incorrect, should be: %d\n",dayHC,day);
2241                break;
2242            }
2243            if (monthHC != month) {
2244                errln(" ==> month %d incorrect, should be: %d\n",monthHC,month);
2245                break;
2246            }
2247            if (yearHC != year) {
2248                errln(" ==> day %d incorrect, should be: %d\n",yearHC,year);
2249                break;
2250            }
2251        }
2252    }
2253    return;
2254}
2255
2256void CalendarTest::TestTimeStamp() {
2257    UErrorCode status = U_ZERO_ERROR;
2258    UDate start = 0.0, time;
2259    Calendar *cal;
2260
2261    // Create a new Gregorian Calendar.
2262    cal = Calendar::createInstance("en_US@calender=gregorian", status);
2263    if (U_FAILURE(status)) {
2264        dataerrln("Error creating Gregorian calendar.");
2265        return;
2266    }
2267
2268    for (int i = 0; i < 20000; i++) {
2269        // Set the Gregorian Calendar to a specific date for testing.
2270        cal->set(2009, UCAL_JULY, 3, 0, 49, 46);
2271
2272        time = cal->getTime(status);
2273        if (U_FAILURE(status)) {
2274            errln("Error calling getTime()");
2275            break;
2276        }
2277
2278        if (i == 0) {
2279            start = time;
2280        } else {
2281            if (start != time) {
2282                errln("start and time not equal.");
2283                break;
2284            }
2285        }
2286    }
2287
2288    delete cal;
2289}
2290
2291void CalendarTest::TestISO8601() {
2292    const char* TEST_LOCALES[] = {
2293        "en_US@calendar=iso8601",
2294        "en_US@calendar=Iso8601",
2295        "th_TH@calendar=iso8601",
2296        "ar_EG@calendar=iso8601",
2297        NULL
2298    };
2299
2300    int32_t TEST_DATA[][3] = {
2301        {2008, 1, 2008},
2302        {2009, 1, 2009},
2303        {2010, 53, 2009},
2304        {2011, 52, 2010},
2305        {2012, 52, 2011},
2306        {2013, 1, 2013},
2307        {2014, 1, 2014},
2308        {0, 0, 0},
2309    };
2310
2311    for (int i = 0; TEST_LOCALES[i] != NULL; i++) {
2312        UErrorCode status = U_ZERO_ERROR;
2313        Calendar *cal = Calendar::createInstance(TEST_LOCALES[i], status);
2314        if (U_FAILURE(status)) {
2315            errln("Error: Failed to create a calendar for locale: %s", TEST_LOCALES[i]);
2316            continue;
2317        }
2318        if (uprv_strcmp(cal->getType(), "gregorian") != 0) {
2319            errln("Error: Gregorian calendar is not used for locale: %s", TEST_LOCALES[i]);
2320            continue;
2321        }
2322        for (int j = 0; TEST_DATA[j][0] != 0; j++) {
2323            cal->set(TEST_DATA[j][0], UCAL_JANUARY, 1);
2324            int32_t weekNum = cal->get(UCAL_WEEK_OF_YEAR, status);
2325            int32_t weekYear = cal->get(UCAL_YEAR_WOY, status);
2326            if (U_FAILURE(status)) {
2327                errln("Error: Failed to get week of year");
2328                break;
2329            }
2330            if (weekNum != TEST_DATA[j][1] || weekYear != TEST_DATA[j][2]) {
2331                errln("Error: Incorrect week of year on January 1st, %d for locale %s: Returned [weekNum=%d, weekYear=%d], Expected [weekNum=%d, weekYear=%d]",
2332                    TEST_DATA[j][0], TEST_LOCALES[i], weekNum, weekYear, TEST_DATA[j][1], TEST_DATA[j][2]);
2333            }
2334        }
2335        delete cal;
2336    }
2337
2338}
2339
2340void
2341CalendarTest::TestAmbiguousWallTimeAPIs(void) {
2342    UErrorCode status = U_ZERO_ERROR;
2343    Calendar* cal = Calendar::createInstance(status);
2344    if (U_FAILURE(status)) {
2345        errln("Fail: Error creating a calendar instance.");
2346        return;
2347    }
2348
2349    if (cal->getRepeatedWallTimeOption() != UCAL_WALLTIME_LAST) {
2350        errln("Fail: Default repeted time option is not UCAL_WALLTIME_LAST");
2351    }
2352    if (cal->getSkippedWallTimeOption() != UCAL_WALLTIME_LAST) {
2353        errln("Fail: Default skipped time option is not UCAL_WALLTIME_LAST");
2354    }
2355
2356    Calendar* cal2 = cal->clone();
2357
2358    if (*cal != *cal2) {
2359        errln("Fail: Cloned calendar != the original");
2360    }
2361    if (!cal->equals(*cal2, status)) {
2362        errln("Fail: The time of cloned calendar is not equal to the original");
2363    } else if (U_FAILURE(status)) {
2364        errln("Fail: Error equals");
2365    }
2366    status = U_ZERO_ERROR;
2367
2368    cal2->setRepeatedWallTimeOption(UCAL_WALLTIME_FIRST);
2369    cal2->setSkippedWallTimeOption(UCAL_WALLTIME_FIRST);
2370
2371    if (*cal == *cal2) {
2372        errln("Fail: Cloned and modified calendar == the original");
2373    }
2374    if (!cal->equals(*cal2, status)) {
2375        errln("Fail: The time of cloned calendar is not equal to the original after changing wall time options");
2376    } else if (U_FAILURE(status)) {
2377        errln("Fail: Error equals after changing wall time options");
2378    }
2379    status = U_ZERO_ERROR;
2380
2381    if (cal2->getRepeatedWallTimeOption() != UCAL_WALLTIME_FIRST) {
2382        errln("Fail: Repeted time option is not UCAL_WALLTIME_FIRST");
2383    }
2384    if (cal2->getSkippedWallTimeOption() != UCAL_WALLTIME_FIRST) {
2385        errln("Fail: Skipped time option is not UCAL_WALLTIME_FIRST");
2386    }
2387
2388    cal2->setRepeatedWallTimeOption(UCAL_WALLTIME_NEXT_VALID);
2389    if (cal2->getRepeatedWallTimeOption() != UCAL_WALLTIME_FIRST) {
2390        errln("Fail: Repeated wall time option was updated other than UCAL_WALLTIME_FIRST");
2391    }
2392
2393    delete cal;
2394    delete cal2;
2395}
2396
2397class CalFields {
2398public:
2399    CalFields(int32_t year, int32_t month, int32_t day, int32_t hour, int32_t min, int32_t sec, int32_t ms = 0);
2400    CalFields(const Calendar& cal, UErrorCode& status);
2401    void setTo(Calendar& cal) const;
2402    char* toString(char* buf, int32_t len) const;
2403    UBool operator==(const CalFields& rhs) const;
2404    UBool operator!=(const CalFields& rhs) const;
2405    UBool isEquivalentTo(const Calendar& cal, UErrorCode& status) const;
2406
2407private:
2408    int32_t year;
2409    int32_t month;
2410    int32_t day;
2411    int32_t hour;
2412    int32_t min;
2413    int32_t sec;
2414    int32_t ms;
2415};
2416
2417CalFields::CalFields(int32_t year, int32_t month, int32_t day, int32_t hour, int32_t min, int32_t sec, int32_t ms)
2418    : year(year), month(month), day(day), hour(hour), min(min), sec(sec), ms(ms) {
2419}
2420
2421CalFields::CalFields(const Calendar& cal, UErrorCode& status) {
2422    year = cal.get(UCAL_YEAR, status);
2423    month = cal.get(UCAL_MONTH, status) + 1;
2424    day = cal.get(UCAL_DAY_OF_MONTH, status);
2425    hour = cal.get(UCAL_HOUR_OF_DAY, status);
2426    min = cal.get(UCAL_MINUTE, status);
2427    sec = cal.get(UCAL_SECOND, status);
2428    ms = cal.get(UCAL_MILLISECOND, status);
2429}
2430
2431void
2432CalFields::setTo(Calendar& cal) const {
2433    cal.clear();
2434    cal.set(year, month - 1, day, hour, min, sec);
2435    cal.set(UCAL_MILLISECOND, ms);
2436}
2437
2438char*
2439CalFields::toString(char* buf, int32_t len) const {
2440    char local[32];
2441    sprintf(local, "%04d-%02d-%02d %02d:%02d:%02d.%03d", year, month, day, hour, min, sec, ms);
2442    uprv_strncpy(buf, local, len - 1);
2443    buf[len - 1] = 0;
2444    return buf;
2445}
2446
2447UBool
2448CalFields::operator==(const CalFields& rhs) const {
2449    return year == rhs.year
2450        && month == rhs.month
2451        && day == rhs.day
2452        && hour == rhs.hour
2453        && min == rhs.min
2454        && sec == rhs.sec
2455        && ms == rhs.ms;
2456}
2457
2458UBool
2459CalFields::operator!=(const CalFields& rhs) const {
2460    return !(*this == rhs);
2461}
2462
2463UBool
2464CalFields::isEquivalentTo(const Calendar& cal, UErrorCode& status) const {
2465    return year == cal.get(UCAL_YEAR, status)
2466        && month == cal.get(UCAL_MONTH, status) + 1
2467        && day == cal.get(UCAL_DAY_OF_MONTH, status)
2468        && hour == cal.get(UCAL_HOUR_OF_DAY, status)
2469        && min == cal.get(UCAL_MINUTE, status)
2470        && sec == cal.get(UCAL_SECOND, status)
2471        && ms == cal.get(UCAL_MILLISECOND, status);
2472}
2473
2474typedef struct {
2475    const char*     tzid;
2476    const CalFields in;
2477    const CalFields expLastGMT;
2478    const CalFields expFirstGMT;
2479} RepeatedWallTimeTestData;
2480
2481static const RepeatedWallTimeTestData RPDATA[] =
2482{
2483    // Time zone            Input wall time                 WALLTIME_LAST in GMT            WALLTIME_FIRST in GMT
2484    {"America/New_York",    CalFields(2011,11,6,0,59,59),   CalFields(2011,11,6,4,59,59),   CalFields(2011,11,6,4,59,59)},
2485    {"America/New_York",    CalFields(2011,11,6,1,0,0),     CalFields(2011,11,6,6,0,0),     CalFields(2011,11,6,5,0,0)},
2486    {"America/New_York",    CalFields(2011,11,6,1,0,1),     CalFields(2011,11,6,6,0,1),     CalFields(2011,11,6,5,0,1)},
2487    {"America/New_York",    CalFields(2011,11,6,1,30,0),    CalFields(2011,11,6,6,30,0),    CalFields(2011,11,6,5,30,0)},
2488    {"America/New_York",    CalFields(2011,11,6,1,59,59),   CalFields(2011,11,6,6,59,59),   CalFields(2011,11,6,5,59,59)},
2489    {"America/New_York",    CalFields(2011,11,6,2,0,0),     CalFields(2011,11,6,7,0,0),     CalFields(2011,11,6,7,0,0)},
2490    {"America/New_York",    CalFields(2011,11,6,2,0,1),     CalFields(2011,11,6,7,0,1),     CalFields(2011,11,6,7,0,1)},
2491
2492    {"Australia/Lord_Howe", CalFields(2011,4,3,1,29,59),    CalFields(2011,4,2,14,29,59),   CalFields(2011,4,2,14,29,59)},
2493    {"Australia/Lord_Howe", CalFields(2011,4,3,1,30,0),     CalFields(2011,4,2,15,0,0),     CalFields(2011,4,2,14,30,0)},
2494    {"Australia/Lord_Howe", CalFields(2011,4,3,1,45,0),     CalFields(2011,4,2,15,15,0),    CalFields(2011,4,2,14,45,0)},
2495    {"Australia/Lord_Howe", CalFields(2011,4,3,1,59,59),    CalFields(2011,4,2,15,29,59),   CalFields(2011,4,2,14,59,59)},
2496    {"Australia/Lord_Howe", CalFields(2011,4,3,2,0,0),      CalFields(2011,4,2,15,30,0),    CalFields(2011,4,2,15,30,0)},
2497    {"Australia/Lord_Howe", CalFields(2011,4,3,2,0,1),      CalFields(2011,4,2,15,30,1),    CalFields(2011,4,2,15,30,1)},
2498
2499    {NULL,                  CalFields(0,0,0,0,0,0),         CalFields(0,0,0,0,0,0),          CalFields(0,0,0,0,0,0)}
2500};
2501
2502void CalendarTest::TestRepeatedWallTime(void) {
2503    UErrorCode status = U_ZERO_ERROR;
2504    GregorianCalendar calGMT((const TimeZone&)*TimeZone::getGMT(), status);
2505    GregorianCalendar calDefault(status);
2506    GregorianCalendar calLast(status);
2507    GregorianCalendar calFirst(status);
2508
2509    if (U_FAILURE(status)) {
2510        errln("Fail: Failed to create a calendar object.");
2511        return;
2512    }
2513
2514    calLast.setRepeatedWallTimeOption(UCAL_WALLTIME_LAST);
2515    calFirst.setRepeatedWallTimeOption(UCAL_WALLTIME_FIRST);
2516
2517    for (int32_t i = 0; RPDATA[i].tzid != NULL; i++) {
2518        char buf[32];
2519        TimeZone *tz = TimeZone::createTimeZone(RPDATA[i].tzid);
2520
2521        // UCAL_WALLTIME_LAST
2522        status = U_ZERO_ERROR;
2523        calLast.setTimeZone(*tz);
2524        RPDATA[i].in.setTo(calLast);
2525        calGMT.setTime(calLast.getTime(status), status);
2526        CalFields outLastGMT(calGMT, status);
2527        if (U_FAILURE(status)) {
2528            errln(UnicodeString("Fail: Failed to get/set time calLast/calGMT (UCAL_WALLTIME_LAST) - ")
2529                + RPDATA[i].in.toString(buf, sizeof(buf)) + "[" + RPDATA[i].tzid + "]");
2530        } else {
2531            if (outLastGMT != RPDATA[i].expLastGMT) {
2532                dataerrln(UnicodeString("Fail: UCAL_WALLTIME_LAST ") + RPDATA[i].in.toString(buf, sizeof(buf)) + "[" + RPDATA[i].tzid + "] is parsed as "
2533                    + outLastGMT.toString(buf, sizeof(buf)) + "[GMT]. Expected: " + RPDATA[i].expLastGMT.toString(buf, sizeof(buf)) + "[GMT]");
2534            }
2535        }
2536
2537        // default
2538        status = U_ZERO_ERROR;
2539        calDefault.setTimeZone(*tz);
2540        RPDATA[i].in.setTo(calDefault);
2541        calGMT.setTime(calDefault.getTime(status), status);
2542        CalFields outDefGMT(calGMT, status);
2543        if (U_FAILURE(status)) {
2544            errln(UnicodeString("Fail: Failed to get/set time calLast/calGMT (default) - ")
2545                + RPDATA[i].in.toString(buf, sizeof(buf)) + "[" + RPDATA[i].tzid + "]");
2546        } else {
2547            if (outDefGMT != RPDATA[i].expLastGMT) {
2548                dataerrln(UnicodeString("Fail: (default) ") + RPDATA[i].in.toString(buf, sizeof(buf)) + "[" + RPDATA[i].tzid + "] is parsed as "
2549                    + outDefGMT.toString(buf, sizeof(buf)) + "[GMT]. Expected: " + RPDATA[i].expLastGMT.toString(buf, sizeof(buf)) + "[GMT]");
2550            }
2551        }
2552
2553        // UCAL_WALLTIME_FIRST
2554        status = U_ZERO_ERROR;
2555        calFirst.setTimeZone(*tz);
2556        RPDATA[i].in.setTo(calFirst);
2557        calGMT.setTime(calFirst.getTime(status), status);
2558        CalFields outFirstGMT(calGMT, status);
2559        if (U_FAILURE(status)) {
2560            errln(UnicodeString("Fail: Failed to get/set time calLast/calGMT (UCAL_WALLTIME_FIRST) - ")
2561                + RPDATA[i].in.toString(buf, sizeof(buf)) + "[" + RPDATA[i].tzid + "]");
2562        } else {
2563            if (outFirstGMT != RPDATA[i].expFirstGMT) {
2564                dataerrln(UnicodeString("Fail: UCAL_WALLTIME_FIRST ") + RPDATA[i].in.toString(buf, sizeof(buf)) + "[" + RPDATA[i].tzid + "] is parsed as "
2565                    + outFirstGMT.toString(buf, sizeof(buf)) + "[GMT]. Expected: " + RPDATA[i].expFirstGMT.toString(buf, sizeof(buf)) + "[GMT]");
2566            }
2567        }
2568        delete tz;
2569    }
2570}
2571
2572typedef struct {
2573    const char*     tzid;
2574    const CalFields in;
2575    UBool           isValid;
2576    const CalFields expLastGMT;
2577    const CalFields expFirstGMT;
2578    const CalFields expNextAvailGMT;
2579} SkippedWallTimeTestData;
2580
2581static SkippedWallTimeTestData SKDATA[] =
2582{
2583     // Time zone           Input wall time                 valid?  WALLTIME_LAST in GMT            WALLTIME_FIRST in GMT           WALLTIME_NEXT_VALID in GMT
2584    {"America/New_York",    CalFields(2011,3,13,1,59,59),   TRUE,   CalFields(2011,3,13,6,59,59),   CalFields(2011,3,13,6,59,59),   CalFields(2011,3,13,6,59,59)},
2585    {"America/New_York",    CalFields(2011,3,13,2,0,0),     FALSE,  CalFields(2011,3,13,7,0,0),     CalFields(2011,3,13,6,0,0),     CalFields(2011,3,13,7,0,0)},
2586    {"America/New_York",    CalFields(2011,3,13,2,1,0),     FALSE,  CalFields(2011,3,13,7,1,0),     CalFields(2011,3,13,6,1,0),     CalFields(2011,3,13,7,0,0)},
2587    {"America/New_York",    CalFields(2011,3,13,2,30,0),    FALSE,  CalFields(2011,3,13,7,30,0),    CalFields(2011,3,13,6,30,0),    CalFields(2011,3,13,7,0,0)},
2588    {"America/New_York",    CalFields(2011,3,13,2,59,59),   FALSE,  CalFields(2011,3,13,7,59,59),   CalFields(2011,3,13,6,59,59),   CalFields(2011,3,13,7,0,0)},
2589    {"America/New_York",    CalFields(2011,3,13,3,0,0),     TRUE,   CalFields(2011,3,13,7,0,0),     CalFields(2011,3,13,7,0,0),     CalFields(2011,3,13,7,0,0)},
2590
2591    {"Pacific/Apia",        CalFields(2011,12,29,23,59,59), TRUE,   CalFields(2011,12,30,9,59,59),  CalFields(2011,12,30,9,59,59),  CalFields(2011,12,30,9,59,59)},
2592    {"Pacific/Apia",        CalFields(2011,12,30,0,0,0),    FALSE,  CalFields(2011,12,30,10,0,0),   CalFields(2011,12,29,10,0,0),   CalFields(2011,12,30,10,0,0)},
2593    {"Pacific/Apia",        CalFields(2011,12,30,12,0,0),   FALSE,  CalFields(2011,12,30,22,0,0),   CalFields(2011,12,29,22,0,0),   CalFields(2011,12,30,10,0,0)},
2594    {"Pacific/Apia",        CalFields(2011,12,30,23,59,59), FALSE,  CalFields(2011,12,31,9,59,59),  CalFields(2011,12,30,9,59,59),  CalFields(2011,12,30,10,0,0)},
2595    {"Pacific/Apia",        CalFields(2011,12,31,0,0,0),    TRUE,   CalFields(2011,12,30,10,0,0),   CalFields(2011,12,30,10,0,0),   CalFields(2011,12,30,10,0,0)},
2596
2597    {NULL,                  CalFields(0,0,0,0,0,0),         TRUE,   CalFields(0,0,0,0,0,0),         CalFields(0,0,0,0,0,0),         CalFields(0,0,0,0,0,0)}
2598};
2599
2600
2601void CalendarTest::TestSkippedWallTime(void) {
2602    UErrorCode status = U_ZERO_ERROR;
2603    GregorianCalendar calGMT((const TimeZone&)*TimeZone::getGMT(), status);
2604    GregorianCalendar calDefault(status);
2605    GregorianCalendar calLast(status);
2606    GregorianCalendar calFirst(status);
2607    GregorianCalendar calNextAvail(status);
2608
2609    if (U_FAILURE(status)) {
2610        errln("Fail: Failed to create a calendar object.");
2611        return;
2612    }
2613
2614    calLast.setSkippedWallTimeOption(UCAL_WALLTIME_LAST);
2615    calFirst.setSkippedWallTimeOption(UCAL_WALLTIME_FIRST);
2616    calNextAvail.setSkippedWallTimeOption(UCAL_WALLTIME_NEXT_VALID);
2617
2618    for (int32_t i = 0; SKDATA[i].tzid != NULL; i++) {
2619        UDate d;
2620        char buf[32];
2621        TimeZone *tz = TimeZone::createTimeZone(SKDATA[i].tzid);
2622
2623        for (int32_t j = 0; j < 2; j++) {
2624            UBool bLenient = (j == 0);
2625
2626            // UCAL_WALLTIME_LAST
2627            status = U_ZERO_ERROR;
2628            calLast.setLenient(bLenient);
2629            calLast.setTimeZone(*tz);
2630            SKDATA[i].in.setTo(calLast);
2631            d = calLast.getTime(status);
2632            if (bLenient || SKDATA[i].isValid) {
2633                calGMT.setTime(d, status);
2634                CalFields outLastGMT(calGMT, status);
2635                if (U_FAILURE(status)) {
2636                    errln(UnicodeString("Fail: Failed to get/set time calLast/calGMT (UCAL_WALLTIME_LAST) - ")
2637                        + SKDATA[i].in.toString(buf, sizeof(buf)) + "[" + SKDATA[i].tzid + "]");
2638                } else {
2639                    if (outLastGMT != SKDATA[i].expLastGMT) {
2640                        dataerrln(UnicodeString("Fail: UCAL_WALLTIME_LAST ") + SKDATA[i].in.toString(buf, sizeof(buf)) + "[" + SKDATA[i].tzid + "] is parsed as "
2641                            + outLastGMT.toString(buf, sizeof(buf)) + "[GMT]. Expected: " + SKDATA[i].expLastGMT.toString(buf, sizeof(buf)) + "[GMT]");
2642                    }
2643                }
2644            } else if (U_SUCCESS(status)) {
2645                // strict, invalid wall time - must report an error
2646                dataerrln(UnicodeString("Fail: An error expected (UCAL_WALLTIME_LAST)") +
2647                    + SKDATA[i].in.toString(buf, sizeof(buf)) + "[" + SKDATA[i].tzid + "]");
2648            }
2649
2650            // default
2651            status = U_ZERO_ERROR;
2652            calDefault.setLenient(bLenient);
2653            calDefault.setTimeZone(*tz);
2654            SKDATA[i].in.setTo(calDefault);
2655            d = calDefault.getTime(status);
2656            if (bLenient || SKDATA[i].isValid) {
2657                calGMT.setTime(d, status);
2658                CalFields outDefGMT(calGMT, status);
2659                if (U_FAILURE(status)) {
2660                    errln(UnicodeString("Fail: Failed to get/set time calDefault/calGMT (default) - ")
2661                        + SKDATA[i].in.toString(buf, sizeof(buf)) + "[" + SKDATA[i].tzid + "]");
2662                } else {
2663                    if (outDefGMT != SKDATA[i].expLastGMT) {
2664                        dataerrln(UnicodeString("Fail: (default) ") + SKDATA[i].in.toString(buf, sizeof(buf)) + "[" + SKDATA[i].tzid + "] is parsed as "
2665                            + outDefGMT.toString(buf, sizeof(buf)) + "[GMT]. Expected: " + SKDATA[i].expLastGMT.toString(buf, sizeof(buf)) + "[GMT]");
2666                    }
2667                }
2668            } else if (U_SUCCESS(status)) {
2669                // strict, invalid wall time - must report an error
2670                dataerrln(UnicodeString("Fail: An error expected (default)") +
2671                    + SKDATA[i].in.toString(buf, sizeof(buf)) + "[" + SKDATA[i].tzid + "]");
2672            }
2673
2674            // UCAL_WALLTIME_FIRST
2675            status = U_ZERO_ERROR;
2676            calFirst.setLenient(bLenient);
2677            calFirst.setTimeZone(*tz);
2678            SKDATA[i].in.setTo(calFirst);
2679            d = calFirst.getTime(status);
2680            if (bLenient || SKDATA[i].isValid) {
2681                calGMT.setTime(d, status);
2682                CalFields outFirstGMT(calGMT, status);
2683                if (U_FAILURE(status)) {
2684                    errln(UnicodeString("Fail: Failed to get/set time calFirst/calGMT (UCAL_WALLTIME_FIRST) - ")
2685                        + SKDATA[i].in.toString(buf, sizeof(buf)) + "[" + SKDATA[i].tzid + "]");
2686                } else {
2687                    if (outFirstGMT != SKDATA[i].expFirstGMT) {
2688                        dataerrln(UnicodeString("Fail: UCAL_WALLTIME_FIRST ") + SKDATA[i].in.toString(buf, sizeof(buf)) + "[" + SKDATA[i].tzid + "] is parsed as "
2689                            + outFirstGMT.toString(buf, sizeof(buf)) + "[GMT]. Expected: " + SKDATA[i].expFirstGMT.toString(buf, sizeof(buf)) + "[GMT]");
2690                    }
2691                }
2692            } else if (U_SUCCESS(status)) {
2693                // strict, invalid wall time - must report an error
2694                dataerrln(UnicodeString("Fail: An error expected (UCAL_WALLTIME_FIRST)") +
2695                    + SKDATA[i].in.toString(buf, sizeof(buf)) + "[" + SKDATA[i].tzid + "]");
2696            }
2697
2698            // UCAL_WALLTIME_NEXT_VALID
2699            status = U_ZERO_ERROR;
2700            calNextAvail.setLenient(bLenient);
2701            calNextAvail.setTimeZone(*tz);
2702            SKDATA[i].in.setTo(calNextAvail);
2703            d = calNextAvail.getTime(status);
2704            if (bLenient || SKDATA[i].isValid) {
2705                calGMT.setTime(d, status);
2706                CalFields outNextAvailGMT(calGMT, status);
2707                if (U_FAILURE(status)) {
2708                    errln(UnicodeString("Fail: Failed to get/set time calNextAvail/calGMT (UCAL_WALLTIME_NEXT_VALID) - ")
2709                        + SKDATA[i].in.toString(buf, sizeof(buf)) + "[" + SKDATA[i].tzid + "]");
2710                } else {
2711                    if (outNextAvailGMT != SKDATA[i].expNextAvailGMT) {
2712                        dataerrln(UnicodeString("Fail: UCAL_WALLTIME_NEXT_VALID ") + SKDATA[i].in.toString(buf, sizeof(buf)) + "[" + SKDATA[i].tzid + "] is parsed as "
2713                            + outNextAvailGMT.toString(buf, sizeof(buf)) + "[GMT]. Expected: " + SKDATA[i].expNextAvailGMT.toString(buf, sizeof(buf)) + "[GMT]");
2714                    }
2715                }
2716            } else if (U_SUCCESS(status)) {
2717                // strict, invalid wall time - must report an error
2718                dataerrln(UnicodeString("Fail: An error expected (UCAL_WALLTIME_NEXT_VALID)") +
2719                    + SKDATA[i].in.toString(buf, sizeof(buf)) + "[" + SKDATA[i].tzid + "]");
2720            }
2721        }
2722
2723        delete tz;
2724    }
2725}
2726
2727void CalendarTest::TestCloneLocale(void) {
2728  UErrorCode status = U_ZERO_ERROR;
2729  LocalPointer<Calendar>  cal(Calendar::createInstance(TimeZone::getGMT()->clone(),
2730                                                       Locale::createFromName("en"), status));
2731  TEST_CHECK_STATUS;
2732  Locale l0 = cal->getLocale(ULOC_VALID_LOCALE, status);
2733  TEST_CHECK_STATUS;
2734  LocalPointer<Calendar> cal2(cal->clone());
2735  Locale l = cal2->getLocale(ULOC_VALID_LOCALE, status);
2736  if(l0!=l) {
2737    errln("Error: cloned locale %s != original locale %s, status %s\n", l0.getName(), l.getName(), u_errorName(status));
2738  }
2739  TEST_CHECK_STATUS;
2740}
2741
2742typedef struct {
2743    const char* zone;
2744    const CalFields base;
2745    int32_t deltaDays;
2746    UCalendarWallTimeOption skippedWTOpt;
2747    const CalFields expected;
2748} TestAddAcrossZoneTransitionData;
2749
2750static const TestAddAcrossZoneTransitionData AAZTDATA[] =
2751{
2752    // Time zone                Base wall time                      day(s)  Skipped time options
2753    //                          Expected wall time
2754
2755    // Add 1 day, from the date before DST transition
2756    {"America/Los_Angeles",     CalFields(2014,3,8,1,59,59,999),    1,      UCAL_WALLTIME_FIRST,
2757                                CalFields(2014,3,9,1,59,59,999)},
2758
2759    {"America/Los_Angeles",     CalFields(2014,3,8,1,59,59,999),    1,      UCAL_WALLTIME_LAST,
2760                                CalFields(2014,3,9,1,59,59,999)},
2761
2762    {"America/Los_Angeles",     CalFields(2014,3,8,1,59,59,999),    1,      UCAL_WALLTIME_NEXT_VALID,
2763                                CalFields(2014,3,9,1,59,59,999)},
2764
2765
2766    {"America/Los_Angeles",     CalFields(2014,3,8,2,0,0,0),        1,      UCAL_WALLTIME_FIRST,
2767                                CalFields(2014,3,9,1,0,0,0)},
2768
2769    {"America/Los_Angeles",     CalFields(2014,3,8,2,0,0,0),        1,      UCAL_WALLTIME_LAST,
2770                                CalFields(2014,3,9,3,0,0,0)},
2771
2772    {"America/Los_Angeles",     CalFields(2014,3,8,2,0,0,0),        1,      UCAL_WALLTIME_NEXT_VALID,
2773                                CalFields(2014,3,9,3,0,0,0)},
2774
2775
2776    {"America/Los_Angeles",     CalFields(2014,3,8,2,30,0,0),       1,      UCAL_WALLTIME_FIRST,
2777                                CalFields(2014,3,9,1,30,0,0)},
2778
2779    {"America/Los_Angeles",     CalFields(2014,3,8,2,30,0,0),       1,      UCAL_WALLTIME_LAST,
2780                                CalFields(2014,3,9,3,30,0,0)},
2781
2782    {"America/Los_Angeles",     CalFields(2014,3,8,2,30,0,0),       1,      UCAL_WALLTIME_NEXT_VALID,
2783                                CalFields(2014,3,9,3,0,0,0)},
2784
2785
2786    {"America/Los_Angeles",     CalFields(2014,3,8,3,0,0,0),        1,      UCAL_WALLTIME_FIRST,
2787                                CalFields(2014,3,9,3,0,0,0)},
2788
2789    {"America/Los_Angeles",     CalFields(2014,3,8,3,0,0,0),        1,      UCAL_WALLTIME_LAST,
2790                                CalFields(2014,3,9,3,0,0,0)},
2791
2792    {"America/Los_Angeles",     CalFields(2014,3,8,3,0,0,0),        1,      UCAL_WALLTIME_NEXT_VALID,
2793                                CalFields(2014,3,9,3,0,0,0)},
2794
2795    // Subtract 1 day, from one day after DST transition
2796    {"America/Los_Angeles",     CalFields(2014,3,10,1,59,59,999),   -1,     UCAL_WALLTIME_FIRST,
2797                                CalFields(2014,3,9,1,59,59,999)},
2798
2799    {"America/Los_Angeles",     CalFields(2014,3,10,1,59,59,999),   -1,     UCAL_WALLTIME_LAST,
2800                                CalFields(2014,3,9,1,59,59,999)},
2801
2802    {"America/Los_Angeles",     CalFields(2014,3,10,1,59,59,999),   -1,     UCAL_WALLTIME_NEXT_VALID,
2803                                CalFields(2014,3,9,1,59,59,999)},
2804
2805
2806    {"America/Los_Angeles",     CalFields(2014,3,10,2,0,0,0),       -1,     UCAL_WALLTIME_FIRST,
2807                                CalFields(2014,3,9,1,0,0,0)},
2808
2809    {"America/Los_Angeles",     CalFields(2014,3,10,2,0,0,0),       -1,     UCAL_WALLTIME_LAST,
2810                                CalFields(2014,3,9,3,0,0,0)},
2811
2812    {"America/Los_Angeles",     CalFields(2014,3,10,2,0,0,0),       -1,     UCAL_WALLTIME_NEXT_VALID,
2813                                CalFields(2014,3,9,3,0,0,0)},
2814
2815
2816    {"America/Los_Angeles",     CalFields(2014,3,10,2,30,0,0),      -1,     UCAL_WALLTIME_FIRST,
2817                                CalFields(2014,3,9,1,30,0,0)},
2818
2819    {"America/Los_Angeles",     CalFields(2014,3,10,2,30,0,0),      -1,     UCAL_WALLTIME_LAST,
2820                                CalFields(2014,3,9,3,30,0,0)},
2821
2822    {"America/Los_Angeles",     CalFields(2014,3,10,2,30,0,0),      -1,     UCAL_WALLTIME_NEXT_VALID,
2823                                CalFields(2014,3,9,3,0,0,0)},
2824
2825
2826    {"America/Los_Angeles",     CalFields(2014,3,10,3,0,0,0),       -1,     UCAL_WALLTIME_FIRST,
2827                                CalFields(2014,3,9,3,0,0,0)},
2828
2829    {"America/Los_Angeles",     CalFields(2014,3,10,3,0,0,0),       -1,     UCAL_WALLTIME_LAST,
2830                                CalFields(2014,3,9,3,0,0,0)},
2831
2832    {"America/Los_Angeles",     CalFields(2014,3,10,3,0,0,0),       -1,     UCAL_WALLTIME_NEXT_VALID,
2833                                CalFields(2014,3,9,3,0,0,0)},
2834
2835
2836    // Test case for ticket#10544
2837    {"America/Santiago",        CalFields(2013,4,27,0,0,0,0),       134,    UCAL_WALLTIME_FIRST,
2838                                CalFields(2013,9,7,23,0,0,0)},
2839
2840    {"America/Santiago",        CalFields(2013,4,27,0,0,0,0),       134,    UCAL_WALLTIME_LAST,
2841                                CalFields(2013,9,8,1,0,0,0)},
2842
2843    {"America/Santiago",        CalFields(2013,4,27,0,0,0,0),       134,    UCAL_WALLTIME_NEXT_VALID,
2844                                CalFields(2013,9,8,1,0,0,0)},
2845
2846
2847    {"America/Santiago",        CalFields(2013,4,27,0,30,0,0),      134,    UCAL_WALLTIME_FIRST,
2848                                CalFields(2013,9,7,23,30,0,0)},
2849
2850    {"America/Santiago",        CalFields(2013,4,27,0,30,0,0),      134,    UCAL_WALLTIME_LAST,
2851                                CalFields(2013,9,8,1,30,0,0)},
2852
2853    {"America/Santiago",        CalFields(2013,4,27,0,30,0,0),      134,    UCAL_WALLTIME_NEXT_VALID,
2854                                CalFields(2013,9,8,1,0,0,0)},
2855
2856
2857    // Extreme transition - Pacific/Apia completely skips 2011-12-30
2858    {"Pacific/Apia",            CalFields(2011,12,29,0,0,0,0),      1,      UCAL_WALLTIME_FIRST,
2859                                CalFields(2011,12,31,0,0,0,0)},
2860
2861    {"Pacific/Apia",            CalFields(2011,12,29,0,0,0,0),      1,      UCAL_WALLTIME_LAST,
2862                                CalFields(2011,12,31,0,0,0,0)},
2863
2864    {"Pacific/Apia",            CalFields(2011,12,29,0,0,0,0),      1,      UCAL_WALLTIME_NEXT_VALID,
2865                                CalFields(2011,12,31,0,0,0,0)},
2866
2867
2868    {"Pacific/Apia",            CalFields(2011,12,31,12,0,0,0),     -1,     UCAL_WALLTIME_FIRST,
2869                                CalFields(2011,12,29,12,0,0,0)},
2870
2871    {"Pacific/Apia",            CalFields(2011,12,31,12,0,0,0),     -1,     UCAL_WALLTIME_LAST,
2872                                CalFields(2011,12,29,12,0,0,0)},
2873
2874    {"Pacific/Apia",            CalFields(2011,12,31,12,0,0,0),     -1,     UCAL_WALLTIME_NEXT_VALID,
2875                                CalFields(2011,12,29,12,0,0,0)},
2876
2877
2878    // 30 minutes DST - Australia/Lord_Howe
2879    {"Australia/Lord_Howe",     CalFields(2013,10,5,2,15,0,0),      1,      UCAL_WALLTIME_FIRST,
2880                                CalFields(2013,10,6,1,45,0,0)},
2881
2882    {"Australia/Lord_Howe",     CalFields(2013,10,5,2,15,0,0),      1,      UCAL_WALLTIME_LAST,
2883                                CalFields(2013,10,6,2,45,0,0)},
2884
2885    {"Australia/Lord_Howe",     CalFields(2013,10,5,2,15,0,0),      1,      UCAL_WALLTIME_NEXT_VALID,
2886                                CalFields(2013,10,6,2,30,0,0)},
2887
2888    {NULL, CalFields(0,0,0,0,0,0,0), 0, UCAL_WALLTIME_LAST, CalFields(0,0,0,0,0,0,0)}
2889};
2890
2891void CalendarTest::TestAddAcrossZoneTransition() {
2892    UErrorCode status = U_ZERO_ERROR;
2893    GregorianCalendar cal(status);
2894    TEST_CHECK_STATUS;
2895
2896    for (int32_t i = 0; AAZTDATA[i].zone; i++) {
2897        status = U_ZERO_ERROR;
2898        TimeZone *tz = TimeZone::createTimeZone(AAZTDATA[i].zone);
2899        cal.adoptTimeZone(tz);
2900        cal.setSkippedWallTimeOption(AAZTDATA[i].skippedWTOpt);
2901        AAZTDATA[i].base.setTo(cal);
2902        cal.add(UCAL_DATE, AAZTDATA[i].deltaDays, status);
2903        TEST_CHECK_STATUS;
2904
2905        if (!AAZTDATA[i].expected.isEquivalentTo(cal, status)) {
2906            CalFields res(cal, status);
2907            TEST_CHECK_STATUS;
2908            char buf[32];
2909            const char *optDisp = AAZTDATA[i].skippedWTOpt == UCAL_WALLTIME_FIRST ? "FIRST" :
2910                    AAZTDATA[i].skippedWTOpt == UCAL_WALLTIME_LAST ? "LAST" : "NEXT_VALID";
2911            errln(UnicodeString("Error: base:") + AAZTDATA[i].base.toString(buf, sizeof(buf)) + ", tz:" + AAZTDATA[i].zone
2912                        + ", delta:" + AAZTDATA[i].deltaDays + " day(s), opt:" + optDisp
2913                        + ", result:" + res.toString(buf, sizeof(buf))
2914                        + " - expected:" + AAZTDATA[i].expected.toString(buf, sizeof(buf)));
2915        }
2916    }
2917}
2918
2919#endif /* #if !UCONFIG_NO_FORMATTING */
2920
2921//eof
2922