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