1/********************************************************************
2 * COPYRIGHT:
3 * Copyright (c) 1997-2010, 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 "calregts.h"
12
13#include "unicode/gregocal.h"
14#include "unicode/simpletz.h"
15#include "unicode/smpdtfmt.h"
16#include "unicode/strenum.h"
17#include "cmemory.h"
18#include "caltest.h"
19
20#include <float.h>
21
22// *****************************************************************************
23// class CalendarRegressionTest
24// *****************************************************************************
25
26// these numbers correspond to using LONG_MIN and LONG_MAX in Java
27// this is 2^52 - 1, the largest allowable mantissa with a 0 exponent in a 64-bit double
28const UDate CalendarRegressionTest::EARLIEST_SUPPORTED_MILLIS = - 4503599627370495.0;
29const UDate CalendarRegressionTest::LATEST_SUPPORTED_MILLIS    =   4503599627370495.0;
30
31#define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break
32
33void
34CalendarRegressionTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
35{
36    // if (exec) logln((UnicodeString)"TestSuite NumberFormatRegressionTest");
37    switch (index) {
38        CASE(0,test4100311);
39        CASE(1,test4074758);
40        CASE(2,test4028518);
41        CASE(3,test4031502);
42        CASE(4,test4035301);
43        CASE(5,test4040996);
44        CASE(6,test4051765);
45        CASE(7,test4061476);
46        CASE(8,test4070502);
47        CASE(9,test4071197);
48        CASE(10,test4071385);
49        CASE(11,test4073929);
50        CASE(12,test4083167);
51        CASE(13,test4086724);
52        CASE(14,test4095407);
53        CASE(15,test4096231);
54        CASE(16,test4096539);
55        CASE(17,test41003112);
56        CASE(18,test4103271);
57        CASE(19,test4106136);
58        CASE(20,test4108764);
59        CASE(21,test4114578);
60        CASE(22,test4118384);
61        CASE(23,test4125881);
62        CASE(24,test4125892);
63        CASE(25,test4141665);
64        CASE(26,test4142933);
65        CASE(27,test4145158);
66        CASE(28,test4145983);
67        CASE(29,test4147269);
68
69        CASE(30,Test4149677);
70        CASE(31,Test4162587);
71        CASE(32,Test4165343);
72        CASE(33,Test4166109);
73        CASE(34,Test4167060);
74        CASE(35,Test4197699);
75        CASE(36,TestJ81);
76        CASE(37,TestJ438);
77        CASE(38,TestLeapFieldDifference);
78        CASE(39,TestMalaysianInstance);
79        CASE(40,test4059654);
80        CASE(41,test4092362);
81        CASE(42,TestWeekShift);
82        CASE(43,TestTimeZoneTransitionAdd);
83        CASE(44,TestDeprecates);
84        CASE(45,TestT5555);
85        CASE(46,TestT6745);
86    default: name = ""; break;
87    }
88}
89
90const char* CalendarRegressionTest::FIELD_NAME [] = {
91    "ERA",
92    "YEAR",
93    "MONTH",
94    "WEEK_OF_YEAR",
95    "WEEK_OF_MONTH",
96    "DAY_OF_MONTH",
97    "DAY_OF_YEAR",
98    "DAY_OF_WEEK",
99    "DAY_OF_WEEK_IN_MONTH",
100    "AM_PM",
101    "HOUR",
102    "HOUR_OF_DAY",
103    "MINUTE",
104    "SECOND",
105    "MILLISECOND",
106    "ZONE_OFFSET",
107    "DST_OFFSET",
108    "YEAR_WOY",
109    "DOW_LOCAL"
110};
111
112UBool
113CalendarRegressionTest::failure(UErrorCode status, const char* msg)
114{
115    if(U_FAILURE(status)) {
116        errcheckln(status, UnicodeString("FAIL: ") + msg + " failed, error " + u_errorName(status));
117        return TRUE;
118    }
119
120    return FALSE;
121}
122
123/*
124 * bug 4100311
125 */
126void
127CalendarRegressionTest::test4100311()
128{
129    UErrorCode status = U_ZERO_ERROR;
130    GregorianCalendar *cal = (GregorianCalendar*)Calendar::createInstance(status);
131    if(U_FAILURE(status)) {
132      dataerrln("Error creating Calendar: %s", u_errorName(status));
133      delete cal;
134      return;
135    }
136    failure(status, "Calendar::createInstance(status)");
137    cal->set(UCAL_YEAR, 1997);
138    cal->set(UCAL_DAY_OF_YEAR, 1);
139    UDate d = cal->getTime(status);             // Should be Jan 1
140    failure(status, "cal->getTime");
141    logln(UnicodeString("") + d);
142    delete cal;
143}
144
145
146/**
147 * @bug 4074758
148 */
149void
150CalendarRegressionTest::test4074758()
151{       //Set system time to between 12-1 (am or pm) and then run
152    UErrorCode status = U_ZERO_ERROR;
153    GregorianCalendar *cal = new GregorianCalendar(status);
154    if(U_FAILURE(status)) {
155      dataerrln("Error creating Calendar: %s", u_errorName(status));
156      delete cal;
157      return;
158    }
159    failure(status, "new GregorianCalendar");
160    for (int32_t h=0; h<25; ++h) {
161        cal->set(97, UCAL_JANUARY, 1, h, 34);
162        //System.out.print(d);
163        logln(UnicodeString("HOUR=") + cal->get(UCAL_HOUR, status)); //prints 0
164        failure(status, "cal->get");
165        logln(UnicodeString("HOUR_OF_DAY=") + cal->get(UCAL_HOUR_OF_DAY, status));
166        failure(status, "cal->get");
167    }
168
169    delete cal;
170}
171
172void
173CalendarRegressionTest::test4028518()
174{
175    UErrorCode status = U_ZERO_ERROR;
176    GregorianCalendar *cal1 = new GregorianCalendar(status) ;
177    if(U_FAILURE(status)) {
178      dataerrln("Error creating Calendar: %s", u_errorName(status));
179      delete cal1;
180      return;
181    }
182    failure(status, "new GregorianCalendar");
183    GregorianCalendar *cal2 = (GregorianCalendar*) cal1->clone() ;
184
185    printdate(cal1, "cal1: ") ;
186    printdate(cal2, "cal2 - cloned(): ") ;
187    cal1->add(UCAL_DATE, 1, status) ;
188    failure(status, "cal1->add");
189    printdate(cal1, "cal1 after adding 1 day:") ;
190    printdate(cal2, "cal2 should be unmodified:") ;
191    delete cal1;
192    delete cal2;
193}
194
195void
196CalendarRegressionTest::printdate(GregorianCalendar *cal, const char *string)
197{
198    UErrorCode status = U_ZERO_ERROR;
199    logln(UnicodeString(string, ""));
200    log(UnicodeString("") + cal->get(UCAL_MONTH, status)) ;
201    failure(status, "cal->get");
202    int32_t date = cal->get(UCAL_DATE, status) + 1 ;
203    failure(status, "cal->get");
204    log(UnicodeString("/") + date) ;
205    logln(UnicodeString("/") + cal->get(UCAL_YEAR, status)) ;
206    failure(status, "cal->get");
207}
208
209/**
210 * @bug 4031502
211 */
212void
213CalendarRegressionTest::test4031502()
214{
215    // This bug actually occurs on Windows NT as well, and doesn't
216    // require the host zone to be set; it can be set in Java.
217    UErrorCode status = U_ZERO_ERROR;
218    StringEnumeration* ids = TimeZone::createEnumeration();
219    UBool bad = FALSE;
220    TimeZone* tz =TimeZone::createTimeZone("Asia/Riyadh87");
221    failure(status, "new TimeZone");
222    GregorianCalendar *cl = new GregorianCalendar(tz, status);
223    if (U_FAILURE(status)) {
224        dataerrln("Fail new GregorianCalendar: %s", u_errorName(status));
225        delete tz;
226        return;
227    }
228    cl->clear();
229    cl->set(1900, 15, 5, 5, 8, 13);
230    cl->get(UCAL_HOUR, status);
231    failure(status, "cl->get(UCAL_HOUR, status)");
232    status = U_ZERO_ERROR;
233    delete cl;
234    for (int32_t i=0; i<ids->count(status); ++i) {
235        TimeZone *zone = TimeZone::createTimeZone(*ids->snext(status));
236        GregorianCalendar *cal = new GregorianCalendar(zone, status);
237        failure(status, "new GregorianCalendar");
238        cal->clear();
239        cal->set(1900, 15, 5, 5, 8, 13);
240        if (cal->get(UCAL_HOUR, status) != 5 || U_FAILURE(status)) {
241            UnicodeString temp;
242            logln(zone->getID(temp) + " " +
243                               //zone.useDaylightTime() + " " +
244                               cal->get(UCAL_DST_OFFSET,status) / (60*60*1000) + " " +
245                               zone->getRawOffset() / (60*60*1000) +
246                               ": HOUR = " + cal->get(UCAL_HOUR,status));
247            bad = TRUE;
248        }
249        delete cal;
250    }
251    if (bad)
252        errln("TimeZone problems with GC");
253    // delete [] ids;  // TODO: bad APIs
254    delete ids;
255}
256
257/**
258 * @bug 4035301
259 */
260void CalendarRegressionTest::test4035301()
261{
262    UErrorCode status = U_ZERO_ERROR;
263    GregorianCalendar *c = new GregorianCalendar(98, 8, 7,status);
264    GregorianCalendar *d = new GregorianCalendar(98, 8, 7,status);
265    if (c->after(*d,status) ||
266        c->after(*c,status) ||
267        c->before(*d,status) ||
268        c->before(*c,status) ||
269        *c != *c ||
270        *c != *d)
271        dataerrln("Fail");
272    delete c;
273    delete d;
274}
275
276/**
277 * @bug 4040996
278 */
279void CalendarRegressionTest::test4040996()
280{
281    int32_t count = 0;
282    StringEnumeration* ids = TimeZone::createEnumeration(-8 * 60 * 60 * 1000);
283    UErrorCode status = U_ZERO_ERROR;
284    count = ids->count(status);
285    SimpleTimeZone *pdt = new SimpleTimeZone(-8 * 60 * 60 * 1000, *ids->snext(status));
286    pdt->setStartRule(UCAL_APRIL, 1, UCAL_SUNDAY, 2 * 60 * 60 * 1000, status);
287    pdt->setEndRule(UCAL_OCTOBER, -1, UCAL_SUNDAY, 2 * 60 * 60 * 1000, status);
288    Calendar *calendar = new GregorianCalendar(pdt, status);
289    if (U_FAILURE(status)) {
290        dataerrln("Fail new GregorianCalendar: %s", u_errorName(status));
291        return;
292    }
293    calendar->set(UCAL_MONTH,3);
294    calendar->set(UCAL_DATE,18);
295    calendar->set(UCAL_SECOND, 30);
296
297    logln(UnicodeString("MONTH: ") + calendar->get(UCAL_MONTH, status));
298    logln(UnicodeString("DAY_OF_MONTH: ") +
299                       calendar->get(UCAL_DATE, status));
300    logln(UnicodeString("MINUTE: ") + calendar->get(UCAL_MINUTE, status));
301    logln(UnicodeString("SECOND: ") + calendar->get(UCAL_SECOND, status));
302
303    calendar->add(UCAL_SECOND,6, status);
304    //This will print out todays date for MONTH and DAY_OF_MONTH
305    //instead of the date it was set to.
306    //This happens when adding MILLISECOND or MINUTE also
307    logln(UnicodeString("MONTH: ") + calendar->get(UCAL_MONTH, status));
308    logln(UnicodeString("DAY_OF_MONTH: ") +
309                       calendar->get(UCAL_DATE, status));
310    logln(UnicodeString("MINUTE: ") + calendar->get(UCAL_MINUTE, status));
311    logln(UnicodeString("SECOND: ") + calendar->get(UCAL_SECOND, status));
312    if (calendar->get(UCAL_MONTH, status) != 3 ||
313        calendar->get(UCAL_DATE, status) != 18 ||
314        calendar->get(UCAL_SECOND, status) != 36)
315        errln(UnicodeString("Fail: Calendar::add misbehaves"));
316
317    delete calendar;
318    delete ids;
319    // delete ids;   // TODO:  BAD API
320}
321
322/**
323 * @bug 4051765
324 */
325void CalendarRegressionTest::test4051765()
326{
327    UErrorCode status = U_ZERO_ERROR;
328    Calendar *cal = Calendar::createInstance(status);
329    if(U_FAILURE(status)) {
330      dataerrln("Error creating Calendar: %s", u_errorName(status));
331      delete cal;
332      return;
333    }
334    cal->setLenient(FALSE);
335    cal->set(UCAL_DAY_OF_WEEK, 0);
336    //try {
337        cal->getTime(status);
338        if( ! U_FAILURE(status))
339            errln("Fail: DAY_OF_WEEK 0 should be disallowed");
340    /*}
341    catch (IllegalArgumentException e) {
342        return;
343    }*/
344
345    delete cal;
346}
347
348/* User error - no bug here
349void CalendarRegressionTest::test4059524() {
350    // Create calendar for April 10, 1997
351    GregorianCalendar calendar  = new GregorianCalendar(status);
352    // print out a bunch of interesting things
353    logln("ERA: " + Calendar::get(Calendar::ERA));
354    logln("YEAR: " + Calendar::get(Calendar::YEAR));
355    logln("MONTH: " + Calendar::get(Calendar::MONTH));
356    logln("WEEK_OF_YEAR: " +
357                       Calendar::get(Calendar::WEEK_OF_YEAR));
358    logln("WEEK_OF_MONTH: " +
359                       Calendar::get(Calendar::WEEK_OF_MONTH));
360    logln("DATE: " + Calendar::get(Calendar::DATE));
361    logln("DAY_OF_MONTH: " +
362                       Calendar::get(Calendar::DAY_OF_MONTH));
363    logln("DAY_OF_YEAR: " + Calendar::get(Calendar::DAY_OF_YEAR));
364    logln("DAY_OF_WEEK: " + Calendar::get(Calendar::DAY_OF_WEEK));
365    logln("DAY_OF_WEEK_IN_MONTH: " +
366                       Calendar::get(Calendar::DAY_OF_WEEK_IN_MONTH));
367    logln("AM_PM: " + Calendar::get(Calendar::AM_PM));
368    logln("HOUR: " + Calendar::get(Calendar::HOUR));
369    logln("HOUR_OF_DAY: " + Calendar::get(Calendar::HOUR_OF_DAY));
370    logln("MINUTE: " + Calendar::get(Calendar::MINUTE));
371    logln("SECOND: " + Calendar::get(Calendar::SECOND));
372    logln("MILLISECOND: " + Calendar::get(Calendar::MILLISECOND));
373    logln("ZONE_OFFSET: "
374                       + (Calendar::get(Calendar::ZONE_OFFSET)/(60*60*1000)));
375    logln("DST_OFFSET: "
376                       + (Calendar::get(Calendar::DST_OFFSET)/(60*60*1000)));
377    calendar  = new GregorianCalendar(1997,3,10);
378    Calendar::getTime();
379    logln("April 10, 1997");
380    logln("ERA: " + Calendar::get(Calendar::ERA));
381    logln("YEAR: " + Calendar::get(Calendar::YEAR));
382    logln("MONTH: " + Calendar::get(Calendar::MONTH));
383    logln("WEEK_OF_YEAR: " +
384                       Calendar::get(Calendar::WEEK_OF_YEAR));
385    logln("WEEK_OF_MONTH: " +
386                       Calendar::get(Calendar::WEEK_OF_MONTH));
387    logln("DATE: " + Calendar::get(Calendar::DATE));
388    logln("DAY_OF_MONTH: " +
389                       Calendar::get(Calendar::DAY_OF_MONTH));
390    logln("DAY_OF_YEAR: " + Calendar::get(Calendar::DAY_OF_YEAR));
391    logln("DAY_OF_WEEK: " + Calendar::get(Calendar::DAY_OF_WEEK));
392    logln("DAY_OF_WEEK_IN_MONTH: " + Calendar::get(Calendar::DAY_OF_WEEK_IN_MONTH));
393    logln("AM_PM: " + Calendar::get(Calendar::AM_PM));
394    logln("HOUR: " + Calendar::get(Calendar::HOUR));
395    logln("HOUR_OF_DAY: " + Calendar::get(Calendar::HOUR_OF_DAY));
396    logln("MINUTE: " + Calendar::get(Calendar::MINUTE));
397    logln("SECOND: " + Calendar::get(Calendar::SECOND));
398    logln("MILLISECOND: " + Calendar::get(Calendar::MILLISECOND));
399    logln("ZONE_OFFSET: "
400                       + (Calendar::get(Calendar::ZONE_OFFSET)/(60*60*1000))); // in hours
401    logln("DST_OFFSET: "
402                       + (Calendar::get(Calendar::DST_OFFSET)/(60*60*1000))); // in hours
403}
404*/
405
406/**
407 * @bug 4059654
408 */
409void CalendarRegressionTest::test4059654() {
410    UErrorCode status = U_ZERO_ERROR;
411    GregorianCalendar *gc = new GregorianCalendar(status);
412    if(U_FAILURE(status)) {
413      dataerrln("Error creating Calendar: %s", u_errorName(status));
414      delete gc;
415      return;
416    }
417
418    gc->set(1997, 3, 1, 15, 16, 17); // April 1, 1997
419
420    gc->set(UCAL_HOUR, 0);
421    gc->set(UCAL_AM_PM, UCAL_AM);
422    gc->set(UCAL_MINUTE, 0);
423    gc->set(UCAL_SECOND, 0);
424    gc->set(UCAL_MILLISECOND, 0);
425
426    UDate cd = gc->getTime(status);
427    GregorianCalendar *exp = new GregorianCalendar(1997, 3, 1, 0, 0, 0, status);
428    if (cd != exp->getTime(status))
429        errln(UnicodeString("Fail: Calendar::set broken. Got ") + cd + " Want " + exp->getTime(status));
430
431    delete gc;
432    delete exp;
433}
434
435/**
436 * @bug 4061476
437 */
438void CalendarRegressionTest::test4061476()
439{
440    UErrorCode status = U_ZERO_ERROR;
441    SimpleDateFormat *fmt = new SimpleDateFormat(UnicodeString("ddMMMyy"), Locale::getUK(),status);
442    Calendar *cal = Calendar::createInstance(TimeZone::createTimeZone("GMT"),
443                                    Locale::getUK(),status);
444    if(U_FAILURE(status)) {
445      dataerrln("Error creating Calendar: %s", u_errorName(status));
446      delete cal;
447      delete fmt;
448      return;
449    }
450    fmt->adoptCalendar(cal);
451    // try {
452            UDate date = fmt->parse("29MAY97", status);
453            failure(status, "fmt->parse");
454            cal->setTime(date, status);
455            failure(status, "cal->setTime");
456     //   }
457    //catch (Exception e) {;}
458    cal->set(UCAL_HOUR_OF_DAY, 13);
459    logln(UnicodeString("Hour: ")+cal->get(UCAL_HOUR_OF_DAY, status));
460    cal->add(UCAL_HOUR_OF_DAY, 6,status);
461    logln(UnicodeString("Hour: ")+cal->get(UCAL_HOUR_OF_DAY, status));
462    if (cal->get(UCAL_HOUR_OF_DAY, status) != 19)
463        errln(UnicodeString("Fail: Want 19 Got ") + cal->get(UCAL_HOUR_OF_DAY, status));
464
465    delete fmt;
466}
467
468/**
469 * @bug 4070502
470 */
471void CalendarRegressionTest::test4070502()
472{
473    UErrorCode status = U_ZERO_ERROR;
474    Calendar *cal = new GregorianCalendar(status);
475    if(status == U_USING_FALLBACK_WARNING || U_FAILURE(status)) {
476      dataerrln("Error creating Calendar: %s", u_errorName(status));
477      delete cal;
478      return;
479    }
480    UDate d = getAssociatedDate(makeDate(1998,0,30), status);
481    cal->setTime(d,status);
482    if (cal->get(UCAL_DAY_OF_WEEK,status) == UCAL_SATURDAY ||
483        cal->get(UCAL_DAY_OF_WEEK,status) == UCAL_SUNDAY)
484        errln(UnicodeString("Fail: Want weekday Got ") + d);
485
486    delete cal;
487}
488
489/**
490 * Get the associated date starting from a specified date
491 * NOTE: the unnecessary "getTime()'s" below are a work-around for a
492 * bug in jdk 1.1.3 (and probably earlier versions also)
493 * <p>
494 * @param date The date to start from
495 */
496UDate
497CalendarRegressionTest::getAssociatedDate(UDate d, UErrorCode& status)
498{
499    GregorianCalendar *cal = new GregorianCalendar(status);
500    cal->setTime(d,status);
501    //cal.add(field, amount); //<-- PROBLEM SEEN WITH field = DATE,MONTH
502    // cal.getTime();  // <--- REMOVE THIS TO SEE BUG
503    for (;;) {
504        int32_t wd = cal->get(UCAL_DAY_OF_WEEK, status);
505        if (wd == UCAL_SATURDAY || wd == UCAL_SUNDAY) {
506            cal->add(UCAL_DATE, 1, status);
507            // cal.getTime();
508        }
509        else
510            break;
511    }
512
513    UDate dd = cal->getTime(status);
514    delete cal;
515    return dd;
516}
517
518/**
519 * @bug 4071197
520 */
521void CalendarRegressionTest::test4071197()
522{
523    dowTest(FALSE);
524    dowTest(TRUE);
525}
526
527void CalendarRegressionTest::dowTest(UBool lenient)
528{
529    UErrorCode status = U_ZERO_ERROR;
530    GregorianCalendar *cal = new GregorianCalendar(status);
531    if(U_FAILURE(status)) {
532      dataerrln("Error creating Calendar: %s", u_errorName(status));
533      delete cal;
534      return;
535    }
536    cal->set(1997, UCAL_AUGUST, 12); // Wednesday
537    // cal.getTime(); // Force update
538    cal->setLenient(lenient);
539    cal->set(1996, UCAL_DECEMBER, 1); // Set the date to be December 1, 1996
540    int32_t dow = cal->get(UCAL_DAY_OF_WEEK, status);
541    int32_t min = cal->getMinimum(UCAL_DAY_OF_WEEK);
542    int32_t max = cal->getMaximum(UCAL_DAY_OF_WEEK);
543    //logln(cal.getTime().toString());
544    if (min != UCAL_SUNDAY || max != UCAL_SATURDAY)
545        errln("FAIL: Min/max bad");
546    if (dow < min || dow > max)
547        errln("FAIL: Day of week %d out of range [%d,%d]\n", dow, min, max);
548    if (dow != UCAL_SUNDAY)
549        errln("FAIL: Day of week should be SUNDAY Got " + dow);
550
551    if(U_FAILURE(status)) {
552      errln("Error checking Calendar: %s", u_errorName(status));
553      delete cal;
554      return;
555    }
556
557    if(cal->getActualMinimum(UCAL_DAY_OF_WEEK, status) != min) {
558        errln("FAIL: actual minimum differs from minimum");
559    }
560    if(cal->getActualMinimum(Calendar::DAY_OF_WEEK, status) != min) {
561        errln("FAIL: actual minimum (Calendar::DAY_OF_WEEK, status) differs from minimum");
562    }
563    if(cal->getActualMinimum(Calendar::DAY_OF_WEEK) != min) {
564        errln("FAIL: actual minimum (Calendar::DAY_OF_WEEK) differs from minimum");
565    }
566    if(((Calendar*)cal)->getActualMinimum(UCAL_DAY_OF_WEEK, status) != min) {
567        errln("FAIL: actual minimum (UCAL_DAY_OF_WEEK, status) differs from minimum");
568    }
569// NOTE: This function does not exist!  jitterbug #3016
570//    if(((Calendar*)cal)->getActualMinimum(Calendar::DAY_OF_WEEK, status) != min) {
571//        errln("FAIL: actual minimum (Calendar::DAY_OF_WEEK, status) differs from minimum");
572//    }
573    if(U_FAILURE(status)) {
574      errln("Error getting actual minimum: %s", u_errorName(status));
575      return;
576    }
577
578    delete cal;
579}
580
581/**
582 * @bug 4071385
583 */
584void CalendarRegressionTest::test4071385()
585{
586    UErrorCode status = U_ZERO_ERROR;
587    Calendar *cal = Calendar::createInstance(status);
588    if(U_FAILURE(status)) {
589      dataerrln("Error creating Calendar: %s", u_errorName(status));
590      delete cal;
591      return;
592    }
593    cal->setTime(makeDate(1998, UCAL_JUNE, 24),status);
594    cal->set(UCAL_MONTH, UCAL_NOVEMBER); // change a field
595    //logln(cal.getTime().toString());
596    if (cal->getTime(status) != makeDate(1998, UCAL_NOVEMBER, 24))
597        errln("Fail");
598
599    delete cal;
600}
601
602/**
603 * @bug 4073929
604 */
605void CalendarRegressionTest::test4073929()
606{
607    UErrorCode status = U_ZERO_ERROR;
608    GregorianCalendar *foo1 = new GregorianCalendar(1997, 8, 27,status);
609    if(U_FAILURE(status)) {
610      dataerrln("Error creating Calendar: %s", u_errorName(status));
611      delete foo1;
612      return;
613    }
614    logln("foo1@%.0f - %d-%d-%d %d:%d:%d.%ds\n", foo1->getTime(status),
615          foo1->get(UCAL_YEAR, status),
616          foo1->get(UCAL_MONTH, status),
617          foo1->get(UCAL_DATE, status),
618          foo1->get(UCAL_HOUR, status),
619          foo1->get(UCAL_MINUTE, status),
620          foo1->get(UCAL_SECOND, status),
621          foo1->get(UCAL_MILLISECOND,status));
622    foo1->add(UCAL_DATE, + 1, status);
623    logln("foo1@%.0f - %d-%d-%d %d:%d:%d.%ds after +\n", foo1->getTime(status),
624          foo1->get(UCAL_YEAR, status),
625          foo1->get(UCAL_MONTH, status),
626          foo1->get(UCAL_DATE, status),
627          foo1->get(UCAL_HOUR, status),
628          foo1->get(UCAL_MINUTE, status),
629          foo1->get(UCAL_SECOND, status),
630          foo1->get(UCAL_MILLISECOND ,status));
631    foo1->add(UCAL_DATE, - 1, status);
632    logln("foo1@%.0f - %d-%d-%d %d:%d:%d.%ds after -\n", foo1->getTime(status),
633          foo1->get(UCAL_YEAR, status),
634          foo1->get(UCAL_MONTH, status),
635          foo1->get(UCAL_DATE, status),
636          foo1->get(UCAL_HOUR, status),
637          foo1->get(UCAL_MINUTE, status),
638          foo1->get(UCAL_SECOND, status),
639          foo1->get(UCAL_MILLISECOND, status));
640
641    foo1->add(UCAL_DATE, + 1, status);
642    int32_t testyear = foo1->get(UCAL_YEAR, status);
643    int32_t testmonth = foo1->get(UCAL_MONTH, status);
644    int32_t testday = foo1->get(UCAL_DATE, status);
645    if (testyear != 1997 ||
646        testmonth != 8 ||
647        testday != 28)
648        errln("Fail: Calendar not initialized");
649
650    delete foo1;
651}
652
653/**
654 * @bug 4083167
655 */
656void CalendarRegressionTest::test4083167()
657{
658    UErrorCode status = U_ZERO_ERROR;
659    TimeZone *saveZone = TimeZone::createDefault();
660    //try {
661    TimeZone *newZone = TimeZone::createTimeZone("UTC");
662    TimeZone::setDefault(*newZone);
663    UDate firstDate = Calendar::getNow();
664        Calendar *cal = new GregorianCalendar(status);
665        if(U_FAILURE(status)) {
666          dataerrln("Error creating Calendar: %s", u_errorName(status));
667          delete cal;
668          return;
669        }
670        cal->setTime(firstDate,status);
671        int32_t hr        = cal->get(UCAL_HOUR_OF_DAY, status);
672        int32_t min        = cal->get(UCAL_MINUTE, status);
673        int32_t sec        = cal->get(UCAL_SECOND, status);
674        int32_t msec    = cal->get(UCAL_MILLISECOND, status);
675        double firstMillisInDay = hr * 3600000 + min * 60000 + sec * 1000 + msec;
676
677        //logln("Current time: " + firstDate.toString());
678
679        for (int32_t validity=0; validity<30; validity++) {
680            UDate lastDate = firstDate + validity*1000*24*60*60.0;
681            cal->setTime(lastDate, status);
682            hr        = cal->get(UCAL_HOUR_OF_DAY, status);
683            min        = cal->get(UCAL_MINUTE, status);
684            sec        = cal->get(UCAL_SECOND, status);
685            msec    = cal->get(UCAL_MILLISECOND, status);
686            double millisInDay = hr * 3600000.0 + min * 60000.0 + sec * 1000.0 + msec;
687            if (firstMillisInDay != millisInDay)
688                errln(UnicodeString("Day has shifted ") + lastDate);
689        }
690    //}
691    //finally {
692        TimeZone::setDefault(*saveZone);
693    //}
694
695    delete saveZone;
696    delete newZone;
697    delete cal;
698}
699
700/**
701 * @bug 4086724
702 */
703void CalendarRegressionTest::test4086724()
704{
705    UErrorCode status = U_ZERO_ERROR;
706    SimpleDateFormat *date;
707    TimeZone *saveZone = TimeZone::createDefault();
708    Locale saveLocale = Locale::getDefault();
709    //try {
710    Locale::setDefault(Locale::getUK(),status);
711    TimeZone *newZone = TimeZone::createTimeZone("GMT");
712    TimeZone::setDefault(*newZone);
713        date = new SimpleDateFormat(UnicodeString("dd MMM yyy (zzzz) 'is in week' ww"),status);
714        Calendar *cal = Calendar::createInstance(status);
715        if(U_FAILURE(status)) {
716          dataerrln("Error creating Calendar: %s", u_errorName(status));
717          delete cal;
718          delete newZone;
719          delete date;
720          return;
721        }
722        cal->set(1997,UCAL_SEPTEMBER,30);
723        UDate now = cal->getTime(status);
724        UnicodeString temp;
725        FieldPosition pos(FieldPosition::DONT_CARE);
726        logln(date->format(now, temp, pos));
727        cal->set(1997,UCAL_JANUARY,1);
728        now=cal->getTime(status);
729        logln(date->format(now,temp, pos));
730        cal->set(1997,UCAL_JANUARY,8);
731        now=cal->getTime(status);
732        logln(date->format(now,temp, pos));
733        cal->set(1996,UCAL_DECEMBER,31);
734        now=cal->getTime(status);
735        logln(date->format(now,temp, pos));
736    //}
737    //finally {
738        Locale::setDefault(saveLocale,status);
739        TimeZone::setDefault(*saveZone);
740    //}
741    logln("*** THE RESULTS OF THIS TEST MUST BE VERIFIED MANUALLY ***");
742
743delete newZone;
744delete cal;
745delete date;
746delete saveZone;
747}
748
749/**
750 * @bug 4092362
751 */
752void CalendarRegressionTest::test4092362() {
753    UErrorCode status = U_ZERO_ERROR;
754    GregorianCalendar *cal1 = new GregorianCalendar(1997, 10, 11, 10, 20, 40,status);
755    if (U_FAILURE(status)) {
756        dataerrln("Fail new GregorianCalendar: %s", u_errorName(status));
757        delete cal1;
758        return;
759    }
760    /*cal1.set( Calendar::YEAR, 1997 );
761    cal1.set( Calendar::MONTH, 10 );
762    cal1.set( Calendar::DATE, 11 );
763    cal1.set( Calendar::HOUR, 10 );
764    cal1.set( Calendar::MINUTE, 20 );
765    cal1.set( Calendar::SECOND, 40 ); */
766
767    logln( UnicodeString(" Cal1 = ") + cal1->getTime(status) );
768    logln( UnicodeString(" Cal1 time in ms = ") + cal1->get(UCAL_MILLISECOND,status) );
769    for( int32_t k = 0; k < 100 ; k++ );
770
771    GregorianCalendar *cal2 = new GregorianCalendar(1997, 10, 11, 10, 20, 40,status);
772    /*cal2.set( Calendar::YEAR, 1997 );
773    cal2.set( Calendar::MONTH, 10 );
774    cal2.set( Calendar::DATE, 11 );
775    cal2.set( Calendar::HOUR, 10 );
776    cal2.set( Calendar::MINUTE, 20 );
777    cal2.set( Calendar::SECOND, 40 ); */
778
779    logln( UnicodeString(" Cal2 = ") + cal2->getTime(status) );
780    logln( UnicodeString(" Cal2 time in ms = ") + cal2->get(UCAL_MILLISECOND,status) );
781    if( *cal1 != *cal2 )
782        errln("Fail: Milliseconds randomized");
783
784    delete cal1;
785    delete cal2;
786}
787
788/**
789 * @bug 4095407
790 */
791void CalendarRegressionTest::test4095407()
792{
793    UErrorCode status = U_ZERO_ERROR;
794    GregorianCalendar *a = new GregorianCalendar(1997,UCAL_NOVEMBER, 13,status);
795    if (U_FAILURE(status)) {
796        dataerrln("Fail new GregorianCalendar: %s", u_errorName(status));
797        delete a;
798        return;
799    }
800    int32_t dow = a->get(UCAL_DAY_OF_WEEK, status);
801    if (dow != UCAL_THURSDAY)
802        errln("Fail: Want THURSDAY Got " + dow);
803
804    delete a;
805}
806
807/**
808 * @bug 4096231
809 */
810void CalendarRegressionTest::test4096231()
811{
812    UErrorCode status = U_ZERO_ERROR;
813    TimeZone *GMT = TimeZone::createTimeZone("GMT");
814    TimeZone *PST = TimeZone::createTimeZone("PST");
815    int32_t sec = 0, min = 0, hr = 0, day = 1, month = 10, year = 1997;
816
817    Calendar *cal1 = new GregorianCalendar(*PST,status);
818    if (U_FAILURE(status)) {
819        dataerrln("Failure new GregorianCalendar: %s", u_errorName(status));
820        delete GMT;
821        delete PST;
822        delete cal1;
823        return;
824    }
825    cal1->setTime(880698639000.0,status);
826    // Issue 1: Changing the timezone doesn't change the
827    //          represented time.  The old API, pre 1.2.2a requires
828    // setTime to be called in order to update the time fields after the time
829    // zone has been set.
830    int32_t h1,h2;
831    logln(UnicodeString("PST 1 is: ") + (h1=cal1->get(UCAL_HOUR_OF_DAY, status)));
832    cal1->setTimeZone(*GMT);
833    logln(UnicodeString("GMT 2 is: ") + (h2=cal1->get(UCAL_HOUR_OF_DAY, status)));
834    if ((*GMT != *PST) && (h1 == h2))
835        errln("Fail: Hour same in different zones");
836
837    Calendar *cal2 = new GregorianCalendar(*GMT,status);
838    Calendar *cal3 = new GregorianCalendar(*PST,status);
839    cal2->set(UCAL_MILLISECOND, 0);
840    cal3->set(UCAL_MILLISECOND, 0);
841
842    cal2->set(cal1->get(UCAL_YEAR,status),
843             cal1->get(UCAL_MONTH,status),
844             cal1->get(UCAL_DATE,status),
845             cal1->get(UCAL_HOUR_OF_DAY,status),
846             cal1->get(UCAL_MINUTE,status),
847             cal1->get(UCAL_SECOND,status));
848
849    double t1,t2,t3,t4;
850    logln(UnicodeString("RGMT 1 is: ") + (t1=cal2->getTime(status)));
851    cal3->set(year, month, day, hr, min, sec);
852    logln(UnicodeString("RPST 1 is: ") + (t2=cal3->getTime(status)));
853    cal3->setTimeZone(*GMT);
854    logln(UnicodeString("RGMT 2 is: ") + (t3=cal3->getTime(status)));
855    cal3->set(cal1->get(UCAL_YEAR,status),
856             cal1->get(UCAL_MONTH,status),
857             cal1->get(UCAL_DATE,status),
858             cal1->get(UCAL_HOUR_OF_DAY,status),
859             cal1->get(UCAL_MINUTE,status),
860             cal1->get(UCAL_SECOND,status));
861    // Issue 2: Calendar continues to use the timezone in its
862    //          constructor for set() conversions, regardless
863    //          of calls to setTimeZone()
864    logln(UnicodeString("RGMT 3 is: ") + (t4=cal3->getTime(status)));
865    if (t1 == t2 ||
866        t1 != t4 ||
867        t2 != t3)
868        errln("Fail: Calendar zone behavior faulty");
869
870    delete cal1;
871    delete cal2;
872    delete cal3;
873    delete GMT;
874    delete PST;
875}
876
877/**
878 * @bug 4096539
879 */
880void CalendarRegressionTest::test4096539()
881{
882    UErrorCode status = U_ZERO_ERROR;
883    int32_t y [] = {31,28,31,30,31,30,31,31,30,31,30,31};
884
885    for (int32_t x=0;x<12;x++) {
886        GregorianCalendar *gc = new
887            GregorianCalendar(1997,x,y[x], status);
888        if (U_FAILURE(status)) {
889            dataerrln("Fail new GregorianCalendar: %s", u_errorName(status));
890            delete gc;
891            return;
892        }
893        int32_t m1,m2;
894        log(UnicodeString("") + (m1=gc->get(UCAL_MONTH,status)+1)+UnicodeString("/")+
895                         gc->get(UCAL_DATE,status)+"/"+gc->get(UCAL_YEAR,status)+
896                         " + 1mo = ");
897
898        gc->add(UCAL_MONTH, 1,status);
899        logln(UnicodeString("") + (m2=gc->get(UCAL_MONTH,status)+1)+UnicodeString("/")+
900                           gc->get(UCAL_DATE,status)+"/"+gc->get(UCAL_YEAR,status)
901                           );
902        int32_t m = (m1 % 12) + 1;
903        if (m2 != m)
904            errln(UnicodeString("Fail: Want ") + m + " Got " + m2);
905        delete gc;
906    }
907
908}
909
910/**
911 * @bug 4100311
912 */
913void CalendarRegressionTest::test41003112()
914{
915    UErrorCode status = U_ZERO_ERROR;
916    GregorianCalendar *cal = (GregorianCalendar*)Calendar::createInstance(status);
917    if(U_FAILURE(status)) {
918      dataerrln("Error creating calendar: %s", u_errorName(status));
919      delete cal;
920      return;
921    }
922    cal->set(UCAL_YEAR, 1997);
923    cal->set(UCAL_DAY_OF_YEAR, 1);
924    //UDate d = cal->getTime(status);             // Should be Jan 1
925    //logln(d.toString());
926    if (cal->get(UCAL_DAY_OF_YEAR, status) != 1)
927        errln("Fail: DAY_OF_YEAR not set");
928    delete cal;
929}
930
931/**
932 * @bug 4103271
933 */
934void CalendarRegressionTest::test4103271()
935{
936    UErrorCode status = U_ZERO_ERROR;
937    SimpleDateFormat sdf(status);
938    int32_t numYears=40, startYear=1997, numDays=15;
939    UnicodeString output, testDesc, str, str2;
940    GregorianCalendar *testCal = (GregorianCalendar*)Calendar::createInstance(status);
941    if(U_FAILURE(status)) {
942      dataerrln("Error creating calendar: %s", u_errorName(status));
943      delete testCal;
944      return;
945    }
946    testCal->clear();
947    sdf.adoptCalendar(testCal);
948    sdf.applyPattern("EEE dd MMM yyyy 'WOY'ww'-'YYYY 'DOY'DDD");
949    UBool fail = FALSE;
950    for (int32_t firstDay=1; firstDay<=2; firstDay++) {
951        for (int32_t minDays=1; minDays<=7; minDays++) {
952            testCal->setMinimalDaysInFirstWeek((uint8_t)minDays);
953            testCal->setFirstDayOfWeek((UCalendarDaysOfWeek)firstDay);
954            testDesc = (UnicodeString("Test") + firstDay + minDays);
955            logln(testDesc + " => 1st day of week=" +
956                               firstDay +
957                               ", minimum days in first week=" +
958                               minDays);
959            for (int32_t j=startYear; j<=startYear+numYears; j++) {
960                testCal->set(j,11,25);
961                for(int32_t i=0; i<numDays; i++) {
962                    testCal->add(UCAL_DATE,1,status);
963                    UnicodeString calWOY;
964                    int32_t actWOY = testCal->get(UCAL_WEEK_OF_YEAR,status);
965                    if (actWOY < 1 || actWOY > 53) {
966                        UDate d = testCal->getTime(status);
967                        //calWOY = String.valueOf(actWOY);
968                        UnicodeString temp;
969                        FieldPosition pos(FieldPosition::DONT_CARE);
970                        output = testDesc + " - " + sdf.format(d,temp,pos) + "\t";
971                        output = output + "\t" + actWOY;
972                        logln(output);
973                        fail = TRUE;
974                    }
975                }
976            }
977        }
978    }
979
980    int32_t DATA [] = {
981        3, 52, 52, 52, 52, 52, 52, 52,
982            1,  1,  1,  1,  1,  1,  1,
983            2,  2,  2,  2,  2,  2,  2,
984        4, 52, 52, 52, 52, 52, 52, 52,
985           53, 53, 53, 53, 53, 53, 53,
986            1,  1,  1,  1,  1,  1,  1,
987    };
988    testCal->setFirstDayOfWeek(UCAL_SUNDAY);
989    for (int32_t j=0; j<44; j+=22) {
990        logln(UnicodeString("Minimal days in first week = ") + DATA[j] +
991                           "  Week starts on Sunday");
992        testCal->setMinimalDaysInFirstWeek((uint8_t)DATA[j]);
993        testCal->set(1997, UCAL_DECEMBER, 21);
994        for (int32_t i=0; i<21; ++i) {
995            int32_t woy = testCal->get(UCAL_WEEK_OF_YEAR,status);
996            str.remove();
997            log(UnicodeString("") + sdf.format(testCal->getTime(status), str) +
998                UnicodeString(" ") + woy);
999            if (woy != DATA[j + 1 + i]) {
1000                log(" ERROR");
1001                fail = TRUE;
1002            }
1003            logln("");
1004
1005            // Now compute the time from the fields, and make sure we
1006            // get the same answer back.  This is a round-trip test.
1007            UDate save = testCal->getTime(status);
1008            testCal->clear();
1009            testCal->set(UCAL_YEAR_WOY, DATA[j+1+i] < 25 ? 1998 : 1997);
1010            testCal->set(UCAL_WEEK_OF_YEAR, DATA[j+1+i]);
1011            testCal->set(UCAL_DAY_OF_WEEK, (i%7) + UCAL_SUNDAY);
1012            if (testCal->getTime(status) != save) {
1013                str.remove();
1014                logln(UnicodeString("  Parse failed: ") +
1015                      sdf.format(testCal->getTime(status), str));
1016                fail= TRUE;
1017            }
1018
1019            testCal->setTime(save,status);
1020            testCal->add(UCAL_DATE, 1,status);
1021        }
1022    }
1023    // Test field disambiguation with a few special hard-coded cases.
1024    // This shouldn't fail if the above cases aren't failing.
1025    int32_t DISAM_int [] = {
1026        // y y_woy woy dow
1027        1997, 1998, 1, UCAL_SUNDAY,
1028        (1998), (1998), (2), (UCAL_SATURDAY),
1029        (1998), (1998), (53), (UCAL_THURSDAY),
1030        (1999), (1998), (53), (UCAL_FRIDAY)
1031    };
1032
1033    UDate DISAM_date [] = {
1034            makeDate(1997, UCAL_DECEMBER, 28),
1035            makeDate(1998, UCAL_JANUARY, 10),
1036            makeDate(1998, UCAL_DECEMBER, 31),
1037            makeDate(1999, UCAL_JANUARY, 1)
1038    };
1039
1040    testCal->setMinimalDaysInFirstWeek(3);
1041    testCal->setFirstDayOfWeek(UCAL_SUNDAY);
1042    int32_t i = 0;
1043
1044    /* Enable this code to display various WOY values
1045    testCal->clear();
1046    for (i=25; i<38; ++i) {
1047        testCal->set(1996, Calendar::DECEMBER, i);
1048        UDate got = testCal->getTime(status);
1049        str.remove();
1050        logln(UnicodeString("") + sdf.format(got, str));
1051    }
1052    for (i=25; i<38; ++i) {
1053        testCal->set(1997, Calendar::DECEMBER, i);
1054        UDate got = testCal->getTime(status);
1055        str.remove();
1056        logln(UnicodeString("") + sdf.format(got, str));
1057    }
1058    for (i=25; i<38; ++i) {
1059        testCal->set(1998, UCAL_DECEMBER, i);
1060        UDate got = testCal->getTime(status);
1061        str.remove();
1062        logln(UnicodeString("") + sdf.format(got, str));
1063    }
1064    */
1065
1066    for (i=0; i < 16; i += 4) {
1067        int32_t y = DISAM_int[i];
1068        int32_t ywoy = DISAM_int[i+1];
1069        int32_t woy = DISAM_int[i+2];
1070        int32_t dow = DISAM_int[i+3];
1071        UDate exp = DISAM_date[i/4];
1072        testCal->clear();
1073        testCal->set(UCAL_YEAR, y);
1074        testCal->set(UCAL_WEEK_OF_YEAR, woy);
1075        testCal->set(UCAL_DAY_OF_WEEK, dow);
1076        UDate got = testCal->getTime(status);
1077        str.remove();
1078        str2.remove();
1079        log(UnicodeString("Y") + y + "-W" + woy +
1080                         "-DOW" + dow + " expect:" + sdf.format(exp, str) +
1081                         " got:" + sdf.format(got, str2));
1082        if (got != exp) {
1083            log("  FAIL (%s:%d, i=%d)", __FILE__, __LINE__, i);
1084            logln(CalendarTest::calToStr(*testCal));
1085            testCal->setTime(exp, status);
1086            logln(CalendarTest::calToStr(*testCal) + UnicodeString( " <<< expected "));
1087            fail = TRUE;
1088        }
1089        logln("");
1090
1091        testCal->clear();
1092        testCal->set(UCAL_YEAR_WOY, ywoy);
1093        testCal->set(UCAL_WEEK_OF_YEAR, woy);
1094        testCal->set(UCAL_DAY_OF_WEEK, dow);
1095        got = testCal->getTime(status);
1096        str.remove();
1097        str2.remove();
1098        log(UnicodeString("YWOY") + ywoy + "-W" + woy +
1099                         "-DOW" + dow + " expect:" + sdf.format(exp, str) +
1100                         " got:" + sdf.format(got, str2));
1101        if (got != exp) {
1102            log("  FAIL");
1103            fail = TRUE;
1104        }
1105        logln("");
1106    }
1107    // Now try adding and rolling
1108    UDate ADDROLL_date [] = {
1109        makeDate(1998, UCAL_DECEMBER, 25), makeDate(1999, UCAL_JANUARY, 1),
1110        makeDate(1997, UCAL_DECEMBER, 28), makeDate(1998, UCAL_JANUARY, 4),
1111        makeDate(1998, UCAL_DECEMBER, 27), makeDate(1997, UCAL_DECEMBER, 28),
1112        makeDate(1999, UCAL_JANUARY, 2), makeDate(1998, UCAL_JANUARY, 3),
1113    };
1114
1115    int32_t ADDROLL_int []= {
1116        (1),
1117        (1),
1118        (1),
1119        (1)
1120    };
1121
1122
1123    UBool ADDROLL_bool [] = {
1124        TRUE,//ADD,
1125        TRUE,
1126        FALSE,
1127        FALSE
1128    };
1129
1130    testCal->setMinimalDaysInFirstWeek(3);
1131    testCal->setFirstDayOfWeek(UCAL_SUNDAY);
1132    for (i=0; i<8; i += 2) {
1133        int32_t amount = ADDROLL_int[i/2];
1134        UDate before = ADDROLL_date[i];
1135        UDate after = ADDROLL_date[i+1];
1136
1137        testCal->setTime(before,status);
1138        if (ADDROLL_bool[i/2])
1139            testCal->add(UCAL_WEEK_OF_YEAR, amount,status);
1140        else
1141            testCal->roll(UCAL_WEEK_OF_YEAR, amount,status);
1142        UDate got = testCal->getTime(status);
1143        str.remove();
1144        str2.remove();
1145        UnicodeString opTypeStr;
1146        if (ADDROLL_bool[i/2]) {
1147            opTypeStr = UnicodeString("add(WOY,", "");
1148        } else {
1149            opTypeStr = UnicodeString("roll(WOY,", "");
1150        }
1151        log(opTypeStr + amount + ") " + sdf.format(before, str) + " => " +
1152                    sdf.format(got, str2));
1153        if (after != got) {
1154            str.remove();
1155            logln(UnicodeString("  exp:") + sdf.format(after, str) + "  FAIL");
1156            fail = TRUE;
1157        }
1158        else logln(" ok");
1159
1160        testCal->setTime(after,status);
1161        if (ADDROLL_bool[i/2])
1162            testCal->add(UCAL_WEEK_OF_YEAR, -amount,status);
1163        else
1164            testCal->roll(UCAL_WEEK_OF_YEAR, -amount,status);
1165        got = testCal->getTime(status);
1166        str.remove();
1167        str2.remove();
1168        log(opTypeStr + (-amount) + ") " + sdf.format(after, str) + " => " +
1169                sdf.format(got, str2));
1170        if (before != got) {
1171            str.remove();
1172            logln(UnicodeString("  exp:") + sdf.format(before, str) + "  FAIL");
1173            fail = TRUE;
1174        }
1175        else logln(" ok");
1176    }
1177    if (fail)
1178        errln("Fail: Week of year misbehaving");
1179}
1180
1181/**
1182 * @bug 4106136
1183 */
1184void CalendarRegressionTest::test4106136()
1185{
1186    UErrorCode status = U_ZERO_ERROR;
1187    Locale saveLocale = Locale::getDefault();
1188    //try {
1189    Locale locales [] = { Locale::getChinese(), Locale::getChina() };
1190        for (int32_t i=0; i<2; ++i) {
1191            Locale::setDefault(locales[i], status);
1192            failure(status, "Locale::setDefault");
1193            int32_t count1, count2, count3;
1194            Calendar::getAvailableLocales(count1);
1195            DateFormat::getAvailableLocales(count2);
1196            NumberFormat::getAvailableLocales(count3);
1197            int32_t n [] = {
1198                count1, count2, count3
1199            };
1200            for (int32_t j=0; j<3; ++j) {
1201                UnicodeString temp;
1202                if (n[j] == 0)
1203                    dataerrln(UnicodeString("Fail: No locales for ") + locales[i].getName());
1204            }
1205        }
1206    //}
1207    //finally {
1208        Locale::setDefault(saveLocale,status);
1209    //}
1210}
1211
1212/**
1213 * @bug 4108764
1214 */
1215void CalendarRegressionTest::test4108764()
1216{
1217    UErrorCode status = U_ZERO_ERROR;
1218    Calendar *cal = Calendar::createInstance(status);
1219    if(U_FAILURE(status)) {
1220      dataerrln("Error creating calendar %s", u_errorName(status));
1221      delete cal;
1222      return;
1223    }
1224    UDate d00 = makeDate(1997, UCAL_MARCH, 15, 12, 00, 00);
1225    UDate d01 = makeDate(1997, UCAL_MARCH, 15, 12, 00, 56);
1226    UDate d10 = makeDate(1997, UCAL_MARCH, 15, 12, 34, 00);
1227    UDate d11 = makeDate(1997, UCAL_MARCH, 15, 12, 34, 56);
1228    UDate epoch = makeDate(1970, UCAL_JANUARY, 1);
1229
1230    cal->setTime(d11,status);
1231
1232    cal->clear( UCAL_MINUTE );
1233    logln(UnicodeString("") + cal->getTime(status));
1234    if (cal->getTime(status)  != d01)
1235        errln("Fail: clear(MINUTE) broken");
1236
1237    cal->set( UCAL_SECOND, 0 );
1238    logln(UnicodeString("") + cal->getTime(status));
1239    if (cal->getTime(status)  != d00)
1240        errln("Fail: set(SECOND, 0) broken");
1241
1242    cal->setTime(d11,status);
1243    cal->set( UCAL_SECOND, 0 );
1244    logln(UnicodeString("") + cal->getTime(status));
1245    if (cal->getTime(status)  != d10)
1246        errln("Fail: set(SECOND, 0) broken #2");
1247
1248    cal->clear( UCAL_MINUTE );
1249    logln(UnicodeString("") + cal->getTime(status));
1250    if (cal->getTime(status)  != d00)
1251        errln("Fail: clear(MINUTE) broken #2");
1252
1253    cal->clear();
1254    logln(UnicodeString("") + cal->getTime(status));
1255    if (cal->getTime(status)  != epoch)
1256        errln(UnicodeString("Fail: clear() broken Want ") + epoch);
1257
1258    delete cal;
1259}
1260
1261/**
1262 * @bug 4114578
1263 */
1264void CalendarRegressionTest::test4114578()
1265{
1266    UErrorCode status = U_ZERO_ERROR;
1267    double ONE_HOUR = 60*60*1000;
1268    Calendar *cal = Calendar::createInstance(status);
1269    if(U_FAILURE(status)) {
1270      dataerrln("Error creating calendar %s", u_errorName(status));
1271      delete cal;
1272      return;
1273    }
1274    cal->adoptTimeZone(TimeZone::createTimeZone("PST"));
1275    UDate onset = makeDate(1998, UCAL_APRIL, 5, 1, 0) + ONE_HOUR;
1276    UDate cease = makeDate(1998, UCAL_OCTOBER, 25, 0, 0) + 2*ONE_HOUR;
1277
1278    UBool fail = FALSE;
1279
1280    const int32_t ADD = 1;
1281    const int32_t ROLL = 2;
1282
1283    double DATA []= {
1284        // Start            Action   Amt    Expected_change
1285        onset - ONE_HOUR,   ADD,      1,     ONE_HOUR,
1286        onset,              ADD,     -1,    -ONE_HOUR,
1287        onset - ONE_HOUR,   ROLL,     1,     ONE_HOUR,
1288        onset,              ROLL,    -1,    -ONE_HOUR,
1289        cease - ONE_HOUR,   ADD,      1,     ONE_HOUR,
1290        cease,              ADD,     -1,    -ONE_HOUR,
1291        cease - ONE_HOUR,   ROLL,     1,     ONE_HOUR,
1292        cease,              ROLL,    -1,    -ONE_HOUR,
1293    };
1294
1295    for (int32_t i=0; i<32; i+=4) {
1296        UDate date = DATA[i];
1297        int32_t amt = (int32_t) DATA[i+2];
1298        double expectedChange = DATA[i+3];
1299
1300        log(UnicodeString("") + date);
1301        cal->setTime(date,status);
1302
1303        switch ((int32_t) DATA[i+1]) {
1304        case ADD:
1305            log(UnicodeString(" add (HOUR,") + (amt<0?"":"+")+amt + ")= ");
1306            cal->add(UCAL_HOUR, amt,status);
1307            break;
1308        case ROLL:
1309            log(UnicodeString(" roll(HOUR,") + (amt<0?"":"+")+amt + ")= ");
1310            cal->roll(UCAL_HOUR, amt,status);
1311            break;
1312        }
1313
1314        log(UnicodeString("") + cal->getTime(status));
1315
1316        double change = cal->getTime(status) - date;
1317        if (change != expectedChange) {
1318            fail = TRUE;
1319            logln(" FAIL");
1320        }
1321        else logln(" OK");
1322    }
1323
1324    if (fail) errln("Fail: roll/add misbehaves around DST onset/cease");
1325
1326    delete cal;
1327}
1328
1329/**
1330 * @bug 4118384
1331 * Make sure maximum for HOUR field is 11, not 12.
1332 */
1333void CalendarRegressionTest::test4118384()
1334{
1335    UErrorCode status = U_ZERO_ERROR;
1336    Calendar *cal = Calendar::createInstance(status);
1337    if(U_FAILURE(status)) {
1338      dataerrln("Error creating calendar %s", u_errorName(status));
1339      delete cal;
1340      return;
1341    }
1342    if (cal->getMaximum(UCAL_HOUR) != 11 ||
1343        cal->getLeastMaximum(UCAL_HOUR) != 11 ||
1344        cal->getActualMaximum(UCAL_HOUR,status) != 11)
1345        errln("Fail: maximum of HOUR field should be 11");
1346
1347    // test deprecated functions
1348    if (cal->getLeastMaximum(Calendar::HOUR) != 11 ||
1349        cal->getMaximum(Calendar::HOUR) != 11) {
1350        errln("Fail: [deprecated functions] maximum of HOUR field should be 11\n");
1351    }
1352
1353    if (cal->getGreatestMinimum(Calendar::HOUR) != 0 ||
1354        cal->getMinimum(Calendar::HOUR) != 0) {
1355        errln("Fail: [deprecated functions] minimum of HOUR field should be 1\n");
1356    }
1357
1358    delete cal;
1359    cal = Calendar::createInstance(Locale("th_TH@calendar=buddhist"),status);
1360    // test deprecated functions
1361    if (cal->getLeastMaximum(Calendar::HOUR) != 11 ||
1362        cal->getMaximum(Calendar::HOUR) != 11) {
1363        errln("Fail: Buddhist:[deprecated functions] maximum of HOUR field should be 11\n");
1364    }
1365
1366    if (cal->getGreatestMinimum(Calendar::HOUR) != 0 ||
1367        cal->getMinimum(Calendar::HOUR) != 0) {
1368        errln("Fail: Buddhist:[deprecated functions] minimum of HOUR field should be 1\n");
1369    }
1370
1371    delete cal;
1372    // test deprecated functions
1373    cal = Calendar::createInstance(Locale("ja_JP@calendar=japanese"),status);
1374    if (cal->getLeastMaximum(Calendar::HOUR) != 11 ||
1375        cal->getMaximum(Calendar::HOUR) != 11) {
1376        errln("Fail: Japanese:[deprecated functions] maximum of HOUR field should be 11\n");
1377    }
1378
1379    if (cal->getGreatestMinimum(Calendar::HOUR) != 0 ||
1380        cal->getMinimum(Calendar::HOUR) != 0) {
1381        errln("Fail: Japanese:[deprecated functions] minimum of HOUR field should be 1\n");
1382    }
1383
1384    delete cal;
1385}
1386
1387/**
1388 * @bug 4125881
1389 * Check isLeapYear for BC years.
1390 */
1391void CalendarRegressionTest::test4125881()
1392{
1393    UErrorCode status = U_ZERO_ERROR;
1394    GregorianCalendar *cal = (GregorianCalendar*) Calendar::createInstance(status);
1395    if(U_FAILURE(status)) {
1396      dataerrln("Error creating calendar %s", u_errorName(status));
1397      delete cal;
1398      return;
1399    }
1400    DateFormat *fmt = new SimpleDateFormat(UnicodeString("MMMM d, yyyy G"),status);
1401    if(!assertSuccess("trying to construct", status))return;
1402    cal->clear();
1403    for (int32_t y=-20; y<=10; ++y) {
1404        cal->set(UCAL_ERA, y < 1 ? GregorianCalendar::BC : GregorianCalendar::AD);
1405        cal->set(UCAL_YEAR, y < 1 ? 1 - y : y);
1406        UnicodeString temp;
1407        logln(UnicodeString("") + y + UnicodeString(" = ") + fmt->format(cal->getTime(status), temp) + " " +
1408                           cal->isLeapYear(y));
1409        if (cal->isLeapYear(y) != ((y+40)%4 == 0))
1410            errln("Leap years broken");
1411    }
1412
1413    delete cal;
1414    delete fmt;
1415}
1416
1417/**
1418 * @bug 4125892
1419 * Prove that GregorianCalendar is proleptic (it used to cut off
1420 * at 45 BC, and not have leap years before then).
1421 */
1422void CalendarRegressionTest::test4125892() {
1423    UErrorCode status = U_ZERO_ERROR;
1424    GregorianCalendar *cal = (GregorianCalendar*) Calendar::createInstance(status);
1425    if(U_FAILURE(status)) {
1426      dataerrln("Error creating calendar %s", u_errorName(status));
1427      delete cal;
1428      return;
1429    }
1430    DateFormat *fmt = new SimpleDateFormat(UnicodeString("MMMM d, yyyy G"),status);
1431    if(!assertSuccess("trying to construct", status))return;
1432    cal->clear();
1433    cal->set(UCAL_ERA, GregorianCalendar::BC);
1434    cal->set(UCAL_YEAR, 81); // 81 BC is a leap year (proleptically)
1435    cal->set(UCAL_MONTH, UCAL_FEBRUARY);
1436    cal->set(UCAL_DATE, 28);
1437    cal->add(UCAL_DATE, 1,status);
1438    if(U_FAILURE(status))
1439        errln("add(DATE,1) failed");
1440    if (cal->get(UCAL_DATE,status) != 29 ||
1441        !cal->isLeapYear(-80)) // -80 == 81 BC
1442        errln("Calendar not proleptic");
1443
1444    delete cal;
1445    delete fmt;
1446}
1447
1448/**
1449 * @bug 4141665
1450 * GregorianCalendar::equals() ignores cutover date
1451 */
1452void CalendarRegressionTest::test4141665()
1453{
1454    UErrorCode status = U_ZERO_ERROR;
1455    GregorianCalendar *cal = new GregorianCalendar(status);
1456    if(U_FAILURE(status)) {
1457      dataerrln("Error creating calendar %s", u_errorName(status));
1458      delete cal;
1459      return;
1460    }
1461    GregorianCalendar *cal2 = (GregorianCalendar*)cal->clone();
1462    UDate cut = cal->getGregorianChange();
1463    UDate cut2 = cut + 100*24*60*60*1000.0; // 100 days later
1464    if (*cal != *cal2) {
1465        errln("Cloned GregorianCalendars not equal");
1466    }
1467    cal2->setGregorianChange(cut2,status);
1468    if ( *cal == *cal2) {
1469        errln("GregorianCalendar::equals() ignores cutover");
1470    }
1471
1472    delete cal;
1473    delete cal2;
1474}
1475
1476/**
1477 * @bug 4142933
1478 * Bug states that ArrayIndexOutOfBoundsException is thrown by GregorianCalendar::roll()
1479 * when IllegalArgumentException should be.
1480 */
1481void CalendarRegressionTest::test4142933()
1482{
1483    UErrorCode status = U_ZERO_ERROR;
1484    GregorianCalendar *calendar = new GregorianCalendar(status);
1485    if(U_FAILURE(status)) {
1486      dataerrln("Error creating calendar %s", u_errorName(status));
1487      delete calendar;
1488      return;
1489    }
1490    //try {
1491    calendar->roll((UCalendarDateFields)-1, TRUE, status);
1492        if(U_SUCCESS(status))
1493            errln("Test failed, no exception thrown");
1494    //}
1495    //catch (IllegalArgumentException e) {
1496        // OK: Do nothing
1497        // logln("Test passed");
1498    //}
1499    //catch (Exception e) {
1500        //errln("Test failed. Unexpected exception is thrown: " + e);
1501        //e.printStackTrace();
1502    //}
1503
1504    delete calendar;
1505}
1506
1507/**
1508 * @bug 4145158
1509 * GregorianCalendar handling of Dates Long.MIN_VALUE and Long.MAX_VALUE is
1510 * confusing; unless the time zone has a raw offset of zero, one or the
1511 * other of these will wrap.  We've modified the test given in the bug
1512 * report to therefore only check the behavior of a calendar with a zero raw
1513 * offset zone.
1514 */
1515void CalendarRegressionTest::test4145158()
1516{
1517    UErrorCode status = U_ZERO_ERROR;
1518    GregorianCalendar *calendar = new GregorianCalendar(status);
1519    if(status == U_USING_FALLBACK_WARNING || U_FAILURE(status)) {
1520      dataerrln("Error creating calendar %s", u_errorName(status));
1521      delete calendar;
1522      return;
1523    }
1524
1525    calendar->adoptTimeZone(TimeZone::createTimeZone("GMT"));
1526
1527    calendar->setTime(makeDate(INT32_MIN),status);
1528    int32_t year1 = calendar->get(UCAL_YEAR,status);
1529    int32_t era1 = calendar->get(UCAL_ERA,status);
1530
1531    calendar->setTime(makeDate(INT32_MAX),status);
1532    int32_t year2 = calendar->get(UCAL_YEAR,status);
1533    int32_t era2 = calendar->get(UCAL_ERA,status);
1534
1535    if (year1 == year2 && era1 == era2) {
1536        errln("Fail: Long.MIN_VALUE or Long.MAX_VALUE wrapping around");
1537    }
1538
1539    delete calendar;
1540}
1541
1542/**
1543 * @bug 4145983
1544 * Maximum value for YEAR field wrong.
1545 */
1546// {sfb} this is not directly applicable in C++, since all
1547// possible doubles are not representable by our Calendar.
1548// In Java, all longs are representable.
1549// We can determine limits programmatically
1550// Using DBL_MAX is a bit of a hack, since for large doubles
1551// Calendar gets squirrely and doesn't behave in any sort
1552// of linear fashion (ie years jump around, up/down, etc) for a
1553// small change in millis.
1554void CalendarRegressionTest::test4145983()
1555{
1556    UErrorCode status = U_ZERO_ERROR;
1557    GregorianCalendar *calendar = new GregorianCalendar(status);
1558    if(U_FAILURE(status)) {
1559      dataerrln("Error creating calendar %s", u_errorName(status));
1560      delete calendar;
1561      return;
1562    }
1563    calendar->adoptTimeZone(TimeZone::createTimeZone("GMT"));
1564    UDate DATES [] = { LATEST_SUPPORTED_MILLIS, EARLIEST_SUPPORTED_MILLIS };
1565    for (int32_t i=0; i<2; ++i) {
1566        calendar->setTime(DATES[i], status);
1567        int32_t year = calendar->get(UCAL_YEAR,status);
1568        int32_t maxYear = calendar->getMaximum(UCAL_YEAR);
1569        if (year > maxYear) {
1570            errln(UnicodeString("Failed for ")+DATES[i]+" ms: year=" +
1571                  year + ", maxYear=" + maxYear);
1572        }
1573    }
1574
1575    delete calendar;
1576}
1577
1578/**
1579 * @bug 4147269
1580 * This is a bug in the validation code of GregorianCalendar::  As reported,
1581 * the bug seems worse than it really is, due to a bug in the way the bug
1582 * report test was written.  In reality the bug is restricted to the DAY_OF_YEAR
1583 * field. - liu 6/29/98
1584 */
1585void CalendarRegressionTest::test4147269()
1586{
1587    UErrorCode status = U_ZERO_ERROR;
1588    GregorianCalendar *calendar = new GregorianCalendar(status);
1589    if(status == U_USING_FALLBACK_WARNING || U_FAILURE(status)) {
1590      dataerrln("Error creating calendar %s", u_errorName(status));
1591      delete calendar;
1592      return;
1593    }
1594    calendar->setLenient(FALSE);
1595    UDate date = makeDate(1996, UCAL_JANUARY, 3); // Arbitrary date
1596    for (int32_t field = 0; field < UCAL_FIELD_COUNT; field++) {
1597        calendar->setTime(date,status);
1598        // Note: In the bug report, getActualMaximum() was called instead
1599        // of getMaximum() -- this was an error.  The validation code doesn't
1600        // use getActualMaximum(), since that's too costly.
1601        int32_t max = calendar->getMaximum((UCalendarDateFields)field);
1602        int32_t value = max+1;
1603        calendar->set((UCalendarDateFields)field, value);
1604        //try {
1605            calendar->getTime(status); // Force time computation
1606            // We expect an exception to be thrown. If we fall through
1607            // to the next line, then we have a bug.
1608            if(U_SUCCESS(status))
1609            errln(UnicodeString("Test failed with field ") + FIELD_NAME[field] +
1610                  ", date before: " + date +
1611                  ", date after: " + calendar->getTime(status) +
1612                  ", value: " + value + " (max = " + max +")");
1613        //} catch (IllegalArgumentException e) {}
1614    }
1615
1616    delete calendar;
1617}
1618
1619/**
1620 * @bug 4149677
1621 * Reported bug is that a GregorianCalendar with a cutover of Date(Long.MAX_VALUE)
1622 * doesn't behave as a pure Julian calendar.
1623 * CANNOT REPRODUCE THIS BUG
1624 */
1625void
1626CalendarRegressionTest::Test4149677()
1627{
1628    UErrorCode status = U_ZERO_ERROR;
1629
1630    TimeZone *zones [] = {
1631        TimeZone::createTimeZone("GMT"),
1632        TimeZone::createTimeZone("PST"),
1633        TimeZone::createTimeZone("EAT")
1634    };
1635    if(U_FAILURE(status)) {
1636        errln("Couldn't create zones");
1637        return;
1638        // could leak memory
1639    }
1640
1641    for (int32_t i=0; i < 3; ++i) {
1642        GregorianCalendar *calendar = new GregorianCalendar(zones[i], status);
1643        if(U_FAILURE(status)) {
1644            dataerrln("Couldnt' create calendar.: %s", u_errorName(status));
1645            return;
1646        }
1647
1648        // Make sure extreme values don't wrap around
1649        calendar->setTime(EARLIEST_SUPPORTED_MILLIS, status);
1650        if(U_FAILURE(status))
1651            errln("setTime failed");
1652        if (calendar->get(UCAL_ERA, status) != GregorianCalendar::BC || U_FAILURE(status)) {
1653            errln("Fail: Date(EARLIEST_SUPPORTED_MILLIS) has an AD year");
1654        }
1655        calendar->setTime(LATEST_SUPPORTED_MILLIS, status);
1656        if(U_FAILURE(status))
1657            errln("setTime failed");
1658        if (calendar->get(UCAL_ERA, status) != GregorianCalendar::AD || U_FAILURE(status)) {
1659            errln("Fail: Date(LATEST_SUPPORTED_MILLIS) has a BC year");
1660        }
1661
1662        calendar->setGregorianChange(LATEST_SUPPORTED_MILLIS, status);
1663        if(U_FAILURE(status))
1664            errln("setGregorianChange failed");
1665        // to obtain a pure Julian calendar
1666
1667        UBool is100Leap = calendar->isLeapYear(100);
1668        if (!is100Leap) {
1669            UnicodeString temp;
1670            errln("test failed with zone " + zones[i]->getID(temp));
1671            errln(" cutover date is Date(Long.MAX_VALUE)");
1672            errln(" isLeapYear(100) returns: " + is100Leap);
1673        }
1674        delete calendar;
1675    }
1676
1677    // no need for cleanup- zones were adopted
1678}
1679
1680/**
1681 * @bug 4162587
1682 * Calendar and Date HOUR broken.  If HOUR is out-of-range, Calendar
1683 * and Date classes will misbehave.
1684 */
1685void
1686CalendarRegressionTest::Test4162587()
1687{
1688    UErrorCode status = U_ZERO_ERROR;
1689    TimeZone *savedef = TimeZone::createDefault();
1690    TimeZone *tz = TimeZone::createTimeZone("PST");
1691    //TimeZone::adoptDefault(tz);
1692    TimeZone::setDefault(*tz);
1693
1694    GregorianCalendar *cal = new GregorianCalendar(tz, status);
1695    if(U_FAILURE(status)) {
1696        dataerrln("Couldn't create calendar.: %s", u_errorName(status));
1697        return;
1698    }
1699    UDate d0, dPlus, dMinus;
1700
1701    for(int32_t i=0; i<5; ++i) {
1702        if (i>0) logln("---");
1703
1704        cal->clear();
1705        cal->set(1998, UCAL_APRIL, 5, i, 0);
1706        d0 = cal->getTime(status);
1707        if(U_FAILURE(status))
1708            errln("Coudln't get time (1)");
1709        //String s0 = d.toString();
1710        logln(UnicodeString("0 ") + i + ": " + d0/*s0*/);
1711
1712        cal->clear();
1713        cal->set(1998, UCAL_APRIL, 4, i+24, 0);
1714        dPlus = cal->getTime(status);
1715        if(U_FAILURE(status))
1716            errln("Coudln't get time (2)");
1717        //String sPlus = d.toString();
1718        logln(UnicodeString("+ ") + i + ": " + dPlus/*sPlus*/);
1719
1720        cal->clear();
1721        cal->set(1998, UCAL_APRIL, 6, i-24, 0);
1722        dMinus = cal->getTime(status);
1723        if(U_FAILURE(status))
1724            errln("Coudln't get time (3)");
1725        //String sMinus = d.toString();
1726        logln(UnicodeString("- ") + i + ": " + dMinus/*sMinus*/);
1727
1728        if (d0 != dPlus || d0 != dMinus) {
1729            errln("Fail: All three lines must match");
1730        }
1731    }
1732    TimeZone::setDefault(*savedef);
1733    //delete tz;
1734    delete cal;
1735    delete savedef;
1736}
1737
1738/**
1739 * @bug 4165343
1740 * Adding 12 months behaves differently from adding 1 year
1741 */
1742void
1743CalendarRegressionTest::Test4165343()
1744{
1745    UErrorCode status = U_ZERO_ERROR;
1746    GregorianCalendar *calendar = new GregorianCalendar(1996, UCAL_FEBRUARY, 29, status);
1747    if(U_FAILURE(status)) {
1748        dataerrln("Couldn't create calendar.: %s", u_errorName(status));
1749        return;
1750    }
1751    UDate start = calendar->getTime(status);
1752    if(U_FAILURE(status))
1753        errln("Couldn't getTime (1)");
1754    logln(UnicodeString("init date: ") + start);
1755    calendar->add(UCAL_MONTH, 12, status);
1756    if(U_FAILURE(status))
1757        errln("Couldn't add(MONTH, 12)");
1758    UDate date1 = calendar->getTime(status);
1759    if(U_FAILURE(status))
1760        errln("Couldn't getTime (2)");
1761    logln(UnicodeString("after adding 12 months: ") + date1);
1762    calendar->setTime(start, status);
1763    if(U_FAILURE(status))
1764        errln("Couldn't setTime");
1765    calendar->add(UCAL_YEAR, 1, status);
1766    if(U_FAILURE(status))
1767        errln("Couldn't add(YEAR, 1)");
1768    UDate date2 = calendar->getTime(status);
1769    if(U_FAILURE(status))
1770        errln("Couldn't getTime (3)");
1771    logln(UnicodeString("after adding one year : ") + date2);
1772    if (date1 == date2) {
1773        logln("Test passed");
1774    } else {
1775        errln("Test failed");
1776    }
1777    delete calendar;
1778}
1779
1780/**
1781 * @bug 4166109
1782 * GregorianCalendar.getActualMaximum() does not account for first day of week.
1783 */
1784void
1785CalendarRegressionTest::Test4166109()
1786{
1787    /* Test month:
1788     *
1789     *      March 1998
1790     * Su Mo Tu We Th Fr Sa
1791     *  1  2  3  4  5  6  7
1792     *  8  9 10 11 12 13 14
1793     * 15 16 17 18 19 20 21
1794     * 22 23 24 25 26 27 28
1795     * 29 30 31
1796     */
1797    UBool passed = TRUE;
1798    UErrorCode status = U_ZERO_ERROR;
1799    UCalendarDateFields field = UCAL_WEEK_OF_MONTH;
1800
1801    GregorianCalendar *calendar = new GregorianCalendar(Locale::getUS(), status);
1802    if(U_FAILURE(status)) {
1803        dataerrln("Couldn't create calendar.: %s", u_errorName(status));
1804        return;
1805    }
1806    calendar->set(1998, UCAL_MARCH, 1);
1807    calendar->setMinimalDaysInFirstWeek(1);
1808    logln(UnicodeString("Date:  ") + calendar->getTime(status)); // 888817448000
1809
1810    int32_t firstInMonth = calendar->get(UCAL_DATE, status);
1811    if(U_FAILURE(status))
1812        errln("get(D_O_M) failed");
1813
1814    for(int32_t firstInWeek = UCAL_SUNDAY; firstInWeek <= UCAL_SATURDAY; firstInWeek++) {
1815        calendar->setFirstDayOfWeek((UCalendarDaysOfWeek)firstInWeek);
1816        int32_t returned = calendar->getActualMaximum(field, status);
1817        int32_t expected = (31 + ((firstInMonth - firstInWeek + 7)% 7) + 6) / 7;
1818
1819        logln(UnicodeString("First day of week = ") + firstInWeek +
1820              "  getActualMaximum(WEEK_OF_MONTH, status) = " + returned +
1821              "  expected = " + expected +
1822              ((returned == expected) ? "  ok" : "  FAIL"));
1823
1824        if (returned != expected) {
1825            passed = FALSE;
1826        }
1827    }
1828    if (!passed) {
1829        errln("Test failed");
1830    }
1831
1832    delete calendar;
1833}
1834
1835/**
1836 * @bug 4167060
1837 * Calendar.getActualMaximum(YEAR) works wrong.
1838 */
1839void
1840CalendarRegressionTest::Test4167060()
1841{
1842    UErrorCode status = U_ZERO_ERROR;
1843    UCalendarDateFields field = UCAL_YEAR;
1844    DateFormat *format = new SimpleDateFormat(UnicodeString("EEE MMM dd HH:mm:ss zzz yyyy G"),
1845        Locale::getUS(), status);
1846    if(U_FAILURE(status)) {
1847        dataerrln("Couldn't create SimpleDateFormat - %s", u_errorName(status));
1848        return;
1849    }
1850
1851    GregorianCalendar *calendars [] = {
1852        new GregorianCalendar(100, UCAL_NOVEMBER, 1, status),
1853        new GregorianCalendar(-99 /*100BC*/, UCAL_JANUARY, 1, status),
1854        new GregorianCalendar(1996, UCAL_FEBRUARY, 29, status),
1855    };
1856    if(U_FAILURE(status)) {
1857        errln("Couldn't create GregorianCalendars");
1858        return;
1859        // could leak
1860    }
1861
1862    UnicodeString id [] = { "Hybrid", "Gregorian", "Julian" };
1863
1864    for (int32_t k=0; k<3; ++k) {
1865        logln("--- " + id[k] + " ---");
1866
1867        for (int32_t j=0; j < 3; ++j) {
1868            GregorianCalendar *calendar = calendars[j];
1869            if (k == 1) {
1870                calendar->setGregorianChange(EARLIEST_SUPPORTED_MILLIS, status);
1871            }
1872            else if (k == 2) {
1873                calendar->setGregorianChange(LATEST_SUPPORTED_MILLIS, status);
1874            }
1875
1876            if(U_FAILURE(status))
1877                errln("setGregorianChange() failed");
1878            format->adoptCalendar((Calendar*)calendar->clone());
1879
1880            UDate dateBefore = calendar->getTime(status);
1881            if(U_FAILURE(status))
1882                errln("getTime() failed");
1883
1884            int32_t maxYear = calendar->getActualMaximum(field, status);
1885            UnicodeString temp;
1886            logln(UnicodeString("maxYear: ") + maxYear + " for " + format->format(calendar->getTime(status), temp));
1887            temp.remove();
1888            logln("date before: " + format->format(dateBefore, temp));
1889
1890            int32_t years[] = {2000, maxYear-1, maxYear, maxYear+1};
1891
1892            for (int32_t i = 0; i < 4; i++) {
1893                UBool valid = years[i] <= maxYear;
1894                calendar->set(field, years[i]);
1895                UDate dateAfter = calendar->getTime(status);
1896                if(U_FAILURE(status))
1897                    errln("getTime() failed");
1898                int32_t newYear = calendar->get(field, status);
1899                if(U_FAILURE(status))
1900                    errln(UnicodeString("get(") + (int32_t)field + ") failed");
1901                calendar->setTime(dateBefore, status); // restore calendar for next use
1902                if(U_FAILURE(status))
1903                    errln("setTime() failed");
1904
1905                temp.remove();
1906                logln(UnicodeString(" Year ") + years[i] + (valid? " ok " : " bad") +
1907                      " => " + format->format(dateAfter, temp));
1908                if (valid && newYear != years[i]) {
1909                    errln(UnicodeString("  FAIL: ") + newYear + " should be valid; date, month and time shouldn't change");
1910                }
1911                // {sfb} this next line is a hack, but it should work since if a
1912                // double has an exponent, adding 1 should not yield the same double
1913                else if (!valid && /*newYear == years[i]*/ dateAfter + 1.0 == dateAfter)  {
1914                    errln(UnicodeString("  FAIL: ") + newYear + " should be invalid");
1915                }
1916            }
1917        }
1918    }
1919
1920    delete format;
1921    delete calendars[0];
1922    delete calendars[1];
1923    delete calendars[2];
1924}
1925
1926/**
1927 * Week of year is wrong at the start and end of the year.
1928 */
1929void CalendarRegressionTest::Test4197699() {
1930    UErrorCode status = U_ZERO_ERROR;
1931    GregorianCalendar cal(status);
1932    cal.setFirstDayOfWeek(UCAL_MONDAY);
1933    cal.setMinimalDaysInFirstWeek(4);
1934    SimpleDateFormat fmt("E dd MMM yyyy  'DOY='D 'WOY='w",
1935                         Locale::getUS(), status);
1936    fmt.setCalendar(cal);
1937    if (U_FAILURE(status)) {
1938        dataerrln("Couldn't initialize test - %s", u_errorName(status));
1939        return;
1940    }
1941
1942    int32_t DATA[] = {
1943        2000,  UCAL_JANUARY,   1,   52,
1944        2001,  UCAL_DECEMBER,  31,  1,
1945    };
1946    int32_t DATA_length = (int32_t)(sizeof(DATA) / sizeof(DATA[0]));
1947
1948    UnicodeString str;
1949    DateFormat& dfmt = *(DateFormat*)&fmt;
1950    for (int32_t i=0; i<DATA_length; ) {
1951        cal.clear();
1952        cal.set(DATA[i], DATA[i+1], DATA[i+2]);
1953        i += 3;
1954        int32_t expWOY = DATA[i++];
1955        int32_t actWOY = cal.get(UCAL_WEEK_OF_YEAR, status);
1956        if (expWOY == actWOY) {
1957            logln(UnicodeString("Ok: ") + dfmt.format(cal.getTime(status), str.remove()));
1958        } else {
1959            errln(UnicodeString("FAIL: ") + dfmt.format(cal.getTime(status), str.remove())
1960                  + ", expected WOY=" + expWOY);
1961            cal.add(UCAL_DATE, -8, status);
1962            for (int j=0; j<14; ++j) {
1963                cal.add(UCAL_DATE, 1, status);
1964                logln(dfmt.format(cal.getTime(status), str.remove()));
1965            }
1966        }
1967        if (U_FAILURE(status)) {
1968            errln("FAIL: Unexpected error from Calendar");
1969            return;
1970        }
1971    }
1972}
1973
1974    enum Action { ADD=1, ROLL=2 };
1975    enum Sign { PLUS=1, MINUS=2 };
1976
1977#define     ONE_HOUR (60*60*1000)
1978#define ONE_DAY (24*ONE_HOUR)
1979
1980    typedef struct {
1981        UCalendarDateFields field;
1982        int8_t actionMask; // ADD or ROLL or both
1983        int8_t signMask; // PLUS or MINUS or both
1984        int32_t amount;
1985        int32_t before; // ms before cutover
1986        int32_t after;  // ms after cutover
1987    } J81_DATA;
1988
1989/**
1990 * Rolling and adding across the Gregorian cutover should work as expected.
1991 * Jitterbug 81.
1992 */
1993void CalendarRegressionTest::TestJ81() {
1994    UErrorCode status = U_ZERO_ERROR;
1995    UnicodeString temp, temp2, temp3;
1996    int32_t i;
1997    GregorianCalendar cal(TimeZone::createTimeZone("GMT"), Locale::getUS(), status);
1998    SimpleDateFormat fmt("HH:mm 'w'w 'd'D E d MMM yyyy", Locale::getUS(), status);
1999    if (U_FAILURE(status)) {
2000        dataerrln("Error: Cannot create calendar or format - %s", u_errorName(status));
2001        return;
2002    }
2003    fmt.setCalendar(cal);
2004    // Get the Gregorian cutover
2005    UDate cutover = cal.getGregorianChange();
2006    UDate days = ONE_DAY;
2007    days = cutover/days;
2008    logln(UnicodeString("Cutover: {") +
2009          fmt.format(cutover, temp) + "}(epoch days-" + (int)days + ", jd" + (2440588 + days) +")");
2010
2011    // Check woy and doy handling.  Reference data:
2012    /* w40 d274 Mon 1 Oct 1582
2013       w40 d275 Tue 2 Oct 1582
2014       w40 d276 Wed 3 Oct 1582
2015       w40 d277 Thu 4 Oct 1582
2016       w40 d278 Fri 15 Oct 1582
2017       w40 d279 Sat 16 Oct 1582
2018       w41 d280 Sun 17 Oct 1582
2019       w41 d281 Mon 18 Oct 1582
2020       w41 d282 Tue 19 Oct 1582
2021       w41 d283 Wed 20 Oct 1582
2022       w41 d284 Thu 21 Oct 1582
2023       w41 d285 Fri 22 Oct 1582
2024       w41 d286 Sat 23 Oct 1582
2025       w42 d287 Sun 24 Oct 1582
2026       w42 d288 Mon 25 Oct 1582
2027       w42 d289 Tue 26 Oct 1582
2028       w42 d290 Wed 27 Oct 1582
2029       w42 d291 Thu 28 Oct 1582
2030       w42 d292 Fri 29 Oct 1582
2031       w42 d293 Sat 30 Oct 1582
2032       w43 d294 Sun 31 Oct 1582
2033       w43 d295 Mon 1 Nov 1582 */
2034    int32_t DOY_DATA[] = {
2035        // dom, woy, doy
2036        1, 40, 274, UCAL_MONDAY,
2037        4, 40, 277, UCAL_THURSDAY,
2038        15, 40, 278, UCAL_FRIDAY,
2039        17, 41, 280, UCAL_SUNDAY,
2040        24, 42, 287, UCAL_SUNDAY,
2041        25, 42, 288, UCAL_MONDAY,
2042        26, 42, 289, UCAL_TUESDAY,
2043        27, 42, 290, UCAL_WEDNESDAY,
2044        28, 42, 291, UCAL_THURSDAY,
2045        29, 42, 292, UCAL_FRIDAY,
2046        30, 42, 293, UCAL_SATURDAY,
2047        31, 43, 294, UCAL_SUNDAY
2048    };
2049    int32_t DOY_DATA_length = (int32_t)(sizeof(DOY_DATA) / sizeof(DOY_DATA[0]));
2050
2051    for (i=0; i<DOY_DATA_length; i+=4) {
2052        // Test time->fields
2053        cal.set(1582, UCAL_OCTOBER, DOY_DATA[i]);
2054        int32_t woy = cal.get(UCAL_WEEK_OF_YEAR, status);
2055        int32_t doy = cal.get(UCAL_DAY_OF_YEAR, status);
2056        int32_t dow = cal.get(UCAL_DAY_OF_WEEK, status);
2057        if (U_FAILURE(status)) {
2058            errln("Error: get() failed");
2059            break;
2060        }
2061        if (woy != DOY_DATA[i+1] || doy != DOY_DATA[i+2] || dow != DOY_DATA[i+3]) {
2062            errln((UnicodeString)"Fail: expect woy=" + DOY_DATA[i+1] +
2063                  ", doy=" + DOY_DATA[i+2] + ", dow=" + DOY_DATA[i+3] + " on " +
2064                  fmt.format(cal.getTime(status), temp.remove()) +
2065                  " set(1582,OCTOBER, " + DOY_DATA[i] + ")");
2066            logln(CalendarTest::calToStr(cal));
2067            status = U_ZERO_ERROR;
2068        }  else {
2069          logln((UnicodeString)"PASS: expect woy=" + DOY_DATA[i+1] +
2070                ", doy=" + DOY_DATA[i+2] + ", dow=" + DOY_DATA[i+3] + " on " +
2071                fmt.format(cal.getTime(status), temp.remove()));
2072          logln(CalendarTest::calToStr(cal));
2073          status = U_ZERO_ERROR;
2074        }
2075        // Test fields->time for WOY
2076        cal.clear();
2077        cal.set(UCAL_YEAR, 1582);
2078        cal.set(UCAL_WEEK_OF_YEAR, DOY_DATA[i+1]);
2079        cal.set(UCAL_DAY_OF_WEEK, DOY_DATA[i+3]);
2080        int32_t dom = cal.get(UCAL_DATE, status);
2081        if (U_FAILURE(status)) {
2082            errln("Error: get() failed");
2083            break;
2084        }
2085        if (dom != DOY_DATA[i]) {
2086            errln((UnicodeString)"Fail: set woy=" + DOY_DATA[i+1] +
2087                  " dow=" + DOY_DATA[i+3] + " => " +
2088                  fmt.format(cal.getTime(status), temp.remove()) +
2089                  ", expected 1582 Oct " + DOY_DATA[i]);
2090            logln(CalendarTest::calToStr(cal));
2091            status = U_ZERO_ERROR;
2092        }
2093
2094        // Test fields->time for DOY
2095        cal.clear();
2096        cal.set(UCAL_YEAR, 1582);
2097        cal.set(UCAL_DAY_OF_YEAR, DOY_DATA[i+2]);
2098        dom = cal.get(UCAL_DATE, status);
2099        if (U_FAILURE(status)) {
2100            errln("Error: get() failed");
2101            break;
2102        }
2103        if (dom != DOY_DATA[i]) {
2104            errln((UnicodeString)"Fail: set doy=" + DOY_DATA[i+2] +
2105                  " => " +
2106                  fmt.format(cal.getTime(status), temp.remove()) +
2107                  ", expected 1582 Oct " + DOY_DATA[i]);
2108            status = U_ZERO_ERROR;
2109        }
2110    }
2111    status = U_ZERO_ERROR;
2112
2113#define ADD_ROLL  ADD|ROLL
2114#define PLUS_MINUS PLUS|MINUS
2115    // Test cases
2116    J81_DATA DATA[] = {
2117        { UCAL_WEEK_OF_YEAR, ADD_ROLL, PLUS_MINUS, 1, -ONE_DAY, +6*ONE_DAY },
2118        { UCAL_WEEK_OF_YEAR, ADD_ROLL, PLUS_MINUS, 1, -ONE_DAY, +6*ONE_DAY },
2119        { UCAL_WEEK_OF_MONTH, ADD|ROLL, PLUS|MINUS, 1, -ONE_DAY, +6*ONE_DAY },
2120        { UCAL_DATE, ADD|ROLL, PLUS|MINUS, 2, -ONE_DAY, +1*ONE_DAY },
2121        { UCAL_DATE, ROLL, PLUS, -6, -ONE_DAY, +14*ONE_DAY },
2122        { UCAL_DATE, ROLL, PLUS, -7, 0, +14*ONE_DAY },
2123        { UCAL_DATE, ROLL, PLUS, -7, +ONE_DAY, +15*ONE_DAY },
2124        { UCAL_DATE, ROLL, PLUS, +18, -ONE_DAY, -4*ONE_DAY },
2125        { UCAL_DAY_OF_YEAR, ADD|ROLL, PLUS|MINUS, 2, -ONE_DAY, +1*ONE_DAY },
2126        { UCAL_DAY_OF_WEEK, ADD|ROLL, PLUS|MINUS, 2, -ONE_DAY, +1*ONE_DAY },
2127        { UCAL_DAY_OF_WEEK_IN_MONTH, ADD|ROLL, PLUS|MINUS, 1, -ONE_DAY, +6*ONE_DAY },
2128        { UCAL_AM_PM, ADD, PLUS|MINUS, 4, -12*ONE_HOUR, +36*ONE_HOUR },
2129        { UCAL_HOUR, ADD, PLUS|MINUS, 48, -12*ONE_HOUR, +36*ONE_HOUR },
2130        { UCAL_HOUR_OF_DAY, ADD, PLUS|MINUS, 48, -12*ONE_HOUR, +36*ONE_HOUR },
2131        { UCAL_MINUTE, ADD, PLUS|MINUS, 48*60, -12*ONE_HOUR, +36*ONE_HOUR },
2132        { UCAL_SECOND, ADD, PLUS|MINUS, 48*60*60, -12*ONE_HOUR, +36*ONE_HOUR },
2133        { UCAL_MILLISECOND, ADD, PLUS|MINUS, 48*ONE_HOUR, -12*ONE_HOUR, +36*ONE_HOUR },
2134        // NOTE: These are not supported yet.  See jitterbug 180.
2135        // Uncomment these lines when add/roll supported on these fields.
2136        // { Calendar::YEAR_WOY, ADD|ROLL, 1, -ONE_DAY, +6*ONE_DAY },
2137        // { Calendar::DOW_LOCAL, ADD|ROLL, 2, -ONE_DAY, +1*ONE_DAY }
2138    };
2139    int32_t DATA_length = (int32_t)(sizeof(DATA) / sizeof(DATA[0]));
2140
2141    // Now run the tests
2142    for (i=0; i<DATA_length; ++i) {
2143        for (Action action=ADD; action<=ROLL; action=(Action)(action+1)) {
2144            if (!(DATA[i].actionMask & action)) {
2145                continue;
2146            }
2147            for (Sign sign=PLUS; sign<=MINUS; sign=(Sign)(sign+1)) {
2148                if (!(DATA[i].signMask & sign)) {
2149                    continue;
2150                }
2151                status = U_ZERO_ERROR;
2152                int32_t amount = DATA[i].amount * (sign==MINUS?-1:1);
2153                UDate date = cutover +
2154                    (sign==PLUS ? DATA[i].before : DATA[i].after);
2155                UDate expected = cutover +
2156                    (sign==PLUS ? DATA[i].after : DATA[i].before);
2157                cal.setTime(date, status);
2158                if (U_FAILURE(status)) {
2159                    errln((UnicodeString)"FAIL: setTime returned error code " + u_errorName(status));
2160                    continue;
2161                }
2162                if (action == ADD) {
2163                    cal.add(DATA[i].field, amount, status);
2164                } else {
2165                    cal.roll(DATA[i].field, amount, status);
2166                }
2167                if (U_FAILURE(status)) {
2168                    errln((UnicodeString)"FAIL: " +
2169                          (action==ADD?"add ":"roll ") + FIELD_NAME[DATA[i].field] +
2170                          " returned error code " + u_errorName(status));
2171                    continue;
2172                }
2173                UDate result = cal.getTime(status);
2174                if (U_FAILURE(status)) {
2175                    errln((UnicodeString)"FAIL: getTime returned error code " + u_errorName(status));
2176                    continue;
2177                }
2178                if (result == expected) {
2179                    logln((UnicodeString)"Ok: {" +
2180                          fmt.format(date, temp.remove()) +
2181                          "}(" + date/ONE_DAY +
2182                          (action==ADD?") add ":") roll ") +
2183                          amount + " " + FIELD_NAME[DATA[i].field] + " -> {" +
2184                          fmt.format(result, temp2.remove()) +
2185                          "}(" + result/ONE_DAY + ")");
2186                } else {
2187                    errln((UnicodeString)"FAIL: {" +
2188                          fmt.format(date, temp.remove()) +
2189                          "}(" + date/ONE_DAY +
2190                          (action==ADD?") add ":") roll ") +
2191                          amount + " " + FIELD_NAME[DATA[i].field] + " -> {" +
2192                          fmt.format(result, temp2.remove()) +
2193                          "}(" + result/ONE_DAY + "), expect {" +
2194                          fmt.format(expected, temp3.remove()) +
2195                          "}(" + expected/ONE_DAY + ")");
2196                }
2197            }
2198        }
2199    }
2200}
2201
2202/**
2203 * Test fieldDifference().
2204 */
2205void CalendarRegressionTest::TestJ438(void) {
2206    UErrorCode ec = U_ZERO_ERROR;
2207    int32_t DATA[] = {
2208        2000, UCAL_JANUARY, 20,   2010, UCAL_JUNE, 15,
2209        2010, UCAL_JUNE, 15,      2000, UCAL_JANUARY, 20,
2210        1964, UCAL_SEPTEMBER, 7,  1999, UCAL_JUNE, 4,
2211        1999, UCAL_JUNE, 4,       1964, UCAL_SEPTEMBER, 7,
2212    };
2213    int32_t DATA_length = (int32_t)(sizeof(DATA)/sizeof(DATA[0]));
2214    Calendar* pcal = Calendar::createInstance(Locale::getUS(), ec);
2215    if(U_FAILURE(ec)) {
2216      dataerrln("Error creating calendar %s", u_errorName(ec));
2217      delete pcal;
2218      return;
2219    }
2220    Calendar& cal = *pcal;
2221    int32_t i;
2222    SimpleDateFormat fmt(UnicodeString("MMM dd yyyy",""), ec);
2223    fmt.setCalendar(cal);
2224    UnicodeString s, t, u;
2225    if (!failure(ec, "setup")) {
2226        for (i=0; i<DATA_length; i+=6) {
2227            int32_t y1 = DATA[i];
2228            int32_t m1 = DATA[i+1];
2229            int32_t d1 = DATA[i+2];
2230            int32_t y2 = DATA[i+3];
2231            int32_t m2 = DATA[i+4];
2232            int32_t d2 = DATA[i+5];
2233
2234            cal.clear();
2235            cal.set(y1, m1, d1);
2236            UDate date1 = cal.getTime(ec);
2237            if (failure(ec, "getTime"))
2238                break;
2239            cal.set(y2, m2, d2);
2240            UDate date2 = cal.getTime(ec);
2241            if (failure(ec, "getTime"))
2242                break;
2243
2244            cal.setTime(date1, ec);
2245            if (failure(ec, "setTime"))
2246                break;
2247            int32_t dy = cal.fieldDifference(date2, UCAL_YEAR, ec);
2248            int32_t dm = cal.fieldDifference(date2, UCAL_MONTH, ec);
2249            int32_t dd = cal.fieldDifference(date2, UCAL_DATE, ec);
2250            if (failure(ec, "fieldDifference"))
2251                break;
2252
2253            {
2254                Calendar *cal2 = cal.clone();
2255                UErrorCode ec2 = U_ZERO_ERROR;
2256
2257                cal2->setTime(date1, ec2);
2258
2259                int32_t dy2 = cal2->fieldDifference(date2, Calendar::YEAR, ec2);
2260                int32_t dm2 = cal2->fieldDifference(date2, Calendar::MONTH, ec2);
2261                int32_t dd2 = cal2->fieldDifference(date2, Calendar::DATE, ec2);
2262                if (failure(ec2, "fieldDifference(date, Calendar::DATE, ec)"))
2263                    break;
2264                if( (dd2 != dd) ||
2265                    (dm2 != dm) ||
2266                    (dy2 != dy)){
2267                    errln("fieldDifference(UCAL_...) and fieldDifference(Calendar::...) give different results!\n");
2268                }
2269                delete cal2;
2270            }
2271
2272
2273            logln(UnicodeString("") +
2274                  fmt.format(date2, s.remove()) + " - " +
2275                  fmt.format(date1, t.remove()) + " = " +
2276                  dy + "y " + dm + "m " + dd + "d");
2277
2278            cal.setTime(date1, ec);
2279            if (failure(ec, "setTime"))
2280                break;
2281            cal.add(UCAL_YEAR, dy, ec);
2282            cal.add(UCAL_MONTH, dm, ec);
2283            cal.add(UCAL_DATE, dd, ec);
2284            if (failure(ec, "add"))
2285                break;
2286            UDate date22 = cal.getTime(ec);
2287            if (failure(ec, "getTime"))
2288                break;
2289            if (date2 != date22) {
2290                errln(UnicodeString("FAIL: ") +
2291                      fmt.format(date1, s.remove()) + " + " +
2292                      dy + "y " + dm + "m " + dd + "d = " +
2293                      fmt.format(date22, t.remove()) + ", exp " +
2294                      fmt.format(date2, u.remove()));
2295            } else {
2296                logln(UnicodeString("Ok: ") +
2297                      fmt.format(date1, s.remove()) + " + " +
2298                      dy + "y " + dm + "m " + dd + "d = " +
2299                      fmt.format(date22, t.remove()));
2300            }
2301        }
2302    }
2303    delete pcal;
2304}
2305
2306void CalendarRegressionTest::TestT5555()
2307{
2308    UErrorCode ec = U_ZERO_ERROR;
2309    Calendar *cal = Calendar::createInstance(ec);
2310
2311    if (cal == NULL || U_FAILURE(ec)) {
2312        dataerrln("FAIL: Calendar::createInstance(): %s", u_errorName(ec));
2313        delete cal;
2314        return;
2315    }
2316
2317    // Set to Wednesday, February 21, 2007
2318    cal->set(2007, UCAL_FEBRUARY, 21);
2319
2320    // Advance three years
2321    cal->add(UCAL_MONTH, 36, ec);
2322
2323    // Set to last Wednesday of the month
2324    cal->set(UCAL_DAY_OF_WEEK_IN_MONTH, -1);
2325
2326    cal->getTime(ec);
2327
2328    int32_t yy, mm, dd, ee;
2329
2330    yy = cal->get(UCAL_YEAR, ec);
2331    mm = cal->get(UCAL_MONTH, ec);
2332    dd = cal->get(UCAL_DATE, ec);
2333    ee = cal->get(UCAL_DAY_OF_WEEK, ec);
2334
2335    // Should be set to Wednesday, February 24, 2010
2336    if (U_FAILURE(ec) || yy != 2010 || mm != UCAL_FEBRUARY || dd != 24 || ee != UCAL_WEDNESDAY) {
2337        errln("FAIL: got date %4d/%02d/%02d, expected 210/02/24: ", yy, mm + 1, dd);
2338    }
2339    delete cal;
2340}
2341
2342typedef struct {
2343    int32_t             startYear;
2344    int32_t             startMonth; // 0-based
2345    int32_t             startDay;   // 1-based
2346    UCalendarDateFields fieldToChange;
2347    int32_t             fieldDelta;
2348    int32_t             endYear;
2349    int32_t             endMonth;   // 0-based
2350    int32_t             endDay;     // 1-based
2351} CoptEthCalTestItem;
2352
2353// year 1724 in coptic calendar =
2354// year 2000 in ethiopic calendar (276 more than coptic) =
2355// year 7500 in ethiopic-amete-alem calendar (5776 more than coptic)
2356// (2007-2008 in gregorian calendar depending on month)
2357static const CoptEthCalTestItem coptEthCalTestItems[] = {
2358    { 1724, 12, 1, UCAL_MONTH, +1, 1725,  0, 1 },
2359    { 1724, 12, 1, UCAL_MONTH, +9, 1725,  8, 1 },
2360    { 1723, 12, 2, UCAL_MONTH, +1, 1724,  0, 2 }, // 1723 is a leap year
2361    { 1723, 12, 2, UCAL_MONTH, +9, 1724,  8, 2 },
2362    { 1725,  0, 1, UCAL_MONTH, -1, 1724, 12, 1 },
2363    { 1725,  0, 1, UCAL_MONTH, -6, 1724,  7, 1 },
2364    { 1724, 12, 1, UCAL_DATE,  +8, 1725,  0, 4 },
2365    { 1723, 12, 1, UCAL_DATE,  +8, 1724,  0, 3 }, // 1723 is a leap year
2366    { 1724,  0, 1, UCAL_DATE,  -1, 1723, 12, 6 }, // 1723 is a leap year
2367    { 0, 0, 0, (UCalendarDateFields)0, 0, 0, 0, 0 } // terminator
2368};
2369
2370typedef struct {
2371    const char * locale;
2372    int32_t      yearOffset;
2373} CoptEthCalLocale;
2374
2375static const CoptEthCalLocale copEthCalLocales[] = {
2376    { "en@calendar=coptic",   0    },
2377    { "en@calendar=ethiopic", 276  },
2378    { NULL,                   0    } // terminator
2379};
2380
2381void CalendarRegressionTest::TestT6745()
2382{
2383    const CoptEthCalLocale * testLocalePtr;
2384    for ( testLocalePtr = copEthCalLocales; testLocalePtr->locale != NULL; ++testLocalePtr) {
2385        UErrorCode status = U_ZERO_ERROR;
2386        Calendar *cal = Calendar::createInstance(Locale(testLocalePtr->locale), status);
2387        if ( U_FAILURE(status) ) {
2388            dataerrln((UnicodeString)"FAIL: Calendar::createInstance, locale " + testLocalePtr->locale + ", status " + u_errorName(status));
2389            continue;
2390        }
2391        const CoptEthCalTestItem * testItemPtr;
2392        for (testItemPtr = coptEthCalTestItems; testItemPtr->fieldDelta != 0; ++testItemPtr) {
2393            status = U_ZERO_ERROR;
2394            cal->set( testItemPtr->startYear + testLocalePtr->yearOffset, testItemPtr->startMonth, testItemPtr->startDay, 9, 0 );
2395            cal->add( testItemPtr->fieldToChange, testItemPtr->fieldDelta, status );
2396            if ( U_FAILURE(status) ) {
2397                errln((UnicodeString)"FAIL: Calendar::add, locale " + testLocalePtr->locale + ", field/delta " +
2398                        testItemPtr->fieldToChange + "/" + testItemPtr->fieldDelta + ", status " + u_errorName(status));
2399                continue;
2400            }
2401            int32_t endYear = testItemPtr->endYear + testLocalePtr->yearOffset;
2402            int32_t year  = cal->get(UCAL_YEAR, status);
2403            int32_t month = cal->get(UCAL_MONTH, status);
2404            int32_t day   = cal->get(UCAL_DATE, status);
2405            if ( U_FAILURE(status) || year != endYear || month != testItemPtr->endMonth || day != testItemPtr->endDay ) {
2406                errln((UnicodeString)"ERROR: Calendar::add, locale " + testLocalePtr->locale + ", field/delta " +
2407                        testItemPtr->fieldToChange + "/" + testItemPtr->fieldDelta + ", status " + u_errorName(status) +
2408                        ", expected " + endYear + "/" + testItemPtr->endMonth + "/" + testItemPtr->endDay +
2409                        ", got " + year + "/" + month + "/" + day );
2410            }
2411        }
2412        delete cal;
2413    }
2414}
2415
2416/**
2417 * Test behavior of fieldDifference around leap years.  Also test a large
2418 * field difference to check binary search.
2419 */
2420void CalendarRegressionTest::TestLeapFieldDifference() {
2421    UErrorCode ec = U_ZERO_ERROR;
2422    Calendar* cal = Calendar::createInstance(ec);
2423    if (cal == NULL || U_FAILURE(ec)) {
2424        dataerrln("FAIL: Calendar::createInstance(): %s", u_errorName(ec));
2425        delete cal;
2426        return;
2427    }
2428    cal->set(2004, UCAL_FEBRUARY, 29);
2429    UDate date2004 = cal->getTime(ec);
2430    cal->set(2000, UCAL_FEBRUARY, 29);
2431    UDate date2000 = cal->getTime(ec);
2432    if (U_FAILURE(ec)) {
2433        errln("FAIL: getTime()");
2434        delete cal;
2435        return;
2436    }
2437    int32_t y = cal->fieldDifference(date2004, UCAL_YEAR, ec);
2438    int32_t d = cal->fieldDifference(date2004, UCAL_DAY_OF_YEAR, ec);
2439    if (U_FAILURE(ec)) {
2440        errln("FAIL: fieldDifference()");
2441        delete cal;
2442        return;
2443    }
2444    if (d == 0) {
2445        logln((UnicodeString)"Ok: 2004/Feb/29 - 2000/Feb/29 = " + y + " years, " + d + " days");
2446    } else {
2447        errln((UnicodeString)"FAIL: 2004/Feb/29 - 2000/Feb/29 = " + y + " years, " + d + " days");
2448    }
2449    cal->setTime(date2004, ec);
2450    y = cal->fieldDifference(date2000, UCAL_YEAR, ec);
2451    d = cal->fieldDifference(date2000, UCAL_DAY_OF_YEAR, ec);
2452    if (U_FAILURE(ec)) {
2453        errln("FAIL: setTime() / fieldDifference()");
2454        delete cal;
2455        return;
2456    }
2457    if (d == 0) {
2458        logln((UnicodeString)"Ok: 2000/Feb/29 - 2004/Feb/29 = " + y + " years, " + d + " days");
2459    } else {
2460        errln((UnicodeString)"FAIL: 2000/Feb/29 - 2004/Feb/29 = " + y + " years, " + d + " days");
2461    }
2462    // Test large difference
2463    cal->set(2001, UCAL_APRIL, 5); // 2452005
2464    UDate ayl = cal->getTime(ec);
2465    cal->set(1964, UCAL_SEPTEMBER, 7); // 2438646
2466    UDate asl = cal->getTime(ec);
2467    if (U_FAILURE(ec)) {
2468        errln("FAIL: getTime()");
2469        delete cal;
2470        return;
2471    }
2472    d = cal->fieldDifference(ayl, UCAL_DATE, ec);
2473    cal->setTime(ayl, ec);
2474    int32_t d2 = cal->fieldDifference(asl, UCAL_DATE, ec);
2475    if (U_FAILURE(ec)) {
2476        errln("FAIL: setTime() / fieldDifference()");
2477        delete cal;
2478        return;
2479    }
2480    if (d == -d2 && d == 13359) {
2481        logln((UnicodeString)"Ok: large field difference symmetrical " + d);
2482    } else {
2483        logln((UnicodeString)"FAIL: large field difference incorrect " + d + ", " + d2 +
2484              ", expect +/- 13359");
2485    }
2486    delete cal;
2487}
2488
2489/**
2490 * Test ms_MY "Malay (Malaysia)" locale.  Bug 1543.
2491 */
2492void CalendarRegressionTest::TestMalaysianInstance() {
2493    Locale loc("ms", "MY");  // Malay (Malaysia)
2494    UErrorCode ec = U_ZERO_ERROR;
2495    Calendar* cal = Calendar::createInstance(loc, ec);
2496    if (U_FAILURE(ec)) {
2497        dataerrln("FAIL: Can't construct calendar for ms_MY: %s", u_errorName(ec));
2498    }
2499    delete cal;
2500}
2501
2502/**
2503 * setFirstDayOfWeek and setMinimalDaysInFirstWeek may change the
2504 * field <=> time mapping, since they affect the interpretation of
2505 * the WEEK_OF_MONTH or WEEK_OF_YEAR fields.
2506 */
2507void CalendarRegressionTest::TestWeekShift() {
2508    UErrorCode ec = U_ZERO_ERROR;
2509    GregorianCalendar cal(TimeZone::createTimeZone("America/Los_Angeles"),
2510                          Locale("en", "US"), ec);
2511    if (U_FAILURE(ec)) {
2512        dataerrln("Fail GregorianCalendar: %s", u_errorName(ec));
2513        return;
2514    }
2515    cal.setTime(UDate(997257600000.0), ec); // Wed Aug 08 01:00:00 PDT 2001
2516    // In pass one, change the first day of week so that the weeks
2517    // shift in August 2001.  In pass two, change the minimal days
2518    // in the first week so that the weeks shift in August 2001.
2519    //     August 2001
2520    // Su Mo Tu We Th Fr Sa
2521    //           1  2  3  4
2522    //  5  6  7  8  9 10 11
2523    // 12 13 14 15 16 17 18
2524    // 19 20 21 22 23 24 25
2525    // 26 27 28 29 30 31
2526    for (int32_t pass=0; pass<2; ++pass) {
2527        if (pass==0) {
2528            cal.setFirstDayOfWeek(UCAL_WEDNESDAY);
2529            cal.setMinimalDaysInFirstWeek(4);
2530        } else {
2531            cal.setFirstDayOfWeek(UCAL_SUNDAY);
2532            cal.setMinimalDaysInFirstWeek(4);
2533        }
2534        cal.add(UCAL_DATE, 1, ec); // Force recalc
2535        cal.add(UCAL_DATE, -1, ec);
2536
2537        UDate time1 = cal.getTime(ec); // Get time -- should not change
2538
2539        // Now change a week parameter and then force a recalc.
2540        // The bug is that the recalc should not be necessary --
2541        // calendar should do so automatically.
2542        if (pass==0) {
2543            cal.setFirstDayOfWeek(UCAL_THURSDAY);
2544        } else {
2545            cal.setMinimalDaysInFirstWeek(5);
2546        }
2547
2548        int32_t woy1 = cal.get(UCAL_WEEK_OF_YEAR, ec);
2549        int32_t wom1 = cal.get(UCAL_WEEK_OF_MONTH, ec);
2550
2551        cal.add(UCAL_DATE, 1, ec); // Force recalc
2552        cal.add(UCAL_DATE, -1, ec);
2553
2554        int32_t woy2 = cal.get(UCAL_WEEK_OF_YEAR, ec);
2555        int32_t wom2 = cal.get(UCAL_WEEK_OF_MONTH, ec);
2556
2557        UDate time2 = cal.getTime(ec);
2558
2559        if (U_FAILURE(ec)) {
2560            errln("FAIL: internal test error");
2561            return;
2562        }
2563
2564        if (time1 != time2) {
2565            errln("FAIL: shifting week should not alter time");
2566        } else {
2567            // logln(time1);
2568        }
2569        if (woy1 == woy2 && wom1 == wom2) {
2570            logln((UnicodeString)"Ok: WEEK_OF_YEAR: " + woy1 +
2571                  ", WEEK_OF_MONTH: " + wom1);
2572        } else {
2573            errln((UnicodeString)"FAIL: WEEK_OF_YEAR: " + woy1 + " => " + woy2 +
2574                  ", WEEK_OF_MONTH: " + wom1 + " => " + wom2 +
2575                  " after week shift");
2576        }
2577    }
2578}
2579
2580/**
2581 * Make sure that when adding a day, we actually wind up in a
2582 * different day.  The DST adjustments we use to keep the hour
2583 * constant across DST changes can backfire and change the day.
2584 */
2585void CalendarRegressionTest::TestTimeZoneTransitionAdd() {
2586    UErrorCode ec = U_ZERO_ERROR;
2587    Locale locale(Locale::getUS()); // could also be CHINA
2588    SimpleDateFormat dateFormat("MM/dd/yyyy HH:mm z", locale, ec);
2589
2590    StringEnumeration *tz = TimeZone::createEnumeration();
2591    if (tz == NULL) {
2592        errln("FAIL: TimeZone::createEnumeration");
2593        return;
2594    }
2595
2596    UnicodeString buf1, buf2;
2597
2598    const UChar* id;
2599    while ((id = tz->unext(NULL, ec)) != NULL && U_SUCCESS(ec)) {
2600        if (U_FAILURE(ec)) {
2601            errln("FAIL: StringEnumeration::unext");
2602            break;
2603        }
2604
2605        TimeZone *t = TimeZone::createTimeZone(id);
2606        if (t == NULL) {
2607            errln("FAIL: TimeZone::createTimeZone");
2608            break;
2609        }
2610        dateFormat.setTimeZone(*t);
2611
2612        Calendar *cal = Calendar::createInstance(t, locale, ec);
2613        if (cal == NULL || U_FAILURE(ec)) {
2614            errln("FAIL: Calendar::createTimeZone");
2615            delete cal;
2616            break;
2617        }
2618
2619        cal->clear();
2620        // Scan the year 2003, overlapping the edges of the year
2621        cal->set(UCAL_YEAR, 2002);
2622        cal->set(UCAL_MONTH, UCAL_DECEMBER);
2623        cal->set(UCAL_DATE, 25);
2624
2625        for (int32_t i=0; i<365+10 && U_SUCCESS(ec); ++i) {
2626            UDate yesterday = cal->getTime(ec);
2627            int32_t yesterday_day = cal->get(UCAL_DATE, ec);
2628            cal->add(UCAL_DATE, 1, ec);
2629            if (yesterday_day == cal->get(UCAL_DATE, ec)) {
2630                errln(UnicodeString(id) + " " +
2631                      dateFormat.format(yesterday, buf1) + " +1d= " +
2632                      dateFormat.format(cal->getTime(ec), buf2));
2633                buf1.truncate(0);
2634                buf2.truncate(0);
2635            }
2636        }
2637        delete cal;
2638    }
2639
2640    if (U_FAILURE(ec)) {
2641        dataerrln("FAIL: %s", u_errorName(ec));
2642    }
2643
2644    delete tz;
2645}
2646
2647UDate
2648CalendarRegressionTest::makeDate(int32_t y, int32_t m, int32_t d,
2649                                    int32_t hr, int32_t min, int32_t sec)
2650{
2651    UDate result;
2652
2653    UErrorCode status = U_ZERO_ERROR;
2654    Calendar *cal = Calendar::createInstance(status);
2655    cal->clear();
2656
2657    cal->set(UCAL_YEAR, y);
2658
2659    if(m != 0)        cal->set(UCAL_MONTH, m);
2660    if(d != 0)        cal->set(UCAL_DATE, d);
2661    if(hr != 0)        cal->set(UCAL_HOUR, hr);
2662    if(min != 0)    cal->set(UCAL_MINUTE, min);
2663    if(sec != 0)    cal->set(UCAL_SECOND, sec);
2664
2665    result = cal->getTime(status);
2666
2667    delete cal;
2668
2669    return result;
2670}
2671
2672void CalendarRegressionTest::TestDeprecates(void)
2673{
2674    UErrorCode status = U_ZERO_ERROR;
2675    Calendar *c1 = Calendar::createInstance("ja_JP@calendar=japanese",status);
2676    Calendar *c2 = Calendar::createInstance("ja_JP_TRADITIONAL",status);
2677
2678    if(!c1 || !c2 || U_FAILURE(status)) {
2679        dataerrln("Couldn't create calendars for roll of HOUR: %s", u_errorName(status));
2680        return;
2681    }
2682
2683    c2->set(UCAL_HOUR,2);
2684    c1->setTime(c2->getTime(status),status);
2685    // *c1 = *c2;
2686
2687    c1->roll(Calendar::HOUR,(int32_t)3,status);
2688    c2->roll(UCAL_HOUR,(int32_t)3,status);
2689
2690    if(U_FAILURE(status)) {
2691        errln("Error code when trying to roll");
2692    } else if(*c1 != *c2) {
2693        errln("roll(EDateField, int32_t) had different effect than roll(UCalendarField, int32_t)");
2694    }
2695
2696    c1->setTime(c2->getTime(status),status);
2697    c1->roll(Calendar::HOUR,(UBool)FALSE,status);
2698    c2->roll(UCAL_HOUR,(UBool)FALSE,status);
2699
2700    if(U_FAILURE(status)) {
2701        errln("Error code when trying to roll(UBool)");
2702    } else if(*c1 != *c2) {
2703        errln("roll(EDateField, UBool) had different effect than roll(UCalendarField, UBool)");
2704    }
2705
2706    delete c1;
2707    delete c2;
2708
2709    status = U_ZERO_ERROR;
2710
2711    c1 = Calendar::createInstance("th_TH_TRADITIONAL",status);
2712    c2 = Calendar::createInstance("th_TH@calendar=buddhist",status);
2713
2714    if(!c1 || !c2 || U_FAILURE(status)) {
2715        errln("Couldn't create calendars for add of HOUR");
2716        return;
2717    }
2718
2719    c2->set(UCAL_HOUR,2);
2720    c1->setTime(c2->getTime(status),status);
2721    //*c1 = *c2;
2722
2723    c1->add(Calendar::HOUR,(int32_t)1,status);
2724
2725    if(U_FAILURE(status)) {
2726        errln("Error code when trying to add Calendar::HOUR - %s", u_errorName(status));
2727    }
2728
2729    c2->add(UCAL_HOUR,(int32_t)1,status);
2730
2731    if(U_FAILURE(status)) {
2732        errln("Error code when trying to add - UCAL_HOUR %s", u_errorName(status));
2733    } else if(*c1 != *c2) {
2734        errln("add(EDateField) had different effect than add(UCalendarField)");
2735    }
2736
2737    delete c1;
2738    delete c2;
2739
2740    status = U_ZERO_ERROR;
2741
2742    c1 = Calendar::createInstance("es_ES",status);
2743    c2 = Calendar::createInstance("es_ES",status);
2744
2745    if(!c1 || !c2 || U_FAILURE(status)) {
2746        errln("Couldn't create calendars for add of YEAR");
2747        return;
2748    }
2749
2750    c2->set(UCAL_YEAR,1900);
2751    c1->setTime(c2->getTime(status),status);
2752    //*c1 = *c2;
2753
2754    c1->add(Calendar::YEAR,(int32_t)9,status);
2755    c2->add(UCAL_YEAR,(int32_t)9,status);
2756
2757    if(U_FAILURE(status)) {
2758        errln("Error code when trying to add YEARs");
2759    } else if(*c1 != *c2) {
2760        errln("add(EDateField YEAR) had different effect than add(UCalendarField YEAR)");
2761    }
2762
2763    delete c1;
2764    delete c2;
2765}
2766
2767
2768#endif /* #if !UCONFIG_NO_FORMATTING */
2769