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