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