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