• 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 #include "unicode/utypes.h"
9 
10 #if !UCONFIG_NO_FORMATTING
11 
12 #include "caltest.h"
13 #include "unicode/dtfmtsym.h"
14 #include "unicode/gregocal.h"
15 #include "unicode/localpointer.h"
16 #include "hebrwcal.h"
17 #include "unicode/smpdtfmt.h"
18 #include "unicode/simpletz.h"
19 #include "dbgutil.h"
20 #include "unicode/udat.h"
21 #include "unicode/ustring.h"
22 #include "cstring.h"
23 #include "unicode/localpointer.h"
24 #include "chnsecal.h"
25 #include "intltest.h"
26 #include "coptccal.h"
27 #include "ethpccal.h"
28 #include "islamcal.h"
29 
30 #define mkcstr(U) u_austrcpy(calloc(8, u_strlen(U) + 1), U)
31 
32 #define TEST_CHECK_STATUS UPRV_BLOCK_MACRO_BEGIN { \
33     if (U_FAILURE(status)) { \
34         if (status == U_MISSING_RESOURCE_ERROR) { \
35             dataerrln("%s:%d: Test failure.  status=%s", __FILE__, __LINE__, u_errorName(status)); \
36         } else { \
37             errln("%s:%d: Test failure.  status=%s", __FILE__, __LINE__, u_errorName(status)); \
38         } \
39         return; \
40     } \
41 } UPRV_BLOCK_MACRO_END
42 
43 #define TEST_CHECK_STATUS_LOCALE(testlocale) UPRV_BLOCK_MACRO_BEGIN { \
44     if (U_FAILURE(status)) { \
45         if (status == U_MISSING_RESOURCE_ERROR) { \
46             dataerrln("%s:%d: Test failure, locale %s.  status=%s", __FILE__, __LINE__, testlocale, u_errorName(status)); \
47         } else { \
48             errln("%s:%d: Test failure, locale %s.  status=%s", __FILE__, __LINE__, testlocale, u_errorName(status)); \
49         } \
50         return; \
51     } \
52 } UPRV_BLOCK_MACRO_END
53 
54 #define TEST_ASSERT(expr) UPRV_BLOCK_MACRO_BEGIN { \
55     if ((expr)==false) { \
56         errln("%s:%d: Test failure \n", __FILE__, __LINE__); \
57     } \
58 } UPRV_BLOCK_MACRO_END
59 
60 // *****************************************************************************
61 // class CalendarTest
62 // *****************************************************************************
63 
calToStr(const Calendar & cal)64 UnicodeString CalendarTest::calToStr(const Calendar & cal)
65 {
66   UnicodeString out;
67   UErrorCode status = U_ZERO_ERROR;
68   int i;
69   UDate d;
70   for(i = 0;i<UCAL_FIELD_COUNT;i++) {
71     out += (UnicodeString("") + fieldName((UCalendarDateFields)i) + "=" +  cal.get((UCalendarDateFields)i, status) + UnicodeString(" "));
72   }
73   out += "[" + UnicodeString(cal.getType()) + "]";
74 
75   if(cal.inDaylightTime(status)) {
76     out += UnicodeString(" (in DST), zone=");
77   }
78   else {
79     out += UnicodeString(", zone=");
80   }
81 
82   UnicodeString str2;
83   out += cal.getTimeZone().getDisplayName(str2);
84   d = cal.getTime(status);
85   out += UnicodeString(" :","") + d;
86 
87   return out;
88 }
89 
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)90 void CalendarTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
91 {
92     if (exec) logln("TestSuite TestCalendar");
93 
94     TESTCASE_AUTO_BEGIN;
95     TESTCASE_AUTO(TestDOW943);
96     TESTCASE_AUTO(TestClonesUnique908);
97     TESTCASE_AUTO(TestGregorianChange768);
98     TESTCASE_AUTO(TestDisambiguation765);
99     TESTCASE_AUTO(TestGMTvsLocal4064654);
100     TESTCASE_AUTO(TestAddSetOrder621);
101     TESTCASE_AUTO(TestAdd520);
102     TESTCASE_AUTO(TestFieldSet4781);
103     //  TESTCASE_AUTO(TestSerialize337);
104     TESTCASE_AUTO(TestSecondsZero121);
105     TESTCASE_AUTO(TestAddSetGet0610);
106     TESTCASE_AUTO(TestFields060);
107     TESTCASE_AUTO(TestEpochStartFields);
108     TESTCASE_AUTO(TestDOWProgression);
109     TESTCASE_AUTO(TestGenericAPI);
110     TESTCASE_AUTO(TestAddRollExtensive);
111     TESTCASE_AUTO(TestDOW_LOCALandYEAR_WOY);
112     TESTCASE_AUTO(TestWOY);
113     TESTCASE_AUTO(TestRog);
114     TESTCASE_AUTO(TestYWOY);
115     TESTCASE_AUTO(TestJD);
116     TESTCASE_AUTO(TestDebug);
117     TESTCASE_AUTO(Test6703);
118     TESTCASE_AUTO(Test3785);
119     TESTCASE_AUTO(Test1624);
120     TESTCASE_AUTO(TestTimeStamp);
121     TESTCASE_AUTO(TestISO8601);
122     TESTCASE_AUTO(TestAmbiguousWallTimeAPIs);
123     TESTCASE_AUTO(TestRepeatedWallTime);
124     TESTCASE_AUTO(TestSkippedWallTime);
125     TESTCASE_AUTO(TestCloneLocale);
126     TESTCASE_AUTO(TestIslamicUmAlQura);
127     TESTCASE_AUTO(TestIslamicTabularDates);
128     TESTCASE_AUTO(TestHebrewMonthValidation);
129     TESTCASE_AUTO(TestWeekData);
130     TESTCASE_AUTO(TestAddAcrossZoneTransition);
131     TESTCASE_AUTO(TestChineseCalendarMapping);
132     TESTCASE_AUTO(TestTimeZoneInLocale);
133     TESTCASE_AUTO(TestBasicConversionISO8601);
134     TESTCASE_AUTO(TestBasicConversionJapanese);
135     TESTCASE_AUTO(TestBasicConversionBuddhist);
136     TESTCASE_AUTO(TestBasicConversionTaiwan);
137     TESTCASE_AUTO(TestBasicConversionPersian);
138     TESTCASE_AUTO(TestBasicConversionIslamic);
139     TESTCASE_AUTO(TestBasicConversionIslamicTBLA);
140     TESTCASE_AUTO(TestBasicConversionIslamicCivil);
141     TESTCASE_AUTO(TestBasicConversionIslamicRGSA);
142     TESTCASE_AUTO(TestBasicConversionIslamicUmalqura);
143     TESTCASE_AUTO(TestBasicConversionHebrew);
144     TESTCASE_AUTO(TestBasicConversionChinese);
145     TESTCASE_AUTO(TestBasicConversionDangi);
146     TESTCASE_AUTO(TestBasicConversionIndian);
147     TESTCASE_AUTO(TestBasicConversionCoptic);
148     TESTCASE_AUTO(TestBasicConversionEthiopic);
149     TESTCASE_AUTO(TestBasicConversionEthiopicAmeteAlem);
150     TESTCASE_AUTO(TestGregorianCalendarInTemporalLeapYear);
151     TESTCASE_AUTO(TestChineseCalendarInTemporalLeapYear);
152     TESTCASE_AUTO(TestDangiCalendarInTemporalLeapYear);
153     TESTCASE_AUTO(TestHebrewCalendarInTemporalLeapYear);
154     TESTCASE_AUTO(TestIslamicCalendarInTemporalLeapYear);
155     TESTCASE_AUTO(TestIslamicCivilCalendarInTemporalLeapYear);
156     TESTCASE_AUTO(TestIslamicUmalquraCalendarInTemporalLeapYear);
157     TESTCASE_AUTO(TestIslamicRGSACalendarInTemporalLeapYear);
158     TESTCASE_AUTO(TestIslamicTBLACalendarInTemporalLeapYear);
159     TESTCASE_AUTO(TestPersianCalendarInTemporalLeapYear);
160     TESTCASE_AUTO(TestIndianCalendarInTemporalLeapYear);
161     TESTCASE_AUTO(TestTaiwanCalendarInTemporalLeapYear);
162     TESTCASE_AUTO(TestJapaneseCalendarInTemporalLeapYear);
163     TESTCASE_AUTO(TestBuddhistCalendarInTemporalLeapYear);
164     TESTCASE_AUTO(TestCopticCalendarInTemporalLeapYear);
165     TESTCASE_AUTO(TestEthiopicCalendarInTemporalLeapYear);
166     TESTCASE_AUTO(TestEthiopicAmeteAlemCalendarInTemporalLeapYear);
167     TESTCASE_AUTO(TestChineseCalendarGetTemporalMonthCode);
168     TESTCASE_AUTO(TestDangiCalendarGetTemporalMonthCode);
169     TESTCASE_AUTO(TestHebrewCalendarGetTemporalMonthCode);
170     TESTCASE_AUTO(TestCopticCalendarGetTemporalMonthCode);
171     TESTCASE_AUTO(TestEthiopicCalendarGetTemporalMonthCode);
172     TESTCASE_AUTO(TestEthiopicAmeteAlemCalendarGetTemporalMonthCode);
173     TESTCASE_AUTO(TestGregorianCalendarSetTemporalMonthCode);
174     TESTCASE_AUTO(TestChineseCalendarSetTemporalMonthCode);
175     TESTCASE_AUTO(TestHebrewCalendarSetTemporalMonthCode);
176     TESTCASE_AUTO(TestCopticCalendarSetTemporalMonthCode);
177     TESTCASE_AUTO(TestEthiopicCalendarSetTemporalMonthCode);
178     TESTCASE_AUTO(TestMostCalendarsOrdinalMonthSet);
179     TESTCASE_AUTO(TestChineseCalendarOrdinalMonthSet);
180     TESTCASE_AUTO(TestDangiCalendarOrdinalMonthSet);
181     TESTCASE_AUTO(TestHebrewCalendarOrdinalMonthSet);
182     TESTCASE_AUTO(TestCalendarAddOrdinalMonth);
183     TESTCASE_AUTO(TestCalendarRollOrdinalMonth);
184     TESTCASE_AUTO(TestLimitsOrdinalMonth);
185     TESTCASE_AUTO(TestActualLimitsOrdinalMonth);
186     TESTCASE_AUTO(TestChineseCalendarMonthInSpecialYear);
187 
188     TESTCASE_AUTO_END;
189 }
190 
191 // ---------------------------------------------------------------------------------
192 
fieldName(UCalendarDateFields f)193 UnicodeString CalendarTest::fieldName(UCalendarDateFields f) {
194     switch (f) {
195 #define FIELD_NAME_STR(x) case x: return (#x)+5
196       FIELD_NAME_STR( UCAL_ERA );
197       FIELD_NAME_STR( UCAL_YEAR );
198       FIELD_NAME_STR( UCAL_MONTH );
199       FIELD_NAME_STR( UCAL_WEEK_OF_YEAR );
200       FIELD_NAME_STR( UCAL_WEEK_OF_MONTH );
201       FIELD_NAME_STR( UCAL_DATE );
202       FIELD_NAME_STR( UCAL_DAY_OF_YEAR );
203       FIELD_NAME_STR( UCAL_DAY_OF_WEEK );
204       FIELD_NAME_STR( UCAL_DAY_OF_WEEK_IN_MONTH );
205       FIELD_NAME_STR( UCAL_AM_PM );
206       FIELD_NAME_STR( UCAL_HOUR );
207       FIELD_NAME_STR( UCAL_HOUR_OF_DAY );
208       FIELD_NAME_STR( UCAL_MINUTE );
209       FIELD_NAME_STR( UCAL_SECOND );
210       FIELD_NAME_STR( UCAL_MILLISECOND );
211       FIELD_NAME_STR( UCAL_ZONE_OFFSET );
212       FIELD_NAME_STR( UCAL_DST_OFFSET );
213       FIELD_NAME_STR( UCAL_YEAR_WOY );
214       FIELD_NAME_STR( UCAL_DOW_LOCAL );
215       FIELD_NAME_STR( UCAL_EXTENDED_YEAR );
216       FIELD_NAME_STR( UCAL_JULIAN_DAY );
217       FIELD_NAME_STR( UCAL_MILLISECONDS_IN_DAY );
218 #undef FIELD_NAME_STR
219     default:
220         return UnicodeString("") + ((int32_t)f);
221     }
222 }
223 
224 /**
225  * Test various API methods for API completeness.
226  */
227 void
TestGenericAPI()228 CalendarTest::TestGenericAPI()
229 {
230     UErrorCode status = U_ZERO_ERROR;
231     UDate d;
232     UnicodeString str;
233     UBool eq = false,b4 = false,af = false;
234 
235     UDate when = date(90, UCAL_APRIL, 15);
236 
237     UnicodeString tzid("TestZone");
238     int32_t tzoffset = 123400;
239 
240     SimpleTimeZone *zone = new SimpleTimeZone(tzoffset, tzid);
241     Calendar *cal = Calendar::createInstance(zone->clone(), status);
242     if (failure(status, "Calendar::createInstance #1", true)) return;
243 
244     if (*zone != cal->getTimeZone()) errln("FAIL: Calendar::getTimeZone failed");
245 
246     Calendar *cal2 = Calendar::createInstance(cal->getTimeZone(), status);
247     if (failure(status, "Calendar::createInstance #2")) return;
248     cal->setTime(when, status);
249     cal2->setTime(when, status);
250     if (failure(status, "Calendar::setTime")) return;
251 
252     if (!(*cal == *cal2)) errln("FAIL: Calendar::operator== failed");
253     if ((*cal != *cal2))  errln("FAIL: Calendar::operator!= failed");
254     if (!cal->equals(*cal2, status) ||
255         cal->before(*cal2, status) ||
256         cal->after(*cal2, status) ||
257         U_FAILURE(status)) errln("FAIL: equals/before/after failed");
258 
259     logln(UnicodeString("cal=")  +cal->getTime(status)  + UnicodeString(calToStr(*cal)));
260     logln(UnicodeString("cal2=")  +cal2->getTime(status)  + UnicodeString(calToStr(*cal2)));
261     logln("cal2->setTime(when+1000)");
262     cal2->setTime(when + 1000, status);
263     logln(UnicodeString("cal2=")  +cal2->getTime(status)  + UnicodeString(calToStr(*cal2)));
264 
265     if (failure(status, "Calendar::setTime")) return;
266     if (cal->equals(*cal2, status) ||
267         cal2->before(*cal, status) ||
268         cal->after(*cal2, status) ||
269         U_FAILURE(status)) errln("FAIL: equals/before/after failed after setTime(+1000)");
270 
271     logln("cal->roll(UCAL_SECOND)");
272     cal->roll(UCAL_SECOND, (UBool) true, status);
273     logln(UnicodeString("cal=")  +cal->getTime(status)  + UnicodeString(calToStr(*cal)));
274     cal->roll(UCAL_SECOND, (int32_t)0, status);
275     logln(UnicodeString("cal=")  +cal->getTime(status)  + UnicodeString(calToStr(*cal)));
276     if (failure(status, "Calendar::roll")) return;
277 
278     if (!(eq=cal->equals(*cal2, status)) ||
279         (b4=cal->before(*cal2, status)) ||
280         (af=cal->after(*cal2, status)) ||
281         U_FAILURE(status)) {
282       errln("FAIL: equals[%c]/before[%c]/after[%c] failed after roll 1 second [should be T/F/F]",
283             eq?'T':'F',
284             b4?'T':'F',
285             af?'T':'F');
286       logln(UnicodeString("cal=")  +cal->getTime(status)  + UnicodeString(calToStr(*cal)));
287       logln(UnicodeString("cal2=")  +cal2->getTime(status)  + UnicodeString(calToStr(*cal2)));
288     }
289 
290     // Roll back to January
291     cal->roll(UCAL_MONTH, (int32_t)(1 + UCAL_DECEMBER - cal->get(UCAL_MONTH, status)), status);
292     if (failure(status, "Calendar::roll")) return;
293     if (cal->equals(*cal2, status) ||
294         cal2->before(*cal, status) ||
295         cal->after(*cal2, status) ||
296         U_FAILURE(status)) errln("FAIL: equals/before/after failed after rollback to January");
297 
298     TimeZone *z = cal->orphanTimeZone();
299     if (z->getID(str) != tzid ||
300         z->getRawOffset() != tzoffset)
301         errln("FAIL: orphanTimeZone failed");
302 
303     int32_t i;
304     for (i=0; i<2; ++i)
305     {
306         UBool lenient = ( i > 0 );
307         cal->setLenient(lenient);
308         if (lenient != cal->isLenient()) errln("FAIL: setLenient/isLenient failed");
309         // Later: Check for lenient behavior
310     }
311 
312     for (i=UCAL_SUNDAY; i<=UCAL_SATURDAY; ++i)
313     {
314         cal->setFirstDayOfWeek((UCalendarDaysOfWeek)i);
315         if (cal->getFirstDayOfWeek() != i) errln("FAIL: set/getFirstDayOfWeek failed");
316         UErrorCode aStatus = U_ZERO_ERROR;
317         if (cal->getFirstDayOfWeek(aStatus) != i || U_FAILURE(aStatus)) errln("FAIL: getFirstDayOfWeek(status) failed");
318     }
319 
320     for (i=1; i<=7; ++i)
321     {
322         cal->setMinimalDaysInFirstWeek((uint8_t)i);
323         if (cal->getMinimalDaysInFirstWeek() != i) errln("FAIL: set/getFirstDayOfWeek failed");
324     }
325 
326     for (i=0; i<UCAL_FIELD_COUNT; ++i)
327     {
328         if (cal->getMinimum((UCalendarDateFields)i) > cal->getGreatestMinimum((UCalendarDateFields)i))
329             errln(UnicodeString("FAIL: getMinimum larger than getGreatestMinimum for field ") + i);
330         if (cal->getLeastMaximum((UCalendarDateFields)i) > cal->getMaximum((UCalendarDateFields)i))
331             errln(UnicodeString("FAIL: getLeastMaximum larger than getMaximum for field ") + i);
332         if (cal->getMinimum((UCalendarDateFields)i) >= cal->getMaximum((UCalendarDateFields)i))
333             errln(UnicodeString("FAIL: getMinimum not less than getMaximum for field ") + i);
334     }
335 
336     cal->adoptTimeZone(TimeZone::createDefault());
337     cal->clear();
338     cal->set(1984, 5, 24);
339     if (cal->getTime(status) != date(84, 5, 24) || U_FAILURE(status))
340         errln("FAIL: Calendar::set(3 args) failed");
341 
342     cal->clear();
343     cal->set(1985, 3, 2, 11, 49);
344     if (cal->getTime(status) != date(85, 3, 2, 11, 49) || U_FAILURE(status))
345         errln("FAIL: Calendar::set(5 args) failed");
346 
347     cal->clear();
348     cal->set(1995, 9, 12, 1, 39, 55);
349     if (cal->getTime(status) != date(95, 9, 12, 1, 39, 55) || U_FAILURE(status))
350         errln("FAIL: Calendar::set(6 args) failed");
351 
352     cal->getTime(status);
353     if (failure(status, "Calendar::getTime")) return;
354     for (i=0; i<UCAL_FIELD_COUNT; ++i)
355     {
356         switch(i) {
357             case UCAL_YEAR: case UCAL_MONTH: case UCAL_DATE:
358             case UCAL_HOUR_OF_DAY: case UCAL_MINUTE: case UCAL_SECOND:
359             case UCAL_EXTENDED_YEAR:
360               if (!cal->isSet((UCalendarDateFields)i)) errln("FAIL: Calendar::isSet F, should be T " + fieldName((UCalendarDateFields)i));
361                 break;
362             default:
363               if (cal->isSet((UCalendarDateFields)i)) errln("FAIL: Calendar::isSet = T, should be F  " + fieldName((UCalendarDateFields)i));
364         }
365         cal->clear((UCalendarDateFields)i);
366         if (cal->isSet((UCalendarDateFields)i)) errln("FAIL: Calendar::clear/isSet failed " + fieldName((UCalendarDateFields)i));
367     }
368 
369     if(cal->getActualMinimum(Calendar::SECOND, status) != 0){
370         errln("Calendar is suppose to return 0 for getActualMinimum");
371     }
372 
373     Calendar *cal3 = Calendar::createInstance(status);
374     cal3->roll(Calendar::SECOND, (int32_t)0, status);
375     if (failure(status, "Calendar::roll(EDateFields, int32_t, UErrorCode)")) return;
376 
377     delete cal;
378     delete cal2;
379     delete cal3;
380 
381     int32_t count;
382     const Locale* loc = Calendar::getAvailableLocales(count);
383     if (count < 1 || loc == 0)
384     {
385         dataerrln("FAIL: getAvailableLocales failed");
386     }
387     else
388     {
389         for (i=0; i<count; ++i)
390         {
391             cal = Calendar::createInstance(loc[i], status);
392             if (U_FAILURE(status)) {
393                 errcheckln(status, UnicodeString("FAIL: Calendar::createInstance #3, locale ") +  loc[i].getName() + " , error " + u_errorName(status));
394                 return;
395             }
396             delete cal;
397         }
398     }
399 
400     cal = Calendar::createInstance(TimeZone::createDefault(), Locale::getEnglish(), status);
401     if (failure(status, "Calendar::createInstance #4")) return;
402     delete cal;
403 
404     cal = Calendar::createInstance(*zone, Locale::getEnglish(), status);
405     if (failure(status, "Calendar::createInstance #5")) return;
406     delete cal;
407 
408     GregorianCalendar *gc = new GregorianCalendar(*zone, status);
409     if (failure(status, "new GregorianCalendar")) return;
410     delete gc;
411 
412     gc = new GregorianCalendar(Locale::getEnglish(), status);
413     if (failure(status, "new GregorianCalendar")) return;
414     delete gc;
415 
416     gc = new GregorianCalendar(Locale::getEnglish(), status);
417     delete gc;
418 
419     gc = new GregorianCalendar(*zone, Locale::getEnglish(), status);
420     if (failure(status, "new GregorianCalendar")) return;
421     delete gc;
422 
423     gc = new GregorianCalendar(zone, status);
424     if (failure(status, "new GregorianCalendar")) return;
425     delete gc;
426 
427     gc = new GregorianCalendar(1998, 10, 14, 21, 43, status);
428     if (gc->getTime(status) != (d =date(98, 10, 14, 21, 43) )|| U_FAILURE(status))
429       errln("FAIL: new GregorianCalendar(ymdhm) failed with " + UnicodeString(u_errorName(status)) + ",  cal="  + gc->getTime(status)  + UnicodeString(calToStr(*gc)) + ", d=" + d);
430     else
431       logln(UnicodeString("GOOD: cal=")  +gc->getTime(status)  + UnicodeString(calToStr(*gc)) + ", d=" + d);
432     delete gc;
433 
434     gc = new GregorianCalendar(1998, 10, 14, 21, 43, 55, status);
435     if (gc->getTime(status) != (d=date(98, 10, 14, 21, 43, 55)) || U_FAILURE(status))
436       errln("FAIL: new GregorianCalendar(ymdhms) failed with " + UnicodeString(u_errorName(status)));
437 
438     GregorianCalendar gc2(Locale::getEnglish(), status);
439     if (failure(status, "new GregorianCalendar")) return;
440     gc2 = *gc;
441     if (gc2 != *gc || !(gc2 == *gc)) errln("FAIL: GregorianCalendar assignment/operator==/operator!= failed");
442     delete gc;
443     delete z;
444 
445     /* Code coverage for Calendar class. */
446     cal = Calendar::createInstance(status);
447     if (failure(status, "Calendar::createInstance #6")) {
448         return;
449     }else {
450         cal->roll(UCAL_HOUR, (int32_t)100, status);
451         cal->clear(UCAL_HOUR);
452 #if !UCONFIG_NO_SERVICE
453         URegistryKey key = cal->registerFactory(nullptr, status);
454         cal->unregister(key, status);
455 #endif
456     }
457     delete cal;
458 
459     status = U_ZERO_ERROR;
460     cal = Calendar::createInstance(Locale("he_IL@calendar=hebrew"), status);
461     if (failure(status, "Calendar::createInstance #7")) {
462         return;
463     } else {
464         cal->roll(Calendar::MONTH, (int32_t)100, status);
465     }
466 
467     LocalPointer<StringEnumeration> values(
468         Calendar::getKeywordValuesForLocale("calendar", Locale("he"), false, status));
469     if (values.isNull() || U_FAILURE(status)) {
470         dataerrln("FAIL: Calendar::getKeywordValuesForLocale(he): %s", u_errorName(status));
471     } else {
472         UBool containsHebrew = false;
473         const char *charValue;
474         int32_t valueLength;
475         while ((charValue = values->next(&valueLength, status)) != nullptr) {
476             if (valueLength == 6 && uprv_strcmp(charValue, "hebrew") == 0) {
477                 containsHebrew = true;
478             }
479         }
480         if (!containsHebrew) {
481             errln("Calendar::getKeywordValuesForLocale(he)->next() does not contain \"hebrew\"");
482         }
483 
484         values->reset(status);
485         containsHebrew = false;
486         UnicodeString hebrew = UNICODE_STRING_SIMPLE("hebrew");
487         const char16_t *ucharValue;
488         while ((ucharValue = values->unext(&valueLength, status)) != nullptr) {
489             UnicodeString value(false, ucharValue, valueLength);
490             if (value == hebrew) {
491                 containsHebrew = true;
492             }
493         }
494         if (!containsHebrew) {
495             errln("Calendar::getKeywordValuesForLocale(he)->unext() does not contain \"hebrew\"");
496         }
497 
498         values->reset(status);
499         containsHebrew = false;
500         const UnicodeString *stringValue;
501         while ((stringValue = values->snext(status)) != nullptr) {
502             if (*stringValue == hebrew) {
503                 containsHebrew = true;
504             }
505         }
506         if (!containsHebrew) {
507             errln("Calendar::getKeywordValuesForLocale(he)->snext() does not contain \"hebrew\"");
508         }
509     }
510     delete cal;
511 }
512 
513 // -------------------------------------
514 
515 /**
516  * This test confirms the correct behavior of add when incrementing
517  * through subsequent days.
518  */
519 void
TestRog()520 CalendarTest::TestRog()
521 {
522     UErrorCode status = U_ZERO_ERROR;
523     GregorianCalendar* gc = new GregorianCalendar(status);
524     if (failure(status, "new GregorianCalendar", true)) return;
525     int32_t year = 1997, month = UCAL_APRIL, date = 1;
526     gc->set(year, month, date);
527     gc->set(UCAL_HOUR_OF_DAY, 23);
528     gc->set(UCAL_MINUTE, 0);
529     gc->set(UCAL_SECOND, 0);
530     gc->set(UCAL_MILLISECOND, 0);
531     for (int32_t i = 0; i < 9; i++, gc->add(UCAL_DATE, 1, status)) {
532         if (U_FAILURE(status)) { errln("Calendar::add failed"); return; }
533         if (gc->get(UCAL_YEAR, status) != year ||
534             gc->get(UCAL_MONTH, status) != month ||
535             gc->get(UCAL_DATE, status) != (date + i)) errln("FAIL: Date wrong");
536         if (U_FAILURE(status)) { errln("Calendar::get failed"); return; }
537     }
538     delete gc;
539 }
540 
541 // -------------------------------------
542 
543 /**
544  * Test the handling of the day of the week, checking for correctness and
545  * for correct minimum and maximum values.
546  */
547 void
TestDOW943()548 CalendarTest::TestDOW943()
549 {
550     dowTest(false);
551     dowTest(true);
552 }
553 
dowTest(UBool lenient)554 void CalendarTest::dowTest(UBool lenient)
555 {
556     UErrorCode status = U_ZERO_ERROR;
557     GregorianCalendar* cal = new GregorianCalendar(status);
558     if (failure(status, "new GregorianCalendar", true)) return;
559     logln("cal - Aug 12, 1997\n");
560     cal->set(1997, UCAL_AUGUST, 12);
561     cal->getTime(status);
562     if (U_FAILURE(status)) { errln("Calendar::getTime failed"); return; }
563     logln((lenient?UnicodeString("LENIENT0: "):UnicodeString("nonlenient0: ")) + UnicodeString(calToStr(*cal)));
564     cal->setLenient(lenient);
565     logln("cal - Dec 1, 1996\n");
566     cal->set(1996, UCAL_DECEMBER, 1);
567     logln((lenient?UnicodeString("LENIENT: "):UnicodeString("nonlenient: ")) + UnicodeString(calToStr(*cal)));
568     int32_t dow = cal->get(UCAL_DAY_OF_WEEK, status);
569     if (U_FAILURE(status)) { errln("Calendar::get failed [%s]", u_errorName(status)); return; }
570     int32_t min = cal->getMinimum(UCAL_DAY_OF_WEEK);
571     int32_t max = cal->getMaximum(UCAL_DAY_OF_WEEK);
572     if (dow < min ||
573         dow > max) errln(UnicodeString("FAIL: Day of week ") + (int32_t)dow + " out of range");
574     if (dow != UCAL_SUNDAY) errln("FAIL: Day of week should be SUNDAY[%d] not %d", UCAL_SUNDAY, dow);
575     if (min != UCAL_SUNDAY ||
576         max != UCAL_SATURDAY) errln("FAIL: Min/max bad");
577     delete cal;
578 }
579 
580 // -------------------------------------
581 
582 /**
583  * Confirm that cloned Calendar objects do not inadvertently share substructures.
584  */
585 void
TestClonesUnique908()586 CalendarTest::TestClonesUnique908()
587 {
588     UErrorCode status = U_ZERO_ERROR;
589     Calendar *c = Calendar::createInstance(status);
590     if (failure(status, "Calendar::createInstance", true)) return;
591     Calendar *d = c->clone();
592     c->set(UCAL_MILLISECOND, 123);
593     d->set(UCAL_MILLISECOND, 456);
594     if (c->get(UCAL_MILLISECOND, status) != 123 ||
595         d->get(UCAL_MILLISECOND, status) != 456) {
596         errln("FAIL: Clones share fields");
597     }
598     if (U_FAILURE(status)) { errln("Calendar::get failed"); return; }
599     delete c;
600     delete d;
601 }
602 
603 // -------------------------------------
604 
605 /**
606  * Confirm that the Gregorian cutoff value works as advertised.
607  */
608 void
TestGregorianChange768()609 CalendarTest::TestGregorianChange768()
610 {
611     UBool b;
612     UErrorCode status = U_ZERO_ERROR;
613     UnicodeString str;
614     GregorianCalendar* c = new GregorianCalendar(status);
615     if (failure(status, "new GregorianCalendar", true)) return;
616     logln(UnicodeString("With cutoff ") + dateToString(c->getGregorianChange(), str));
617     b = c->isLeapYear(1800);
618     logln(UnicodeString(" isLeapYear(1800) = ") + (b ? "true" : "false"));
619     logln(UnicodeString(" (should be false)"));
620     if (b) errln("FAIL");
621     c->setGregorianChange(date(0, 0, 1), status);
622     if (U_FAILURE(status)) { errln("GregorianCalendar::setGregorianChange failed"); return; }
623     logln(UnicodeString("With cutoff ") + dateToString(c->getGregorianChange(), str));
624     b = c->isLeapYear(1800);
625     logln(UnicodeString(" isLeapYear(1800) = ") + (b ? "true" : "false"));
626     logln(UnicodeString(" (should be true)"));
627     if (!b) errln("FAIL");
628     delete c;
629 }
630 
631 // -------------------------------------
632 
633 /**
634  * Confirm the functioning of the field disambiguation algorithm.
635  */
636 void
TestDisambiguation765()637 CalendarTest::TestDisambiguation765()
638 {
639     UErrorCode status = U_ZERO_ERROR;
640     Calendar *c = Calendar::createInstance("en_US", status);
641     if (failure(status, "Calendar::createInstance", true)) return;
642     c->setLenient(false);
643     c->clear();
644     c->set(UCAL_YEAR, 1997);
645     c->set(UCAL_MONTH, UCAL_JUNE);
646     c->set(UCAL_DATE, 3);
647     verify765("1997 third day of June = ", c, 1997, UCAL_JUNE, 3);
648     c->clear();
649     c->set(UCAL_YEAR, 1997);
650     c->set(UCAL_DAY_OF_WEEK, UCAL_TUESDAY);
651     c->set(UCAL_MONTH, UCAL_JUNE);
652     c->set(UCAL_DAY_OF_WEEK_IN_MONTH, 1);
653     verify765("1997 first Tuesday in June = ", c, 1997, UCAL_JUNE, 3);
654     c->clear();
655     c->set(UCAL_YEAR, 1997);
656     c->set(UCAL_DAY_OF_WEEK, UCAL_TUESDAY);
657     c->set(UCAL_MONTH, UCAL_JUNE);
658     c->set(UCAL_DAY_OF_WEEK_IN_MONTH, - 1);
659     verify765("1997 last Tuesday in June = ", c, 1997, UCAL_JUNE, 24);
660 
661     status = U_ZERO_ERROR;
662     c->clear();
663     c->set(UCAL_YEAR, 1997);
664     c->set(UCAL_DAY_OF_WEEK, UCAL_TUESDAY);
665     c->set(UCAL_MONTH, UCAL_JUNE);
666     c->set(UCAL_DAY_OF_WEEK_IN_MONTH, 0);
667     c->getTime(status);
668     verify765("1997 zero-th Tuesday in June = ", status);
669 
670     c->clear();
671     c->set(UCAL_YEAR, 1997);
672     c->set(UCAL_DAY_OF_WEEK, UCAL_TUESDAY);
673     c->set(UCAL_MONTH, UCAL_JUNE);
674     c->set(UCAL_WEEK_OF_MONTH, 1);
675     verify765("1997 Tuesday in week 1 of June = ", c, 1997, UCAL_JUNE, 3);
676     c->clear();
677     c->set(UCAL_YEAR, 1997);
678     c->set(UCAL_DAY_OF_WEEK, UCAL_TUESDAY);
679     c->set(UCAL_MONTH, UCAL_JUNE);
680     c->set(UCAL_WEEK_OF_MONTH, 5);
681     verify765("1997 Tuesday in week 5 of June = ", c, 1997, UCAL_JULY, 1);
682 
683     status = U_ZERO_ERROR;
684     c->clear();
685     c->set(UCAL_YEAR, 1997);
686     c->set(UCAL_DAY_OF_WEEK, UCAL_TUESDAY);
687     c->set(UCAL_MONTH, UCAL_JUNE);
688     c->set(UCAL_WEEK_OF_MONTH, 0);
689     c->setMinimalDaysInFirstWeek(1);
690     c->getTime(status);
691     verify765("1997 Tuesday in week 0 of June = ", status);
692 
693     /* Note: The following test used to expect YEAR 1997, WOY 1 to
694      * resolve to a date in Dec 1996; that is, to behave as if
695      * YEAR_WOY were 1997.  With the addition of a new explicit
696      * YEAR_WOY field, YEAR_WOY must itself be set if that is what is
697      * desired.  Using YEAR in combination with WOY is ambiguous, and
698      * results in the first WOY/DOW day of the year satisfying the
699      * given fields (there may be up to two such days). In this case,
700      * it properly resolves to Tue Dec 30 1997, which has a WOY value
701      * of 1 (for YEAR_WOY 1998) and a DOW of Tuesday, and falls in the
702      * _calendar_ year 1997, as specified. - aliu */
703     c->clear();
704     c->set(UCAL_YEAR_WOY, 1997); // aliu
705     c->set(UCAL_DAY_OF_WEEK, UCAL_TUESDAY);
706     c->set(UCAL_WEEK_OF_YEAR, 1);
707     verify765("1997 Tuesday in week 1 of yearWOY = ", c, 1996, UCAL_DECEMBER, 31);
708     c->clear(); // - add test for YEAR
709     c->setMinimalDaysInFirstWeek(1);
710     c->set(UCAL_YEAR, 1997);
711     c->set(UCAL_DAY_OF_WEEK, UCAL_TUESDAY);
712     c->set(UCAL_WEEK_OF_YEAR, 1);
713     verify765("1997 Tuesday in week 1 of year = ", c, 1997, UCAL_DECEMBER, 30);
714     c->clear();
715     c->set(UCAL_YEAR, 1997);
716     c->set(UCAL_DAY_OF_WEEK, UCAL_TUESDAY);
717     c->set(UCAL_WEEK_OF_YEAR, 10);
718     verify765("1997 Tuesday in week 10 of year = ", c, 1997, UCAL_MARCH, 4);
719     //try {
720 
721     // {sfb} week 0 is no longer a valid week of year
722     /*c->clear();
723     c->set(Calendar::YEAR, 1997);
724     c->set(Calendar::DAY_OF_WEEK, Calendar::TUESDAY);
725     //c->set(Calendar::WEEK_OF_YEAR, 0);
726     c->set(Calendar::WEEK_OF_YEAR, 1);
727     verify765("1997 Tuesday in week 0 of year = ", c, 1996, Calendar::DECEMBER, 24);*/
728 
729     //}
730     //catch(IllegalArgumentException ex) {
731     //    errln("FAIL: Exception seen:");
732     //    ex.printStackTrace(log);
733     //}
734     delete c;
735 }
736 
737 // -------------------------------------
738 
739 void
verify765(const UnicodeString & msg,Calendar * c,int32_t year,int32_t month,int32_t day)740 CalendarTest::verify765(const UnicodeString& msg, Calendar* c, int32_t year, int32_t month, int32_t day)
741 {
742     UnicodeString str;
743     UErrorCode status = U_ZERO_ERROR;
744     int32_t y = c->get(UCAL_YEAR, status);
745     int32_t m = c->get(UCAL_MONTH, status);
746     int32_t d = c->get(UCAL_DATE, status);
747     if ( y == year &&
748          m == month &&
749          d == day) {
750         if (U_FAILURE(status)) { errln("FAIL: Calendar::get failed"); return; }
751         logln("PASS: " + msg + dateToString(c->getTime(status), str));
752         if (U_FAILURE(status)) { errln("Calendar::getTime failed"); return; }
753     }
754     else {
755         errln("FAIL: " + msg + dateToString(c->getTime(status), str) + "; expected " + (int32_t)year + "/" + (int32_t)(month + 1) + "/" + (int32_t)day +
756             "; got " + (int32_t)y + "/" + (int32_t)(m + 1) + "/" + (int32_t)d + " for Locale: " + c->getLocaleID(ULOC_ACTUAL_LOCALE,status));
757         if (U_FAILURE(status)) { errln("Calendar::getTime failed"); return; }
758     }
759 }
760 
761 // -------------------------------------
762 
763 void
verify765(const UnicodeString & msg,UErrorCode status)764 CalendarTest::verify765(const UnicodeString& msg/*, IllegalArgumentException e*/, UErrorCode status)
765 {
766     if (status != U_ILLEGAL_ARGUMENT_ERROR) errln("FAIL: No IllegalArgumentException for " + msg);
767     else logln("PASS: " + msg + "IllegalArgument as expected");
768 }
769 
770 // -------------------------------------
771 
772 /**
773  * Confirm that the offset between local time and GMT behaves as expected.
774  */
775 void
TestGMTvsLocal4064654()776 CalendarTest::TestGMTvsLocal4064654()
777 {
778     test4064654(1997, 1, 1, 12, 0, 0);
779     test4064654(1997, 4, 16, 18, 30, 0);
780 }
781 
782 // -------------------------------------
783 
784 void
test4064654(int32_t yr,int32_t mo,int32_t dt,int32_t hr,int32_t mn,int32_t sc)785 CalendarTest::test4064654(int32_t yr, int32_t mo, int32_t dt, int32_t hr, int32_t mn, int32_t sc)
786 {
787     UDate date;
788     UErrorCode status = U_ZERO_ERROR;
789     UnicodeString str;
790     Calendar *gmtcal = Calendar::createInstance(status);
791     if (failure(status, "Calendar::createInstance", true)) return;
792     gmtcal->adoptTimeZone(TimeZone::createTimeZone("Africa/Casablanca"));
793     gmtcal->set(yr, mo - 1, dt, hr, mn, sc);
794     gmtcal->set(UCAL_MILLISECOND, 0);
795     date = gmtcal->getTime(status);
796     if (U_FAILURE(status)) { errln("Calendar::getTime failed"); return; }
797     logln("date = " + dateToString(date, str));
798     Calendar *cal = Calendar::createInstance(status);
799     if (U_FAILURE(status)) { errln("Calendar::createInstance failed"); return; }
800     cal->setTime(date, status);
801     if (U_FAILURE(status)) { errln("Calendar::setTime failed"); return; }
802     int32_t offset = cal->getTimeZone().getOffset((uint8_t)cal->get(UCAL_ERA, status),
803                                                   cal->get(UCAL_YEAR, status),
804                                                   cal->get(UCAL_MONTH, status),
805                                                   cal->get(UCAL_DATE, status),
806                                                   (uint8_t)cal->get(UCAL_DAY_OF_WEEK, status),
807                                                   cal->get(UCAL_MILLISECOND, status), status);
808     if (U_FAILURE(status)) { errln("Calendar::get failed"); return; }
809     logln("offset for " + dateToString(date, str) + "= " + (offset / 1000 / 60 / 60.0) + "hr");
810     int32_t utc = ((cal->get(UCAL_HOUR_OF_DAY, status) * 60 +
811                     cal->get(UCAL_MINUTE, status)) * 60 +
812                    cal->get(UCAL_SECOND, status)) * 1000 +
813         cal->get(UCAL_MILLISECOND, status) - offset;
814     if (U_FAILURE(status)) { errln("Calendar::get failed"); return; }
815     int32_t expected = ((hr * 60 + mn) * 60 + sc) * 1000;
816     if (utc != expected) errln(UnicodeString("FAIL: Discrepancy of ") + (utc - expected) +
817                                " millis = " + ((utc - expected) / 1000 / 60 / 60.0) + " hr");
818     delete gmtcal;
819     delete cal;
820 }
821 
822 // -------------------------------------
823 
824 /**
825  * The operations of adding and setting should not exhibit pathological
826  * dependence on the order of operations.  This test checks for this.
827  */
828 void
TestAddSetOrder621()829 CalendarTest::TestAddSetOrder621()
830 {
831     UDate d = date(97, 4, 14, 13, 23, 45);
832     UErrorCode status = U_ZERO_ERROR;
833     Calendar *cal = Calendar::createInstance(status);
834     if (failure(status, "Calendar::createInstance", true)) return;
835 
836     cal->setTime(d, status);
837     if (U_FAILURE(status)) {
838         errln("Calendar::setTime failed");
839         delete cal;
840         return;
841     }
842     cal->add(UCAL_DATE, - 5, status);
843     if (U_FAILURE(status)) {
844         errln("Calendar::add failed");
845         delete cal;
846         return;
847     }
848     cal->set(UCAL_HOUR_OF_DAY, 0);
849     cal->set(UCAL_MINUTE, 0);
850     cal->set(UCAL_SECOND, 0);
851     UnicodeString s;
852     dateToString(cal->getTime(status), s);
853     if (U_FAILURE(status)) {
854         errln("Calendar::getTime failed");
855         delete cal;
856         return;
857     }
858     delete cal;
859 
860     cal = Calendar::createInstance(status);
861     if (U_FAILURE(status)) {
862         errln("Calendar::createInstance failed");
863         delete cal;
864         return;
865     }
866     cal->setTime(d, status);
867     if (U_FAILURE(status)) {
868         errln("Calendar::setTime failed");
869         delete cal;
870         return;
871     }
872     cal->set(UCAL_HOUR_OF_DAY, 0);
873     cal->set(UCAL_MINUTE, 0);
874     cal->set(UCAL_SECOND, 0);
875     cal->add(UCAL_DATE, - 5, status);
876     if (U_FAILURE(status)) {
877         errln("Calendar::add failed");
878         delete cal;
879         return;
880     }
881     UnicodeString s2;
882     dateToString(cal->getTime(status), s2);
883     if (U_FAILURE(status)) {
884         errln("Calendar::getTime failed");
885         delete cal;
886         return;
887     }
888     if (s == s2)
889         logln("Pass: " + s + " == " + s2);
890     else
891         errln("FAIL: " + s + " != " + s2);
892     delete cal;
893 }
894 
895 // -------------------------------------
896 
897 /**
898  * Confirm that adding to various fields works.
899  */
900 void
TestAdd520()901 CalendarTest::TestAdd520()
902 {
903     int32_t y = 1997, m = UCAL_FEBRUARY, d = 1;
904     UErrorCode status = U_ZERO_ERROR;
905     GregorianCalendar *temp = new GregorianCalendar(y, m, d, status);
906     if (failure(status, "new GregorianCalendar", true)) return;
907     check520(temp, y, m, d);
908     temp->add(UCAL_YEAR, 1, status);
909     if (U_FAILURE(status)) { errln("Calendar::add failed"); return; }
910     y++;
911     check520(temp, y, m, d);
912     temp->add(UCAL_MONTH, 1, status);
913     if (U_FAILURE(status)) { errln("Calendar::add failed"); return; }
914     m++;
915     check520(temp, y, m, d);
916     temp->add(UCAL_DATE, 1, status);
917     if (U_FAILURE(status)) { errln("Calendar::add failed"); return; }
918     d++;
919     check520(temp, y, m, d);
920     temp->add(UCAL_DATE, 2, status);
921     if (U_FAILURE(status)) { errln("Calendar::add failed"); return; }
922     d += 2;
923     check520(temp, y, m, d);
924     temp->add(UCAL_DATE, 28, status);
925     if (U_FAILURE(status)) { errln("Calendar::add failed"); return; }
926     d = 1;++m;
927     check520(temp, y, m, d);
928     delete temp;
929 }
930 
931 // -------------------------------------
932 
933 /**
934  * Execute adding and rolling in GregorianCalendar extensively,
935  */
936 void
TestAddRollExtensive()937 CalendarTest::TestAddRollExtensive()
938 {
939     int32_t maxlimit = 40;
940     int32_t y = 1997, m = UCAL_FEBRUARY, d = 1, hr = 1, min = 1, sec = 0, ms = 0;
941     UErrorCode status = U_ZERO_ERROR;
942     GregorianCalendar *temp = new GregorianCalendar(y, m, d, status);
943     if (failure(status, "new GregorianCalendar", true)) return;
944 
945     temp->set(UCAL_HOUR, hr);
946     temp->set(UCAL_MINUTE, min);
947     temp->set(UCAL_SECOND, sec);
948     temp->set(UCAL_MILLISECOND, ms);
949     temp->setMinimalDaysInFirstWeek(1);
950 
951     UCalendarDateFields e;
952 
953     logln("Testing GregorianCalendar add...");
954     e = UCAL_YEAR;
955     while (e < UCAL_FIELD_COUNT) {
956         int32_t i;
957         int32_t limit = maxlimit;
958         status = U_ZERO_ERROR;
959         for (i = 0; i < limit; i++) {
960             temp->add(e, 1, status);
961             if (U_FAILURE(status)) {
962                 limit = i;
963                 status = U_ZERO_ERROR;
964                 break;      // Suppress compile warning. Shouldn't be necessary, but it is.
965             }
966         }
967         for (i = 0; i < limit; i++) {
968             temp->add(e, -1, status);
969             if (U_FAILURE(status)) { errln("GregorianCalendar::add -1 failed"); return; }
970         }
971         check520(temp, y, m, d, hr, min, sec, ms, e);
972 
973         e = (UCalendarDateFields) ((int32_t) e + 1);
974     }
975 
976     logln("Testing GregorianCalendar roll...");
977     e = UCAL_YEAR;
978     while (e < UCAL_FIELD_COUNT) {
979         int32_t i;
980         int32_t limit = maxlimit;
981         status = U_ZERO_ERROR;
982         for (i = 0; i < limit; i++) {
983             logln(calToStr(*temp) + UnicodeString("  " ) + fieldName(e) + UnicodeString("++") );
984             temp->roll(e, 1, status);
985             if (U_FAILURE(status)) {
986               logln("caltest.cpp:%d e=%d, i=%d - roll(+) err %s\n",  __LINE__, (int) e, (int) i, u_errorName(status));
987               logln(calToStr(*temp));
988               limit = i; status = U_ZERO_ERROR;
989             }
990         }
991         for (i = 0; i < limit; i++) {
992             logln("caltest.cpp:%d e=%d, i=%d\n",  __LINE__, (int) e, (int) i);
993             logln(calToStr(*temp) + UnicodeString("  " ) + fieldName(e) + UnicodeString("--") );
994             temp->roll(e, -1, status);
995             if (U_FAILURE(status)) { errln(UnicodeString("GregorianCalendar::roll ") + CalendarTest::fieldName(e) + " count=" + UnicodeString('@'+i) + " by -1 failed with " + u_errorName(status) ); return; }
996         }
997         check520(temp, y, m, d, hr, min, sec, ms, e);
998 
999         e = (UCalendarDateFields) ((int32_t) e + 1);
1000     }
1001 
1002     delete temp;
1003 }
1004 
1005 // -------------------------------------
1006 void
check520(Calendar * c,int32_t y,int32_t m,int32_t d,int32_t hr,int32_t min,int32_t sec,int32_t ms,UCalendarDateFields field)1007 CalendarTest::check520(Calendar* c,
1008                         int32_t y, int32_t m, int32_t d,
1009                         int32_t hr, int32_t min, int32_t sec,
1010                         int32_t ms, UCalendarDateFields field)
1011 
1012 {
1013     UErrorCode status = U_ZERO_ERROR;
1014     if (c->get(UCAL_YEAR, status) != y ||
1015         c->get(UCAL_MONTH, status) != m ||
1016         c->get(UCAL_DATE, status) != d ||
1017         c->get(UCAL_HOUR, status) != hr ||
1018         c->get(UCAL_MINUTE, status) != min ||
1019         c->get(UCAL_SECOND, status) != sec ||
1020         c->get(UCAL_MILLISECOND, status) != ms) {
1021         errln(UnicodeString("U_FAILURE for field ") + (int32_t)field +
1022                 ": Expected y/m/d h:m:s:ms of " +
1023                 y + "/" + (m + 1) + "/" + d + " " +
1024               hr + ":" + min + ":" + sec + ":" + ms +
1025               "; got " + c->get(UCAL_YEAR, status) +
1026               "/" + (c->get(UCAL_MONTH, status) + 1) +
1027               "/" + c->get(UCAL_DATE, status) +
1028               " " + c->get(UCAL_HOUR, status) + ":" +
1029               c->get(UCAL_MINUTE, status) + ":" +
1030               c->get(UCAL_SECOND, status) + ":" +
1031               c->get(UCAL_MILLISECOND, status)
1032               );
1033 
1034         if (U_FAILURE(status)) { errln("Calendar::get failed"); return; }
1035     }
1036     else
1037         logln(UnicodeString("Confirmed: ") + y + "/" +
1038                 (m + 1) + "/" + d + " " +
1039                 hr + ":" + min + ":" + sec + ":" + ms);
1040 }
1041 
1042 // -------------------------------------
1043 void
check520(Calendar * c,int32_t y,int32_t m,int32_t d)1044 CalendarTest::check520(Calendar* c,
1045                         int32_t y, int32_t m, int32_t d)
1046 
1047 {
1048     UErrorCode status = U_ZERO_ERROR;
1049     if (c->get(UCAL_YEAR, status) != y ||
1050         c->get(UCAL_MONTH, status) != m ||
1051         c->get(UCAL_DATE, status) != d) {
1052         errln(UnicodeString("FAILURE: Expected y/m/d of ") +
1053               y + "/" + (m + 1) + "/" + d + " " +
1054               "; got " + c->get(UCAL_YEAR, status) +
1055               "/" + (c->get(UCAL_MONTH, status) + 1) +
1056               "/" + c->get(UCAL_DATE, status)
1057               );
1058 
1059         if (U_FAILURE(status)) { errln("Calendar::get failed"); return; }
1060     }
1061     else
1062         logln(UnicodeString("Confirmed: ") + y + "/" +
1063                 (m + 1) + "/" + d);
1064 }
1065 
1066 // -------------------------------------
1067 
1068 /**
1069  * Test that setting of fields works.  In particular, make sure that all instances
1070  * of GregorianCalendar don't share a static instance of the fields array.
1071  */
1072 void
TestFieldSet4781()1073 CalendarTest::TestFieldSet4781()
1074 {
1075     // try {
1076         UErrorCode status = U_ZERO_ERROR;
1077         GregorianCalendar *g = new GregorianCalendar(status);
1078         if (failure(status, "new GregorianCalendar", true)) return;
1079         GregorianCalendar *g2 = new GregorianCalendar(status);
1080         if (U_FAILURE(status)) { errln("Couldn't create GregorianCalendar"); return; }
1081         g2->set(UCAL_HOUR, 12, status);
1082         g2->set(UCAL_MINUTE, 0, status);
1083         g2->set(UCAL_SECOND, 0, status);
1084         if (U_FAILURE(status)) { errln("Calendar::set failed"); return; }
1085         if (*g == *g2) logln("Same");
1086         else logln("Different");
1087     //}
1088         //catch(IllegalArgumentException e) {
1089         //errln("Unexpected exception seen: " + e);
1090     //}
1091         delete g;
1092         delete g2;
1093 }
1094 
1095 // -------------------------------------
1096 
1097 /* We don't support serialization on C++
1098 void
1099 CalendarTest::TestSerialize337()
1100 {
1101     Calendar cal = Calendar::getInstance();
1102     UBool ok = false;
1103     try {
1104         FileOutputStream f = new FileOutputStream(FILENAME);
1105         ObjectOutput s = new ObjectOutputStream(f);
1106         s.writeObject(PREFIX);
1107         s.writeObject(cal);
1108         s.writeObject(POSTFIX);
1109         f.close();
1110         FileInputStream in = new FileInputStream(FILENAME);
1111         ObjectInputStream t = new ObjectInputStream(in);
1112         UnicodeString& pre = (UnicodeString&) t.readObject();
1113         Calendar c = (Calendar) t.readObject();
1114         UnicodeString& post = (UnicodeString&) t.readObject();
1115         in.close();
1116         ok = pre.equals(PREFIX) &&
1117             post.equals(POSTFIX) &&
1118             cal->equals(c);
1119         File fl = new File(FILENAME);
1120         fl.delete();
1121     }
1122     catch(IOException e) {
1123         errln("FAIL: Exception received:");
1124         e.printStackTrace(log);
1125     }
1126     catch(ClassNotFoundException e) {
1127         errln("FAIL: Exception received:");
1128         e.printStackTrace(log);
1129     }
1130     if (!ok) errln("Serialization of Calendar object failed.");
1131 }
1132 
1133 UnicodeString& CalendarTest::PREFIX = "abc";
1134 
1135 UnicodeString& CalendarTest::POSTFIX = "def";
1136 
1137 UnicodeString& CalendarTest::FILENAME = "tmp337.bin";
1138  */
1139 
1140 // -------------------------------------
1141 
1142 /**
1143  * Verify that the seconds of a Calendar can be zeroed out through the
1144  * expected sequence of operations.
1145  */
1146 void
TestSecondsZero121()1147 CalendarTest::TestSecondsZero121()
1148 {
1149     UErrorCode status = U_ZERO_ERROR;
1150     Calendar *cal = new GregorianCalendar(status);
1151     if (failure(status, "new GregorianCalendar", true)) return;
1152     cal->setTime(Calendar::getNow(), status);
1153     if (U_FAILURE(status)) { errln("Calendar::setTime failed"); return; }
1154     cal->set(UCAL_SECOND, 0);
1155     if (U_FAILURE(status)) { errln("Calendar::set failed"); return; }
1156     UDate d = cal->getTime(status);
1157     if (U_FAILURE(status)) { errln("Calendar::getTime failed"); return; }
1158     UnicodeString s;
1159     dateToString(d, s);
1160     if (s.indexOf("DATE_FORMAT_FAILURE") >= 0) {
1161         dataerrln("Got: \"DATE_FORMAT_FAILURE\".");
1162     } else if (s.indexOf(":00 ") < 0) {
1163         errln("Expected to see :00 in " + s);
1164     }
1165     delete cal;
1166 }
1167 
1168 // -------------------------------------
1169 
1170 /**
1171  * Verify that a specific sequence of adding and setting works as expected;
1172  * it should not vary depending on when and whether the get method is
1173  * called.
1174  */
1175 void
TestAddSetGet0610()1176 CalendarTest::TestAddSetGet0610()
1177 {
1178     UnicodeString EXPECTED_0610("1993/0/5", "");
1179     UErrorCode status = U_ZERO_ERROR;
1180     {
1181         Calendar *calendar = new GregorianCalendar(status);
1182         if (failure(status, "new GregorianCalendar", true)) return;
1183         calendar->set(1993, UCAL_JANUARY, 4);
1184         logln("1A) " + value(calendar));
1185         calendar->add(UCAL_DATE, 1, status);
1186         if (U_FAILURE(status)) { errln("Calendar::add failed"); return; }
1187         UnicodeString v = value(calendar);
1188         logln("1B) " + v);
1189         logln("--) 1993/0/5");
1190         if (!(v == EXPECTED_0610)) errln("Expected " + EXPECTED_0610 + "; saw " + v);
1191         delete calendar;
1192     }
1193     {
1194         Calendar *calendar = new GregorianCalendar(1993, UCAL_JANUARY, 4, status);
1195         if (U_FAILURE(status)) { errln("Couldn't create GregorianCalendar"); return; }
1196         logln("2A) " + value(calendar));
1197         calendar->add(UCAL_DATE, 1, status);
1198         if (U_FAILURE(status)) { errln("Calendar::add failed"); return; }
1199         UnicodeString v = value(calendar);
1200         logln("2B) " + v);
1201         logln("--) 1993/0/5");
1202         if (!(v == EXPECTED_0610)) errln("Expected " + EXPECTED_0610 + "; saw " + v);
1203         delete calendar;
1204     }
1205     {
1206         Calendar *calendar = new GregorianCalendar(1993, UCAL_JANUARY, 4, status);
1207         if (U_FAILURE(status)) { errln("Couldn't create GregorianCalendar"); return; }
1208         logln("3A) " + value(calendar));
1209         calendar->getTime(status);
1210         if (U_FAILURE(status)) { errln("Calendar::getTime failed"); return; }
1211         calendar->add(UCAL_DATE, 1, status);
1212         if (U_FAILURE(status)) { errln("Calendar::add failed"); return; }
1213         UnicodeString v = value(calendar);
1214         logln("3B) " + v);
1215         logln("--) 1993/0/5");
1216         if (!(v == EXPECTED_0610)) errln("Expected " + EXPECTED_0610 + "; saw " + v);
1217         delete calendar;
1218     }
1219 }
1220 
1221 // -------------------------------------
1222 
1223 UnicodeString
value(Calendar * calendar)1224 CalendarTest::value(Calendar* calendar)
1225 {
1226     UErrorCode status = U_ZERO_ERROR;
1227     return UnicodeString("") + (int32_t)calendar->get(UCAL_YEAR, status) +
1228         "/" + (int32_t)calendar->get(UCAL_MONTH, status) +
1229         "/" + (int32_t)calendar->get(UCAL_DATE, status) +
1230         (U_FAILURE(status) ? " FAIL: Calendar::get failed" : "");
1231 }
1232 
1233 
1234 // -------------------------------------
1235 
1236 /**
1237  * Verify that various fields on a known date are set correctly.
1238  */
1239 void
TestFields060()1240 CalendarTest::TestFields060()
1241 {
1242     UErrorCode status = U_ZERO_ERROR;
1243     int32_t year = 1997;
1244     int32_t month = UCAL_OCTOBER;
1245     int32_t dDate = 22;
1246     GregorianCalendar *calendar = 0;
1247     calendar = new GregorianCalendar(year, month, dDate, status);
1248     if (failure(status, "new GregorianCalendar", true)) return;
1249     for (int32_t i = 0; i < EXPECTED_FIELDS_length;) {
1250         UCalendarDateFields field = (UCalendarDateFields)EXPECTED_FIELDS[i++];
1251         int32_t expected = EXPECTED_FIELDS[i++];
1252         if (calendar->get(field, status) != expected) {
1253             errln(UnicodeString("Expected field ") + (int32_t)field + " to have value " + (int32_t)expected +
1254                   "; received " + (int32_t)calendar->get(field, status) + " instead");
1255             if (U_FAILURE(status)) { errln("Calendar::get failed"); return; }
1256         }
1257     }
1258     delete calendar;
1259 }
1260 
1261 int32_t CalendarTest::EXPECTED_FIELDS[] = {
1262     UCAL_YEAR, 1997,
1263     UCAL_MONTH, UCAL_OCTOBER,
1264     UCAL_DATE, 22,
1265     UCAL_DAY_OF_WEEK, UCAL_WEDNESDAY,
1266     UCAL_DAY_OF_WEEK_IN_MONTH, 4,
1267     UCAL_DAY_OF_YEAR, 295
1268 };
1269 
1270 const int32_t CalendarTest::EXPECTED_FIELDS_length = (int32_t)(sizeof(CalendarTest::EXPECTED_FIELDS) /
1271     sizeof(CalendarTest::EXPECTED_FIELDS[0]));
1272 
1273 // -------------------------------------
1274 
1275 /**
1276  * Verify that various fields on a known date are set correctly.  In this
1277  * case, the start of the epoch (January 1 1970).
1278  */
1279 void
TestEpochStartFields()1280 CalendarTest::TestEpochStartFields()
1281 {
1282     UErrorCode status = U_ZERO_ERROR;
1283     TimeZone *z = TimeZone::createDefault();
1284     Calendar *c = Calendar::createInstance(status);
1285     if (failure(status, "Calendar::createInstance", true)) return;
1286     UDate d = - z->getRawOffset();
1287     GregorianCalendar *gc = new GregorianCalendar(status);
1288     if (U_FAILURE(status)) { errln("Couldn't create GregorianCalendar"); return; }
1289     gc->setTimeZone(*z);
1290     gc->setTime(d, status);
1291     if (U_FAILURE(status)) { errln("Calendar::setTime failed"); return; }
1292     UBool idt = gc->inDaylightTime(status);
1293     if (U_FAILURE(status)) { errln("GregorianCalendar::inDaylightTime failed"); return; }
1294     if (idt) {
1295         UnicodeString str;
1296         logln("Warning: Skipping test because " + dateToString(d, str) + " is in DST.");
1297     }
1298     else {
1299         c->setTime(d, status);
1300         if (U_FAILURE(status)) { errln("Calendar::setTime failed"); return; }
1301         for (int32_t i = 0; i < UCAL_ZONE_OFFSET;++i) {
1302             if (c->get((UCalendarDateFields)i, status) != EPOCH_FIELDS[i])
1303                 dataerrln(UnicodeString("Expected field ") + i + " to have value " + EPOCH_FIELDS[i] +
1304                       "; saw " + c->get((UCalendarDateFields)i, status) + " instead");
1305             if (U_FAILURE(status)) { errln("Calendar::get failed"); return; }
1306         }
1307         if (c->get(UCAL_ZONE_OFFSET, status) != z->getRawOffset())
1308         {
1309             errln(UnicodeString("Expected field ZONE_OFFSET to have value ") + z->getRawOffset() +
1310                   "; saw " + c->get(UCAL_ZONE_OFFSET, status) + " instead");
1311             if (U_FAILURE(status)) { errln("Calendar::get failed"); return; }
1312         }
1313         if (c->get(UCAL_DST_OFFSET, status) != 0)
1314         {
1315             errln(UnicodeString("Expected field DST_OFFSET to have value 0") +
1316                   "; saw " + c->get(UCAL_DST_OFFSET, status) + " instead");
1317             if (U_FAILURE(status)) { errln("Calendar::get failed"); return; }
1318         }
1319     }
1320     delete c;
1321     delete z;
1322     delete gc;
1323 }
1324 
1325 int32_t CalendarTest::EPOCH_FIELDS[] = {
1326     1, 1970, 0, 1, 1, 1, 1, 5, 1, 0, 0, 0, 0, 0, 0, - 28800000, 0
1327 };
1328 
1329 // -------------------------------------
1330 
1331 /**
1332  * Test that the days of the week progress properly when add is called repeatedly
1333  * for increments of 24 days.
1334  */
1335 void
TestDOWProgression()1336 CalendarTest::TestDOWProgression()
1337 {
1338     UErrorCode status = U_ZERO_ERROR;
1339     Calendar *cal = new GregorianCalendar(1972, UCAL_OCTOBER, 26, status);
1340     if (failure(status, "new GregorianCalendar", true)) return;
1341     marchByDelta(cal, 24);
1342     delete cal;
1343 }
1344 
1345 // -------------------------------------
1346 
1347 void
TestDOW_LOCALandYEAR_WOY()1348 CalendarTest::TestDOW_LOCALandYEAR_WOY()
1349 {
1350     /* Note: I've commented out the loop_addroll tests for YEAR and
1351      * YEAR_WOY below because these two fields should NOT behave
1352      * identically when adding.  YEAR should keep the month/dom
1353      * invariant.  YEAR_WOY should keep the woy/dow invariant.  I've
1354      * added a new test that checks for this in place of the old call
1355      * to loop_addroll. - aliu */
1356     UErrorCode status = U_ZERO_ERROR;
1357     int32_t times = 20;
1358     Calendar *cal=Calendar::createInstance(Locale::getGermany(), status);
1359     if (failure(status, "Calendar::createInstance", true)) return;
1360     SimpleDateFormat *sdf=new SimpleDateFormat(UnicodeString("YYYY'-W'ww-ee"), Locale::getGermany(), status);
1361     if (U_FAILURE(status)) { dataerrln("Couldn't create SimpleDateFormat - %s", u_errorName(status)); return; }
1362 
1363     // ICU no longer use localized date-time pattern characters by default.
1364     // So we set pattern chars using 'J' instead of 'Y'.
1365     DateFormatSymbols *dfs = new DateFormatSymbols(Locale::getGermany(), status);
1366     dfs->setLocalPatternChars(UnicodeString("GyMdkHmsSEDFwWahKzJeugAZvcLQq"));
1367     sdf->adoptDateFormatSymbols(dfs);
1368     sdf->applyLocalizedPattern(UnicodeString("JJJJ'-W'ww-ee"), status);
1369     if (U_FAILURE(status)) { errln("Couldn't apply localized pattern"); return; }
1370 
1371     cal->clear();
1372     cal->set(1997, UCAL_DECEMBER, 25);
1373     doYEAR_WOYLoop(cal, sdf, times, status);
1374     //loop_addroll(cal, /*sdf,*/ times, UCAL_YEAR_WOY, UCAL_YEAR,  status);
1375     yearAddTest(*cal, status); // aliu
1376     loop_addroll(cal, /*sdf,*/ times, UCAL_DOW_LOCAL, UCAL_DAY_OF_WEEK, status);
1377     if (U_FAILURE(status)) { errln("Error in parse/calculate test for 1997"); return; }
1378 
1379     cal->clear();
1380     cal->set(1998, UCAL_DECEMBER, 25);
1381     doYEAR_WOYLoop(cal, sdf, times, status);
1382     //loop_addroll(cal, /*sdf,*/ times, UCAL_YEAR_WOY, UCAL_YEAR,  status);
1383     yearAddTest(*cal, status); // aliu
1384     loop_addroll(cal, /*sdf,*/ times, UCAL_DOW_LOCAL, UCAL_DAY_OF_WEEK, status);
1385     if (U_FAILURE(status)) { errln("Error in parse/calculate test for 1998"); return; }
1386 
1387     cal->clear();
1388     cal->set(1582, UCAL_OCTOBER, 1);
1389     doYEAR_WOYLoop(cal, sdf, times, status);
1390     //loop_addroll(cal, /*sdf,*/ times, Calendar::YEAR_WOY, Calendar::YEAR,  status);
1391     yearAddTest(*cal, status); // aliu
1392     loop_addroll(cal, /*sdf,*/ times, UCAL_DOW_LOCAL, UCAL_DAY_OF_WEEK, status);
1393     if (U_FAILURE(status)) { errln("Error in parse/calculate test for 1582"); return; }
1394     delete sdf;
1395     delete cal;
1396 
1397     return;
1398 }
1399 
1400 /**
1401  * Confirm that adding a YEAR and adding a YEAR_WOY work properly for
1402  * the given Calendar at its current setting.
1403  */
yearAddTest(Calendar & cal,UErrorCode & status)1404 void CalendarTest::yearAddTest(Calendar& cal, UErrorCode& status) {
1405     /**
1406      * When adding the YEAR, the month and day should remain constant.
1407      * When adding the YEAR_WOY, the WOY and DOW should remain constant. - aliu
1408      * Examples:
1409      *  Wed Jan 14 1998 / 1998-W03-03 Add(YEAR_WOY, 1) -> Wed Jan 20 1999 / 1999-W03-03
1410      *                                Add(YEAR, 1)     -> Thu Jan 14 1999 / 1999-W02-04
1411      *  Thu Jan 14 1999 / 1999-W02-04 Add(YEAR_WOY, 1) -> Thu Jan 13 2000 / 2000-W02-04
1412      *                                Add(YEAR, 1)     -> Fri Jan 14 2000 / 2000-W02-05
1413      *  Sun Oct 31 1582 / 1582-W42-07 Add(YEAR_WOY, 1) -> Sun Oct 23 1583 / 1583-W42-07
1414      *                                Add(YEAR, 1)     -> Mon Oct 31 1583 / 1583-W44-01
1415      */
1416     int32_t y   = cal.get(UCAL_YEAR, status);
1417     int32_t mon = cal.get(UCAL_MONTH, status);
1418     int32_t day = cal.get(UCAL_DATE, status);
1419     int32_t ywy = cal.get(UCAL_YEAR_WOY, status);
1420     int32_t woy = cal.get(UCAL_WEEK_OF_YEAR, status);
1421     int32_t dow = cal.get(UCAL_DOW_LOCAL, status);
1422     UDate t = cal.getTime(status);
1423 
1424     if(U_FAILURE(status)){
1425         errln(UnicodeString("Failed to create Calendar for locale. Error: ") + UnicodeString(u_errorName(status)));
1426         return;
1427     }
1428     UnicodeString str, str2;
1429     SimpleDateFormat fmt(UnicodeString("EEE MMM dd yyyy / YYYY'-W'ww-ee"), status);
1430     fmt.setCalendar(cal);
1431 
1432     fmt.format(t, str.remove());
1433     str += ".add(YEAR, 1)    =>";
1434     cal.add(UCAL_YEAR, 1, status);
1435     int32_t y2   = cal.get(UCAL_YEAR, status);
1436     int32_t mon2 = cal.get(UCAL_MONTH, status);
1437     int32_t day2 = cal.get(UCAL_DATE, status);
1438     fmt.format(cal.getTime(status), str);
1439     if (y2 != (y+1) || mon2 != mon || day2 != day) {
1440         str += (UnicodeString)", expected year " +
1441             (y+1) + ", month " + (mon+1) + ", day " + day;
1442         errln((UnicodeString)"FAIL: " + str);
1443         logln( UnicodeString(" -> ") + CalendarTest::calToStr(cal) );
1444     } else {
1445         logln(str);
1446     }
1447 
1448     fmt.format(t, str.remove());
1449     str += ".add(YEAR_WOY, 1)=>";
1450     cal.setTime(t, status);
1451     logln( UnicodeString(" <- ") + CalendarTest::calToStr(cal) );
1452     cal.add(UCAL_YEAR_WOY, 1, status);
1453     int32_t ywy2 = cal.get(UCAL_YEAR_WOY, status);
1454     int32_t woy2 = cal.get(UCAL_WEEK_OF_YEAR, status);
1455     int32_t dow2 = cal.get(UCAL_DOW_LOCAL, status);
1456     fmt.format(cal.getTime(status), str);
1457     if (ywy2 != (ywy+1) || woy2 != woy || dow2 != dow) {
1458         str += (UnicodeString)", expected yearWOY " +
1459             (ywy+1) + ", woy " + woy + ", dowLocal " + dow;
1460         errln((UnicodeString)"FAIL: " + str);
1461         logln( UnicodeString(" -> ") + CalendarTest::calToStr(cal) );
1462     } else {
1463         logln(str);
1464     }
1465 }
1466 
1467 // -------------------------------------
1468 
loop_addroll(Calendar * cal,int times,UCalendarDateFields field,UCalendarDateFields field2,UErrorCode & errorCode)1469 void CalendarTest::loop_addroll(Calendar *cal, /*SimpleDateFormat *sdf,*/ int times, UCalendarDateFields field, UCalendarDateFields field2, UErrorCode& errorCode) {
1470     Calendar *calclone;
1471     SimpleDateFormat fmt(UnicodeString("EEE MMM dd yyyy / YYYY'-W'ww-ee"), errorCode);
1472     fmt.setCalendar(*cal);
1473     int i;
1474 
1475     for(i = 0; i<times; i++) {
1476         calclone = cal->clone();
1477         UDate start = cal->getTime(errorCode);
1478         cal->add(field,1,errorCode);
1479         if (U_FAILURE(errorCode)) { errln("Error in add"); delete calclone; return; }
1480         calclone->add(field2,1,errorCode);
1481         if (U_FAILURE(errorCode)) { errln("Error in add"); delete calclone; return; }
1482         if(cal->getTime(errorCode) != calclone->getTime(errorCode)) {
1483             UnicodeString str("FAIL: Results of add differ. "), str2;
1484             str += fmt.format(start, str2) + " ";
1485             str += UnicodeString("Add(") + fieldName(field) + ", 1) -> " +
1486                 fmt.format(cal->getTime(errorCode), str2.remove()) + "; ";
1487             str += UnicodeString("Add(") + fieldName(field2) + ", 1) -> " +
1488                 fmt.format(calclone->getTime(errorCode), str2.remove());
1489             errln(str);
1490             delete calclone;
1491             return;
1492         }
1493         delete calclone;
1494     }
1495 
1496     for(i = 0; i<times; i++) {
1497         calclone = cal->clone();
1498         cal->roll(field,(int32_t)1,errorCode);
1499         if (U_FAILURE(errorCode)) { errln("Error in roll"); delete calclone; return; }
1500         calclone->roll(field2,(int32_t)1,errorCode);
1501         if (U_FAILURE(errorCode)) { errln("Error in roll"); delete calclone; return; }
1502         if(cal->getTime(errorCode) != calclone->getTime(errorCode)) {
1503             delete calclone;
1504             errln("Results of roll differ!");
1505             return;
1506         }
1507         delete calclone;
1508     }
1509 }
1510 
1511 // -------------------------------------
1512 
1513 void
doYEAR_WOYLoop(Calendar * cal,SimpleDateFormat * sdf,int32_t times,UErrorCode & errorCode)1514 CalendarTest::doYEAR_WOYLoop(Calendar *cal, SimpleDateFormat *sdf,
1515                                     int32_t times, UErrorCode& errorCode) {
1516 
1517     UnicodeString us;
1518     UDate tst, original;
1519     Calendar *tstres = new GregorianCalendar(Locale::getGermany(), errorCode);
1520     for(int i=0; i<times; ++i) {
1521         sdf->format(Formattable(cal->getTime(errorCode),Formattable::kIsDate), us, errorCode);
1522         //logln("expected: "+us);
1523         if (U_FAILURE(errorCode)) { errln("Format error"); return; }
1524         tst=sdf->parse(us,errorCode);
1525         if (U_FAILURE(errorCode)) { errln("Parse error"); return; }
1526         tstres->clear();
1527         tstres->setTime(tst, errorCode);
1528         //logln((UnicodeString)"Parsed week of year is "+tstres->get(UCAL_WEEK_OF_YEAR, errorCode));
1529         if (U_FAILURE(errorCode)) { errln("Set time error"); return; }
1530         original = cal->getTime(errorCode);
1531         us.remove();
1532         sdf->format(Formattable(tst,Formattable::kIsDate), us, errorCode);
1533         //logln("got: "+us);
1534         if (U_FAILURE(errorCode)) { errln("Get time error"); return; }
1535         if(original!=tst) {
1536             us.remove();
1537             sdf->format(Formattable(original, Formattable::kIsDate), us, errorCode);
1538             errln("FAIL: Parsed time doesn't match with regular");
1539             logln("expected "+us + " " + calToStr(*cal));
1540             us.remove();
1541             sdf->format(Formattable(tst, Formattable::kIsDate), us, errorCode);
1542             logln("got "+us + " " + calToStr(*tstres));
1543         }
1544         tstres->clear();
1545         tstres->set(UCAL_YEAR_WOY, cal->get(UCAL_YEAR_WOY, errorCode));
1546         tstres->set(UCAL_WEEK_OF_YEAR, cal->get(UCAL_WEEK_OF_YEAR, errorCode));
1547         tstres->set(UCAL_DOW_LOCAL, cal->get(UCAL_DOW_LOCAL, errorCode));
1548         if(cal->get(UCAL_YEAR, errorCode) != tstres->get(UCAL_YEAR, errorCode)) {
1549             errln("FAIL: Different Year!");
1550             logln((UnicodeString)"Expected "+cal->get(UCAL_YEAR, errorCode));
1551             logln((UnicodeString)"Got "+tstres->get(UCAL_YEAR, errorCode));
1552             return;
1553         }
1554         if(cal->get(UCAL_DAY_OF_YEAR, errorCode) != tstres->get(UCAL_DAY_OF_YEAR, errorCode)) {
1555             errln("FAIL: Different Day Of Year!");
1556             logln((UnicodeString)"Expected "+cal->get(UCAL_DAY_OF_YEAR, errorCode));
1557             logln((UnicodeString)"Got "+tstres->get(UCAL_DAY_OF_YEAR, errorCode));
1558             return;
1559         }
1560         //logln(calToStr(*cal));
1561         cal->add(UCAL_DATE, 1, errorCode);
1562         if (U_FAILURE(errorCode)) { errln("Add error"); return; }
1563         us.remove();
1564     }
1565     delete (tstres);
1566 }
1567 // -------------------------------------
1568 
1569 void
marchByDelta(Calendar * cal,int32_t delta)1570 CalendarTest::marchByDelta(Calendar* cal, int32_t delta)
1571 {
1572     UErrorCode status = U_ZERO_ERROR;
1573     Calendar *cur = cal->clone();
1574     int32_t initialDOW = cur->get(UCAL_DAY_OF_WEEK, status);
1575     if (U_FAILURE(status)) { errln("Calendar::get failed"); return; }
1576     int32_t DOW, newDOW = initialDOW;
1577     do {
1578         UnicodeString str;
1579         DOW = newDOW;
1580         logln(UnicodeString("DOW = ") + DOW + "  " + dateToString(cur->getTime(status), str));
1581         if (U_FAILURE(status)) { errln("Calendar::getTime failed"); return; }
1582         cur->add(UCAL_DAY_OF_WEEK, delta, status);
1583         if (U_FAILURE(status)) { errln("Calendar::add failed"); return; }
1584         newDOW = cur->get(UCAL_DAY_OF_WEEK, status);
1585         if (U_FAILURE(status)) { errln("Calendar::get failed"); return; }
1586         int32_t expectedDOW = 1 + (DOW + delta - 1) % 7;
1587         if (newDOW != expectedDOW) {
1588             errln(UnicodeString("Day of week should be ") + expectedDOW + " instead of " + newDOW +
1589                   " on " + dateToString(cur->getTime(status), str));
1590             if (U_FAILURE(status)) { errln("Calendar::getTime failed"); return; }
1591             return;
1592         }
1593     }
1594     while (newDOW != initialDOW);
1595     delete cur;
1596 }
1597 
1598 #define CHECK(status, msg) UPRV_BLOCK_MACRO_BEGIN { \
1599     if (U_FAILURE(status)) { \
1600         errcheckln(status, msg); \
1601         return; \
1602     } \
1603 } UPRV_BLOCK_MACRO_END
1604 
TestWOY()1605 void CalendarTest::TestWOY() {
1606     /*
1607       FDW = Mon, MDFW = 4:
1608          Sun Dec 26 1999, WOY 51
1609          Mon Dec 27 1999, WOY 52
1610          Tue Dec 28 1999, WOY 52
1611          Wed Dec 29 1999, WOY 52
1612          Thu Dec 30 1999, WOY 52
1613          Fri Dec 31 1999, WOY 52
1614          Sat Jan 01 2000, WOY 52 ***
1615          Sun Jan 02 2000, WOY 52 ***
1616          Mon Jan 03 2000, WOY 1
1617          Tue Jan 04 2000, WOY 1
1618          Wed Jan 05 2000, WOY 1
1619          Thu Jan 06 2000, WOY 1
1620          Fri Jan 07 2000, WOY 1
1621          Sat Jan 08 2000, WOY 1
1622          Sun Jan 09 2000, WOY 1
1623          Mon Jan 10 2000, WOY 2
1624 
1625       FDW = Mon, MDFW = 2:
1626          Sun Dec 26 1999, WOY 52
1627          Mon Dec 27 1999, WOY 1  ***
1628          Tue Dec 28 1999, WOY 1  ***
1629          Wed Dec 29 1999, WOY 1  ***
1630          Thu Dec 30 1999, WOY 1  ***
1631          Fri Dec 31 1999, WOY 1  ***
1632          Sat Jan 01 2000, WOY 1
1633          Sun Jan 02 2000, WOY 1
1634          Mon Jan 03 2000, WOY 2
1635          Tue Jan 04 2000, WOY 2
1636          Wed Jan 05 2000, WOY 2
1637          Thu Jan 06 2000, WOY 2
1638          Fri Jan 07 2000, WOY 2
1639          Sat Jan 08 2000, WOY 2
1640          Sun Jan 09 2000, WOY 2
1641          Mon Jan 10 2000, WOY 3
1642     */
1643 
1644     UnicodeString str;
1645     UErrorCode status = U_ZERO_ERROR;
1646     int32_t i;
1647 
1648     GregorianCalendar cal(status);
1649     SimpleDateFormat fmt(UnicodeString("EEE MMM dd yyyy', WOY' w"), status);
1650     if (failure(status, "Cannot construct calendar/format", true)) return;
1651 
1652     UCalendarDaysOfWeek fdw = (UCalendarDaysOfWeek) 0;
1653 
1654     //for (int8_t pass=2; pass<=2; ++pass) {
1655     for (int8_t pass=1; pass<=2; ++pass) {
1656         switch (pass) {
1657         case 1:
1658             fdw = UCAL_MONDAY;
1659             cal.setFirstDayOfWeek(fdw);
1660             cal.setMinimalDaysInFirstWeek(4);
1661             fmt.adoptCalendar(cal.clone());
1662             break;
1663         case 2:
1664             fdw = UCAL_MONDAY;
1665             cal.setFirstDayOfWeek(fdw);
1666             cal.setMinimalDaysInFirstWeek(2);
1667             fmt.adoptCalendar(cal.clone());
1668             break;
1669         }
1670 
1671         //for (i=2; i<=6; ++i) {
1672         for (i=0; i<16; ++i) {
1673         UDate t, t2;
1674         int32_t t_y, t_woy, t_dow;
1675         cal.clear();
1676         cal.set(1999, UCAL_DECEMBER, 26 + i);
1677         fmt.format(t = cal.getTime(status), str.remove());
1678         CHECK(status, "Fail: getTime failed");
1679         logln(UnicodeString("* ") + str);
1680         int32_t dow = cal.get(UCAL_DAY_OF_WEEK, status);
1681         int32_t woy = cal.get(UCAL_WEEK_OF_YEAR, status);
1682         int32_t year = cal.get(UCAL_YEAR, status);
1683         int32_t mon = cal.get(UCAL_MONTH, status);
1684         logln(calToStr(cal));
1685         CHECK(status, "Fail: get failed");
1686         int32_t dowLocal = dow - fdw;
1687         if (dowLocal < 0) dowLocal += 7;
1688         dowLocal++;
1689         int32_t yearWoy = year;
1690         if (mon == UCAL_JANUARY) {
1691             if (woy >= 52) --yearWoy;
1692         } else {
1693             if (woy == 1) ++yearWoy;
1694         }
1695 
1696         // Basic fields->time check y/woy/dow
1697         // Since Y/WOY is ambiguous, we do a check of the fields,
1698         // not of the specific time.
1699         cal.clear();
1700         cal.set(UCAL_YEAR, year);
1701         cal.set(UCAL_WEEK_OF_YEAR, woy);
1702         cal.set(UCAL_DAY_OF_WEEK, dow);
1703         t_y = cal.get(UCAL_YEAR, status);
1704         t_woy = cal.get(UCAL_WEEK_OF_YEAR, status);
1705         t_dow = cal.get(UCAL_DAY_OF_WEEK, status);
1706         CHECK(status, "Fail: get failed");
1707         if (t_y != year || t_woy != woy || t_dow != dow) {
1708             str = "Fail: y/woy/dow fields->time => ";
1709             fmt.format(cal.getTime(status), str);
1710             errln(str);
1711             logln(calToStr(cal));
1712             logln("[get!=set] Y%d!=%d || woy%d!=%d || dow%d!=%d\n",
1713                   t_y, year, t_woy, woy, t_dow, dow);
1714         } else {
1715           logln("y/woy/dow fields->time OK");
1716         }
1717 
1718         // Basic fields->time check y/woy/dow_local
1719         // Since Y/WOY is ambiguous, we do a check of the fields,
1720         // not of the specific time.
1721         cal.clear();
1722         cal.set(UCAL_YEAR, year);
1723         cal.set(UCAL_WEEK_OF_YEAR, woy);
1724         cal.set(UCAL_DOW_LOCAL, dowLocal);
1725         t_y = cal.get(UCAL_YEAR, status);
1726         t_woy = cal.get(UCAL_WEEK_OF_YEAR, status);
1727         t_dow = cal.get(UCAL_DOW_LOCAL, status);
1728         CHECK(status, "Fail: get failed");
1729         if (t_y != year || t_woy != woy || t_dow != dowLocal) {
1730             str = "Fail: y/woy/dow_local fields->time => ";
1731             fmt.format(cal.getTime(status), str);
1732             errln(str);
1733         }
1734 
1735         // Basic fields->time check y_woy/woy/dow
1736         cal.clear();
1737         cal.set(UCAL_YEAR_WOY, yearWoy);
1738         cal.set(UCAL_WEEK_OF_YEAR, woy);
1739         cal.set(UCAL_DAY_OF_WEEK, dow);
1740         t2 = cal.getTime(status);
1741         CHECK(status, "Fail: getTime failed");
1742         if (t != t2) {
1743             str = "Fail: y_woy/woy/dow fields->time => ";
1744             fmt.format(t2, str);
1745             errln(str);
1746             logln(calToStr(cal));
1747             logln("%.f != %.f\n", t, t2);
1748         } else {
1749           logln("y_woy/woy/dow OK");
1750         }
1751 
1752         // Basic fields->time check y_woy/woy/dow_local
1753         cal.clear();
1754         cal.set(UCAL_YEAR_WOY, yearWoy);
1755         cal.set(UCAL_WEEK_OF_YEAR, woy);
1756         cal.set(UCAL_DOW_LOCAL, dowLocal);
1757         t2 = cal.getTime(status);
1758         CHECK(status, "Fail: getTime failed");
1759         if (t != t2) {
1760             str = "Fail: y_woy/woy/dow_local fields->time => ";
1761             fmt.format(t2, str);
1762             errln(str);
1763         }
1764 
1765         logln("Testing DOW_LOCAL.. dow%d\n", dow);
1766         // Make sure DOW_LOCAL disambiguates over DOW
1767         int32_t wrongDow = dow - 3;
1768         if (wrongDow < 1) wrongDow += 7;
1769         cal.setTime(t, status);
1770         cal.set(UCAL_DAY_OF_WEEK, wrongDow);
1771         cal.set(UCAL_DOW_LOCAL, dowLocal);
1772         t2 = cal.getTime(status);
1773         CHECK(status, "Fail: set/getTime failed");
1774         if (t != t2) {
1775             str = "Fail: DOW_LOCAL fields->time => ";
1776             fmt.format(t2, str);
1777             errln(str);
1778             logln(calToStr(cal));
1779             logln("%.f :   DOW%d, DOW_LOCAL%d -> %.f\n",
1780                   t, wrongDow, dowLocal, t2);
1781         }
1782 
1783         // Make sure DOW disambiguates over DOW_LOCAL
1784         int32_t wrongDowLocal = dowLocal - 3;
1785         if (wrongDowLocal < 1) wrongDowLocal += 7;
1786         cal.setTime(t, status);
1787         cal.set(UCAL_DOW_LOCAL, wrongDowLocal);
1788         cal.set(UCAL_DAY_OF_WEEK, dow);
1789         t2 = cal.getTime(status);
1790         CHECK(status, "Fail: set/getTime failed");
1791         if (t != t2) {
1792             str = "Fail: DOW       fields->time => ";
1793             fmt.format(t2, str);
1794             errln(str);
1795         }
1796 
1797         // Make sure YEAR_WOY disambiguates over YEAR
1798         cal.setTime(t, status);
1799         cal.set(UCAL_YEAR, year - 2);
1800         cal.set(UCAL_YEAR_WOY, yearWoy);
1801         t2 = cal.getTime(status);
1802         CHECK(status, "Fail: set/getTime failed");
1803         if (t != t2) {
1804             str = "Fail: YEAR_WOY  fields->time => ";
1805             fmt.format(t2, str);
1806             errln(str);
1807         }
1808 
1809         // Make sure YEAR disambiguates over YEAR_WOY
1810         cal.setTime(t, status);
1811         cal.set(UCAL_YEAR_WOY, yearWoy - 2);
1812         cal.set(UCAL_YEAR, year);
1813         t2 = cal.getTime(status);
1814         CHECK(status, "Fail: set/getTime failed");
1815         if (t != t2) {
1816             str = "Fail: YEAR      fields->time => ";
1817             fmt.format(t2, str);
1818             errln(str);
1819         }
1820     }
1821     }
1822 
1823     /*
1824       FDW = Mon, MDFW = 4:
1825          Sun Dec 26 1999, WOY 51
1826          Mon Dec 27 1999, WOY 52
1827          Tue Dec 28 1999, WOY 52
1828          Wed Dec 29 1999, WOY 52
1829          Thu Dec 30 1999, WOY 52
1830          Fri Dec 31 1999, WOY 52
1831          Sat Jan 01 2000, WOY 52
1832          Sun Jan 02 2000, WOY 52
1833     */
1834 
1835     // Roll the DOW_LOCAL within week 52
1836     for (i=27; i<=33; ++i) {
1837         int32_t amount;
1838         for (amount=-7; amount<=7; ++amount) {
1839             str = "roll(";
1840             cal.set(1999, UCAL_DECEMBER, i);
1841             UDate t, t2;
1842             fmt.format(cal.getTime(status), str);
1843             CHECK(status, "Fail: getTime failed");
1844             str += UnicodeString(", ") + amount + ") = ";
1845 
1846             cal.roll(UCAL_DOW_LOCAL, amount, status);
1847             CHECK(status, "Fail: roll failed");
1848 
1849             t = cal.getTime(status);
1850             int32_t newDom = i + amount;
1851             while (newDom < 27) newDom += 7;
1852             while (newDom > 33) newDom -= 7;
1853             cal.set(1999, UCAL_DECEMBER, newDom);
1854             t2 = cal.getTime(status);
1855             CHECK(status, "Fail: getTime failed");
1856             fmt.format(t, str);
1857 
1858             if (t != t2) {
1859                 str.append(", exp ");
1860                 fmt.format(t2, str);
1861                 errln(str);
1862             } else {
1863                 logln(str);
1864             }
1865         }
1866     }
1867 }
1868 
TestYWOY()1869 void CalendarTest::TestYWOY()
1870 {
1871    UnicodeString str;
1872    UErrorCode status = U_ZERO_ERROR;
1873 
1874    GregorianCalendar cal(status);
1875    if (failure(status, "construct GregorianCalendar", true)) return;
1876 
1877    cal.setFirstDayOfWeek(UCAL_SUNDAY);
1878    cal.setMinimalDaysInFirstWeek(1);
1879 
1880    logln("Setting:  ywoy=2004, woy=1, dow=MONDAY");
1881    cal.clear();
1882    cal.set(UCAL_YEAR_WOY,2004);
1883    cal.set(UCAL_WEEK_OF_YEAR,1);
1884    cal.set(UCAL_DAY_OF_WEEK, UCAL_MONDAY);
1885 
1886    logln(calToStr(cal));
1887    if(cal.get(UCAL_YEAR, status) != 2003) {
1888      errln("year not 2003");
1889    }
1890 
1891    logln("+ setting DOW to THURSDAY");
1892    cal.clear();
1893    cal.set(UCAL_YEAR_WOY,2004);
1894    cal.set(UCAL_WEEK_OF_YEAR,1);
1895    cal.set(UCAL_DAY_OF_WEEK, UCAL_THURSDAY);
1896 
1897    logln(calToStr(cal));
1898    if(cal.get(UCAL_YEAR, status) != 2004) {
1899      errln("year not 2004");
1900    }
1901 
1902    logln("+ setting DOW_LOCAL to 1");
1903    cal.clear();
1904    cal.set(UCAL_YEAR_WOY,2004);
1905    cal.set(UCAL_WEEK_OF_YEAR,1);
1906    cal.set(UCAL_DAY_OF_WEEK, UCAL_THURSDAY);
1907    cal.set(UCAL_DOW_LOCAL, 1);
1908 
1909    logln(calToStr(cal));
1910    if(cal.get(UCAL_YEAR, status) != 2003) {
1911      errln("year not 2003");
1912    }
1913 
1914    cal.setFirstDayOfWeek(UCAL_MONDAY);
1915    cal.setMinimalDaysInFirstWeek(4);
1916    UDate t = 946713600000.;
1917    cal.setTime(t, status);
1918    cal.set(UCAL_DAY_OF_WEEK, 4);
1919    cal.set(UCAL_DOW_LOCAL, 6);
1920    if(cal.getTime(status) != t) {
1921      logln(calToStr(cal));
1922      errln("FAIL:  DOW_LOCAL did not take precedence");
1923    }
1924 
1925 }
1926 
TestJD()1927 void CalendarTest::TestJD()
1928 {
1929   int32_t jd;
1930   static const int32_t kEpochStartAsJulianDay = 2440588;
1931   UErrorCode status = U_ZERO_ERROR;
1932   GregorianCalendar cal(status);
1933   if (failure(status, "construct GregorianCalendar", true)) return;
1934   cal.setTimeZone(*TimeZone::getGMT());
1935   cal.clear();
1936   jd = cal.get(UCAL_JULIAN_DAY, status);
1937   if(jd != kEpochStartAsJulianDay) {
1938     errln("Wanted JD of %d at time=0, [epoch 1970] but got %d\n", kEpochStartAsJulianDay, jd);
1939   } else {
1940     logln("Wanted JD of %d at time=0, [epoch 1970], got %d\n", kEpochStartAsJulianDay, jd);
1941   }
1942 
1943   cal.setTime(Calendar::getNow(), status);
1944   cal.clear();
1945   cal.set(UCAL_JULIAN_DAY, kEpochStartAsJulianDay);
1946   UDate epochTime = cal.getTime(status);
1947   if(epochTime != 0) {
1948     errln("Wanted time of 0 at jd=%d, got %.1lf\n", kEpochStartAsJulianDay, epochTime);
1949   } else {
1950     logln("Wanted time of 0 at jd=%d, got %.1lf\n", kEpochStartAsJulianDay, epochTime);
1951   }
1952 
1953 }
1954 
1955 // make sure the ctestfw utilities are in sync with the Calendar
TestDebug()1956 void CalendarTest::TestDebug()
1957 {
1958     for(int32_t  t=0;t<=UDBG_ENUM_COUNT;t++) {
1959         int32_t count = udbg_enumCount((UDebugEnumType)t);
1960         if(count == -1) {
1961             logln("enumCount(%d) returned -1", count);
1962             continue;
1963         }
1964         for(int32_t i=0;i<=count;i++) {
1965             if(t<=UDBG_HIGHEST_CONTIGUOUS_ENUM && i<count) {
1966                 if( i!=udbg_enumArrayValue((UDebugEnumType)t, i)) {
1967                     errln("FAIL: udbg_enumArrayValue(%d,%d) returned %d, expected %d", t, i, udbg_enumArrayValue((UDebugEnumType)t,i), i);
1968                 }
1969             } else {
1970                 logln("Testing count+1:");
1971             }
1972                   const char *name = udbg_enumName((UDebugEnumType)t,i);
1973                   if(name==nullptr) {
1974                           if(i==count || t>UDBG_HIGHEST_CONTIGUOUS_ENUM  ) {
1975                                 logln(" null name - expected.\n");
1976                           } else {
1977                                 errln("FAIL: udbg_enumName(%d,%d) returned nullptr", t, i);
1978                           }
1979                           name = "(null)";
1980                   }
1981           logln("udbg_enumArrayValue(%d,%d) = %s, returned %d", t, i,
1982                       name, udbg_enumArrayValue((UDebugEnumType)t,i));
1983             logln("udbg_enumString = " + udbg_enumString((UDebugEnumType)t,i));
1984         }
1985         if(udbg_enumExpectedCount((UDebugEnumType)t) != count && t<=UDBG_HIGHEST_CONTIGUOUS_ENUM) {
1986             errln("FAIL: udbg_enumExpectedCount(%d): %d, != UCAL_FIELD_COUNT=%d ", t, udbg_enumExpectedCount((UDebugEnumType)t), count);
1987         } else {
1988             logln("udbg_ucal_fieldCount: %d, UCAL_FIELD_COUNT=udbg_enumCount %d ", udbg_enumExpectedCount((UDebugEnumType)t), count);
1989         }
1990     }
1991 }
1992 
1993 
1994 #undef CHECK
1995 
1996 // List of interesting locales
testLocaleID(int32_t i)1997 const char *CalendarTest::testLocaleID(int32_t i)
1998 {
1999   switch(i) {
2000   case 0: return "he_IL@calendar=hebrew";
2001   case 1: return "en_US@calendar=hebrew";
2002   case 2: return "fr_FR@calendar=hebrew";
2003   case 3: return "fi_FI@calendar=hebrew";
2004   case 4: return "nl_NL@calendar=hebrew";
2005   case 5: return "hu_HU@calendar=hebrew";
2006   case 6: return "nl_BE@currency=MTL;calendar=islamic";
2007   case 7: return "th_TH_TRADITIONAL@calendar=gregorian";
2008   case 8: return "ar_JO@calendar=islamic-civil";
2009   case 9: return "fi_FI@calendar=islamic";
2010   case 10: return "fr_CH@calendar=islamic-civil";
2011   case 11: return "he_IL@calendar=islamic-civil";
2012   case 12: return "hu_HU@calendar=buddhist";
2013   case 13: return "hu_HU@calendar=islamic";
2014   case 14: return "en_US@calendar=japanese";
2015   default: return nullptr;
2016   }
2017 }
2018 
testLocaleCount()2019 int32_t CalendarTest::testLocaleCount()
2020 {
2021   static int32_t gLocaleCount = -1;
2022   if(gLocaleCount < 0) {
2023     int32_t i;
2024     for(i=0;testLocaleID(i) != nullptr;i++) {
2025       // do nothing
2026     }
2027     gLocaleCount = i;
2028   }
2029   return gLocaleCount;
2030 }
2031 
doMinDateOfCalendar(Calendar * adopt,UBool & isGregorian,UErrorCode & status)2032 static UDate doMinDateOfCalendar(Calendar* adopt, UBool &isGregorian, UErrorCode& status) {
2033   if(U_FAILURE(status)) return 0.0;
2034 
2035   adopt->clear();
2036   adopt->set(UCAL_EXTENDED_YEAR, adopt->getActualMinimum(UCAL_EXTENDED_YEAR, status));
2037   UDate ret = adopt->getTime(status);
2038   isGregorian = dynamic_cast<GregorianCalendar*>(adopt) != nullptr;
2039   delete adopt;
2040   return ret;
2041 }
2042 
minDateOfCalendar(const Locale & locale,UBool & isGregorian,UErrorCode & status)2043 UDate CalendarTest::minDateOfCalendar(const Locale& locale, UBool &isGregorian, UErrorCode& status) {
2044   if(U_FAILURE(status)) return 0.0;
2045   return doMinDateOfCalendar(Calendar::createInstance(locale, status), isGregorian, status);
2046 }
2047 
minDateOfCalendar(const Calendar & cal,UBool & isGregorian,UErrorCode & status)2048 UDate CalendarTest::minDateOfCalendar(const Calendar& cal, UBool &isGregorian, UErrorCode& status) {
2049   if(U_FAILURE(status)) return 0.0;
2050   return doMinDateOfCalendar(cal.clone(), isGregorian, status);
2051 }
2052 
Test6703()2053 void CalendarTest::Test6703()
2054 {
2055     UErrorCode status = U_ZERO_ERROR;
2056     Calendar *cal;
2057 
2058     Locale loc1("en@calendar=fubar");
2059     cal = Calendar::createInstance(loc1, status);
2060     if (failure(status, "Calendar::createInstance", true)) return;
2061     delete cal;
2062 
2063     status = U_ZERO_ERROR;
2064     Locale loc2("en");
2065     cal = Calendar::createInstance(loc2, status);
2066     if (failure(status, "Calendar::createInstance")) return;
2067     delete cal;
2068 
2069     status = U_ZERO_ERROR;
2070     Locale loc3("en@calendar=roc");
2071     cal = Calendar::createInstance(loc3, status);
2072     if (failure(status, "Calendar::createInstance")) return;
2073     delete cal;
2074 
2075     return;
2076 }
2077 
Test3785()2078 void CalendarTest::Test3785()
2079 {
2080     UErrorCode status = U_ZERO_ERROR;
2081     UnicodeString uzone = UNICODE_STRING_SIMPLE("Europe/Paris");
2082     UnicodeString exp1 = UNICODE_STRING_SIMPLE("Mon 30 Jumada II 1433 AH, 01:47:03");
2083     UnicodeString exp2 = UNICODE_STRING_SIMPLE("Mon 1 Rajab 1433 AH, 01:47:04");
2084 
2085     LocalUDateFormatPointer df(udat_open(UDAT_NONE, UDAT_NONE, "en@calendar=islamic", uzone.getTerminatedBuffer(),
2086                                          uzone.length(), nullptr, 0, &status));
2087     if (df.isNull() || U_FAILURE(status)) return;
2088 
2089     char16_t upattern[64];
2090     u_uastrcpy(upattern, "EEE d MMMM y G, HH:mm:ss");
2091     udat_applyPattern(df.getAlias(), false, upattern, u_strlen(upattern));
2092 
2093     char16_t ubuffer[1024];
2094     UDate ud0 = 1337557623000.0;
2095 
2096     status = U_ZERO_ERROR;
2097     udat_format(df.getAlias(), ud0, ubuffer, 1024, nullptr, &status);
2098     if (U_FAILURE(status)) {
2099         errln("Error formatting date 1\n");
2100         return;
2101     }
2102     //printf("formatted: '%s'\n", mkcstr(ubuffer));
2103 
2104     UnicodeString act1(ubuffer);
2105     if ( act1 != exp1 ) {
2106         errln("Unexpected result from date 1 format\n");
2107     }
2108     ud0 += 1000.0; // add one second
2109 
2110     status = U_ZERO_ERROR;
2111     udat_format(df.getAlias(), ud0, ubuffer, 1024, nullptr, &status);
2112     if (U_FAILURE(status)) {
2113         errln("Error formatting date 2\n");
2114         return;
2115     }
2116     //printf("formatted: '%s'\n", mkcstr(ubuffer));
2117     UnicodeString act2(ubuffer);
2118     if ( act2 != exp2 ) {
2119         errln("Unexpected result from date 2 format\n");
2120     }
2121 
2122     return;
2123 }
2124 
Test1624()2125 void CalendarTest::Test1624() {
2126     UErrorCode status = U_ZERO_ERROR;
2127     Locale loc("he_IL@calendar=hebrew");
2128     HebrewCalendar hc(loc,status);
2129 
2130     for (int32_t year = 5600; year < 5800; year++ ) {
2131 
2132         for (int32_t month = HebrewCalendar::TISHRI; month <= HebrewCalendar::ELUL; month++) {
2133             // skip the adar 1 month if year is not a leap year
2134             if (HebrewCalendar::isLeapYear(year) == false && month == HebrewCalendar::ADAR_1) {
2135                 continue;
2136             }
2137             int32_t day = 15;
2138             hc.set(year,month,day);
2139             int32_t dayHC = hc.get(UCAL_DATE,status);
2140             int32_t monthHC = hc.get(UCAL_MONTH,status);
2141             int32_t yearHC = hc.get(UCAL_YEAR,status);
2142 
2143             if (failure(status, "HebrewCalendar.get()", true)) continue;
2144 
2145             if (dayHC != day) {
2146                 errln(" ==> day %d incorrect, should be: %d\n",dayHC,day);
2147                 break;
2148             }
2149             if (monthHC != month) {
2150                 errln(" ==> month %d incorrect, should be: %d\n",monthHC,month);
2151                 break;
2152             }
2153             if (yearHC != year) {
2154                 errln(" ==> day %d incorrect, should be: %d\n",yearHC,year);
2155                 break;
2156             }
2157         }
2158     }
2159     return;
2160 }
2161 
TestTimeStamp()2162 void CalendarTest::TestTimeStamp() {
2163     UErrorCode status = U_ZERO_ERROR;
2164     UDate start = 0.0, time;
2165     Calendar *cal;
2166 
2167     // Create a new Gregorian Calendar.
2168     cal = Calendar::createInstance("en_US@calendar=gregorian", status);
2169     if (U_FAILURE(status)) {
2170         dataerrln("Error creating Gregorian calendar.");
2171         return;
2172     }
2173 
2174     for (int i = 0; i < 20000; i++) {
2175         // Set the Gregorian Calendar to a specific date for testing.
2176         cal->set(2009, UCAL_JULY, 3, 0, 49, 46);
2177 
2178         time = cal->getTime(status);
2179         if (U_FAILURE(status)) {
2180             errln("Error calling getTime()");
2181             break;
2182         }
2183 
2184         if (i == 0) {
2185             start = time;
2186         } else {
2187             if (start != time) {
2188                 errln("start and time not equal.");
2189                 break;
2190             }
2191         }
2192     }
2193 
2194     delete cal;
2195 }
2196 
TestISO8601()2197 void CalendarTest::TestISO8601() {
2198     const char* TEST_LOCALES[] = {
2199         "en_US@calendar=iso8601",
2200         "en_US@calendar=Iso8601",
2201         "th_TH@calendar=iso8601",
2202         "ar_EG@calendar=iso8601",
2203         nullptr
2204     };
2205 
2206     int32_t TEST_DATA[][3] = {
2207         {2008, 1, 2008},
2208         {2009, 1, 2009},
2209         {2010, 53, 2009},
2210         {2011, 52, 2010},
2211         {2012, 52, 2011},
2212         {2013, 1, 2013},
2213         {2014, 1, 2014},
2214         {0, 0, 0},
2215     };
2216 
2217     for (int i = 0; TEST_LOCALES[i] != nullptr; i++) {
2218         UErrorCode status = U_ZERO_ERROR;
2219         Calendar *cal = Calendar::createInstance(TEST_LOCALES[i], status);
2220         if (U_FAILURE(status)) {
2221             errln("Error: Failed to create a calendar for locale: %s", TEST_LOCALES[i]);
2222             continue;
2223         }
2224         if (uprv_strcmp(cal->getType(), "iso8601") != 0) {
2225             errln("Error: iso8601 calendar is not used for locale: %s", TEST_LOCALES[i]);
2226             continue;
2227         }
2228         for (int j = 0; TEST_DATA[j][0] != 0; j++) {
2229             cal->set(TEST_DATA[j][0], UCAL_JANUARY, 1);
2230             int32_t weekNum = cal->get(UCAL_WEEK_OF_YEAR, status);
2231             int32_t weekYear = cal->get(UCAL_YEAR_WOY, status);
2232             if (U_FAILURE(status)) {
2233                 errln("Error: Failed to get week of year");
2234                 break;
2235             }
2236             if (weekNum != TEST_DATA[j][1] || weekYear != TEST_DATA[j][2]) {
2237                 errln("Error: Incorrect week of year on January 1st, %d for locale %s: Returned [weekNum=%d, weekYear=%d], Expected [weekNum=%d, weekYear=%d]",
2238                     TEST_DATA[j][0], TEST_LOCALES[i], weekNum, weekYear, TEST_DATA[j][1], TEST_DATA[j][2]);
2239             }
2240         }
2241         delete cal;
2242     }
2243 
2244 }
2245 
2246 void
TestAmbiguousWallTimeAPIs()2247 CalendarTest::TestAmbiguousWallTimeAPIs() {
2248     UErrorCode status = U_ZERO_ERROR;
2249     Calendar* cal = Calendar::createInstance(status);
2250     if (U_FAILURE(status)) {
2251         errln("Fail: Error creating a calendar instance.");
2252         return;
2253     }
2254 
2255     if (cal->getRepeatedWallTimeOption() != UCAL_WALLTIME_LAST) {
2256         errln("Fail: Default repeted time option is not UCAL_WALLTIME_LAST");
2257     }
2258     if (cal->getSkippedWallTimeOption() != UCAL_WALLTIME_LAST) {
2259         errln("Fail: Default skipped time option is not UCAL_WALLTIME_LAST");
2260     }
2261 
2262     Calendar* cal2 = cal->clone();
2263 
2264     if (*cal != *cal2) {
2265         errln("Fail: Cloned calendar != the original");
2266     }
2267     if (!cal->equals(*cal2, status)) {
2268         errln("Fail: The time of cloned calendar is not equal to the original");
2269     } else if (U_FAILURE(status)) {
2270         errln("Fail: Error equals");
2271     }
2272     status = U_ZERO_ERROR;
2273 
2274     cal2->setRepeatedWallTimeOption(UCAL_WALLTIME_FIRST);
2275     cal2->setSkippedWallTimeOption(UCAL_WALLTIME_FIRST);
2276 
2277     if (*cal == *cal2) {
2278         errln("Fail: Cloned and modified calendar == the original");
2279     }
2280     if (!cal->equals(*cal2, status)) {
2281         errln("Fail: The time of cloned calendar is not equal to the original after changing wall time options");
2282     } else if (U_FAILURE(status)) {
2283         errln("Fail: Error equals after changing wall time options");
2284     }
2285     status = U_ZERO_ERROR;
2286 
2287     if (cal2->getRepeatedWallTimeOption() != UCAL_WALLTIME_FIRST) {
2288         errln("Fail: Repeted time option is not UCAL_WALLTIME_FIRST");
2289     }
2290     if (cal2->getSkippedWallTimeOption() != UCAL_WALLTIME_FIRST) {
2291         errln("Fail: Skipped time option is not UCAL_WALLTIME_FIRST");
2292     }
2293 
2294     cal2->setRepeatedWallTimeOption(UCAL_WALLTIME_NEXT_VALID);
2295     if (cal2->getRepeatedWallTimeOption() != UCAL_WALLTIME_FIRST) {
2296         errln("Fail: Repeated wall time option was updated other than UCAL_WALLTIME_FIRST");
2297     }
2298 
2299     delete cal;
2300     delete cal2;
2301 }
2302 
2303 class CalFields {
2304 public:
2305     CalFields(int32_t year, int32_t month, int32_t day, int32_t hour, int32_t min, int32_t sec, int32_t ms = 0);
2306     CalFields(const Calendar& cal, UErrorCode& status);
2307     void setTo(Calendar& cal) const;
2308     char* toString(char* buf, int32_t len) const;
2309     bool operator==(const CalFields& rhs) const;
2310     bool operator!=(const CalFields& rhs) const;
2311     UBool isEquivalentTo(const Calendar& cal, UErrorCode& status) const;
2312 
2313 private:
2314     int32_t year;
2315     int32_t month;
2316     int32_t day;
2317     int32_t hour;
2318     int32_t min;
2319     int32_t sec;
2320     int32_t ms;
2321 };
2322 
CalFields(int32_t year,int32_t month,int32_t day,int32_t hour,int32_t min,int32_t sec,int32_t ms)2323 CalFields::CalFields(int32_t year, int32_t month, int32_t day, int32_t hour, int32_t min, int32_t sec, int32_t ms)
2324     : year(year), month(month), day(day), hour(hour), min(min), sec(sec), ms(ms) {
2325 }
2326 
CalFields(const Calendar & cal,UErrorCode & status)2327 CalFields::CalFields(const Calendar& cal, UErrorCode& status) {
2328     year = cal.get(UCAL_YEAR, status);
2329     month = cal.get(UCAL_MONTH, status) + 1;
2330     day = cal.get(UCAL_DAY_OF_MONTH, status);
2331     hour = cal.get(UCAL_HOUR_OF_DAY, status);
2332     min = cal.get(UCAL_MINUTE, status);
2333     sec = cal.get(UCAL_SECOND, status);
2334     ms = cal.get(UCAL_MILLISECOND, status);
2335 }
2336 
2337 void
setTo(Calendar & cal) const2338 CalFields::setTo(Calendar& cal) const {
2339     cal.clear();
2340     cal.set(year, month - 1, day, hour, min, sec);
2341     cal.set(UCAL_MILLISECOND, ms);
2342 }
2343 
2344 char*
toString(char * buf,int32_t len) const2345 CalFields::toString(char* buf, int32_t len) const {
2346     char local[32];
2347     snprintf(local, sizeof(local), "%04d-%02d-%02d %02d:%02d:%02d.%03d", year, month, day, hour, min, sec, ms);
2348     uprv_strncpy(buf, local, len - 1);
2349     buf[len - 1] = 0;
2350     return buf;
2351 }
2352 
2353 bool
operator ==(const CalFields & rhs) const2354 CalFields::operator==(const CalFields& rhs) const {
2355     return year == rhs.year
2356         && month == rhs.month
2357         && day == rhs.day
2358         && hour == rhs.hour
2359         && min == rhs.min
2360         && sec == rhs.sec
2361         && ms == rhs.ms;
2362 }
2363 
2364 bool
operator !=(const CalFields & rhs) const2365 CalFields::operator!=(const CalFields& rhs) const {
2366     return !(*this == rhs);
2367 }
2368 
2369 UBool
isEquivalentTo(const Calendar & cal,UErrorCode & status) const2370 CalFields::isEquivalentTo(const Calendar& cal, UErrorCode& status) const {
2371     return year == cal.get(UCAL_YEAR, status)
2372         && month == cal.get(UCAL_MONTH, status) + 1
2373         && day == cal.get(UCAL_DAY_OF_MONTH, status)
2374         && hour == cal.get(UCAL_HOUR_OF_DAY, status)
2375         && min == cal.get(UCAL_MINUTE, status)
2376         && sec == cal.get(UCAL_SECOND, status)
2377         && ms == cal.get(UCAL_MILLISECOND, status);
2378 }
2379 
2380 typedef struct {
2381     const char*     tzid;
2382     const CalFields in;
2383     const CalFields expLastGMT;
2384     const CalFields expFirstGMT;
2385 } RepeatedWallTimeTestData;
2386 
2387 static const RepeatedWallTimeTestData RPDATA[] =
2388 {
2389     // Time zone            Input wall time                 WALLTIME_LAST in GMT            WALLTIME_FIRST in GMT
2390     {"America/New_York",    CalFields(2011,11,6,0,59,59),   CalFields(2011,11,6,4,59,59),   CalFields(2011,11,6,4,59,59)},
2391     {"America/New_York",    CalFields(2011,11,6,1,0,0),     CalFields(2011,11,6,6,0,0),     CalFields(2011,11,6,5,0,0)},
2392     {"America/New_York",    CalFields(2011,11,6,1,0,1),     CalFields(2011,11,6,6,0,1),     CalFields(2011,11,6,5,0,1)},
2393     {"America/New_York",    CalFields(2011,11,6,1,30,0),    CalFields(2011,11,6,6,30,0),    CalFields(2011,11,6,5,30,0)},
2394     {"America/New_York",    CalFields(2011,11,6,1,59,59),   CalFields(2011,11,6,6,59,59),   CalFields(2011,11,6,5,59,59)},
2395     {"America/New_York",    CalFields(2011,11,6,2,0,0),     CalFields(2011,11,6,7,0,0),     CalFields(2011,11,6,7,0,0)},
2396     {"America/New_York",    CalFields(2011,11,6,2,0,1),     CalFields(2011,11,6,7,0,1),     CalFields(2011,11,6,7,0,1)},
2397 
2398     {"Australia/Lord_Howe", CalFields(2011,4,3,1,29,59),    CalFields(2011,4,2,14,29,59),   CalFields(2011,4,2,14,29,59)},
2399     {"Australia/Lord_Howe", CalFields(2011,4,3,1,30,0),     CalFields(2011,4,2,15,0,0),     CalFields(2011,4,2,14,30,0)},
2400     {"Australia/Lord_Howe", CalFields(2011,4,3,1,45,0),     CalFields(2011,4,2,15,15,0),    CalFields(2011,4,2,14,45,0)},
2401     {"Australia/Lord_Howe", CalFields(2011,4,3,1,59,59),    CalFields(2011,4,2,15,29,59),   CalFields(2011,4,2,14,59,59)},
2402     {"Australia/Lord_Howe", CalFields(2011,4,3,2,0,0),      CalFields(2011,4,2,15,30,0),    CalFields(2011,4,2,15,30,0)},
2403     {"Australia/Lord_Howe", CalFields(2011,4,3,2,0,1),      CalFields(2011,4,2,15,30,1),    CalFields(2011,4,2,15,30,1)},
2404 
2405     {nullptr,                  CalFields(0,0,0,0,0,0),         CalFields(0,0,0,0,0,0),          CalFields(0,0,0,0,0,0)}
2406 };
2407 
TestRepeatedWallTime()2408 void CalendarTest::TestRepeatedWallTime() {
2409     UErrorCode status = U_ZERO_ERROR;
2410     GregorianCalendar calGMT((const TimeZone&)*TimeZone::getGMT(), status);
2411     GregorianCalendar calDefault(status);
2412     GregorianCalendar calLast(status);
2413     GregorianCalendar calFirst(status);
2414 
2415     if (U_FAILURE(status)) {
2416         errln("Fail: Failed to create a calendar object.");
2417         return;
2418     }
2419 
2420     calLast.setRepeatedWallTimeOption(UCAL_WALLTIME_LAST);
2421     calFirst.setRepeatedWallTimeOption(UCAL_WALLTIME_FIRST);
2422 
2423     for (int32_t i = 0; RPDATA[i].tzid != nullptr; i++) {
2424         char buf[32];
2425         TimeZone *tz = TimeZone::createTimeZone(RPDATA[i].tzid);
2426 
2427         // UCAL_WALLTIME_LAST
2428         status = U_ZERO_ERROR;
2429         calLast.setTimeZone(*tz);
2430         RPDATA[i].in.setTo(calLast);
2431         calGMT.setTime(calLast.getTime(status), status);
2432         CalFields outLastGMT(calGMT, status);
2433         if (U_FAILURE(status)) {
2434             errln(UnicodeString("Fail: Failed to get/set time calLast/calGMT (UCAL_WALLTIME_LAST) - ")
2435                 + RPDATA[i].in.toString(buf, sizeof(buf)) + "[" + RPDATA[i].tzid + "]");
2436         } else {
2437             if (outLastGMT != RPDATA[i].expLastGMT) {
2438                 dataerrln(UnicodeString("Fail: UCAL_WALLTIME_LAST ") + RPDATA[i].in.toString(buf, sizeof(buf)) + "[" + RPDATA[i].tzid + "] is parsed as "
2439                     + outLastGMT.toString(buf, sizeof(buf)) + "[GMT]. Expected: " + RPDATA[i].expLastGMT.toString(buf, sizeof(buf)) + "[GMT]");
2440             }
2441         }
2442 
2443         // default
2444         status = U_ZERO_ERROR;
2445         calDefault.setTimeZone(*tz);
2446         RPDATA[i].in.setTo(calDefault);
2447         calGMT.setTime(calDefault.getTime(status), status);
2448         CalFields outDefGMT(calGMT, status);
2449         if (U_FAILURE(status)) {
2450             errln(UnicodeString("Fail: Failed to get/set time calLast/calGMT (default) - ")
2451                 + RPDATA[i].in.toString(buf, sizeof(buf)) + "[" + RPDATA[i].tzid + "]");
2452         } else {
2453             if (outDefGMT != RPDATA[i].expLastGMT) {
2454                 dataerrln(UnicodeString("Fail: (default) ") + RPDATA[i].in.toString(buf, sizeof(buf)) + "[" + RPDATA[i].tzid + "] is parsed as "
2455                     + outDefGMT.toString(buf, sizeof(buf)) + "[GMT]. Expected: " + RPDATA[i].expLastGMT.toString(buf, sizeof(buf)) + "[GMT]");
2456             }
2457         }
2458 
2459         // UCAL_WALLTIME_FIRST
2460         status = U_ZERO_ERROR;
2461         calFirst.setTimeZone(*tz);
2462         RPDATA[i].in.setTo(calFirst);
2463         calGMT.setTime(calFirst.getTime(status), status);
2464         CalFields outFirstGMT(calGMT, status);
2465         if (U_FAILURE(status)) {
2466             errln(UnicodeString("Fail: Failed to get/set time calLast/calGMT (UCAL_WALLTIME_FIRST) - ")
2467                 + RPDATA[i].in.toString(buf, sizeof(buf)) + "[" + RPDATA[i].tzid + "]");
2468         } else {
2469             if (outFirstGMT != RPDATA[i].expFirstGMT) {
2470                 dataerrln(UnicodeString("Fail: UCAL_WALLTIME_FIRST ") + RPDATA[i].in.toString(buf, sizeof(buf)) + "[" + RPDATA[i].tzid + "] is parsed as "
2471                     + outFirstGMT.toString(buf, sizeof(buf)) + "[GMT]. Expected: " + RPDATA[i].expFirstGMT.toString(buf, sizeof(buf)) + "[GMT]");
2472             }
2473         }
2474         delete tz;
2475     }
2476 }
2477 
2478 typedef struct {
2479     const char*     tzid;
2480     const CalFields in;
2481     UBool           isValid;
2482     const CalFields expLastGMT;
2483     const CalFields expFirstGMT;
2484     const CalFields expNextAvailGMT;
2485 } SkippedWallTimeTestData;
2486 
2487 static SkippedWallTimeTestData SKDATA[] =
2488 {
2489      // Time zone           Input wall time                 valid?  WALLTIME_LAST in GMT            WALLTIME_FIRST in GMT           WALLTIME_NEXT_VALID in GMT
2490     {"America/New_York",    CalFields(2011,3,13,1,59,59),   true,   CalFields(2011,3,13,6,59,59),   CalFields(2011,3,13,6,59,59),   CalFields(2011,3,13,6,59,59)},
2491     {"America/New_York",    CalFields(2011,3,13,2,0,0),     false,  CalFields(2011,3,13,7,0,0),     CalFields(2011,3,13,6,0,0),     CalFields(2011,3,13,7,0,0)},
2492     {"America/New_York",    CalFields(2011,3,13,2,1,0),     false,  CalFields(2011,3,13,7,1,0),     CalFields(2011,3,13,6,1,0),     CalFields(2011,3,13,7,0,0)},
2493     {"America/New_York",    CalFields(2011,3,13,2,30,0),    false,  CalFields(2011,3,13,7,30,0),    CalFields(2011,3,13,6,30,0),    CalFields(2011,3,13,7,0,0)},
2494     {"America/New_York",    CalFields(2011,3,13,2,59,59),   false,  CalFields(2011,3,13,7,59,59),   CalFields(2011,3,13,6,59,59),   CalFields(2011,3,13,7,0,0)},
2495     {"America/New_York",    CalFields(2011,3,13,3,0,0),     true,   CalFields(2011,3,13,7,0,0),     CalFields(2011,3,13,7,0,0),     CalFields(2011,3,13,7,0,0)},
2496 
2497     {"Pacific/Apia",        CalFields(2011,12,29,23,59,59), true,   CalFields(2011,12,30,9,59,59),  CalFields(2011,12,30,9,59,59),  CalFields(2011,12,30,9,59,59)},
2498     {"Pacific/Apia",        CalFields(2011,12,30,0,0,0),    false,  CalFields(2011,12,30,10,0,0),   CalFields(2011,12,29,10,0,0),   CalFields(2011,12,30,10,0,0)},
2499     {"Pacific/Apia",        CalFields(2011,12,30,12,0,0),   false,  CalFields(2011,12,30,22,0,0),   CalFields(2011,12,29,22,0,0),   CalFields(2011,12,30,10,0,0)},
2500     {"Pacific/Apia",        CalFields(2011,12,30,23,59,59), false,  CalFields(2011,12,31,9,59,59),  CalFields(2011,12,30,9,59,59),  CalFields(2011,12,30,10,0,0)},
2501     {"Pacific/Apia",        CalFields(2011,12,31,0,0,0),    true,   CalFields(2011,12,30,10,0,0),   CalFields(2011,12,30,10,0,0),   CalFields(2011,12,30,10,0,0)},
2502 
2503     {nullptr,                  CalFields(0,0,0,0,0,0),         true,   CalFields(0,0,0,0,0,0),         CalFields(0,0,0,0,0,0),         CalFields(0,0,0,0,0,0)}
2504 };
2505 
2506 
TestSkippedWallTime()2507 void CalendarTest::TestSkippedWallTime() {
2508     UErrorCode status = U_ZERO_ERROR;
2509     GregorianCalendar calGMT((const TimeZone&)*TimeZone::getGMT(), status);
2510     GregorianCalendar calDefault(status);
2511     GregorianCalendar calLast(status);
2512     GregorianCalendar calFirst(status);
2513     GregorianCalendar calNextAvail(status);
2514 
2515     if (U_FAILURE(status)) {
2516         errln("Fail: Failed to create a calendar object.");
2517         return;
2518     }
2519 
2520     calLast.setSkippedWallTimeOption(UCAL_WALLTIME_LAST);
2521     calFirst.setSkippedWallTimeOption(UCAL_WALLTIME_FIRST);
2522     calNextAvail.setSkippedWallTimeOption(UCAL_WALLTIME_NEXT_VALID);
2523 
2524     for (int32_t i = 0; SKDATA[i].tzid != nullptr; i++) {
2525         UDate d;
2526         char buf[32];
2527         TimeZone *tz = TimeZone::createTimeZone(SKDATA[i].tzid);
2528 
2529         for (int32_t j = 0; j < 2; j++) {
2530             UBool bLenient = (j == 0);
2531 
2532             // UCAL_WALLTIME_LAST
2533             status = U_ZERO_ERROR;
2534             calLast.setLenient(bLenient);
2535             calLast.setTimeZone(*tz);
2536             SKDATA[i].in.setTo(calLast);
2537             d = calLast.getTime(status);
2538             if (bLenient || SKDATA[i].isValid) {
2539                 calGMT.setTime(d, status);
2540                 CalFields outLastGMT(calGMT, status);
2541                 if (U_FAILURE(status)) {
2542                     errln(UnicodeString("Fail: Failed to get/set time calLast/calGMT (UCAL_WALLTIME_LAST) - ")
2543                         + SKDATA[i].in.toString(buf, sizeof(buf)) + "[" + SKDATA[i].tzid + "]");
2544                 } else {
2545                     if (outLastGMT != SKDATA[i].expLastGMT) {
2546                         dataerrln(UnicodeString("Fail: UCAL_WALLTIME_LAST ") + SKDATA[i].in.toString(buf, sizeof(buf)) + "[" + SKDATA[i].tzid + "] is parsed as "
2547                             + outLastGMT.toString(buf, sizeof(buf)) + "[GMT]. Expected: " + SKDATA[i].expLastGMT.toString(buf, sizeof(buf)) + "[GMT]");
2548                     }
2549                 }
2550             } else if (U_SUCCESS(status)) {
2551                 // strict, invalid wall time - must report an error
2552                 dataerrln(UnicodeString("Fail: An error expected (UCAL_WALLTIME_LAST)") +
2553                     + SKDATA[i].in.toString(buf, sizeof(buf)) + "[" + SKDATA[i].tzid + "]");
2554             }
2555 
2556             // default
2557             status = U_ZERO_ERROR;
2558             calDefault.setLenient(bLenient);
2559             calDefault.setTimeZone(*tz);
2560             SKDATA[i].in.setTo(calDefault);
2561             d = calDefault.getTime(status);
2562             if (bLenient || SKDATA[i].isValid) {
2563                 calGMT.setTime(d, status);
2564                 CalFields outDefGMT(calGMT, status);
2565                 if (U_FAILURE(status)) {
2566                     errln(UnicodeString("Fail: Failed to get/set time calDefault/calGMT (default) - ")
2567                         + SKDATA[i].in.toString(buf, sizeof(buf)) + "[" + SKDATA[i].tzid + "]");
2568                 } else {
2569                     if (outDefGMT != SKDATA[i].expLastGMT) {
2570                         dataerrln(UnicodeString("Fail: (default) ") + SKDATA[i].in.toString(buf, sizeof(buf)) + "[" + SKDATA[i].tzid + "] is parsed as "
2571                             + outDefGMT.toString(buf, sizeof(buf)) + "[GMT]. Expected: " + SKDATA[i].expLastGMT.toString(buf, sizeof(buf)) + "[GMT]");
2572                     }
2573                 }
2574             } else if (U_SUCCESS(status)) {
2575                 // strict, invalid wall time - must report an error
2576                 dataerrln(UnicodeString("Fail: An error expected (default)") +
2577                     + SKDATA[i].in.toString(buf, sizeof(buf)) + "[" + SKDATA[i].tzid + "]");
2578             }
2579 
2580             // UCAL_WALLTIME_FIRST
2581             status = U_ZERO_ERROR;
2582             calFirst.setLenient(bLenient);
2583             calFirst.setTimeZone(*tz);
2584             SKDATA[i].in.setTo(calFirst);
2585             d = calFirst.getTime(status);
2586             if (bLenient || SKDATA[i].isValid) {
2587                 calGMT.setTime(d, status);
2588                 CalFields outFirstGMT(calGMT, status);
2589                 if (U_FAILURE(status)) {
2590                     errln(UnicodeString("Fail: Failed to get/set time calFirst/calGMT (UCAL_WALLTIME_FIRST) - ")
2591                         + SKDATA[i].in.toString(buf, sizeof(buf)) + "[" + SKDATA[i].tzid + "]");
2592                 } else {
2593                     if (outFirstGMT != SKDATA[i].expFirstGMT) {
2594                         dataerrln(UnicodeString("Fail: UCAL_WALLTIME_FIRST ") + SKDATA[i].in.toString(buf, sizeof(buf)) + "[" + SKDATA[i].tzid + "] is parsed as "
2595                             + outFirstGMT.toString(buf, sizeof(buf)) + "[GMT]. Expected: " + SKDATA[i].expFirstGMT.toString(buf, sizeof(buf)) + "[GMT]");
2596                     }
2597                 }
2598             } else if (U_SUCCESS(status)) {
2599                 // strict, invalid wall time - must report an error
2600                 dataerrln(UnicodeString("Fail: An error expected (UCAL_WALLTIME_FIRST)") +
2601                     + SKDATA[i].in.toString(buf, sizeof(buf)) + "[" + SKDATA[i].tzid + "]");
2602             }
2603 
2604             // UCAL_WALLTIME_NEXT_VALID
2605             status = U_ZERO_ERROR;
2606             calNextAvail.setLenient(bLenient);
2607             calNextAvail.setTimeZone(*tz);
2608             SKDATA[i].in.setTo(calNextAvail);
2609             d = calNextAvail.getTime(status);
2610             if (bLenient || SKDATA[i].isValid) {
2611                 calGMT.setTime(d, status);
2612                 CalFields outNextAvailGMT(calGMT, status);
2613                 if (U_FAILURE(status)) {
2614                     errln(UnicodeString("Fail: Failed to get/set time calNextAvail/calGMT (UCAL_WALLTIME_NEXT_VALID) - ")
2615                         + SKDATA[i].in.toString(buf, sizeof(buf)) + "[" + SKDATA[i].tzid + "]");
2616                 } else {
2617                     if (outNextAvailGMT != SKDATA[i].expNextAvailGMT) {
2618                         dataerrln(UnicodeString("Fail: UCAL_WALLTIME_NEXT_VALID ") + SKDATA[i].in.toString(buf, sizeof(buf)) + "[" + SKDATA[i].tzid + "] is parsed as "
2619                             + outNextAvailGMT.toString(buf, sizeof(buf)) + "[GMT]. Expected: " + SKDATA[i].expNextAvailGMT.toString(buf, sizeof(buf)) + "[GMT]");
2620                     }
2621                 }
2622             } else if (U_SUCCESS(status)) {
2623                 // strict, invalid wall time - must report an error
2624                 dataerrln(UnicodeString("Fail: An error expected (UCAL_WALLTIME_NEXT_VALID)") +
2625                     + SKDATA[i].in.toString(buf, sizeof(buf)) + "[" + SKDATA[i].tzid + "]");
2626             }
2627         }
2628 
2629         delete tz;
2630     }
2631 }
2632 
TestCloneLocale()2633 void CalendarTest::TestCloneLocale() {
2634   UErrorCode status = U_ZERO_ERROR;
2635   LocalPointer<Calendar>  cal(Calendar::createInstance(TimeZone::getGMT()->clone(),
2636                                                        Locale::createFromName("en"), status));
2637   TEST_CHECK_STATUS;
2638   Locale l0 = cal->getLocale(ULOC_VALID_LOCALE, status);
2639   TEST_CHECK_STATUS;
2640   LocalPointer<Calendar> cal2(cal->clone());
2641   Locale l = cal2->getLocale(ULOC_VALID_LOCALE, status);
2642   if(l0!=l) {
2643     errln("Error: cloned locale %s != original locale %s, status %s\n", l0.getName(), l.getName(), u_errorName(status));
2644   }
2645   TEST_CHECK_STATUS;
2646 }
2647 
TestTimeZoneInLocale()2648 void CalendarTest::TestTimeZoneInLocale() {
2649     const char *tests[][3]  = {
2650         { "en-u-tz-usden",                     "America/Denver",             "gregorian" },
2651         { "es-u-tz-usden",                     "America/Denver",             "gregorian" },
2652         { "ms-u-tz-mykul",                     "Asia/Kuala_Lumpur",          "gregorian" },
2653         { "zh-u-tz-mykul",                     "Asia/Kuala_Lumpur",          "gregorian" },
2654         { "fr-u-ca-buddhist-tz-phmnl",         "Asia/Manila",                "buddhist" },
2655         { "th-u-ca-chinese-tz-gblon",          "Europe/London",              "chinese" },
2656         { "de-u-ca-coptic-tz-ciabj",           "Africa/Abidjan",             "coptic" },
2657         { "ja-u-ca-dangi-tz-hkhkg",            "Asia/Hong_Kong",             "dangi" },
2658         { "da-u-ca-ethioaa-tz-ruunera",        "Asia/Ust-Nera",              "ethiopic-amete-alem" },
2659         { "ko-u-ca-ethiopic-tz-cvrai",         "Atlantic/Cape_Verde",        "ethiopic" },
2660         { "fil-u-ca-gregory-tz-aubne",         "Australia/Brisbane",         "gregorian" },
2661         { "fa-u-ca-hebrew-tz-brrbr",           "America/Rio_Branco",         "hebrew" },
2662         { "gr-u-ca-indian-tz-lccas",           "America/St_Lucia",           "indian" },
2663         { "or-u-ca-islamic-tz-cayyn",          "America/Swift_Current",      "islamic" },
2664         { "my-u-ca-islamic-umalqura-tz-kzala", "Asia/Almaty",                "islamic-umalqura" },
2665         { "lo-u-ca-islamic-tbla-tz-bmbda",     "Atlantic/Bermuda",           "islamic-tbla" },
2666         { "km-u-ca-islamic-civil-tz-aqplm",    "Antarctica/Palmer",          "islamic-civil" },
2667         { "kk-u-ca-islamic-rgsa-tz-usanc",     "America/Anchorage",          "islamic-rgsa" },
2668         { "ar-u-ca-iso8601-tz-bjptn",          "Africa/Porto-Novo",          "iso8601" },
2669         { "he-u-ca-japanese-tz-tzdar",         "Africa/Dar_es_Salaam",       "japanese" },
2670         { "bs-u-ca-persian-tz-etadd",          "Africa/Addis_Ababa",         "persian" },
2671         { "it-u-ca-roc-tz-aruaq",              "America/Argentina/San_Juan", "roc" },
2672     };
2673 
2674     for (int32_t i = 0; i < UPRV_LENGTHOF(tests); ++i) {
2675         UErrorCode status = U_ZERO_ERROR;
2676         const char **testLine = tests[i];
2677         Locale locale(testLine[0]);
2678         UnicodeString expected(testLine[1], -1, US_INV);
2679         UnicodeString actual;
2680 
2681         LocalPointer<Calendar> calendar(
2682                 Calendar::createInstance(locale, status));
2683         if (failure(status, "Calendar::createInstance", true)) continue;
2684 
2685         assertEquals("TimeZone from Calendar::createInstance",
2686                      expected, calendar->getTimeZone().getID(actual));
2687 
2688         assertEquals("Calendar Type from Calendar::createInstance",
2689                      testLine[2], calendar->getType());
2690     }
2691 }
2692 
AsssertCalendarFieldValue(Calendar * cal,double time,const char * type,int32_t era,int32_t year,int32_t month,int32_t week_of_year,int32_t week_of_month,int32_t date,int32_t day_of_year,int32_t day_of_week,int32_t day_of_week_in_month,int32_t am_pm,int32_t hour,int32_t hour_of_day,int32_t minute,int32_t second,int32_t millisecond,int32_t zone_offset,int32_t dst_offset,int32_t year_woy,int32_t dow_local,int32_t extended_year,int32_t julian_day,int32_t milliseconds_in_day,int32_t is_leap_month)2693 void CalendarTest::AsssertCalendarFieldValue(
2694     Calendar* cal, double time, const char* type,
2695     int32_t era, int32_t year, int32_t month, int32_t week_of_year,
2696     int32_t week_of_month, int32_t date, int32_t day_of_year, int32_t day_of_week,
2697     int32_t day_of_week_in_month, int32_t am_pm, int32_t hour, int32_t hour_of_day,
2698     int32_t minute, int32_t second, int32_t millisecond, int32_t zone_offset,
2699     int32_t dst_offset, int32_t year_woy, int32_t dow_local, int32_t extended_year,
2700     int32_t julian_day, int32_t milliseconds_in_day, int32_t is_leap_month) {
2701 
2702     UErrorCode status = U_ZERO_ERROR;
2703     cal->setTime(time, status);
2704     assertEquals("getType", type, cal->getType());
2705 
2706     assertEquals("UCAL_ERA", era, cal->get(UCAL_ERA, status));
2707     assertEquals("UCAL_YEAR", year, cal->get(UCAL_YEAR, status));
2708     assertEquals("UCAL_MONTH", month, cal->get(UCAL_MONTH, status));
2709     assertEquals("UCAL_WEEK_OF_YEAR", week_of_year, cal->get(UCAL_WEEK_OF_YEAR, status));
2710     assertEquals("UCAL_WEEK_OF_MONTH", week_of_month, cal->get(UCAL_WEEK_OF_MONTH, status));
2711     assertEquals("UCAL_DATE", date, cal->get(UCAL_DATE, status));
2712     assertEquals("UCAL_DAY_OF_YEAR", day_of_year, cal->get(UCAL_DAY_OF_YEAR, status));
2713     assertEquals("UCAL_DAY_OF_WEEK", day_of_week, cal->get(UCAL_DAY_OF_WEEK, status));
2714     assertEquals("UCAL_DAY_OF_WEEK_IN_MONTH", day_of_week_in_month, cal->get(UCAL_DAY_OF_WEEK_IN_MONTH, status));
2715     assertEquals("UCAL_AM_PM", am_pm, cal->get(UCAL_AM_PM, status));
2716     assertEquals("UCAL_HOUR", hour, cal->get(UCAL_HOUR, status));
2717     assertEquals("UCAL_HOUR_OF_DAY", hour_of_day, cal->get(UCAL_HOUR_OF_DAY, status));
2718     assertEquals("UCAL_MINUTE", minute, cal->get(UCAL_MINUTE, status));
2719     assertEquals("UCAL_SECOND", second, cal->get(UCAL_SECOND, status));
2720     assertEquals("UCAL_MILLISECOND", millisecond, cal->get(UCAL_MILLISECOND, status));
2721     assertEquals("UCAL_ZONE_OFFSET", zone_offset, cal->get(UCAL_ZONE_OFFSET, status));
2722     assertEquals("UCAL_DST_OFFSET", dst_offset, cal->get(UCAL_DST_OFFSET, status));
2723     assertEquals("UCAL_YEAR_WOY", year_woy, cal->get(UCAL_YEAR_WOY, status));
2724     assertEquals("UCAL_DOW_LOCAL", dow_local, cal->get(UCAL_DOW_LOCAL, status));
2725     assertEquals("UCAL_EXTENDED_YEAR", extended_year, cal->get(UCAL_EXTENDED_YEAR, status));
2726     assertEquals("UCAL_JULIAN_DAY", julian_day, cal->get(UCAL_JULIAN_DAY, status));
2727     assertEquals("UCAL_MILLISECONDS_IN_DAY", milliseconds_in_day, cal->get(UCAL_MILLISECONDS_IN_DAY, status));
2728     assertEquals("UCAL_IS_LEAP_MONTH", is_leap_month, cal->get(UCAL_IS_LEAP_MONTH, status));
2729 }
2730 
2731 static constexpr double test_time = 1667277891323; // Nov 1, 2022 4:44:51 GMT
2732 
TestBasicConversionGregorian()2733 void CalendarTest::TestBasicConversionGregorian() {
2734     UErrorCode status = U_ZERO_ERROR;
2735     LocalPointer<Calendar> cal(icu::Calendar::createInstance(
2736         *TimeZone::getGMT(), Locale("en@calendar=gregorian"), status));
2737     if (U_FAILURE(status)) {
2738         errln("Fail: Cannot get Gregorian calendar");
2739         return;
2740     }
2741     AsssertCalendarFieldValue(
2742         cal.getAlias(), test_time, "gregorian",
2743         1, 2022, 10, 45, 1, 1, 305, 3, 1, 0, 4, 4, 44, 51,
2744         323, 0, 0, 2022, 3, 2022, 2459885, 17091323, 0);
2745 }
TestBasicConversionISO8601()2746 void CalendarTest::TestBasicConversionISO8601() {
2747     UErrorCode status = U_ZERO_ERROR;
2748     LocalPointer<Calendar> cal(icu::Calendar::createInstance(
2749         *TimeZone::getGMT(), Locale("en@calendar=iso8601"), status));
2750     if (U_FAILURE(status)) {
2751         errln("Fail: Cannot get ISO8601 calendar");
2752         return;
2753     }
2754     AsssertCalendarFieldValue(
2755         cal.getAlias(), test_time, "iso8601",
2756         1, 2022, 10, 44, 1, 1, 305, 3, 1, 0, 4, 4, 44, 51,
2757         323, 0, 0, 2022, 2, 2022, 2459885, 17091323, 0);
2758 }
TestBasicConversionJapanese()2759 void CalendarTest::TestBasicConversionJapanese() {
2760     UErrorCode status = U_ZERO_ERROR;
2761     LocalPointer<Calendar> cal(icu::Calendar::createInstance(
2762         *TimeZone::getGMT(), Locale("en@calendar=japanese"), status));
2763     if (U_FAILURE(status)) {
2764         errln("Fail: Cannot get Japanese calendar");
2765         return;
2766     }
2767     AsssertCalendarFieldValue(
2768         cal.getAlias(), test_time, "japanese",
2769         236, 4, 10, 45, 1, 1, 305, 3, 1, 0, 4, 4, 44, 51,
2770         323, 0, 0, 2022, 3, 2022, 2459885, 17091323, 0);
2771 }
TestBasicConversionBuddhist()2772 void CalendarTest::TestBasicConversionBuddhist() {
2773     UErrorCode status = U_ZERO_ERROR;
2774     LocalPointer<Calendar> cal(icu::Calendar::createInstance(
2775         *TimeZone::getGMT(), Locale("en@calendar=buddhist"), status));
2776     if (U_FAILURE(status)) {
2777         errln("Fail: Cannot get Buddhist calendar");
2778         return;
2779     }
2780     AsssertCalendarFieldValue(
2781         cal.getAlias(), test_time, "buddhist",
2782         0, 2565, 10, 45, 1, 1, 305, 3, 1, 0, 4, 4, 44, 51,
2783         323, 0, 0, 2022, 3, 2022, 2459885, 17091323, 0);
2784 }
TestBasicConversionTaiwan()2785 void CalendarTest::TestBasicConversionTaiwan() {
2786     UErrorCode status = U_ZERO_ERROR;
2787     LocalPointer<Calendar> cal(icu::Calendar::createInstance(
2788         *TimeZone::getGMT(), Locale("en@calendar=roc"), status));
2789     if (U_FAILURE(status)) {
2790         errln("Fail: Cannot get Taiwan calendar");
2791         return;
2792     }
2793     AsssertCalendarFieldValue(
2794         cal.getAlias(), test_time, "roc",
2795         1, 111, 10, 45, 1, 1, 305, 3, 1, 0, 4, 4, 44, 51,
2796         323, 0, 0, 2022, 3, 2022, 2459885, 17091323, 0);
2797 
2798 }
TestBasicConversionPersian()2799 void CalendarTest::TestBasicConversionPersian() {
2800     UErrorCode status = U_ZERO_ERROR;
2801     LocalPointer<Calendar> cal(icu::Calendar::createInstance(
2802         *TimeZone::getGMT(), Locale("en@calendar=persian"), status));
2803     if (U_FAILURE(status)) {
2804         errln("Fail: Cannot get Persian calendar");
2805         return;
2806     }
2807     AsssertCalendarFieldValue(
2808         cal.getAlias(), test_time, "persian",
2809         0, 1401, 7, 33, 2, 10, 226, 3, 2, 0, 4, 4, 44, 51,
2810         323, 0, 0, 1401, 3, 1401, 2459885, 17091323, 0);
2811 }
TestBasicConversionIslamic()2812 void CalendarTest::TestBasicConversionIslamic() {
2813     UErrorCode status = U_ZERO_ERROR;
2814     LocalPointer<Calendar> cal(icu::Calendar::createInstance(
2815         *TimeZone::getGMT(), Locale("en@calendar=islamic"), status));
2816     if (U_FAILURE(status)) {
2817         errln("Fail: Cannot get Islamic calendar");
2818         return;
2819     }
2820     AsssertCalendarFieldValue(
2821         cal.getAlias(), test_time, "islamic",
2822         0, 1444, 3, 15, 2, 7, 96, 3, 1, 0, 4, 4, 44, 51,
2823         323, 0, 0, 1444, 3, 1444, 2459885, 17091323, 0);
2824 }
TestBasicConversionIslamicTBLA()2825 void CalendarTest::TestBasicConversionIslamicTBLA() {
2826     UErrorCode status = U_ZERO_ERROR;
2827     LocalPointer<Calendar> cal(icu::Calendar::createInstance(
2828         *TimeZone::getGMT(), Locale("en@calendar=islamic-tbla"), status));
2829     if (U_FAILURE(status)) {
2830         errln("Fail: Cannot get IslamicTBLA calendar");
2831         return;
2832     }
2833     AsssertCalendarFieldValue(
2834         cal.getAlias(), test_time, "islamic-tbla",
2835         0, 1444, 3, 15, 2, 7, 96, 3, 1, 0, 4, 4, 44, 51,
2836         323, 0, 0, 1444, 3, 1444, 2459885, 17091323, 0);
2837 
2838 }
TestBasicConversionIslamicCivil()2839 void CalendarTest::TestBasicConversionIslamicCivil() {
2840     UErrorCode status = U_ZERO_ERROR;
2841     LocalPointer<Calendar> cal(icu::Calendar::createInstance(
2842         *TimeZone::getGMT(), Locale("en@calendar=islamic-civil"), status));
2843     if (U_FAILURE(status)) {
2844         errln("Fail: Cannot get IslamicCivil calendar");
2845         return;
2846     }
2847     AsssertCalendarFieldValue(
2848         cal.getAlias(), test_time, "islamic-civil",
2849         0, 1444, 3, 15, 2, 6, 95, 3, 1, 0, 4, 4, 44, 51,
2850         323, 0, 0, 1444, 3, 1444, 2459885, 17091323, 0);
2851 
2852 }
TestBasicConversionIslamicRGSA()2853 void CalendarTest::TestBasicConversionIslamicRGSA() {
2854     UErrorCode status = U_ZERO_ERROR;
2855     LocalPointer<Calendar> cal(icu::Calendar::createInstance(
2856         *TimeZone::getGMT(), Locale("en@calendar=islamic-rgsa"), status));
2857     if (U_FAILURE(status)) {
2858         errln("Fail: Cannot get IslamicRGSA calendar");
2859         return;
2860     }
2861     AsssertCalendarFieldValue(
2862         cal.getAlias(), test_time, "islamic-rgsa",
2863         0, 1444, 3, 15, 2, 7, 96, 3, 1, 0, 4, 4, 44, 51,
2864         323, 0, 0, 1444, 3, 1444, 2459885, 17091323, 0);
2865 
2866 }
TestBasicConversionIslamicUmalqura()2867 void CalendarTest::TestBasicConversionIslamicUmalqura() {
2868     UErrorCode status = U_ZERO_ERROR;
2869     LocalPointer<Calendar> cal(icu::Calendar::createInstance(
2870         *TimeZone::getGMT(), Locale("en@calendar=islamic-umalqura"), status));
2871     if (U_FAILURE(status)) {
2872         errln("Fail: Cannot get IslamicUmalqura calendar");
2873         return;
2874     }
2875     AsssertCalendarFieldValue(
2876         cal.getAlias(), test_time, "islamic-umalqura",
2877         0, 1444, 3, 15, 2, 7, 95, 3, 1, 0, 4, 4, 44, 51,
2878         323, 0, 0, 1444, 3, 1444, 2459885, 17091323, 0);
2879 }
TestBasicConversionHebrew()2880 void CalendarTest::TestBasicConversionHebrew() {
2881     UErrorCode status = U_ZERO_ERROR;
2882     LocalPointer<Calendar> cal(icu::Calendar::createInstance(
2883         *TimeZone::getGMT(), Locale("en@calendar=hebrew"), status));
2884     if (U_FAILURE(status)) {
2885         errln("Fail: Cannot get Hebrew calendar");
2886         return;
2887     }
2888     AsssertCalendarFieldValue(
2889         cal.getAlias(), test_time, "hebrew",
2890         0, 5783, 1, 6, 2, 7, 37, 3, 1, 0, 4, 4, 44, 51,
2891         323, 0, 0, 5783, 3, 5783, 2459885, 17091323, 0);
2892 }
TestBasicConversionChinese()2893 void CalendarTest::TestBasicConversionChinese() {
2894     UErrorCode status = U_ZERO_ERROR;
2895     LocalPointer<Calendar> cal(icu::Calendar::createInstance(
2896         *TimeZone::getGMT(), Locale("en@calendar=chinese"), status));
2897     if (U_FAILURE(status)) {
2898         errln("Fail: Cannot get Chinese calendar");
2899         return;
2900     }
2901     AsssertCalendarFieldValue(
2902         cal.getAlias(), test_time, "chinese",
2903         78, 39, 9, 40, 2, 8, 274, 3, 2, 0, 4, 4, 44, 51,
2904         323, 0, 0, 4659, 3, 4659, 2459885, 17091323, 0);
2905 }
TestBasicConversionDangi()2906 void CalendarTest::TestBasicConversionDangi() {
2907     UErrorCode status = U_ZERO_ERROR;
2908     LocalPointer<Calendar> cal(icu::Calendar::createInstance(
2909         *TimeZone::getGMT(), Locale("en@calendar=dangi"), status));
2910     if (U_FAILURE(status)) {
2911         errln("Fail: Cannot get Dangi calendar");
2912         return;
2913     }
2914     AsssertCalendarFieldValue(
2915         cal.getAlias(), test_time, "dangi",
2916         78, 39, 9, 40, 2, 8, 274, 3, 2, 0, 4, 4, 44, 51,
2917         323, 0, 0, 4355, 3, 4355, 2459885, 17091323, 0);
2918 }
TestBasicConversionIndian()2919 void CalendarTest::TestBasicConversionIndian() {
2920     UErrorCode status = U_ZERO_ERROR;
2921     LocalPointer<Calendar> cal(icu::Calendar::createInstance(
2922         *TimeZone::getGMT(), Locale("en@calendar=indian"), status));
2923     if (U_FAILURE(status)) {
2924         errln("Fail: Cannot get Indian calendar");
2925         return;
2926     }
2927     AsssertCalendarFieldValue(
2928         cal.getAlias(), test_time, "indian",
2929         0, 1944, 7, 33, 2, 10, 225, 3, 2, 0, 4, 4, 44, 51,
2930         323, 0, 0, 1944, 3, 1944, 2459885, 17091323, 0);
2931 }
TestBasicConversionCoptic()2932 void CalendarTest::TestBasicConversionCoptic() {
2933     UErrorCode status = U_ZERO_ERROR;
2934     LocalPointer<Calendar> cal(icu::Calendar::createInstance(
2935         *TimeZone::getGMT(), Locale("en@calendar=coptic"), status));
2936     if (U_FAILURE(status)) {
2937         errln("Fail: Cannot get Coptic calendar");
2938         return;
2939     }
2940     AsssertCalendarFieldValue(
2941         cal.getAlias(), test_time, "coptic",
2942         1, 1739, 1, 8, 4, 22, 52, 3, 4, 0, 4, 4, 44, 51,
2943         323, 0, 0, 1739, 3, 1739, 2459885, 17091323, 0);
2944 }
TestBasicConversionEthiopic()2945 void CalendarTest::TestBasicConversionEthiopic() {
2946     UErrorCode status = U_ZERO_ERROR;
2947     LocalPointer<Calendar> cal(icu::Calendar::createInstance(
2948         *TimeZone::getGMT(), Locale("en@calendar=ethiopic"), status));
2949     if (U_FAILURE(status)) {
2950         errln("Fail: Cannot get Ethiopic calendar");
2951         return;
2952     }
2953     AsssertCalendarFieldValue(
2954         cal.getAlias(), test_time, "ethiopic",
2955         1, 2015, 1, 8, 4, 22, 52, 3, 4, 0, 4, 4, 44, 51,
2956         323, 0, 0, 2015, 3, 2015, 2459885, 17091323, 0);
2957 }
TestBasicConversionEthiopicAmeteAlem()2958 void CalendarTest::TestBasicConversionEthiopicAmeteAlem() {
2959     UErrorCode status = U_ZERO_ERROR;
2960     LocalPointer<Calendar> cal(icu::Calendar::createInstance(
2961         *TimeZone::getGMT(), Locale("en@calendar=ethiopic-amete-alem"), status));
2962     if (U_FAILURE(status)) {
2963         errln("Fail: Cannot get EthiopicAmeteAlem calendar");
2964         return;
2965     }
2966     AsssertCalendarFieldValue(
2967         cal.getAlias(), test_time, "ethiopic-amete-alem",
2968         0, 7515, 1, 8, 4, 22, 52, 3, 4, 0, 4, 4, 44, 51,
2969         323, 0, 0, 2015, 3, 2015, 2459885, 17091323, 0);
2970 }
2971 
2972 
setAndTestCalendar(Calendar * cal,int32_t initMonth,int32_t initDay,int32_t initYear,UErrorCode & status)2973 void CalendarTest::setAndTestCalendar(Calendar* cal, int32_t initMonth, int32_t initDay, int32_t initYear, UErrorCode& status) {
2974         cal->clear();
2975         cal->setLenient(false);
2976         cal->set(initYear, initMonth, initDay);
2977         int32_t day = cal->get(UCAL_DAY_OF_MONTH, status);
2978         int32_t month = cal->get(UCAL_MONTH, status);
2979         int32_t year = cal->get(UCAL_YEAR, status);
2980         if(U_FAILURE(status))
2981             return;
2982 
2983         if(initDay != day || initMonth != month || initYear != year)
2984         {
2985             errln(" year init values:\tmonth %i\tday %i\tyear %i", initMonth, initDay, initYear);
2986             errln("values post set():\tmonth %i\tday %i\tyear %i",month, day, year);
2987         }
2988 }
2989 
setAndTestWholeYear(Calendar * cal,int32_t startYear,UErrorCode & status)2990 void CalendarTest::setAndTestWholeYear(Calendar* cal, int32_t startYear, UErrorCode& status) {
2991         for(int32_t startMonth = 0; startMonth < 12; startMonth++) {
2992             for(int32_t startDay = 1; startDay < 31; startDay++ ) {
2993                     setAndTestCalendar(cal, startMonth, startDay, startYear, status);
2994                     if(U_FAILURE(status) && startDay == 30) {
2995                         status = U_ZERO_ERROR;
2996                         continue;
2997                     }
2998                     TEST_CHECK_STATUS;
2999             }
3000         }
3001 }
3002 
3003 // =====================================================================
3004 
3005 typedef struct {
3006     int16_t  gYear;
3007     int8_t   gMon;
3008     int8_t   gDay;
3009     int16_t  uYear;
3010     int8_t   uMon;
3011     int8_t   uDay;
3012 } GregoUmmAlQuraMap;
3013 
3014 // data from
3015 // Official Umm-al-Qura calendar of SA:
3016 // home, http://www.ummulqura.org.sa/default.aspx
3017 // converter, http://www.ummulqura.org.sa/Index.aspx
3018 static const GregoUmmAlQuraMap guMappings[] = {
3019 //  gregorian,    ummAlQura
3020 //  year mo da,   year mo da
3021 //  (using 1-based months here)
3022   { 1882,11,12,   1300, 1, 1 },
3023   { 1892, 7,25,   1310, 1, 1 },
3024   { 1896, 6,12,   1314, 1, 1 },
3025   { 1898, 5,22,   1316, 1, 1 },
3026   { 1900, 4,30,   1318, 1, 1 },
3027   { 1901, 4,20,   1319, 1, 1 },
3028   { 1902, 4,10,   1320, 1, 1 },
3029   { 1903, 3,30,   1321, 1, 1 },
3030   { 1904, 3,19,   1322, 1, 1 },
3031   { 1905, 3, 8,   1323, 1, 1 },
3032   { 1906, 2,25,   1324, 1, 1 },
3033   { 1907, 2,14,   1325, 1, 1 },
3034   { 1908, 2, 4,   1326, 1, 1 },
3035   { 1909, 1,23,   1327, 1, 1 },
3036   { 1910, 1,13,   1328, 1, 1 },
3037   { 1911, 1, 2,   1329, 1, 1 },
3038   { 1911,12,22,   1330, 1, 1 },
3039   { 1912,12,10,   1331, 1, 1 },
3040   { 1913,11,30,   1332, 1, 1 },
3041   { 1914,11,19,   1333, 1, 1 },
3042   { 1915,11, 9,   1334, 1, 1 },
3043   { 1916,10,28,   1335, 1, 1 },
3044   { 1917,10,18,   1336, 1, 1 },
3045   { 1918,10, 7,   1337, 1, 1 },
3046   { 1919, 9,26,   1338, 1, 1 },
3047   { 1920, 9,14,   1339, 1, 1 },
3048   { 1921, 9, 4,   1340, 1, 1 },
3049   { 1922, 8,24,   1341, 1, 1 },
3050   { 1923, 8,14,   1342, 1, 1 },
3051   { 1924, 8, 2,   1343, 1, 1 },
3052   { 1925, 7,22,   1344, 1, 1 },
3053   { 1926, 7,11,   1345, 1, 1 },
3054   { 1927, 6,30,   1346, 1, 1 },
3055   { 1928, 6,19,   1347, 1, 1 },
3056   { 1929, 6, 9,   1348, 1, 1 },
3057   { 1930, 5,29,   1349, 1, 1 },
3058   { 1931, 5,19,   1350, 1, 1 },
3059   { 1932, 5, 7,   1351, 1, 1 },
3060   { 1933, 4,26,   1352, 1, 1 },
3061   { 1934, 4,15,   1353, 1, 1 },
3062   { 1935, 4, 5,   1354, 1, 1 },
3063   { 1936, 3,24,   1355, 1, 1 },
3064   { 1937, 3,14,   1356, 1, 1 },
3065   { 1938, 3, 4,   1357, 1, 1 },
3066   { 1939, 2,21,   1358, 1, 1 },
3067   { 1940, 2,10,   1359, 1, 1 },
3068   { 1941, 1,29,   1360, 1, 1 },
3069   { 1942, 1,18,   1361, 1, 1 },
3070   { 1943, 1, 8,   1362, 1, 1 },
3071   { 1943,12,28,   1363, 1, 1 },
3072   { 1944,12,17,   1364, 1, 1 },
3073   { 1945,12, 6,   1365, 1, 1 },
3074   { 1946,11,25,   1366, 1, 1 },
3075   { 1947,11,14,   1367, 1, 1 },
3076   { 1948,11, 3,   1368, 1, 1 },
3077   { 1949,10,23,   1369, 1, 1 },
3078   { 1950,10,13,   1370, 1, 1 },
3079   { 1951,10, 3,   1371, 1, 1 },
3080   { 1952, 9,21,   1372, 1, 1 },
3081   { 1953, 9,10,   1373, 1, 1 },
3082   { 1954, 8,30,   1374, 1, 1 },
3083   { 1955, 8,19,   1375, 1, 1 },
3084   { 1956, 8, 8,   1376, 1, 1 },
3085   { 1957, 7,29,   1377, 1, 1 },
3086   { 1958, 7,18,   1378, 1, 1 },
3087   { 1959, 7, 8,   1379, 1, 1 },
3088   { 1960, 6,26,   1380, 1, 1 },
3089   { 1961, 6,15,   1381, 1, 1 },
3090   { 1962, 6, 4,   1382, 1, 1 },
3091   { 1963, 5,24,   1383, 1, 1 },
3092   { 1964, 5,13,   1384, 1, 1 },
3093   { 1965, 5, 3,   1385, 1, 1 },
3094   { 1966, 4,22,   1386, 1, 1 },
3095   { 1967, 4,11,   1387, 1, 1 },
3096   { 1968, 3,30,   1388, 1, 1 },
3097   { 1969, 3,19,   1389, 1, 1 },
3098   { 1970, 3, 9,   1390, 1, 1 },
3099   { 1971, 2,27,   1391, 1, 1 },
3100   { 1972, 2,16,   1392, 1, 1 },
3101   { 1973, 2, 5,   1393, 1, 1 },
3102   { 1974, 1,25,   1394, 1, 1 },
3103   { 1975, 1,14,   1395, 1, 1 },
3104   { 1976, 1, 3,   1396, 1, 1 },
3105   { 1976,12,22,   1397, 1, 1 },
3106   { 1977,12,12,   1398, 1, 1 },
3107   { 1978,12, 1,   1399, 1, 1 },
3108   { 1979,11,21,   1400, 1, 1 },
3109   { 1980,11, 9,   1401, 1, 1 },
3110   { 1981,10,29,   1402, 1, 1 },
3111   { 1982,10,18,   1403, 1, 1 },
3112   { 1983,10, 8,   1404, 1, 1 },
3113   { 1984, 9,26,   1405, 1, 1 },
3114   { 1985, 9,16,   1406, 1, 1 },
3115   { 1986, 9, 6,   1407, 1, 1 },
3116   { 1987, 8,26,   1408, 1, 1 },
3117   { 1988, 8,14,   1409, 1, 1 },
3118   { 1989, 8, 3,   1410, 1, 1 },
3119   { 1990, 7,23,   1411, 1, 1 },
3120   { 1991, 7,13,   1412, 1, 1 },
3121   { 1992, 7, 2,   1413, 1, 1 },
3122   { 1993, 6,21,   1414, 1, 1 },
3123   { 1994, 6,11,   1415, 1, 1 },
3124   { 1995, 5,31,   1416, 1, 1 },
3125   { 1996, 5,19,   1417, 1, 1 },
3126   { 1997, 5, 8,   1418, 1, 1 },
3127   { 1998, 4,28,   1419, 1, 1 },
3128   { 1999, 4,17,   1420, 1, 1 },
3129   { 1999, 5,16,   1420, 2, 1 },
3130   { 1999, 6,15,   1420, 3, 1 },
3131   { 1999, 7,14,   1420, 4, 1 },
3132   { 1999, 8,12,   1420, 5, 1 },
3133   { 1999, 9,11,   1420, 6, 1 },
3134   { 1999,10,10,   1420, 7, 1 },
3135   { 1999,11, 9,   1420, 8, 1 },
3136   { 1999,12, 9,   1420, 9, 1 },
3137   { 2000, 1, 8,   1420,10, 1 },
3138   { 2000, 2, 7,   1420,11, 1 },
3139   { 2000, 3, 7,   1420,12, 1 },
3140   { 2000, 4, 6,   1421, 1, 1 },
3141   { 2000, 5, 5,   1421, 2, 1 },
3142   { 2000, 6, 3,   1421, 3, 1 },
3143   { 2000, 7, 3,   1421, 4, 1 },
3144   { 2000, 8, 1,   1421, 5, 1 },
3145   { 2000, 8,30,   1421, 6, 1 },
3146   { 2000, 9,28,   1421, 7, 1 },
3147   { 2000,10,28,   1421, 8, 1 },
3148   { 2000,11,27,   1421, 9, 1 },
3149   { 2000,12,27,   1421,10, 1 },
3150   { 2001, 1,26,   1421,11, 1 },
3151   { 2001, 2,24,   1421,12, 1 },
3152   { 2001, 3,26,   1422, 1, 1 },
3153   { 2001, 4,25,   1422, 2, 1 },
3154   { 2001, 5,24,   1422, 3, 1 },
3155   { 2001, 6,22,   1422, 4, 1 },
3156   { 2001, 7,22,   1422, 5, 1 },
3157   { 2001, 8,20,   1422, 6, 1 },
3158   { 2001, 9,18,   1422, 7, 1 },
3159   { 2001,10,17,   1422, 8, 1 },
3160   { 2001,11,16,   1422, 9, 1 },
3161   { 2001,12,16,   1422,10, 1 },
3162   { 2002, 1,15,   1422,11, 1 },
3163   { 2002, 2,13,   1422,12, 1 },
3164   { 2002, 3,15,   1423, 1, 1 },
3165   { 2002, 4,14,   1423, 2, 1 },
3166   { 2002, 5,13,   1423, 3, 1 },
3167   { 2002, 6,12,   1423, 4, 1 },
3168   { 2002, 7,11,   1423, 5, 1 },
3169   { 2002, 8,10,   1423, 6, 1 },
3170   { 2002, 9, 8,   1423, 7, 1 },
3171   { 2002,10, 7,   1423, 8, 1 },
3172   { 2002,11, 6,   1423, 9, 1 },
3173   { 2002,12, 5,   1423,10, 1 },
3174   { 2003, 1, 4,   1423,11, 1 },
3175   { 2003, 2, 2,   1423,12, 1 },
3176   { 2003, 3, 4,   1424, 1, 1 },
3177   { 2003, 4, 3,   1424, 2, 1 },
3178   { 2003, 5, 2,   1424, 3, 1 },
3179   { 2003, 6, 1,   1424, 4, 1 },
3180   { 2003, 7, 1,   1424, 5, 1 },
3181   { 2003, 7,30,   1424, 6, 1 },
3182   { 2003, 8,29,   1424, 7, 1 },
3183   { 2003, 9,27,   1424, 8, 1 },
3184   { 2003,10,26,   1424, 9, 1 },
3185   { 2003,11,25,   1424,10, 1 },
3186   { 2003,12,24,   1424,11, 1 },
3187   { 2004, 1,23,   1424,12, 1 },
3188   { 2004, 2,21,   1425, 1, 1 },
3189   { 2004, 3,22,   1425, 2, 1 },
3190   { 2004, 4,20,   1425, 3, 1 },
3191   { 2004, 5,20,   1425, 4, 1 },
3192   { 2004, 6,19,   1425, 5, 1 },
3193   { 2004, 7,18,   1425, 6, 1 },
3194   { 2004, 8,17,   1425, 7, 1 },
3195   { 2004, 9,15,   1425, 8, 1 },
3196   { 2004,10,15,   1425, 9, 1 },
3197   { 2004,11,14,   1425,10, 1 },
3198   { 2004,12,13,   1425,11, 1 },
3199   { 2005, 1,12,   1425,12, 1 },
3200   { 2005, 2,10,   1426, 1, 1 },
3201   { 2005, 3,11,   1426, 2, 1 },
3202   { 2005, 4,10,   1426, 3, 1 },
3203   { 2005, 5, 9,   1426, 4, 1 },
3204   { 2005, 6, 8,   1426, 5, 1 },
3205   { 2005, 7, 7,   1426, 6, 1 },
3206   { 2005, 8, 6,   1426, 7, 1 },
3207   { 2005, 9, 5,   1426, 8, 1 },
3208   { 2005,10, 4,   1426, 9, 1 },
3209   { 2005,11, 3,   1426,10, 1 },
3210   { 2005,12, 3,   1426,11, 1 },
3211   { 2006, 1, 1,   1426,12, 1 },
3212   { 2006, 1,31,   1427, 1, 1 },
3213   { 2006, 3, 1,   1427, 2, 1 },
3214   { 2006, 3,30,   1427, 3, 1 },
3215   { 2006, 4,29,   1427, 4, 1 },
3216   { 2006, 5,28,   1427, 5, 1 },
3217   { 2006, 6,27,   1427, 6, 1 },
3218   { 2006, 7,26,   1427, 7, 1 },
3219   { 2006, 8,25,   1427, 8, 1 },
3220   { 2006, 9,24,   1427, 9, 1 },
3221   { 2006,10,23,   1427,10, 1 },
3222   { 2006,11,22,   1427,11, 1 },
3223   { 2006,12,22,   1427,12, 1 },
3224   { 2007, 1,20,   1428, 1, 1 },
3225   { 2007, 2,19,   1428, 2, 1 },
3226   { 2007, 3,20,   1428, 3, 1 },
3227   { 2007, 4,18,   1428, 4, 1 },
3228   { 2007, 5,18,   1428, 5, 1 },
3229   { 2007, 6,16,   1428, 6, 1 },
3230   { 2007, 7,15,   1428, 7, 1 },
3231   { 2007, 8,14,   1428, 8, 1 },
3232   { 2007, 9,13,   1428, 9, 1 },
3233   { 2007,10,13,   1428,10, 1 },
3234   { 2007,11,11,   1428,11, 1 },
3235   { 2007,12,11,   1428,12, 1 },
3236   { 2008, 1,10,   1429, 1, 1 },
3237   { 2008, 2, 8,   1429, 2, 1 },
3238   { 2008, 3, 9,   1429, 3, 1 },
3239   { 2008, 4, 7,   1429, 4, 1 },
3240   { 2008, 5, 6,   1429, 5, 1 },
3241   { 2008, 6, 5,   1429, 6, 1 },
3242   { 2008, 7, 4,   1429, 7, 1 },
3243   { 2008, 8, 2,   1429, 8, 1 },
3244   { 2008, 9, 1,   1429, 9, 1 },
3245   { 2008,10, 1,   1429,10, 1 },
3246   { 2008,10,30,   1429,11, 1 },
3247   { 2008,11,29,   1429,12, 1 },
3248   { 2008,12,29,   1430, 1, 1 },
3249   { 2009, 1,27,   1430, 2, 1 },
3250   { 2009, 2,26,   1430, 3, 1 },
3251   { 2009, 3,28,   1430, 4, 1 },
3252   { 2009, 4,26,   1430, 5, 1 },
3253   { 2009, 5,25,   1430, 6, 1 },
3254   { 2009, 6,24,   1430, 7, 1 },
3255   { 2009, 7,23,   1430, 8, 1 },
3256   { 2009, 8,22,   1430, 9, 1 },
3257   { 2009, 9,20,   1430,10, 1 },
3258   { 2009,10,20,   1430,11, 1 },
3259   { 2009,11,18,   1430,12, 1 },
3260   { 2009,12,18,   1431, 1, 1 },
3261   { 2010, 1,16,   1431, 2, 1 },
3262   { 2010, 2,15,   1431, 3, 1 },
3263   { 2010, 3,17,   1431, 4, 1 },
3264   { 2010, 4,15,   1431, 5, 1 },
3265   { 2010, 5,15,   1431, 6, 1 },
3266   { 2010, 6,13,   1431, 7, 1 },
3267   { 2010, 7,13,   1431, 8, 1 },
3268   { 2010, 8,11,   1431, 9, 1 },
3269   { 2010, 9,10,   1431,10, 1 },
3270   { 2010,10, 9,   1431,11, 1 },
3271   { 2010,11, 7,   1431,12, 1 },
3272   { 2010,12, 7,   1432, 1, 1 },
3273   { 2011, 1, 5,   1432, 2, 1 },
3274   { 2011, 2, 4,   1432, 3, 1 },
3275   { 2011, 3, 6,   1432, 4, 1 },
3276   { 2011, 4, 5,   1432, 5, 1 },
3277   { 2011, 5, 4,   1432, 6, 1 },
3278   { 2011, 6, 3,   1432, 7, 1 },
3279   { 2011, 7, 2,   1432, 8, 1 },
3280   { 2011, 8, 1,   1432, 9, 1 },
3281   { 2011, 8,30,   1432,10, 1 },
3282   { 2011, 9,29,   1432,11, 1 },
3283   { 2011,10,28,   1432,12, 1 },
3284   { 2011,11,26,   1433, 1, 1 },
3285   { 2011,12,26,   1433, 2, 1 },
3286   { 2012, 1,24,   1433, 3, 1 },
3287   { 2012, 2,23,   1433, 4, 1 },
3288   { 2012, 3,24,   1433, 5, 1 },
3289   { 2012, 4,22,   1433, 6, 1 },
3290   { 2012, 5,22,   1433, 7, 1 },
3291   { 2012, 6,21,   1433, 8, 1 },
3292   { 2012, 7,20,   1433, 9, 1 },
3293   { 2012, 8,19,   1433,10, 1 },
3294   { 2012, 9,17,   1433,11, 1 },
3295   { 2012,10,17,   1433,12, 1 },
3296   { 2012,11,15,   1434, 1, 1 },
3297   { 2012,12,14,   1434, 2, 1 },
3298   { 2013, 1,13,   1434, 3, 1 },
3299   { 2013, 2,11,   1434, 4, 1 },
3300   { 2013, 3,13,   1434, 5, 1 },
3301   { 2013, 4,11,   1434, 6, 1 },
3302   { 2013, 5,11,   1434, 7, 1 },
3303   { 2013, 6,10,   1434, 8, 1 },
3304   { 2013, 7, 9,   1434, 9, 1 },
3305   { 2013, 8, 8,   1434,10, 1 },
3306   { 2013, 9, 7,   1434,11, 1 },
3307   { 2013,10, 6,   1434,12, 1 },
3308   { 2013,11, 4,   1435, 1, 1 },
3309   { 2013,12, 4,   1435, 2, 1 },
3310   { 2014, 1, 2,   1435, 3, 1 },
3311   { 2014, 2, 1,   1435, 4, 1 },
3312   { 2014, 3, 2,   1435, 5, 1 },
3313   { 2014, 4, 1,   1435, 6, 1 },
3314   { 2014, 4,30,   1435, 7, 1 },
3315   { 2014, 5,30,   1435, 8, 1 },
3316   { 2014, 6,28,   1435, 9, 1 },
3317   { 2014, 7,28,   1435,10, 1 },
3318   { 2014, 8,27,   1435,11, 1 },
3319   { 2014, 9,25,   1435,12, 1 },
3320   { 2014,10,25,   1436, 1, 1 },
3321   { 2014,11,23,   1436, 2, 1 },
3322   { 2014,12,23,   1436, 3, 1 },
3323   { 2015, 1,21,   1436, 4, 1 },
3324   { 2015, 2,20,   1436, 5, 1 },
3325   { 2015, 3,21,   1436, 6, 1 },
3326   { 2015, 4,20,   1436, 7, 1 },
3327   { 2015, 5,19,   1436, 8, 1 },
3328   { 2015, 6,18,   1436, 9, 1 },
3329   { 2015, 7,17,   1436,10, 1 },
3330   { 2015, 8,16,   1436,11, 1 },
3331   { 2015, 9,14,   1436,12, 1 },
3332   { 2015,10,14,   1437, 1, 1 },
3333   { 2015,11,13,   1437, 2, 1 },
3334   { 2015,12,12,   1437, 3, 1 },
3335   { 2016, 1,11,   1437, 4, 1 },
3336   { 2016, 2,10,   1437, 5, 1 },
3337   { 2016, 3,10,   1437, 6, 1 },
3338   { 2016, 4, 8,   1437, 7, 1 },
3339   { 2016, 5, 8,   1437, 8, 1 },
3340   { 2016, 6, 6,   1437, 9, 1 },
3341   { 2016, 7, 6,   1437,10, 1 },
3342   { 2016, 8, 4,   1437,11, 1 },
3343   { 2016, 9, 2,   1437,12, 1 },
3344   { 2016,10, 2,   1438, 1, 1 },
3345   { 2016,11, 1,   1438, 2, 1 },
3346   { 2016,11,30,   1438, 3, 1 },
3347   { 2016,12,30,   1438, 4, 1 },
3348   { 2017, 1,29,   1438, 5, 1 },
3349   { 2017, 2,28,   1438, 6, 1 },
3350   { 2017, 3,29,   1438, 7, 1 },
3351   { 2017, 4,27,   1438, 8, 1 },
3352   { 2017, 5,27,   1438, 9, 1 },
3353   { 2017, 6,25,   1438,10, 1 },
3354   { 2017, 7,24,   1438,11, 1 },
3355   { 2017, 8,23,   1438,12, 1 },
3356   { 2017, 9,21,   1439, 1, 1 },
3357   { 2017,10,21,   1439, 2, 1 },
3358   { 2017,11,19,   1439, 3, 1 },
3359   { 2017,12,19,   1439, 4, 1 },
3360   { 2018, 1,18,   1439, 5, 1 },
3361   { 2018, 2,17,   1439, 6, 1 },
3362   { 2018, 3,18,   1439, 7, 1 },
3363   { 2018, 4,17,   1439, 8, 1 },
3364   { 2018, 5,16,   1439, 9, 1 },
3365   { 2018, 6,15,   1439,10, 1 },
3366   { 2018, 7,14,   1439,11, 1 },
3367   { 2018, 8,12,   1439,12, 1 },
3368   { 2018, 9,11,   1440, 1, 1 },
3369   { 2019, 8,31,   1441, 1, 1 },
3370   { 2020, 8,20,   1442, 1, 1 },
3371   { 2021, 8, 9,   1443, 1, 1 },
3372   { 2022, 7,30,   1444, 1, 1 },
3373   { 2023, 7,19,   1445, 1, 1 },
3374   { 2024, 7, 7,   1446, 1, 1 },
3375   { 2025, 6,26,   1447, 1, 1 },
3376   { 2026, 6,16,   1448, 1, 1 },
3377   { 2027, 6, 6,   1449, 1, 1 },
3378   { 2028, 5,25,   1450, 1, 1 },
3379   { 2029, 5,14,   1451, 1, 1 },
3380   { 2030, 5, 4,   1452, 1, 1 },
3381   { 2031, 4,23,   1453, 1, 1 },
3382   { 2032, 4,11,   1454, 1, 1 },
3383   { 2033, 4, 1,   1455, 1, 1 },
3384   { 2034, 3,22,   1456, 1, 1 },
3385   { 2035, 3,11,   1457, 1, 1 },
3386   { 2036, 2,29,   1458, 1, 1 },
3387   { 2037, 2,17,   1459, 1, 1 },
3388   { 2038, 2, 6,   1460, 1, 1 },
3389   { 2039, 1,26,   1461, 1, 1 },
3390   { 2040, 1,15,   1462, 1, 1 },
3391   { 2041, 1, 4,   1463, 1, 1 },
3392   { 2041,12,25,   1464, 1, 1 },
3393   { 2042,12,14,   1465, 1, 1 },
3394   { 2043,12, 3,   1466, 1, 1 },
3395   { 2044,11,21,   1467, 1, 1 },
3396   { 2045,11,11,   1468, 1, 1 },
3397   { 2046,10,31,   1469, 1, 1 },
3398   { 2047,10,21,   1470, 1, 1 },
3399   { 2048,10, 9,   1471, 1, 1 },
3400   { 2049, 9,29,   1472, 1, 1 },
3401   { 2050, 9,18,   1473, 1, 1 },
3402   { 2051, 9, 7,   1474, 1, 1 },
3403   { 2052, 8,26,   1475, 1, 1 },
3404   { 2053, 8,15,   1476, 1, 1 },
3405   { 2054, 8, 5,   1477, 1, 1 },
3406   { 2055, 7,26,   1478, 1, 1 },
3407   { 2056, 7,14,   1479, 1, 1 },
3408   { 2057, 7, 3,   1480, 1, 1 },
3409   { 2058, 6,22,   1481, 1, 1 },
3410   { 2059, 6,11,   1482, 1, 1 },
3411   { 2061, 5,21,   1484, 1, 1 },
3412   { 2063, 4,30,   1486, 1, 1 },
3413   { 2065, 4, 7,   1488, 1, 1 },
3414   { 2067, 3,17,   1490, 1, 1 },
3415   { 2069, 2,23,   1492, 1, 1 },
3416   { 2071, 2, 2,   1494, 1, 1 },
3417   { 2073, 1,10,   1496, 1, 1 },
3418   { 2074,12,20,   1498, 1, 1 },
3419   { 2076,11,28,   1500, 1, 1 },
3420   {    0, 0, 0,      0, 0, 0 }, // terminator
3421 };
3422 
3423 static const char16_t zoneSA[] = {0x41,0x73,0x69,0x61,0x2F,0x52,0x69,0x79,0x61,0x64,0x68,0}; // "Asia/Riyadh"
3424 
TestIslamicUmAlQura()3425 void CalendarTest::TestIslamicUmAlQura() {
3426 
3427     UErrorCode status = U_ZERO_ERROR;
3428     Locale umalquraLoc("ar_SA@calendar=islamic-umalqura");
3429     Locale gregoLoc("ar_SA@calendar=gregorian");
3430     TimeZone* tzSA = TimeZone::createTimeZone(UnicodeString(true, zoneSA, -1));
3431     Calendar* tstCal = Calendar::createInstance(*tzSA, umalquraLoc, status);
3432     Calendar* gregCal = Calendar::createInstance(*tzSA, gregoLoc, status);
3433 
3434     IslamicCalendar* iCal = dynamic_cast<IslamicCalendar*>(tstCal);
3435     if(uprv_strcmp(iCal->getType(), "islamic-umalqura") != 0) {
3436         errln("wrong type of calendar created - %s", iCal->getType());
3437     }
3438 
3439     int32_t firstYear = 1318;
3440     int32_t lastYear = 1368;    // just enough to be pretty sure
3441     //int32_t lastYear = 1480;    // the whole shootin' match
3442 
3443     tstCal->clear();
3444     tstCal->setLenient(false);
3445 
3446     int32_t day=0, month=0, year=0, initDay = 27, initMonth = IslamicCalendar::RAJAB, initYear = 1434;
3447 
3448     for( int32_t startYear = firstYear; startYear <= lastYear; startYear++) {
3449         setAndTestWholeYear(tstCal, startYear, status);
3450         status = U_ZERO_ERROR;
3451     }
3452 
3453     initMonth = IslamicCalendar::RABI_2;
3454     initDay = 5;
3455     int32_t loopCnt = 25;
3456     tstCal->clear();
3457     setAndTestCalendar( tstCal, initMonth, initDay, initYear, status);
3458     TEST_CHECK_STATUS;
3459 
3460     for(int x=1; x<=loopCnt; x++) {
3461         day = tstCal->get(UCAL_DAY_OF_MONTH,status);
3462         month = tstCal->get(UCAL_MONTH,status);
3463         year = tstCal->get(UCAL_YEAR,status);
3464         TEST_CHECK_STATUS;
3465         tstCal->roll(UCAL_DAY_OF_MONTH, (UBool)true, status);
3466         TEST_CHECK_STATUS;
3467     }
3468 
3469     if(day != (initDay + loopCnt - 1) || month != IslamicCalendar::RABI_2 || year != 1434)
3470       errln("invalid values for RABI_2 date after roll of %d", loopCnt);
3471 
3472     status = U_ZERO_ERROR;
3473     tstCal->clear();
3474     initMonth = 2;
3475     initDay = 30;
3476     setAndTestCalendar( tstCal, initMonth, initDay, initYear, status);
3477     if(U_SUCCESS(status)) {
3478         errln("error NOT detected status %i",status);
3479         errln("      init values:\tmonth %i\tday %i\tyear %i", initMonth, initDay, initYear);
3480         int32_t day = tstCal->get(UCAL_DAY_OF_MONTH, status);
3481         int32_t month = tstCal->get(UCAL_MONTH, status);
3482         int32_t year = tstCal->get(UCAL_YEAR, status);
3483         errln("values post set():\tmonth %i\tday %i\tyear %i",month, day, year);
3484     }
3485 
3486     status = U_ZERO_ERROR;
3487     tstCal->clear();
3488     initMonth = 3;
3489     initDay = 30;
3490     setAndTestCalendar( tstCal, initMonth, initDay, initYear, status);
3491     TEST_CHECK_STATUS;
3492 
3493     SimpleDateFormat* formatter = new SimpleDateFormat("yyyy-MM-dd", Locale::getUS(), status);
3494     UDate date = formatter->parse("1975-05-06", status);
3495     Calendar* is_cal = Calendar::createInstance(umalquraLoc, status);
3496     is_cal->setTime(date, status);
3497     int32_t is_day = is_cal->get(UCAL_DAY_OF_MONTH,status);
3498     int32_t is_month = is_cal->get(UCAL_MONTH,status);
3499     int32_t is_year = is_cal->get(UCAL_YEAR,status);
3500     TEST_CHECK_STATUS;
3501     if(is_day != 24 || is_month != IslamicCalendar::RABI_2 || is_year != 1395)
3502         errln("unexpected conversion date month %i not %i or day %i not 24 or year %i not 1395", is_month, IslamicCalendar::RABI_2, is_day, is_year);
3503 
3504     UDate date2 = is_cal->getTime(status);
3505     TEST_CHECK_STATUS;
3506     if(date2 != date) {
3507         errln("before(%f) and after(%f) dates don't match up!",date, date2);
3508     }
3509 
3510     // check against data
3511     const GregoUmmAlQuraMap* guMapPtr;
3512     gregCal->clear();
3513     tstCal->clear();
3514     for (guMapPtr = guMappings; guMapPtr->gYear != 0; guMapPtr++) {
3515         status = U_ZERO_ERROR;
3516         gregCal->set(guMapPtr->gYear, guMapPtr->gMon - 1, guMapPtr->gDay, 12, 0);
3517         date = gregCal->getTime(status);
3518         tstCal->setTime(date, status);
3519         int32_t uYear = tstCal->get(UCAL_YEAR, status);
3520         int32_t uMon = tstCal->get(UCAL_MONTH, status) + 1;
3521         int32_t uDay = tstCal->get(UCAL_DATE, status);
3522         if(U_FAILURE(status)) {
3523             errln("For gregorian %4d-%02d-%02d, get status %s",
3524                     guMapPtr->gYear, guMapPtr->gMon, guMapPtr->gDay, u_errorName(status) );
3525         } else if (uYear != guMapPtr->uYear || uMon != guMapPtr->uMon || uDay != guMapPtr->uDay) {
3526             errln("For gregorian %4d-%02d-%02d, expect umalqura %4d-%02d-%02d, get %4d-%02d-%02d",
3527                     guMapPtr->gYear, guMapPtr->gMon, guMapPtr->gDay,
3528                     guMapPtr->uYear, guMapPtr->uMon, guMapPtr->uDay, uYear, uMon, uDay );
3529         }
3530     }
3531 
3532     delete is_cal;
3533     delete formatter;
3534     delete gregCal;
3535     delete tstCal;
3536     delete tzSA;
3537 }
3538 
TestIslamicTabularDates()3539 void CalendarTest::TestIslamicTabularDates() {
3540     UErrorCode status = U_ZERO_ERROR;
3541     Locale islamicLoc("ar_SA@calendar=islamic-civil");
3542     Locale tblaLoc("ar_SA@calendar=islamic-tbla");
3543     SimpleDateFormat* formatter = new SimpleDateFormat("yyyy-MM-dd", Locale::getUS(), status);
3544     UDate date = formatter->parse("1975-05-06", status);
3545 
3546     Calendar* tstCal = Calendar::createInstance(islamicLoc, status);
3547     tstCal->setTime(date, status);
3548     int32_t is_day = tstCal->get(UCAL_DAY_OF_MONTH,status);
3549     int32_t is_month = tstCal->get(UCAL_MONTH,status);
3550     int32_t is_year = tstCal->get(UCAL_YEAR,status);
3551     TEST_CHECK_STATUS;
3552     delete tstCal;
3553 
3554     tstCal = Calendar::createInstance(tblaLoc, status);
3555     tstCal->setTime(date, status);
3556     int32_t tbla_day = tstCal->get(UCAL_DAY_OF_MONTH,status);
3557     int32_t tbla_month = tstCal->get(UCAL_MONTH,status);
3558     int32_t tbla_year = tstCal->get(UCAL_YEAR,status);
3559     TEST_CHECK_STATUS;
3560 
3561     if(tbla_month != is_month || tbla_year != is_year)
3562         errln("unexpected difference between islamic and tbla month %d : %d and/or year %d : %d",tbla_month,is_month,tbla_year,is_year);
3563 
3564     if(tbla_day - is_day != 1)
3565         errln("unexpected day difference between islamic and tbla: %d : %d ",tbla_day,is_day);
3566     delete tstCal;
3567     delete formatter;
3568 }
3569 
TestHebrewMonthValidation()3570 void CalendarTest::TestHebrewMonthValidation() {
3571     UErrorCode status = U_ZERO_ERROR;
3572     LocalPointer<Calendar>  cal(Calendar::createInstance(Locale::createFromName("he_IL@calendar=hebrew"), status));
3573     if (failure(status, "Calendar::createInstance, locale:he_IL@calendar=hebrew", true)) return;
3574     Calendar *pCal = cal.getAlias();
3575 
3576     UDate d;
3577     pCal->setLenient(false);
3578 
3579     // 5776 is a leap year and has month Adar I
3580     pCal->set(5776, HebrewCalendar::ADAR_1, 1);
3581     d = pCal->getTime(status);
3582     if (U_FAILURE(status)) {
3583         errln("Fail: 5776 Adar I 1 is a valid date.");
3584     }
3585     status = U_ZERO_ERROR;
3586 
3587     // 5777 is NOT a lear year and does not have month Adar I
3588     pCal->set(5777, HebrewCalendar::ADAR_1, 1);
3589     d = pCal->getTime(status);
3590     (void)d;
3591     if (status == U_ILLEGAL_ARGUMENT_ERROR) {
3592         logln("Info: U_ILLEGAL_ARGUMENT_ERROR, because 5777 Adar I 1 is not a valid date.");
3593     } else {
3594         errln("Fail: U_ILLEGAL_ARGUMENT_ERROR should be set for input date 5777 Adar I 1.");
3595     }
3596 }
3597 
TestWeekData()3598 void CalendarTest::TestWeekData() {
3599     // Each line contains two locales using the same set of week rule data.
3600     const char* LOCALE_PAIRS[] = {
3601         "en",       "en_US",
3602         "de",       "de_DE",
3603         "de_DE",    "en_DE",
3604         "en_GB",    "und_GB",
3605         "ar_EG",    "en_EG",
3606         "ar_SA",    "fr_SA",
3607         0
3608     };
3609 
3610     UErrorCode status;
3611 
3612     for (int32_t i = 0; LOCALE_PAIRS[i] != 0; i += 2) {
3613         status = U_ZERO_ERROR;
3614         LocalPointer<Calendar>  cal1(Calendar::createInstance(LOCALE_PAIRS[i], status));
3615         LocalPointer<Calendar>  cal2(Calendar::createInstance(LOCALE_PAIRS[i + 1], status));
3616         TEST_CHECK_STATUS_LOCALE(LOCALE_PAIRS[i]);
3617 
3618         // First day of week
3619         UCalendarDaysOfWeek dow1 = cal1->getFirstDayOfWeek(status);
3620         UCalendarDaysOfWeek dow2 = cal2->getFirstDayOfWeek(status);
3621         TEST_CHECK_STATUS;
3622         TEST_ASSERT(dow1 == dow2);
3623 
3624         // Minimum days in first week
3625         uint8_t minDays1 = cal1->getMinimalDaysInFirstWeek();
3626         uint8_t minDays2 = cal2->getMinimalDaysInFirstWeek();
3627         TEST_ASSERT(minDays1 == minDays2);
3628 
3629         // Weekdays and Weekends
3630         for (int32_t d = UCAL_SUNDAY; d <= UCAL_SATURDAY; d++) {
3631             status = U_ZERO_ERROR;
3632             UCalendarWeekdayType wdt1 = cal1->getDayOfWeekType((UCalendarDaysOfWeek)d, status);
3633             UCalendarWeekdayType wdt2 = cal2->getDayOfWeekType((UCalendarDaysOfWeek)d, status);
3634             TEST_CHECK_STATUS;
3635             TEST_ASSERT(wdt1 == wdt2);
3636         }
3637     }
3638 }
3639 
3640 typedef struct {
3641     const char* zone;
3642     const CalFields base;
3643     int32_t deltaDays;
3644     UCalendarWallTimeOption skippedWTOpt;
3645     const CalFields expected;
3646 } TestAddAcrossZoneTransitionData;
3647 
3648 static const TestAddAcrossZoneTransitionData AAZTDATA[] =
3649 {
3650     // Time zone                Base wall time                      day(s)  Skipped time options
3651     //                          Expected wall time
3652 
3653     // Add 1 day, from the date before DST transition
3654     {"America/Los_Angeles",     CalFields(2014,3,8,1,59,59,999),    1,      UCAL_WALLTIME_FIRST,
3655                                 CalFields(2014,3,9,1,59,59,999)},
3656 
3657     {"America/Los_Angeles",     CalFields(2014,3,8,1,59,59,999),    1,      UCAL_WALLTIME_LAST,
3658                                 CalFields(2014,3,9,1,59,59,999)},
3659 
3660     {"America/Los_Angeles",     CalFields(2014,3,8,1,59,59,999),    1,      UCAL_WALLTIME_NEXT_VALID,
3661                                 CalFields(2014,3,9,1,59,59,999)},
3662 
3663 
3664     {"America/Los_Angeles",     CalFields(2014,3,8,2,0,0,0),        1,      UCAL_WALLTIME_FIRST,
3665                                 CalFields(2014,3,9,1,0,0,0)},
3666 
3667     {"America/Los_Angeles",     CalFields(2014,3,8,2,0,0,0),        1,      UCAL_WALLTIME_LAST,
3668                                 CalFields(2014,3,9,3,0,0,0)},
3669 
3670     {"America/Los_Angeles",     CalFields(2014,3,8,2,0,0,0),        1,      UCAL_WALLTIME_NEXT_VALID,
3671                                 CalFields(2014,3,9,3,0,0,0)},
3672 
3673 
3674     {"America/Los_Angeles",     CalFields(2014,3,8,2,30,0,0),       1,      UCAL_WALLTIME_FIRST,
3675                                 CalFields(2014,3,9,1,30,0,0)},
3676 
3677     {"America/Los_Angeles",     CalFields(2014,3,8,2,30,0,0),       1,      UCAL_WALLTIME_LAST,
3678                                 CalFields(2014,3,9,3,30,0,0)},
3679 
3680     {"America/Los_Angeles",     CalFields(2014,3,8,2,30,0,0),       1,      UCAL_WALLTIME_NEXT_VALID,
3681                                 CalFields(2014,3,9,3,0,0,0)},
3682 
3683 
3684     {"America/Los_Angeles",     CalFields(2014,3,8,3,0,0,0),        1,      UCAL_WALLTIME_FIRST,
3685                                 CalFields(2014,3,9,3,0,0,0)},
3686 
3687     {"America/Los_Angeles",     CalFields(2014,3,8,3,0,0,0),        1,      UCAL_WALLTIME_LAST,
3688                                 CalFields(2014,3,9,3,0,0,0)},
3689 
3690     {"America/Los_Angeles",     CalFields(2014,3,8,3,0,0,0),        1,      UCAL_WALLTIME_NEXT_VALID,
3691                                 CalFields(2014,3,9,3,0,0,0)},
3692 
3693     // Subtract 1 day, from one day after DST transition
3694     {"America/Los_Angeles",     CalFields(2014,3,10,1,59,59,999),   -1,     UCAL_WALLTIME_FIRST,
3695                                 CalFields(2014,3,9,1,59,59,999)},
3696 
3697     {"America/Los_Angeles",     CalFields(2014,3,10,1,59,59,999),   -1,     UCAL_WALLTIME_LAST,
3698                                 CalFields(2014,3,9,1,59,59,999)},
3699 
3700     {"America/Los_Angeles",     CalFields(2014,3,10,1,59,59,999),   -1,     UCAL_WALLTIME_NEXT_VALID,
3701                                 CalFields(2014,3,9,1,59,59,999)},
3702 
3703 
3704     {"America/Los_Angeles",     CalFields(2014,3,10,2,0,0,0),       -1,     UCAL_WALLTIME_FIRST,
3705                                 CalFields(2014,3,9,1,0,0,0)},
3706 
3707     {"America/Los_Angeles",     CalFields(2014,3,10,2,0,0,0),       -1,     UCAL_WALLTIME_LAST,
3708                                 CalFields(2014,3,9,3,0,0,0)},
3709 
3710     {"America/Los_Angeles",     CalFields(2014,3,10,2,0,0,0),       -1,     UCAL_WALLTIME_NEXT_VALID,
3711                                 CalFields(2014,3,9,3,0,0,0)},
3712 
3713 
3714     {"America/Los_Angeles",     CalFields(2014,3,10,2,30,0,0),      -1,     UCAL_WALLTIME_FIRST,
3715                                 CalFields(2014,3,9,1,30,0,0)},
3716 
3717     {"America/Los_Angeles",     CalFields(2014,3,10,2,30,0,0),      -1,     UCAL_WALLTIME_LAST,
3718                                 CalFields(2014,3,9,3,30,0,0)},
3719 
3720     {"America/Los_Angeles",     CalFields(2014,3,10,2,30,0,0),      -1,     UCAL_WALLTIME_NEXT_VALID,
3721                                 CalFields(2014,3,9,3,0,0,0)},
3722 
3723 
3724     {"America/Los_Angeles",     CalFields(2014,3,10,3,0,0,0),       -1,     UCAL_WALLTIME_FIRST,
3725                                 CalFields(2014,3,9,3,0,0,0)},
3726 
3727     {"America/Los_Angeles",     CalFields(2014,3,10,3,0,0,0),       -1,     UCAL_WALLTIME_LAST,
3728                                 CalFields(2014,3,9,3,0,0,0)},
3729 
3730     {"America/Los_Angeles",     CalFields(2014,3,10,3,0,0,0),       -1,     UCAL_WALLTIME_NEXT_VALID,
3731                                 CalFields(2014,3,9,3,0,0,0)},
3732 
3733 
3734     // Test case for ticket#10544
3735     {"America/Santiago",        CalFields(2013,4,27,0,0,0,0),       134,    UCAL_WALLTIME_FIRST,
3736                                 CalFields(2013,9,7,23,0,0,0)},
3737 
3738     {"America/Santiago",        CalFields(2013,4,27,0,0,0,0),       134,    UCAL_WALLTIME_LAST,
3739                                 CalFields(2013,9,8,1,0,0,0)},
3740 
3741     {"America/Santiago",        CalFields(2013,4,27,0,0,0,0),       134,    UCAL_WALLTIME_NEXT_VALID,
3742                                 CalFields(2013,9,8,1,0,0,0)},
3743 
3744 
3745     {"America/Santiago",        CalFields(2013,4,27,0,30,0,0),      134,    UCAL_WALLTIME_FIRST,
3746                                 CalFields(2013,9,7,23,30,0,0)},
3747 
3748     {"America/Santiago",        CalFields(2013,4,27,0,30,0,0),      134,    UCAL_WALLTIME_LAST,
3749                                 CalFields(2013,9,8,1,30,0,0)},
3750 
3751     {"America/Santiago",        CalFields(2013,4,27,0,30,0,0),      134,    UCAL_WALLTIME_NEXT_VALID,
3752                                 CalFields(2013,9,8,1,0,0,0)},
3753 
3754 
3755     // Extreme transition - Pacific/Apia completely skips 2011-12-30
3756     {"Pacific/Apia",            CalFields(2011,12,29,0,0,0,0),      1,      UCAL_WALLTIME_FIRST,
3757                                 CalFields(2011,12,31,0,0,0,0)},
3758 
3759     {"Pacific/Apia",            CalFields(2011,12,29,0,0,0,0),      1,      UCAL_WALLTIME_LAST,
3760                                 CalFields(2011,12,31,0,0,0,0)},
3761 
3762     {"Pacific/Apia",            CalFields(2011,12,29,0,0,0,0),      1,      UCAL_WALLTIME_NEXT_VALID,
3763                                 CalFields(2011,12,31,0,0,0,0)},
3764 
3765 
3766     {"Pacific/Apia",            CalFields(2011,12,31,12,0,0,0),     -1,     UCAL_WALLTIME_FIRST,
3767                                 CalFields(2011,12,29,12,0,0,0)},
3768 
3769     {"Pacific/Apia",            CalFields(2011,12,31,12,0,0,0),     -1,     UCAL_WALLTIME_LAST,
3770                                 CalFields(2011,12,29,12,0,0,0)},
3771 
3772     {"Pacific/Apia",            CalFields(2011,12,31,12,0,0,0),     -1,     UCAL_WALLTIME_NEXT_VALID,
3773                                 CalFields(2011,12,29,12,0,0,0)},
3774 
3775 
3776     // 30 minutes DST - Australia/Lord_Howe
3777     {"Australia/Lord_Howe",     CalFields(2013,10,5,2,15,0,0),      1,      UCAL_WALLTIME_FIRST,
3778                                 CalFields(2013,10,6,1,45,0,0)},
3779 
3780     {"Australia/Lord_Howe",     CalFields(2013,10,5,2,15,0,0),      1,      UCAL_WALLTIME_LAST,
3781                                 CalFields(2013,10,6,2,45,0,0)},
3782 
3783     {"Australia/Lord_Howe",     CalFields(2013,10,5,2,15,0,0),      1,      UCAL_WALLTIME_NEXT_VALID,
3784                                 CalFields(2013,10,6,2,30,0,0)},
3785 
3786     {nullptr, CalFields(0,0,0,0,0,0,0), 0, UCAL_WALLTIME_LAST, CalFields(0,0,0,0,0,0,0)}
3787 };
3788 
TestAddAcrossZoneTransition()3789 void CalendarTest::TestAddAcrossZoneTransition() {
3790     UErrorCode status = U_ZERO_ERROR;
3791     GregorianCalendar cal(status);
3792     TEST_CHECK_STATUS;
3793 
3794     for (int32_t i = 0; AAZTDATA[i].zone; i++) {
3795         status = U_ZERO_ERROR;
3796         TimeZone *tz = TimeZone::createTimeZone(AAZTDATA[i].zone);
3797         cal.adoptTimeZone(tz);
3798         cal.setSkippedWallTimeOption(AAZTDATA[i].skippedWTOpt);
3799         AAZTDATA[i].base.setTo(cal);
3800         cal.add(UCAL_DATE, AAZTDATA[i].deltaDays, status);
3801         TEST_CHECK_STATUS;
3802 
3803         if (!AAZTDATA[i].expected.isEquivalentTo(cal, status)) {
3804             CalFields res(cal, status);
3805             TEST_CHECK_STATUS;
3806             char buf[32];
3807             const char *optDisp = AAZTDATA[i].skippedWTOpt == UCAL_WALLTIME_FIRST ? "FIRST" :
3808                     AAZTDATA[i].skippedWTOpt == UCAL_WALLTIME_LAST ? "LAST" : "NEXT_VALID";
3809             dataerrln(UnicodeString("Error: base:") + AAZTDATA[i].base.toString(buf, sizeof(buf)) + ", tz:" + AAZTDATA[i].zone
3810                         + ", delta:" + AAZTDATA[i].deltaDays + " day(s), opt:" + optDisp
3811                         + ", result:" + res.toString(buf, sizeof(buf))
3812                         + " - expected:" + AAZTDATA[i].expected.toString(buf, sizeof(buf)));
3813         }
3814     }
3815 }
3816 
3817 // Data in a separate file (Gregorian to Chinese lunar map)
3818 #define INCLUDED_FROM_CALTEST_CPP
3819 #include "caltestdata.h"
3820 
TestChineseCalendarMapping()3821 void CalendarTest::TestChineseCalendarMapping() {
3822     UErrorCode status = U_ZERO_ERROR;
3823     LocalPointer<TimeZone> zone(TimeZone::createTimeZone(UnicodeString("China")));
3824     Locale locEnCalGregory = Locale::createFromName("en@calendar=gregorian");
3825     Locale locEnCalChinese = Locale::createFromName("en@calendar=chinese");
3826     LocalPointer<Calendar>  calGregory(Calendar::createInstance(zone->clone(), locEnCalGregory, status));
3827     LocalPointer<Calendar>  calChinese(Calendar::createInstance(zone.orphan(), locEnCalChinese, status));
3828     if ( U_FAILURE(status) ) {
3829         errln("Fail: Calendar::createInstance fails for en with calendar=gregorian or calendar=chinese: %s", u_errorName(status));
3830     } else {
3831         const GregoToLunar * mapPtr = gregoToLunar; // in "caltestdata.h" included above
3832         calGregory->clear();
3833         calChinese->clear();
3834         for (; mapPtr->gyr != 0; mapPtr++) {
3835             status = U_ZERO_ERROR;
3836             calGregory->set(mapPtr->gyr, mapPtr->gmo - 1, mapPtr->gda, 8, 0);
3837             UDate date = calGregory->getTime(status);
3838             calChinese->setTime(date, status);
3839             if ( U_FAILURE(status) ) {
3840                 errln("Fail: for Gregorian %4d-%02d-%02d, calGregory->getTime or calChinese->setTime reports: %s",
3841                         mapPtr->gyr, mapPtr->gmo, mapPtr->gda, u_errorName(status));
3842                 continue;
3843             }
3844             int32_t era = calChinese->get(UCAL_ERA, status);
3845             int32_t yr  = calChinese->get(UCAL_YEAR, status);
3846             int32_t mo  = calChinese->get(UCAL_MONTH, status) + 1;
3847             int32_t lp  = calChinese->get(UCAL_IS_LEAP_MONTH, status);
3848             int32_t da  = calChinese->get(UCAL_DATE, status);
3849             if ( U_FAILURE(status) ) {
3850                 errln("Fail: for Gregorian %4d-%02d-%02d, calChinese->get (for era, yr, mo, leapmo, da) reports: %s",
3851                         mapPtr->gyr, mapPtr->gmo, mapPtr->gda, u_errorName(status));
3852                 continue;
3853             }
3854             if (yr != mapPtr->cyr || mo != mapPtr->cmo || lp != mapPtr->clp || da != mapPtr->cda) {
3855                 errln("Fail: for Gregorian %4d-%02d-%02d, expected Chinese %2d-%02d(%d)-%02d, got %2d-%02d(%d)-%02d",
3856                         mapPtr->gyr, mapPtr->gmo, mapPtr->gda, mapPtr->cyr, mapPtr->cmo, mapPtr->clp, mapPtr->cda, yr, mo, lp, da);
3857                 continue;
3858             }
3859             // If Grego->Chinese worked, try reverse mapping
3860             calChinese->set(UCAL_ERA, era);
3861             calChinese->set(UCAL_YEAR, mapPtr->cyr);
3862             calChinese->set(UCAL_MONTH, mapPtr->cmo - 1);
3863             calChinese->set(UCAL_IS_LEAP_MONTH, mapPtr->clp);
3864             calChinese->set(UCAL_DATE, mapPtr->cda);
3865             calChinese->set(UCAL_HOUR_OF_DAY, 8);
3866             date = calChinese->getTime(status);
3867             calGregory->setTime(date, status);
3868             if ( U_FAILURE(status) ) {
3869                 errln("Fail: for Chinese %2d-%02d(%d)-%02d, calChinese->getTime or calGregory->setTime reports: %s",
3870                         mapPtr->cyr, mapPtr->cmo, mapPtr->clp, mapPtr->cda, u_errorName(status));
3871                 continue;
3872             }
3873             yr  = calGregory->get(UCAL_YEAR, status);
3874             mo  = calGregory->get(UCAL_MONTH, status) + 1;
3875             da  = calGregory->get(UCAL_DATE, status);
3876             if ( U_FAILURE(status) ) {
3877                 errln("Fail: for Chinese %2d-%02d(%d)-%02d, calGregory->get (for yr, mo, da) reports: %s",
3878                         mapPtr->cyr, mapPtr->cmo, mapPtr->clp, mapPtr->cda, u_errorName(status));
3879                 continue;
3880             }
3881             if (yr != mapPtr->gyr || mo != mapPtr->gmo || da != mapPtr->gda) {
3882                 errln("Fail: for Chinese %2d-%02d(%d)-%02d, Gregorian %4d-%02d-%02d, got %4d-%02d-%02d",
3883                         mapPtr->cyr, mapPtr->cmo, mapPtr->clp, mapPtr->cda, mapPtr->gyr, mapPtr->gmo, mapPtr->gda, yr, mo, da);
3884                 continue;
3885             }
3886         }
3887     }
3888 }
3889 
TestGregorianCalendarInTemporalLeapYear()3890 void CalendarTest::TestGregorianCalendarInTemporalLeapYear() {
3891     // test from year 1800 to 2500
3892     UErrorCode status = U_ZERO_ERROR;
3893     GregorianCalendar gc(status);
3894     if (failure(status, "construct GregorianCalendar")) return;
3895     for (int32_t year = 1900; year < 2400; ++year) {
3896         gc.set(year, UCAL_MARCH, 7);
3897         assertEquals("Calendar::inTemporalLeapYear",
3898                  gc.isLeapYear(year) == true, gc.inTemporalLeapYear(status) == true);
3899         if (failure(status, "inTemporalLeapYear")) return;
3900     }
3901 }
3902 
RunChineseCalendarInTemporalLeapYearTest(Calendar * cal)3903 void CalendarTest::RunChineseCalendarInTemporalLeapYearTest(Calendar* cal) {
3904     UErrorCode status = U_ZERO_ERROR;
3905     GregorianCalendar gc(status);
3906     if (failure(status, "construct GregorianCalendar")) return;
3907     LocalPointer<Calendar> leapTest(cal->clone());
3908     // Start our test from 1900, Jan 1.
3909     // Check every 29 days in exhausted mode.
3910     int32_t incrementDays = 29;
3911     int32_t startYear = 1900;
3912     int32_t stopYear = 2400;
3913 
3914     if (quick) {
3915         incrementDays = 317;
3916         stopYear = 2100;
3917     }
3918     int32_t yearForHasLeapMonth = -1;
3919     bool hasLeapMonth = false;
3920     for (gc.set(startYear, UCAL_JANUARY, 1);
3921          gc.get(UCAL_YEAR, status) <= stopYear;
3922          gc.add(UCAL_DATE, incrementDays, status)) {
3923         cal->setTime(gc.getTime(status), status);
3924         if (failure(status, "add/get/set/getTime/setTime incorrect")) return;
3925 
3926         int32_t cal_year = cal->get(UCAL_EXTENDED_YEAR, status);
3927         if (yearForHasLeapMonth != cal_year) {
3928             leapTest->set(UCAL_EXTENDED_YEAR, cal_year);
3929             leapTest->set(UCAL_MONTH, 0);
3930             leapTest->set(UCAL_DATE, 1);
3931             // seek any leap month
3932             // check any leap month in the next 12 months.
3933             for (hasLeapMonth = false;
3934                  (!hasLeapMonth) && cal_year == leapTest->get(UCAL_EXTENDED_YEAR, status);
3935                  leapTest->add(UCAL_MONTH, 1, status)) {
3936                 hasLeapMonth = leapTest->get(UCAL_IS_LEAP_MONTH, status) != 0;
3937             }
3938             yearForHasLeapMonth = cal_year;
3939         }
3940         if (failure(status, "error while figure out expectation")) return;
3941 
3942         bool actualInLeap =  cal->inTemporalLeapYear(status);
3943         if (failure(status, "inTemporalLeapYear")) return;
3944         if (hasLeapMonth != actualInLeap) {
3945             logln("Gregorian y=%d m=%d d=%d => cal y=%d m=%s%d d=%d expected:%s actual:%s\n",
3946                    gc.get(UCAL_YEAR, status),
3947                    gc.get(UCAL_MONTH, status),
3948                    gc.get(UCAL_DATE, status),
3949                    cal->get(UCAL_EXTENDED_YEAR, status),
3950                    cal->get(UCAL_IS_LEAP_MONTH, status) == 1 ? "L" : "",
3951                    cal->get(UCAL_MONTH, status),
3952                    cal->get(UCAL_DAY_OF_MONTH, status),
3953                    hasLeapMonth ? "true" : "false",
3954                    actualInLeap ? "true" : "false");
3955         }
3956         assertEquals("inTemporalLeapYear", hasLeapMonth, actualInLeap);
3957     }
3958 }
3959 
TestChineseCalendarInTemporalLeapYear()3960 void CalendarTest::TestChineseCalendarInTemporalLeapYear() {
3961     UErrorCode status = U_ZERO_ERROR;
3962     Locale l(Locale::getRoot());
3963     l.setKeywordValue("calendar", "chinese", status);
3964     LocalPointer<Calendar> cal(Calendar::createInstance(l, status));
3965     if (failure(status, "construct ChineseCalendar")) return;
3966     RunChineseCalendarInTemporalLeapYearTest(cal.getAlias());
3967 }
3968 
TestDangiCalendarInTemporalLeapYear()3969 void CalendarTest::TestDangiCalendarInTemporalLeapYear() {
3970     UErrorCode status = U_ZERO_ERROR;
3971     Locale l(Locale::getRoot());
3972     l.setKeywordValue("calendar", "dangi", status);
3973     LocalPointer<Calendar> cal(Calendar::createInstance(l, status));
3974     if (failure(status, "construct DangiCalendar")) return;
3975     RunChineseCalendarInTemporalLeapYearTest(cal.getAlias());
3976 }
3977 
TestHebrewCalendarInTemporalLeapYear()3978 void CalendarTest::TestHebrewCalendarInTemporalLeapYear() {
3979     UErrorCode status = U_ZERO_ERROR;
3980     GregorianCalendar gc(status);
3981     Locale l(Locale::getRoot());
3982     l.setKeywordValue("calendar", "hebrew", status);
3983     LocalPointer<Calendar> cal(Calendar::createInstance(l, status));
3984     LocalPointer<Calendar> leapTest(Calendar::createInstance(l, status));
3985     if (failure(status, "construct HebrewCalendar")) return;
3986     // Start our test from 1900, Jan 1.
3987     // Check every 29 days in exhausted mode.
3988     int32_t incrementDays = 29;
3989     int32_t startYear = 1900;
3990     int32_t stopYear = 2400;
3991 
3992     if (quick) {
3993         incrementDays = 317;
3994         stopYear = 2100;
3995     }
3996     int32_t yearForHasLeapMonth = -1;
3997     bool hasLeapMonth = false;
3998     for (gc.set(startYear, UCAL_JANUARY, 1);
3999          gc.get(UCAL_YEAR, status) <= stopYear;
4000          gc.add(UCAL_DATE, incrementDays, status)) {
4001         if (failure(status, "add/get/set/getTime/setTime incorrect")) return;
4002 
4003         int32_t cal_year = cal->get(UCAL_EXTENDED_YEAR, status);
4004         if (yearForHasLeapMonth != cal_year) {
4005             leapTest->set(UCAL_EXTENDED_YEAR, cal_year);
4006             leapTest->set(UCAL_MONTH, 0);
4007             leapTest->set(UCAL_DATE, 1);
4008             // If 10 months after TISHRI is TAMUZ, then it is a leap year.
4009             hasLeapMonth = leapTest->get(UCAL_MONTH, status) == icu::HebrewCalendar::TAMUZ;
4010             yearForHasLeapMonth = cal_year;
4011         }
4012         bool actualInLeap =  cal->inTemporalLeapYear(status);
4013         if (failure(status, "inTemporalLeapYear")) return;
4014         if (hasLeapMonth != actualInLeap) {
4015             logln("Gregorian y=%d m=%d d=7 => cal y=%d m=%d d=%d expected:%s actual:%s\n",
4016                    gc.get(UCAL_YEAR, status),
4017                    gc.get(UCAL_MONTH, status),
4018                    cal->get(UCAL_EXTENDED_YEAR, status),
4019                    cal->get(UCAL_MONTH, status),
4020                    cal->get(UCAL_DAY_OF_MONTH, status),
4021                    hasLeapMonth ? "true" : "false",
4022                    actualInLeap ? "true" : "false");
4023         }
4024         assertEquals("inTemporalLeapYear", hasLeapMonth, actualInLeap);
4025     }
4026 }
4027 
RunIslamicCalendarInTemporalLeapYearTest(Calendar * cal)4028 void CalendarTest::RunIslamicCalendarInTemporalLeapYearTest(Calendar* cal) {
4029     UErrorCode status = U_ZERO_ERROR;
4030     GregorianCalendar gc(status);
4031     if (failure(status, "construct GregorianCalendar")) return;
4032     // Start our test from 1900, Jan 1.
4033     // Check every 29 days in exhausted mode.
4034     int32_t incrementDays = 29;
4035     int32_t startYear = 1900;
4036     int32_t stopYear = 2400;
4037 
4038     if (quick) {
4039         incrementDays = 317;
4040         stopYear = 2100;
4041     }
4042     int32_t yearForHasLeapMonth = -1;
4043     bool hasLeapMonth = false;
4044     for (gc.set(startYear, UCAL_JANUARY, 1);
4045          gc.get(UCAL_YEAR, status) <= stopYear;
4046          gc.add(UCAL_DATE, incrementDays, status)) {
4047         cal->setTime(gc.getTime(status), status);
4048         if (failure(status, "set/getTime/setTime incorrect")) return;
4049         int32_t cal_year = cal->get(UCAL_EXTENDED_YEAR, status);
4050         if (yearForHasLeapMonth != cal_year) {
4051             // If that year has exactly 355 days, it is a leap year.
4052             hasLeapMonth = cal->getActualMaximum(UCAL_DAY_OF_YEAR, status) == 355;
4053             yearForHasLeapMonth = cal_year;
4054         }
4055 
4056         bool actualInLeap =  cal->inTemporalLeapYear(status);
4057         if (failure(status, "inTemporalLeapYear")) return;
4058         if (hasLeapMonth != actualInLeap) {
4059             logln("Gregorian y=%d m=%d d=%d => cal y=%d m=%s%d d=%d expected:%s actual:%s\n",
4060                    gc.get(UCAL_EXTENDED_YEAR, status),
4061                    gc.get(UCAL_MONTH, status),
4062                    gc.get(UCAL_DAY_OF_MONTH, status),
4063                    cal->get(UCAL_EXTENDED_YEAR, status),
4064                    cal->get(UCAL_IS_LEAP_MONTH, status) == 1 ? "L" : "",
4065                    cal->get(UCAL_MONTH, status),
4066                    cal->get(UCAL_DAY_OF_MONTH, status),
4067                    hasLeapMonth ? "true" : "false",
4068                    actualInLeap ? "true" : "false");
4069         }
4070         assertEquals("inTemporalLeapYear", hasLeapMonth, actualInLeap);
4071     }
4072 }
4073 
TestIslamicCalendarInTemporalLeapYear()4074 void CalendarTest::TestIslamicCalendarInTemporalLeapYear() {
4075     UErrorCode status = U_ZERO_ERROR;
4076     Locale l(Locale::getRoot());
4077     l.setKeywordValue("calendar", "islamic", status);
4078     LocalPointer<Calendar> cal(Calendar::createInstance(l, status));
4079     if (failure(status, "construct IslamicCalendar")) return;
4080     RunIslamicCalendarInTemporalLeapYearTest(cal.getAlias());
4081 }
4082 
TestIslamicCivilCalendarInTemporalLeapYear()4083 void CalendarTest::TestIslamicCivilCalendarInTemporalLeapYear() {
4084     UErrorCode status = U_ZERO_ERROR;
4085     Locale l(Locale::getRoot());
4086     l.setKeywordValue("calendar", "islamic-civil", status);
4087     LocalPointer<Calendar> cal(Calendar::createInstance(l, status));
4088     if (failure(status, "construct IslamicCivilCalendar")) return;
4089     RunIslamicCalendarInTemporalLeapYearTest(cal.getAlias());
4090 }
4091 
TestIslamicUmalquraCalendarInTemporalLeapYear()4092 void CalendarTest::TestIslamicUmalquraCalendarInTemporalLeapYear() {
4093     UErrorCode status = U_ZERO_ERROR;
4094     Locale l(Locale::getRoot());
4095     l.setKeywordValue("calendar", "islamic-umalqura", status);
4096     LocalPointer<Calendar> cal(Calendar::createInstance(l, status));
4097     if (failure(status, "construct IslamicUmalquraCalendar")) return;
4098     RunIslamicCalendarInTemporalLeapYearTest(cal.getAlias());
4099 }
4100 
TestIslamicRGSACalendarInTemporalLeapYear()4101 void CalendarTest::TestIslamicRGSACalendarInTemporalLeapYear() {
4102     UErrorCode status = U_ZERO_ERROR;
4103     Locale l(Locale::getRoot());
4104     l.setKeywordValue("calendar", "islamic-rgsa", status);
4105     LocalPointer<Calendar> cal(Calendar::createInstance(l, status));
4106     if (failure(status, "construct IslamicRGSACalendar")) return;
4107     RunIslamicCalendarInTemporalLeapYearTest(cal.getAlias());
4108 }
4109 
TestIslamicTBLACalendarInTemporalLeapYear()4110 void CalendarTest::TestIslamicTBLACalendarInTemporalLeapYear() {
4111     UErrorCode status = U_ZERO_ERROR;
4112     Locale l(Locale::getRoot());
4113     l.setKeywordValue("calendar", "islamic-tbla", status);
4114     LocalPointer<Calendar> cal(Calendar::createInstance(l, status));
4115     if (failure(status, "construct IslamicTBLACalendar")) return;
4116     RunIslamicCalendarInTemporalLeapYearTest(cal.getAlias());
4117 }
4118 
Run366DaysIsLeapYearCalendarInTemporalLeapYearTest(Calendar * cal)4119 void CalendarTest::Run366DaysIsLeapYearCalendarInTemporalLeapYearTest(Calendar* cal) {
4120     UErrorCode status = U_ZERO_ERROR;
4121     GregorianCalendar gc(status);
4122     if (failure(status, "construct GregorianCalendar")) return;
4123     // Start our test from 1900, Jan 1.
4124     // Check every 29 days in exhausted mode.
4125     int32_t incrementDays = 29;
4126     int32_t startYear = 1900;
4127     int32_t stopYear = 2400;
4128 
4129     if (quick) {
4130         incrementDays = 317;
4131         stopYear = 2100;
4132     }
4133     int32_t yearForHasLeapMonth = -1;
4134     bool hasLeapMonth = false;
4135     for (gc.set(startYear, UCAL_JANUARY, 1);
4136          gc.get(UCAL_YEAR, status) <= stopYear;
4137          gc.add(UCAL_DATE, incrementDays, status)) {
4138         cal->setTime(gc.getTime(status), status);
4139         if (failure(status, "set/getTime/setTime incorrect")) return;
4140         int32_t cal_year = cal->get(UCAL_EXTENDED_YEAR, status);
4141         if (yearForHasLeapMonth != cal_year) {
4142             // If that year has exactly 355 days, it is a leap year.
4143             hasLeapMonth = cal->getActualMaximum(UCAL_DAY_OF_YEAR, status) == 366;
4144             if (failure(status, "getActualMaximum incorrect")) return;
4145             yearForHasLeapMonth = cal_year;
4146         }
4147         bool actualInLeap =  cal->inTemporalLeapYear(status);
4148         if (failure(status, "inTemporalLeapYear")) return;
4149         if (hasLeapMonth != actualInLeap) {
4150             logln("Gregorian y=%d m=%d d=%d => cal y=%d m=%s%d d=%d expected:%s actual:%s\n",
4151                    gc.get(UCAL_EXTENDED_YEAR, status),
4152                    gc.get(UCAL_MONTH, status),
4153                    gc.get(UCAL_DAY_OF_MONTH, status),
4154                    cal->get(UCAL_EXTENDED_YEAR, status),
4155                    cal->get(UCAL_IS_LEAP_MONTH, status) == 1 ? "L" : "",
4156                    cal->get(UCAL_MONTH, status),
4157                    cal->get(UCAL_DAY_OF_MONTH, status),
4158                    hasLeapMonth ? "true" : "false",
4159                    actualInLeap ? "true" : "false");
4160         }
4161         assertEquals("inTemporalLeapYear", hasLeapMonth, actualInLeap);
4162     }
4163 }
4164 
TestTaiwanCalendarInTemporalLeapYear()4165 void CalendarTest::TestTaiwanCalendarInTemporalLeapYear() {
4166     UErrorCode status = U_ZERO_ERROR;
4167     Locale l(Locale::getRoot());
4168     l.setKeywordValue("calendar", "roc", status);
4169     LocalPointer<Calendar> cal(Calendar::createInstance(l, status));
4170     if (failure(status, "construct TaiwanCalendar")) return;
4171     Run366DaysIsLeapYearCalendarInTemporalLeapYearTest(cal.getAlias());
4172 }
4173 
TestJapaneseCalendarInTemporalLeapYear()4174 void CalendarTest::TestJapaneseCalendarInTemporalLeapYear() {
4175     UErrorCode status = U_ZERO_ERROR;
4176     Locale l(Locale::getRoot());
4177     l.setKeywordValue("calendar", "japanese", status);
4178     LocalPointer<Calendar> cal(Calendar::createInstance(l, status));
4179     if (failure(status, "construct JapaneseCalendar")) return;
4180     Run366DaysIsLeapYearCalendarInTemporalLeapYearTest(cal.getAlias());
4181 }
4182 
TestBuddhistCalendarInTemporalLeapYear()4183 void CalendarTest::TestBuddhistCalendarInTemporalLeapYear() {
4184     UErrorCode status = U_ZERO_ERROR;
4185     Locale l(Locale::getRoot());
4186     l.setKeywordValue("calendar", "buddhist", status);
4187     LocalPointer<Calendar> cal(Calendar::createInstance(l, status));
4188     if (failure(status, "construct BuddhistCalendar")) return;
4189     Run366DaysIsLeapYearCalendarInTemporalLeapYearTest(cal.getAlias());
4190 }
4191 
TestPersianCalendarInTemporalLeapYear()4192 void CalendarTest::TestPersianCalendarInTemporalLeapYear() {
4193     UErrorCode status = U_ZERO_ERROR;
4194     Locale l(Locale::getRoot());
4195     l.setKeywordValue("calendar", "persian", status);
4196     LocalPointer<Calendar> cal(Calendar::createInstance(l, status));
4197     if (failure(status, "construct PersianCalendar")) return;
4198     Run366DaysIsLeapYearCalendarInTemporalLeapYearTest(cal.getAlias());
4199 }
4200 
TestIndianCalendarInTemporalLeapYear()4201 void CalendarTest::TestIndianCalendarInTemporalLeapYear() {
4202     UErrorCode status = U_ZERO_ERROR;
4203     Locale l(Locale::getRoot());
4204     l.setKeywordValue("calendar", "indian", status);
4205     LocalPointer<Calendar> cal(Calendar::createInstance(l, status));
4206     if (failure(status, "construct IndianCalendar")) return;
4207     Run366DaysIsLeapYearCalendarInTemporalLeapYearTest(cal.getAlias());
4208 }
4209 
TestCopticCalendarInTemporalLeapYear()4210 void CalendarTest::TestCopticCalendarInTemporalLeapYear() {
4211     UErrorCode status = U_ZERO_ERROR;
4212     Locale l(Locale::getRoot());
4213     l.setKeywordValue("calendar", "coptic", status);
4214     LocalPointer<Calendar> cal(Calendar::createInstance(l, status));
4215     if (failure(status, "construct CopticCalendar")) return;
4216     Run366DaysIsLeapYearCalendarInTemporalLeapYearTest(cal.getAlias());
4217 }
4218 
TestEthiopicCalendarInTemporalLeapYear()4219 void CalendarTest::TestEthiopicCalendarInTemporalLeapYear() {
4220     UErrorCode status = U_ZERO_ERROR;
4221     Locale l(Locale::getRoot());
4222     l.setKeywordValue("calendar", "ethiopic", status);
4223     LocalPointer<Calendar> cal(Calendar::createInstance(l, status));
4224     if (failure(status, "construct EthiopicCalendar")) return;
4225     Run366DaysIsLeapYearCalendarInTemporalLeapYearTest(cal.getAlias());
4226 }
4227 
TestEthiopicAmeteAlemCalendarInTemporalLeapYear()4228 void CalendarTest::TestEthiopicAmeteAlemCalendarInTemporalLeapYear() {
4229     UErrorCode status = U_ZERO_ERROR;
4230     Locale l(Locale::getRoot());
4231     l.setKeywordValue("calendar", "ethiopic-amete-alem", status);
4232     LocalPointer<Calendar> cal(Calendar::createInstance(l, status));
4233     if (failure(status, "construct EthiopicAmeteAlemCalendar")) return;
4234     Run366DaysIsLeapYearCalendarInTemporalLeapYearTest(cal.getAlias());
4235 }
4236 
monthCode(int32_t month,bool leap)4237 std::string monthCode(int32_t month, bool leap) {
4238     std::string code("M");
4239     if (month < 10) {
4240         code += "0";
4241         code += ('0' + month);
4242     } else {
4243         code += "1";
4244         code += ('0' + (month % 10));
4245     }
4246     if (leap) {
4247         code += "L";
4248     }
4249     return code;
4250 }
hebrewMonthCode(int32_t icuMonth)4251 std::string hebrewMonthCode(int32_t icuMonth) {
4252     if (icuMonth == icu::HebrewCalendar::ADAR_1) {
4253         return monthCode(icuMonth, true);
4254     }
4255     return monthCode(icuMonth < icu::HebrewCalendar::ADAR_1 ? icuMonth+1 : icuMonth, false);
4256 }
4257 
RunChineseCalendarGetTemporalMonthCode(Calendar * cal)4258 void CalendarTest::RunChineseCalendarGetTemporalMonthCode(Calendar* cal) {
4259     UErrorCode status = U_ZERO_ERROR;
4260     GregorianCalendar gc(status);
4261     if (failure(status, "construct GregorianCalendar")) return;
4262     // Start our test from 1900, Jan 1.
4263     // Check every 29 days in exhausted mode.
4264     int32_t incrementDays = 29;
4265     int32_t startYear = 1900;
4266     int32_t stopYear = 2400;
4267 
4268     if (quick) {
4269         incrementDays = 317;
4270         startYear = 1950;
4271         stopYear = 2050;
4272     }
4273     for (gc.set(startYear, UCAL_JANUARY, 1);
4274          gc.get(UCAL_YEAR, status) <= stopYear;
4275          gc.add(UCAL_DATE, incrementDays, status)) {
4276         cal->setTime(gc.getTime(status), status);
4277         if (failure(status, "set/getTime/setTime incorrect")) return;
4278         int32_t cal_month = cal->get(UCAL_MONTH, status);
4279         std::string expected = monthCode(
4280             cal_month + 1, cal->get(UCAL_IS_LEAP_MONTH, status) != 0);
4281         assertEquals("getTemporalMonthCode", expected.c_str(), cal->getTemporalMonthCode(status));
4282         if (failure(status, "getTemporalMonthCode")) return;
4283     }
4284 }
4285 
TestChineseCalendarGetTemporalMonthCode()4286 void CalendarTest::TestChineseCalendarGetTemporalMonthCode() {
4287     UErrorCode status = U_ZERO_ERROR;
4288     Locale l(Locale::getRoot());
4289     l.setKeywordValue("calendar", "chinese", status);
4290     LocalPointer<Calendar> cal(Calendar::createInstance(l, status));
4291     if (failure(status, "construct ChineseCalendar")) return;
4292     RunChineseCalendarGetTemporalMonthCode(cal.getAlias());
4293 }
4294 
TestDangiCalendarGetTemporalMonthCode()4295 void CalendarTest::TestDangiCalendarGetTemporalMonthCode() {
4296     UErrorCode status = U_ZERO_ERROR;
4297     Locale l(Locale::getRoot());
4298     l.setKeywordValue("calendar", "dangi", status);
4299     LocalPointer<Calendar> cal(Calendar::createInstance(l, status));
4300     if (failure(status, "construct DangiCalendar")) return;
4301     RunChineseCalendarGetTemporalMonthCode(cal.getAlias());
4302 }
4303 
TestHebrewCalendarGetTemporalMonthCode()4304 void CalendarTest::TestHebrewCalendarGetTemporalMonthCode() {
4305     UErrorCode status = U_ZERO_ERROR;
4306     Locale l(Locale::getRoot());
4307     l.setKeywordValue("calendar", "hebrew", status);
4308     LocalPointer<Calendar> cal(Calendar::createInstance(l, status));
4309     GregorianCalendar gc(status);
4310     if (failure(status, "construct Calendar")) return;
4311     // Start our test from 1900, Jan 1.
4312     // Check every 29 days in exhausted mode.
4313     int32_t incrementDays = 29;
4314     int32_t startYear = 1900;
4315     int32_t stopYear = 2400;
4316 
4317     if (quick) {
4318         incrementDays = 317;
4319         stopYear = 2100;
4320     }
4321     for (gc.set(startYear, UCAL_JANUARY, 1);
4322          gc.get(UCAL_YEAR, status) <= stopYear;
4323          gc.add(UCAL_DATE, incrementDays, status)) {
4324         cal->setTime(gc.getTime(status), status);
4325         if (failure(status, "set/getTime/setTime incorrect")) return;
4326         std::string expected = hebrewMonthCode(cal->get(UCAL_MONTH, status));
4327         if (failure(status, "get failed")) return;
4328         assertEquals("getTemporalMonthCode", expected.c_str(), cal->getTemporalMonthCode(status));
4329         if (failure(status, "getTemporalMonthCode")) return;
4330     }
4331 }
4332 
RunCECalendarGetTemporalMonthCode(Calendar * cal)4333 void CalendarTest::RunCECalendarGetTemporalMonthCode(Calendar* cal) {
4334     UErrorCode status = U_ZERO_ERROR;
4335     GregorianCalendar gc(status);
4336     if (failure(status, "construct Calendar")) return;
4337     // Start testing from 1900
4338     gc.set(1900, UCAL_JANUARY, 1);
4339     cal->setTime(gc.getTime(status), status);
4340     int32_t year = cal->get(UCAL_YEAR, status);
4341     for (int32_t m = 0; m < 13; m++) {
4342         std::string expected = monthCode(m+1, false);
4343         for (int32_t y = year; y < year + 500 ; y++) {
4344             cal->set(y, m, 1);
4345             assertEquals("getTemporalMonthCode", expected.c_str(), cal->getTemporalMonthCode(status));
4346             if (failure(status, "getTemporalMonthCode")) continue;
4347         }
4348     }
4349 
4350 }
4351 
TestCopticCalendarGetTemporalMonthCode()4352 void CalendarTest::TestCopticCalendarGetTemporalMonthCode() {
4353     UErrorCode status = U_ZERO_ERROR;
4354     Locale l(Locale::getRoot());
4355     l.setKeywordValue("calendar", "coptic", status);
4356     LocalPointer<Calendar> cal(Calendar::createInstance(l, status));
4357     if (failure(status, "construct CopticCalendar")) return;
4358     RunCECalendarGetTemporalMonthCode(cal.getAlias());
4359 }
4360 
TestEthiopicCalendarGetTemporalMonthCode()4361 void CalendarTest::TestEthiopicCalendarGetTemporalMonthCode() {
4362     UErrorCode status = U_ZERO_ERROR;
4363     Locale l(Locale::getRoot());
4364     l.setKeywordValue("calendar", "ethiopic", status);
4365     LocalPointer<Calendar> cal(Calendar::createInstance(l, status));
4366     if (failure(status, "construct EthiopicCalendar")) return;
4367     RunCECalendarGetTemporalMonthCode(cal.getAlias());
4368 }
4369 
TestEthiopicAmeteAlemCalendarGetTemporalMonthCode()4370 void CalendarTest::TestEthiopicAmeteAlemCalendarGetTemporalMonthCode() {
4371     UErrorCode status = U_ZERO_ERROR;
4372     Locale l(Locale::getRoot());
4373     l.setKeywordValue("calendar", "ethiopic-amete-alem", status);
4374     LocalPointer<Calendar> cal(Calendar::createInstance(l, status));
4375     if (failure(status, "construct EthiopicAmeteAlemCalendar")) return;
4376     RunCECalendarGetTemporalMonthCode(cal.getAlias());
4377 }
4378 
TestGregorianCalendarSetTemporalMonthCode()4379 void CalendarTest::TestGregorianCalendarSetTemporalMonthCode() {
4380 
4381     struct TestCase {
4382       int32_t gYear;
4383       int32_t gMonth;
4384       int32_t gDate;
4385       const char* monthCode;
4386       int32_t ordinalMonth;
4387     } cases[] = {
4388       { 1911, UCAL_JANUARY, 31, "M01", 0 },
4389       { 1970, UCAL_FEBRUARY, 22, "M02", 1 },
4390       { 543, UCAL_MARCH, 3, "M03", 2 },
4391       { 2340, UCAL_APRIL, 21, "M04", 3 },
4392       { 1234, UCAL_MAY, 21, "M05", 4 },
4393       { 1931, UCAL_JUNE, 17, "M06", 5 },
4394       { 2000, UCAL_JULY, 1, "M07", 6 },
4395       { 2033, UCAL_AUGUST, 3, "M08", 7 },
4396       { 2013, UCAL_SEPTEMBER, 9, "M09", 8 },
4397       { 1849, UCAL_OCTOBER, 31, "M10", 9 },
4398       { 1433, UCAL_NOVEMBER, 30, "M11", 10 },
4399       { 2022, UCAL_DECEMBER, 25, "M12", 11 },
4400     };
4401     UErrorCode status = U_ZERO_ERROR;
4402     GregorianCalendar gc1(status);
4403     GregorianCalendar gc2(status);
4404     if (failure(status, "construct GregorianCalendar")) return;
4405     for (auto& cas : cases) {
4406         gc1.clear();
4407         gc2.clear();
4408         gc1.set(cas.gYear, cas.gMonth, cas.gDate);
4409 
4410         gc2.set(UCAL_YEAR, cas.gYear);
4411         gc2.setTemporalMonthCode(cas.monthCode, status);
4412         gc2.set(UCAL_DATE, cas.gDate);
4413         if (failure(status, "set/setTemporalMonthCode")) return;
4414 
4415         assertTrue("by set and setTemporalMonthCode()", gc1.equals(gc2, status));
4416         const char* actualMonthCode1 = gc1.getTemporalMonthCode(status);
4417         const char* actualMonthCode2 = gc2.getTemporalMonthCode(status);
4418         if (failure(status, "getTemporalMonthCode")) continue;
4419         assertEquals("getTemporalMonthCode()", 0,
4420                      uprv_strcmp(actualMonthCode1, actualMonthCode2));
4421         assertEquals("getTemporalMonthCode()", 0,
4422                      uprv_strcmp(cas.monthCode, actualMonthCode2));
4423         assertEquals("ordinalMonth", cas.ordinalMonth, gc2.get(UCAL_ORDINAL_MONTH, status));
4424         assertEquals("ordinalMonth", gc1.get(UCAL_ORDINAL_MONTH, status),
4425                      gc2.get(UCAL_ORDINAL_MONTH, status));
4426     }
4427 }
4428 
TestChineseCalendarSetTemporalMonthCode()4429 void CalendarTest::TestChineseCalendarSetTemporalMonthCode() {
4430     UErrorCode status = U_ZERO_ERROR;
4431     Locale l(Locale::getRoot());
4432     l.setKeywordValue("calendar", "chinese", status);
4433     LocalPointer<Calendar> cc1(Calendar::createInstance(l, status));
4434     if (failure(status, "construct ChineseCalendar")) return;
4435     LocalPointer<Calendar> cc2(cc1->clone());
4436 
4437     struct TestCase {
4438       int32_t gYear;
4439       int32_t gMonth;
4440       int32_t gDate;
4441       int32_t cYear;
4442       int32_t cMonth;
4443       int32_t cDate;
4444       const char* cMonthCode;
4445       bool cLeapMonth;
4446       int32_t cOrdinalMonth;
4447     } cases[] = {
4448       // https://www.hko.gov.hk/tc/gts/time/calendar/pdf/files/2022.pdf
4449       { 2022, UCAL_DECEMBER, 15, 4659, UCAL_NOVEMBER, 22, "M11", false, 10},
4450       // M01L is very hard to find. Cannot find a year has M01L in these several
4451       // centuries.
4452       // M02L https://www.hko.gov.hk/tc/gts/time/calendar/pdf/files/2004.pdf
4453       { 2004, UCAL_MARCH, 20, 4641, UCAL_FEBRUARY, 30, "M02", false, 1},
4454       { 2004, UCAL_MARCH, 21, 4641, UCAL_FEBRUARY, 1, "M02L", true, 2},
4455       { 2004, UCAL_APRIL, 18, 4641, UCAL_FEBRUARY, 29, "M02L", true, 2},
4456       { 2004, UCAL_APRIL, 19, 4641, UCAL_MARCH, 1, "M03", false, 3},
4457       // M03L https://www.hko.gov.hk/tc/gts/time/calendar/pdf/files/1995.pdf
4458       { 1955, UCAL_APRIL, 21, 4592, UCAL_MARCH, 29, "M03", false, 2},
4459       { 1955, UCAL_APRIL, 22, 4592, UCAL_MARCH, 1, "M03L", true, 3},
4460       { 1955, UCAL_MAY, 21, 4592, UCAL_MARCH, 30, "M03L", true, 3},
4461       { 1955, UCAL_MAY, 22, 4592, UCAL_APRIL, 1, "M04", false, 4},
4462       // M12 https://www.hko.gov.hk/tc/gts/time/calendar/pdf/files/1996.pdf
4463       { 1956, UCAL_FEBRUARY, 11, 4592, UCAL_DECEMBER, 30, "M12", false, 12},
4464       // M04L https://www.hko.gov.hk/tc/gts/time/calendar/pdf/files/2001.pdf
4465       { 2001, UCAL_MAY, 22, 4638, UCAL_APRIL, 30, "M04", false, 3},
4466       { 2001, UCAL_MAY, 23, 4638, UCAL_APRIL, 1, "M04L", true, 4},
4467       { 2001, UCAL_JUNE, 20, 4638, UCAL_APRIL, 29, "M04L", true, 4},
4468       { 2001, UCAL_JUNE, 21, 4638, UCAL_MAY, 1, "M05", false, 5},
4469       // M05L https://www.hko.gov.hk/tc/gts/time/calendar/pdf/files/2009.pdf
4470       { 2009, UCAL_JUNE, 22, 4646, UCAL_MAY, 30, "M05", false, 4},
4471       { 2009, UCAL_JUNE, 23, 4646, UCAL_MAY, 1, "M05L", true, 5},
4472       { 2009, UCAL_JULY, 21, 4646, UCAL_MAY, 29, "M05L", true, 5},
4473       { 2009, UCAL_JULY, 22, 4646, UCAL_JUNE, 1, "M06", false, 6},
4474       // M06L https://www.hko.gov.hk/tc/gts/time/calendar/pdf/files/2017.pdf
4475       { 2017, UCAL_JULY, 22, 4654, UCAL_JUNE, 29, "M06", false, 5},
4476       { 2017, UCAL_JULY, 23, 4654, UCAL_JUNE, 1, "M06L", true, 6},
4477       { 2017, UCAL_AUGUST, 21, 4654, UCAL_JUNE, 30, "M06L", true, 6},
4478       { 2017, UCAL_AUGUST, 22, 4654, UCAL_JULY, 1, "M07", false, 7},
4479       // M07L https://www.hko.gov.hk/tc/gts/time/calendar/pdf/files/2006.pdf
4480       { 2006, UCAL_AUGUST, 23, 4643, UCAL_JULY, 30, "M07", false, 6},
4481       { 2006, UCAL_AUGUST, 24, 4643, UCAL_JULY, 1, "M07L", true, 7},
4482       { 2006, UCAL_SEPTEMBER, 21, 4643, UCAL_JULY, 29, "M07L", true, 7},
4483       { 2006, UCAL_SEPTEMBER, 22, 4643, UCAL_AUGUST, 1, "M08", false, 8},
4484       // M08L https://www.hko.gov.hk/tc/gts/time/calendar/pdf/files/1995.pdf
4485       { 1995, UCAL_SEPTEMBER, 24, 4632, UCAL_AUGUST, 30, "M08", false, 7},
4486       { 1995, UCAL_SEPTEMBER, 25, 4632, UCAL_AUGUST, 1, "M08L", true, 8},
4487       { 1995, UCAL_OCTOBER, 23, 4632, UCAL_AUGUST, 29, "M08L", true, 8},
4488       { 1995, UCAL_OCTOBER, 24, 4632, UCAL_SEPTEMBER, 1, "M09", false, 9},
4489       // M09L https://www.hko.gov.hk/tc/gts/time/calendar/pdf/files/2014.pdf
4490       { 2014, UCAL_OCTOBER, 23, 4651, UCAL_SEPTEMBER, 30, "M09", false, 8},
4491       { 2014, UCAL_OCTOBER, 24, 4651, UCAL_SEPTEMBER, 1, "M09L", true, 9},
4492       { 2014, UCAL_NOVEMBER, 21, 4651, UCAL_SEPTEMBER, 29, "M09L", true, 9},
4493       { 2014, UCAL_NOVEMBER, 22, 4651, UCAL_OCTOBER, 1, "M10", false, 10},
4494       // M10L https://www.hko.gov.hk/tc/gts/time/calendar/pdf/files/1984.pdf
4495       { 1984, UCAL_NOVEMBER, 22, 4621, UCAL_OCTOBER, 30, "M10", false, 9},
4496       { 1984, UCAL_NOVEMBER, 23, 4621, UCAL_OCTOBER, 1, "M10L", true, 10},
4497       { 1984, UCAL_DECEMBER, 21, 4621, UCAL_OCTOBER, 29, "M10L", true, 10},
4498       { 1984, UCAL_DECEMBER, 22, 4621, UCAL_NOVEMBER, 1, "M11", false, 11},
4499       // M11L https://www.hko.gov.hk/tc/gts/time/calendar/pdf/files/2033.pdf
4500       //      https://www.hko.gov.hk/tc/gts/time/calendar/pdf/files/2034.pdf
4501       { 2033, UCAL_DECEMBER, 21, 4670, UCAL_NOVEMBER, 30, "M11", false, 10},
4502       { 2033, UCAL_DECEMBER, 22, 4670, UCAL_NOVEMBER, 1, "M11L", true, 11},
4503       { 2034, UCAL_JANUARY, 19, 4670, UCAL_NOVEMBER, 29, "M11L", true, 11},
4504       { 2034, UCAL_JANUARY, 20, 4670, UCAL_DECEMBER, 1, "M12", false, 12},
4505       // M12L is very hard to find. Cannot find a year has M01L in these several
4506       // centuries.
4507     };
4508     GregorianCalendar gc1(status);
4509     if (failure(status, "construct Calendar")) return;
4510     for (auto& cas : cases) {
4511         gc1.clear();
4512         cc1->clear();
4513         cc2->clear();
4514         gc1.set(cas.gYear, cas.gMonth, cas.gDate);
4515         cc1->setTime(gc1.getTime(status), status);
4516 
4517         cc2->set(UCAL_EXTENDED_YEAR, cas.cYear);
4518         cc2->setTemporalMonthCode(cas.cMonthCode, status);
4519         cc2->set(UCAL_DATE, cas.cDate);
4520 
4521         assertEquals("year", cas.cYear, cc1->get(UCAL_EXTENDED_YEAR, status));
4522         assertEquals("month", cas.cMonth, cc1->get(UCAL_MONTH, status));
4523         assertEquals("date", cas.cDate, cc1->get(UCAL_DATE, status));
4524         assertEquals("is_leap_month", cas.cLeapMonth ? 1 : 0, cc1->get(UCAL_IS_LEAP_MONTH, status));
4525         assertEquals("getTemporalMonthCode()", 0,
4526                      uprv_strcmp(cas.cMonthCode, cc1->getTemporalMonthCode(status)));
4527         if (failure(status, "getTemporalMonthCode")) continue;
4528         assertEquals("ordinalMonth", cas.cOrdinalMonth, cc1->get(UCAL_ORDINAL_MONTH, status));
4529         if (! cc2->equals(*cc1, status)) {
4530             printf("g=%f %f vs %f. diff = %f %d/%d%s/%d vs %d/%d%s/%d\n",
4531                    gc1.getTime(status), cc1->getTime(status), cc2->getTime(status),
4532                    cc1->getTime(status) - cc2->getTime(status),
4533                    cc1->get(UCAL_EXTENDED_YEAR, status),
4534                    cc1->get(UCAL_MONTH, status)+1,
4535                    cc1->get(UCAL_IS_LEAP_MONTH, status) == 0 ? "" : "L",
4536                    cc1->get(UCAL_DATE, status),
4537                    cc2->get(UCAL_EXTENDED_YEAR, status),
4538                    cc2->get(UCAL_MONTH, status)+1,
4539                    cc2->get(UCAL_IS_LEAP_MONTH, status) == 0 ? "" : "L",
4540                    cc2->get(UCAL_DATE, status));
4541         }
4542         assertTrue("by set() and setTemporalMonthCode()", cc2->equals(*cc1, status));
4543     }
4544 }
4545 
TestHebrewCalendarSetTemporalMonthCode()4546 void CalendarTest::TestHebrewCalendarSetTemporalMonthCode() {
4547     UErrorCode status = U_ZERO_ERROR;
4548     Locale l(Locale::getRoot());
4549     l.setKeywordValue("calendar", "hebrew", status);
4550     LocalPointer<Calendar> cc1(Calendar::createInstance(l, status));
4551     if (failure(status, "construct HebrewCalendar")) return;
4552     LocalPointer<Calendar> cc2(cc1->clone());
4553 
4554     struct TestCase {
4555       int32_t gYear;
4556       int32_t gMonth;
4557       int32_t gDate;
4558       int32_t cYear;
4559       int32_t cMonth;
4560       int32_t cDate;
4561       const char* cMonthCode;
4562       int32_t cOrdinalMonth;
4563     } cases[] = {
4564       { 2022, UCAL_JANUARY, 11, 5782, icu::HebrewCalendar::SHEVAT, 9, "M05", 4},
4565       { 2022, UCAL_FEBRUARY, 12, 5782, icu::HebrewCalendar::ADAR_1, 11, "M05L", 5},
4566       { 2022, UCAL_MARCH, 13, 5782, icu::HebrewCalendar::ADAR, 10, "M06", 6},
4567       { 2022, UCAL_APRIL, 14, 5782, icu::HebrewCalendar::NISAN, 13, "M07", 7},
4568       { 2022, UCAL_MAY, 15, 5782, icu::HebrewCalendar::IYAR, 14, "M08", 8},
4569       { 2022, UCAL_JUNE, 16, 5782, icu::HebrewCalendar::SIVAN, 17, "M09", 9},
4570       { 2022, UCAL_JULY, 17, 5782, icu::HebrewCalendar::TAMUZ, 18, "M10", 10},
4571       { 2022, UCAL_AUGUST, 18, 5782, icu::HebrewCalendar::AV, 21, "M11", 11},
4572       { 2022, UCAL_SEPTEMBER, 19, 5782, icu::HebrewCalendar::ELUL, 23, "M12", 12},
4573       { 2022, UCAL_OCTOBER, 20, 5783, icu::HebrewCalendar::TISHRI, 25, "M01", 0},
4574       { 2022, UCAL_NOVEMBER, 21, 5783, icu::HebrewCalendar::HESHVAN, 27, "M02", 1},
4575       { 2022, UCAL_DECEMBER, 22, 5783, icu::HebrewCalendar::KISLEV, 28, "M03", 2},
4576       { 2023, UCAL_JANUARY, 20, 5783, icu::HebrewCalendar::TEVET, 27, "M04", 3},
4577     };
4578     GregorianCalendar gc1(status);
4579     if (failure(status, "construct Calendar")) return;
4580     for (auto& cas : cases) {
4581         gc1.clear();
4582         cc1->clear();
4583         cc2->clear();
4584         gc1.set(cas.gYear, cas.gMonth, cas.gDate);
4585         cc1->setTime(gc1.getTime(status), status);
4586 
4587         cc2->set(UCAL_EXTENDED_YEAR, cas.cYear);
4588         cc2->setTemporalMonthCode(cas.cMonthCode, status);
4589         cc2->set(UCAL_DATE, cas.cDate);
4590 
4591         assertEquals("year", cas.cYear, cc1->get(UCAL_EXTENDED_YEAR, status));
4592         assertEquals("month", cas.cMonth, cc1->get(UCAL_MONTH, status));
4593         assertEquals("date", cas.cDate, cc1->get(UCAL_DATE, status));
4594         assertEquals("getTemporalMonthCode()", 0,
4595                      uprv_strcmp(cas.cMonthCode, cc1->getTemporalMonthCode(status)));
4596         if (failure(status, "getTemporalMonthCode")) continue;
4597         if (! cc2->equals(*cc1, status)) {
4598             printf("g=%f %f vs %f. diff = %f %d/%d/%d vs %d/%d/%d\n",
4599                    gc1.getTime(status), cc1->getTime(status), cc2->getTime(status),
4600                    cc1->getTime(status) - cc2->getTime(status),
4601                    cc1->get(UCAL_EXTENDED_YEAR, status),
4602                    cc1->get(UCAL_MONTH, status)+1,
4603                    cc1->get(UCAL_DATE, status),
4604                    cc2->get(UCAL_EXTENDED_YEAR, status),
4605                    cc2->get(UCAL_MONTH, status)+1,
4606                    cc2->get(UCAL_DATE, status));
4607         }
4608         assertTrue("by set() and setTemporalMonthCode()", cc2->equals(*cc1, status));
4609         assertEquals("ordinalMonth", cas.cOrdinalMonth, cc1->get(UCAL_ORDINAL_MONTH, status));
4610         assertEquals("ordinalMonth", cas.cOrdinalMonth, cc2->get(UCAL_ORDINAL_MONTH, status));
4611     }
4612 }
4613 
TestCopticCalendarSetTemporalMonthCode()4614 void CalendarTest::TestCopticCalendarSetTemporalMonthCode() {
4615     UErrorCode status = U_ZERO_ERROR;
4616     Locale l(Locale::getRoot());
4617     l.setKeywordValue("calendar", "coptic", status);
4618     LocalPointer<Calendar> cc1(Calendar::createInstance(l, status));
4619     if (failure(status, "construct CopticCalendar")) return;
4620     LocalPointer<Calendar> cc2(cc1->clone());
4621 
4622     struct TestCase {
4623       int32_t gYear;
4624       int32_t gMonth;
4625       int32_t gDate;
4626       int32_t cYear;
4627       int32_t cMonth;
4628       int32_t cDate;
4629       const char* cMonthCode;
4630       int32_t cOrdinalMonth;
4631     } cases[] = {
4632       { 1900, UCAL_JANUARY, 1, 1616, icu::CopticCalendar::KIAHK, 23, "M04", 3},
4633       { 1900, UCAL_SEPTEMBER, 6, 1616, icu::CopticCalendar::NASIE, 1, "M13", 12},
4634       { 1900, UCAL_SEPTEMBER, 10, 1616, icu::CopticCalendar::NASIE, 5, "M13", 12},
4635       { 1900, UCAL_SEPTEMBER, 11, 1617, icu::CopticCalendar::TOUT, 1, "M01", 0},
4636 
4637       { 2022, UCAL_JANUARY, 11, 1738, icu::CopticCalendar::TOBA, 3, "M05", 4},
4638       { 2022, UCAL_FEBRUARY, 12, 1738, icu::CopticCalendar::AMSHIR, 5, "M06", 5},
4639       { 2022, UCAL_MARCH, 13, 1738, icu::CopticCalendar::BARAMHAT, 4, "M07", 6},
4640       { 2022, UCAL_APRIL, 14, 1738, icu::CopticCalendar::BARAMOUDA, 6, "M08", 7},
4641       { 2022, UCAL_MAY, 15, 1738, icu::CopticCalendar::BASHANS, 7, "M09", 8},
4642       { 2022, UCAL_JUNE, 16, 1738, icu::CopticCalendar::PAONA, 9, "M10", 9},
4643       { 2022, UCAL_JULY, 17, 1738, icu::CopticCalendar::EPEP, 10, "M11", 10},
4644       { 2022, UCAL_AUGUST, 18, 1738, icu::CopticCalendar::MESRA, 12, "M12", 11},
4645       { 2022, UCAL_SEPTEMBER, 6, 1738, icu::CopticCalendar::NASIE, 1, "M13", 12},
4646       { 2022, UCAL_SEPTEMBER, 10, 1738, icu::CopticCalendar::NASIE, 5, "M13", 12},
4647       { 2022, UCAL_SEPTEMBER, 11, 1739, icu::CopticCalendar::TOUT, 1, "M01", 0},
4648       { 2022, UCAL_SEPTEMBER, 19, 1739, icu::CopticCalendar::TOUT, 9, "M01", 0},
4649       { 2022, UCAL_OCTOBER, 20, 1739, icu::CopticCalendar::BABA, 10, "M02", 1},
4650       { 2022, UCAL_NOVEMBER, 21, 1739, icu::CopticCalendar::HATOR, 12, "M03", 2},
4651       { 2022, UCAL_DECEMBER, 22, 1739, icu::CopticCalendar::KIAHK, 13, "M04", 3},
4652 
4653       { 2023, UCAL_JANUARY, 1, 1739, icu::CopticCalendar::KIAHK, 23, "M04", 3},
4654       { 2023, UCAL_SEPTEMBER, 6, 1739, icu::CopticCalendar::NASIE, 1, "M13", 12},
4655       { 2023, UCAL_SEPTEMBER, 11, 1739, icu::CopticCalendar::NASIE, 6, "M13", 12},
4656       { 2023, UCAL_SEPTEMBER, 12, 1740, icu::CopticCalendar::TOUT, 1, "M01", 0},
4657 
4658       { 2030, UCAL_JANUARY, 1, 1746, icu::CopticCalendar::KIAHK, 23, "M04", 3},
4659       { 2030, UCAL_SEPTEMBER, 6, 1746, icu::CopticCalendar::NASIE, 1, "M13", 12},
4660       { 2030, UCAL_SEPTEMBER, 10, 1746, icu::CopticCalendar::NASIE, 5, "M13", 12},
4661       { 2030, UCAL_SEPTEMBER, 11, 1747, icu::CopticCalendar::TOUT, 1, "M01", 0},
4662     };
4663     GregorianCalendar gc1(status);
4664     if (failure(status, "construct Calendar")) return;
4665     for (auto& cas : cases) {
4666         gc1.clear();
4667         cc1->clear();
4668         cc2->clear();
4669         gc1.set(cas.gYear, cas.gMonth, cas.gDate);
4670         cc1->setTime(gc1.getTime(status), status);
4671 
4672         cc2->set(UCAL_EXTENDED_YEAR, cas.cYear);
4673         cc2->setTemporalMonthCode(cas.cMonthCode, status);
4674         cc2->set(UCAL_DATE, cas.cDate);
4675 
4676         assertEquals("year", cas.cYear, cc1->get(UCAL_EXTENDED_YEAR, status));
4677         assertEquals("month", cas.cMonth, cc1->get(UCAL_MONTH, status));
4678         assertEquals("date", cas.cDate, cc1->get(UCAL_DATE, status));
4679         assertEquals("getTemporalMonthCode()", 0,
4680                      uprv_strcmp(cas.cMonthCode, cc1->getTemporalMonthCode(status)));
4681         if (failure(status, "getTemporalMonthCode")) continue;
4682         assertTrue("by set() and setTemporalMonthCode()", cc2->equals(*cc1, status));
4683         if (! cc2->equals(*cc1, status)) {
4684             printf("g=%f %f vs %f. diff = %f %d/%d/%d vs %d/%d/%d\n",
4685                    gc1.getTime(status), cc1->getTime(status), cc2->getTime(status),
4686                    cc1->getTime(status) - cc2->getTime(status),
4687                    cc1->get(UCAL_EXTENDED_YEAR, status),
4688                    cc1->get(UCAL_MONTH, status)+1,
4689                    cc1->get(UCAL_DATE, status),
4690                    cc2->get(UCAL_EXTENDED_YEAR, status),
4691                    cc2->get(UCAL_MONTH, status)+1,
4692                    cc2->get(UCAL_DATE, status));
4693         }
4694         assertEquals("ordinalMonth", cas.cOrdinalMonth, cc1->get(UCAL_ORDINAL_MONTH, status));
4695         assertEquals("ordinalMonth", cas.cOrdinalMonth, cc2->get(UCAL_ORDINAL_MONTH, status));
4696     }
4697 }
4698 
TestEthiopicCalendarSetTemporalMonthCode()4699 void CalendarTest::TestEthiopicCalendarSetTemporalMonthCode() {
4700     UErrorCode status = U_ZERO_ERROR;
4701     Locale l(Locale::getRoot());
4702     l.setKeywordValue("calendar", "ethiopic", status);
4703     LocalPointer<Calendar> cc1(Calendar::createInstance(l, status));
4704     if (failure(status, "construct EthiopicCalendar")) return;
4705     LocalPointer<Calendar> cc2(cc1->clone());
4706 
4707     struct TestCase {
4708       int32_t gYear;
4709       int32_t gMonth;
4710       int32_t gDate;
4711       int32_t cYear;
4712       int32_t cMonth;
4713       int32_t cDate;
4714       const char* cMonthCode;
4715       int32_t cOrdinalMonth;
4716     } cases[] = {
4717       { 1900, UCAL_JANUARY, 1, 1892, icu::EthiopicCalendar::TAHSAS, 23, "M04", 3},
4718       { 1900, UCAL_SEPTEMBER, 6, 1892, icu::EthiopicCalendar::PAGUMEN, 1, "M13", 12},
4719       { 1900, UCAL_SEPTEMBER, 10, 1892, icu::EthiopicCalendar::PAGUMEN, 5, "M13", 12},
4720       { 1900, UCAL_SEPTEMBER, 11, 1893, icu::EthiopicCalendar::MESKEREM, 1, "M01", 0},
4721 
4722       { 2022, UCAL_JANUARY, 11, 2014, icu::EthiopicCalendar::TER, 3, "M05", 4},
4723       { 2022, UCAL_FEBRUARY, 12, 2014, icu::EthiopicCalendar::YEKATIT, 5, "M06", 5},
4724       { 2022, UCAL_MARCH, 13, 2014, icu::EthiopicCalendar::MEGABIT, 4, "M07", 6},
4725       { 2022, UCAL_APRIL, 14, 2014, icu::EthiopicCalendar::MIAZIA, 6, "M08", 7},
4726       { 2022, UCAL_MAY, 15, 2014, icu::EthiopicCalendar::GENBOT, 7, "M09", 8},
4727       { 2022, UCAL_JUNE, 16, 2014, icu::EthiopicCalendar::SENE, 9, "M10", 9},
4728       { 2022, UCAL_JULY, 17, 2014, icu::EthiopicCalendar::HAMLE, 10, "M11", 10},
4729       { 2022, UCAL_AUGUST, 18, 2014, icu::EthiopicCalendar::NEHASSA, 12, "M12", 11},
4730       { 2022, UCAL_SEPTEMBER, 6, 2014, icu::EthiopicCalendar::PAGUMEN, 1, "M13", 12},
4731       { 2022, UCAL_SEPTEMBER, 10, 2014, icu::EthiopicCalendar::PAGUMEN, 5, "M13", 12},
4732       { 2022, UCAL_SEPTEMBER, 11, 2015, icu::EthiopicCalendar::MESKEREM, 1, "M01", 0},
4733       { 2022, UCAL_SEPTEMBER, 19, 2015, icu::EthiopicCalendar::MESKEREM, 9, "M01", 0},
4734       { 2022, UCAL_OCTOBER, 20, 2015, icu::EthiopicCalendar::TEKEMT, 10, "M02", 1},
4735       { 2022, UCAL_NOVEMBER, 21, 2015, icu::EthiopicCalendar::HEDAR, 12, "M03", 2},
4736       { 2022, UCAL_DECEMBER, 22, 2015, icu::EthiopicCalendar::TAHSAS, 13, "M04", 3},
4737 
4738       { 2023, UCAL_JANUARY, 1, 2015, icu::EthiopicCalendar::TAHSAS, 23, "M04", 3},
4739       { 2023, UCAL_SEPTEMBER, 6, 2015, icu::EthiopicCalendar::PAGUMEN, 1, "M13", 12},
4740       { 2023, UCAL_SEPTEMBER, 11, 2015, icu::EthiopicCalendar::PAGUMEN, 6, "M13", 12},
4741       { 2023, UCAL_SEPTEMBER, 12, 2016, icu::EthiopicCalendar::MESKEREM, 1, "M01", 0},
4742 
4743       { 2030, UCAL_JANUARY, 1, 2022, icu::EthiopicCalendar::TAHSAS, 23, "M04", 3},
4744       { 2030, UCAL_SEPTEMBER, 6, 2022, icu::EthiopicCalendar::PAGUMEN, 1, "M13", 12},
4745       { 2030, UCAL_SEPTEMBER, 10, 2022, icu::EthiopicCalendar::PAGUMEN, 5, "M13", 12},
4746       { 2030, UCAL_SEPTEMBER, 11, 2023, icu::EthiopicCalendar::MESKEREM, 1, "M01", 0},
4747     };
4748     GregorianCalendar gc1(status);
4749     if (failure(status, "construct Calendar")) return;
4750     for (auto& cas : cases) {
4751         gc1.clear();
4752         cc1->clear();
4753         cc2->clear();
4754         gc1.set(cas.gYear, cas.gMonth, cas.gDate);
4755         cc1->setTime(gc1.getTime(status), status);
4756 
4757         cc2->set(UCAL_EXTENDED_YEAR, cas.cYear);
4758         cc2->setTemporalMonthCode(cas.cMonthCode, status);
4759         cc2->set(UCAL_DATE, cas.cDate);
4760 
4761         assertEquals("year", cas.cYear, cc1->get(UCAL_EXTENDED_YEAR, status));
4762         assertEquals("month", cas.cMonth, cc1->get(UCAL_MONTH, status));
4763         assertEquals("date", cas.cDate, cc1->get(UCAL_DATE, status));
4764         assertEquals("getTemporalMonthCode()", 0,
4765                      uprv_strcmp(cas.cMonthCode, cc1->getTemporalMonthCode(status)));
4766         if (failure(status, "getTemporalMonthCode")) continue;
4767         if (! cc2->equals(*cc1, status)) {
4768             printf("g=%f %f vs %f. diff = %f %d/%d/%d vs %d/%d/%d\n",
4769                    gc1.getTime(status), cc1->getTime(status), cc2->getTime(status),
4770                    cc1->getTime(status) - cc2->getTime(status),
4771                    cc1->get(UCAL_EXTENDED_YEAR, status),
4772                    cc1->get(UCAL_MONTH, status)+1,
4773                    cc1->get(UCAL_DATE, status),
4774                    cc2->get(UCAL_EXTENDED_YEAR, status),
4775                    cc2->get(UCAL_MONTH, status)+1,
4776                    cc2->get(UCAL_DATE, status));
4777         }
4778         assertTrue("by set() and setTemporalMonthCode()", cc2->equals(*cc1, status));
4779         assertEquals("ordinalMonth", cas.cOrdinalMonth, cc1->get(UCAL_ORDINAL_MONTH, status));
4780         assertEquals("ordinalMonth", cas.cOrdinalMonth, cc2->get(UCAL_ORDINAL_MONTH, status));
4781     }
4782 }
4783 
VerifyMonth(CalendarTest * test,const char * message,Calendar * cc,int32_t expectedMonth,int32_t expectedOrdinalMonth,bool expectedLeapMonth,const char * expectedMonthCode)4784 void VerifyMonth(CalendarTest* test, const char* message, Calendar* cc, int32_t expectedMonth,
4785                  int32_t expectedOrdinalMonth, bool expectedLeapMonth,
4786                  const char* expectedMonthCode) {
4787     UErrorCode status = U_ZERO_ERROR;
4788     std::string buf(message);
4789     buf.append(" get(UCAL_MONTH)");
4790     test->assertEquals(buf.c_str(), expectedMonth, cc->get(UCAL_MONTH, status));
4791     buf = message;
4792     buf.append(" get(UCAL_ORDINAL_MONTH)");
4793     test->assertEquals(buf.c_str(), expectedOrdinalMonth, cc->get(UCAL_ORDINAL_MONTH, status));
4794     buf = message;
4795     buf.append(" get(UCAL_IS_LEAP_MONTH)");
4796     test->assertEquals(buf.c_str(), expectedLeapMonth ? 1 : 0, cc->get(UCAL_IS_LEAP_MONTH, status));
4797     buf = message;
4798     buf.append(" getTemporalMonthCode()");
4799     test->assertTrue(buf.c_str(), uprv_strcmp(cc->getTemporalMonthCode(status), expectedMonthCode) == 0);
4800 }
4801 
TestMostCalendarsOrdinalMonthSet()4802 void CalendarTest::TestMostCalendarsOrdinalMonthSet() {
4803     UErrorCode status = U_ZERO_ERROR;
4804     Locale l(Locale::getRoot());
4805     std::unique_ptr<icu::StringEnumeration> enumeration(
4806         Calendar::getKeywordValuesForLocale("calendar", l, false, status));
4807     for (const char* name = enumeration->next(nullptr, status);
4808         U_SUCCESS(status) && name != nullptr;
4809         name = enumeration->next(nullptr, status)) {
4810 
4811         // Test these three calendars differently.
4812         if (uprv_strcmp(name, "chinese") == 0) continue;
4813         if (uprv_strcmp(name, "dangi") == 0) continue;
4814         if (uprv_strcmp(name, "hebrew") == 0) continue;
4815 
4816         l.setKeywordValue("calendar", name, status);
4817         LocalPointer<Calendar> cc1(Calendar::createInstance(l, status));
4818         if (failure(status, "Construct Calendar")) return;
4819 
4820         LocalPointer<Calendar> cc2(cc1->clone());
4821         LocalPointer<Calendar> cc3(cc1->clone());
4822 
4823         cc1->set(UCAL_EXTENDED_YEAR, 2134);
4824         cc2->set(UCAL_EXTENDED_YEAR, 2134);
4825         cc3->set(UCAL_EXTENDED_YEAR, 2134);
4826         cc1->set(UCAL_MONTH, 5);
4827         cc2->set(UCAL_ORDINAL_MONTH, 5);
4828         cc3->setTemporalMonthCode("M06", status);
4829         if (failure(status, "setTemporalMonthCode failure")) return;
4830         cc1->set(UCAL_DATE, 23);
4831         cc2->set(UCAL_DATE, 23);
4832         cc3->set(UCAL_DATE, 23);
4833         assertTrue("M06 cc2==cc1 set month by UCAL_MONTH and UCAL_UCAL_ORDINAL_MONTH", cc2->equals(*cc1, status));
4834         assertTrue("M06 cc2==cc3 set month by UCAL_MONTH and setTemporalMonthCode", cc2->equals(*cc3, status));
4835         if (failure(status, "equals failure")) return;
4836         VerifyMonth(this, "cc1", cc1.getAlias(), 5, 5, false, "M06");
4837         VerifyMonth(this, "cc2", cc2.getAlias(), 5, 5, false, "M06");
4838         VerifyMonth(this, "cc3", cc3.getAlias(), 5, 5, false, "M06");
4839 
4840         cc1->set(UCAL_ORDINAL_MONTH, 6);
4841         cc2->setTemporalMonthCode("M07", status);
4842         if (failure(status, "setTemporalMonthCode failure")) return;
4843         cc3->set(UCAL_MONTH, 6);
4844         assertTrue("M07 cc2==cc1 set month by UCAL_MONTH and UCAL_UCAL_ORDINAL_MONTH", cc2->equals(*cc1, status));
4845         assertTrue("M07 cc2==cc3 set month by UCAL_MONTH and setTemporalMonthCode", cc2->equals(*cc3, status));
4846         if (failure(status, "equals failure")) return;
4847         VerifyMonth(this, "cc1", cc1.getAlias(), 6, 6, false, "M07");
4848         VerifyMonth(this, "cc2", cc2.getAlias(), 6, 6, false, "M07");
4849         VerifyMonth(this, "cc3", cc3.getAlias(), 6, 6, false, "M07");
4850 
4851         cc1->setTemporalMonthCode("M08", status);
4852         if (failure(status, "setTemporalMonthCode failure")) return;
4853         cc2->set(UCAL_MONTH, 7);
4854         cc3->set(UCAL_ORDINAL_MONTH, 7);
4855         assertTrue("M08 cc2==cc1 set month by UCAL_MONTH and UCAL_UCAL_ORDINAL_MONTH", cc2->equals(*cc1, status));
4856         assertTrue("M08 cc2==cc3 set month by UCAL_MONTH and setTemporalMonthCode", cc2->equals(*cc3, status));
4857         if (failure(status, "equals failure")) return;
4858         VerifyMonth(this, "cc1", cc1.getAlias(), 7, 7, false, "M08");
4859         VerifyMonth(this, "cc2", cc2.getAlias(), 7, 7, false, "M08");
4860         VerifyMonth(this, "cc3", cc3.getAlias(), 7, 7, false, "M08");
4861 
4862         cc1->set(UCAL_DATE, 3);
4863         // For "M13", do not return error for these three calendars.
4864         if ((uprv_strcmp(name, "coptic") == 0) ||
4865             (uprv_strcmp(name, "ethiopic") == 0) ||
4866             (uprv_strcmp(name, "ethiopic-amete-alem") == 0)) {
4867 
4868             cc1->setTemporalMonthCode("M13", status);
4869             assertEquals("setTemporalMonthCode(\"M13\")", U_ZERO_ERROR, status);
4870             assertEquals("get(UCAL_MONTH) after setTemporalMonthCode(\"M13\")",
4871                          12, cc1->get(UCAL_MONTH, status));
4872             assertEquals("get(UCAL_ORDINAL_MONTH) after setTemporalMonthCode(\"M13\")",
4873                          12, cc1->get(UCAL_ORDINAL_MONTH, status));
4874             assertEquals("get", U_ZERO_ERROR, status);
4875         } else {
4876             cc1->setTemporalMonthCode("M13", status);
4877             assertEquals("setTemporalMonthCode(\"M13\")", U_ILLEGAL_ARGUMENT_ERROR, status);
4878         }
4879         status = U_ZERO_ERROR;
4880 
4881         // Out of bound monthCodes should return error.
4882         // These are not valid for calendar do not have a leap month
4883         const char* kInvalidMonthCodes[] = {
4884           "M00", "M14", "M01L", "M02L", "M03L", "M04L", "M05L", "M06L", "M07L",
4885           "M08L", "M09L", "M10L", "M11L", "M12L"};
4886         for (auto& cas : kInvalidMonthCodes) {
4887            cc1->setTemporalMonthCode(cas, status);
4888            assertEquals("setTemporalMonthCode(\"M13\")", U_ILLEGAL_ARGUMENT_ERROR, status);
4889            status = U_ZERO_ERROR;
4890         }
4891 
4892     }
4893 }
4894 
TestChineseCalendarOrdinalMonthSet()4895 void CalendarTest::TestChineseCalendarOrdinalMonthSet() {
4896     UErrorCode status = U_ZERO_ERROR;
4897     Locale l(Locale::getRoot());
4898     l.setKeywordValue("calendar", "chinese", status);
4899     LocalPointer<Calendar> cc1(Calendar::createInstance(l, status));
4900     if (failure(status, "Construct Calendar")) return;
4901 
4902     LocalPointer<Calendar> cc2(cc1->clone());
4903     LocalPointer<Calendar> cc3(cc1->clone());
4904 
4905     constexpr int32_t notLeapYear = 4591;
4906     constexpr int32_t leapMarchYear = 4592;
4907 
4908     cc1->set(UCAL_EXTENDED_YEAR, leapMarchYear);
4909     cc2->set(UCAL_EXTENDED_YEAR, leapMarchYear);
4910     cc3->set(UCAL_EXTENDED_YEAR, leapMarchYear);
4911 
4912     cc1->set(UCAL_MONTH, UCAL_MARCH); cc1->set(UCAL_IS_LEAP_MONTH, 1);
4913     cc2->set(UCAL_ORDINAL_MONTH, 3);
4914     cc3->setTemporalMonthCode("M03L", status);
4915     if (failure(status, "setTemporalMonthCode failure")) return;
4916     cc1->set(UCAL_DATE, 1);
4917     cc2->set(UCAL_DATE, 1);
4918     cc3->set(UCAL_DATE, 1);
4919     assertTrue("4592 M03L cc2==cc1 set month by UCAL_MONTH and UCAL_UCAL_ORDINAL_MONTH", cc2->equals(*cc1, status));
4920     assertTrue("4592 M03L cc2==cc3 set month by UCAL_MONTH and setTemporalMonthCode", cc2->equals(*cc3, status));
4921     if (failure(status, "equals failure")) return;
4922     VerifyMonth(this, "4592 M03L cc1", cc1.getAlias(), UCAL_MARCH, 3, true, "M03L");
4923     VerifyMonth(this, "4592 M03L cc2", cc2.getAlias(), UCAL_MARCH, 3, true, "M03L");
4924     VerifyMonth(this, "4592 M03L cc3", cc3.getAlias(), UCAL_MARCH, 3, true, "M03L");
4925 
4926     cc1->set(UCAL_EXTENDED_YEAR, notLeapYear);
4927     cc2->set(UCAL_EXTENDED_YEAR, notLeapYear);
4928     cc3->set(UCAL_EXTENDED_YEAR, notLeapYear);
4929     cc1->set(UCAL_ORDINAL_MONTH, 5);
4930     cc2->setTemporalMonthCode("M06", status);
4931     if (failure(status, "setTemporalMonthCode failure")) return;
4932     cc3->set(UCAL_MONTH, UCAL_JUNE); cc3->set(UCAL_IS_LEAP_MONTH, 0);
4933     assertTrue("4591 M06 cc2==cc1 set month by UCAL_MONTH and UCAL_UCAL_ORDINAL_MONTH", cc2->equals(*cc1, status));
4934     assertTrue("4591 M06 cc2==cc3 set month by UCAL_MONTH and setTemporalMonthCode", cc2->equals(*cc3, status));
4935     if (failure(status, "equals failure")) return;
4936     VerifyMonth(this, "4591 M06 cc1", cc1.getAlias(), UCAL_JUNE, 5, false, "M06");
4937     VerifyMonth(this, "4591 M06 cc2", cc2.getAlias(), UCAL_JUNE, 5, false, "M06");
4938     VerifyMonth(this, "4591 M06 cc3", cc3.getAlias(), UCAL_JUNE, 5, false, "M06");
4939 
4940     cc1->set(UCAL_EXTENDED_YEAR, leapMarchYear);
4941     cc2->set(UCAL_EXTENDED_YEAR, leapMarchYear);
4942     cc3->set(UCAL_EXTENDED_YEAR, leapMarchYear);
4943     cc1->setTemporalMonthCode("M04", status);
4944     if (failure(status, "setTemporalMonthCode failure")) return;
4945     cc2->set(UCAL_MONTH, UCAL_APRIL); cc2->set(UCAL_IS_LEAP_MONTH, 0);
4946     cc3->set(UCAL_ORDINAL_MONTH, 4);
4947     assertTrue("4592 M04 cc2==cc1 set month by UCAL_MONTH and UCAL_UCAL_ORDINAL_MONTH", cc2->equals(*cc1, status));
4948     assertTrue("4592 M04 cc2==cc3 set month by UCAL_MONTH and setTemporalMonthCode", cc2->equals(*cc3, status));
4949     if (failure(status, "equals failure")) return;
4950     // 4592 has leap March so April is the 5th month in that year.
4951     VerifyMonth(this, "4592 M04 cc1", cc1.getAlias(), UCAL_APRIL, 4, false, "M04");
4952     VerifyMonth(this, "4592 M04 cc2", cc2.getAlias(), UCAL_APRIL, 4, false, "M04");
4953     VerifyMonth(this, "4592 M04 cc3", cc3.getAlias(), UCAL_APRIL, 4, false, "M04");
4954 
4955     cc1->set(UCAL_EXTENDED_YEAR, notLeapYear);
4956     cc2->set(UCAL_EXTENDED_YEAR, notLeapYear);
4957     cc3->set(UCAL_EXTENDED_YEAR, notLeapYear);
4958     assertTrue("4591 M04 no leap month before cc2==cc1 set month by UCAL_MONTH and UCAL_UCAL_ORDINAL_MONTH", cc2->equals(*cc1, status));
4959     assertTrue("4591 M04 no leap month before cc2==cc3 set month by UCAL_MONTH and setTemporalMonthCode", cc2->equals(*cc3, status));
4960     if (failure(status, "equals failure")) return;
4961     // 4592 has no leap month before April so April is the 4th month in that year.
4962     VerifyMonth(this, "4591 M04 cc1", cc1.getAlias(), UCAL_APRIL, 3, false, "M04");
4963     VerifyMonth(this, "4591 M04 cc2", cc2.getAlias(), UCAL_APRIL, 3, false, "M04");
4964     VerifyMonth(this, "4591 M04 cc3", cc3.getAlias(), UCAL_APRIL, 3, false, "M04");
4965 
4966     // Out of bound monthCodes should return error.
4967     // These are not valid for calendar do not have a leap month
4968     UErrorCode expectedStatus = U_ILLEGAL_ARGUMENT_ERROR;
4969     const char* kInvalidMonthCodes[] = { "M00", "M13", "M14" };
4970 
4971 
4972     for (auto& cas : kInvalidMonthCodes) {
4973        cc1->setTemporalMonthCode(cas, status);
4974        if (status != expectedStatus) {
4975            errln("setTemporalMonthCode(%s) should return U_ILLEGAL_ARGUMENT_ERROR", cas);
4976        }
4977        status = U_ZERO_ERROR;
4978     }
4979 }
4980 
TestDangiCalendarOrdinalMonthSet()4981 void CalendarTest::TestDangiCalendarOrdinalMonthSet() {
4982     UErrorCode status = U_ZERO_ERROR;
4983     Locale l(Locale::getRoot());
4984     const char* name = "dangi";
4985     l.setKeywordValue("calendar", name, status);
4986     LocalPointer<Calendar> cc1(Calendar::createInstance(l, status));
4987     if (failure(status, "Construct Calendar")) return;
4988 
4989     LocalPointer<Calendar> cc2(cc1->clone());
4990     LocalPointer<Calendar> cc3(cc1->clone());
4991 
4992     constexpr int32_t notLeapYear = 4287;
4993     constexpr int32_t leapMarchYear = 4288;
4994 
4995     cc1->set(UCAL_EXTENDED_YEAR, leapMarchYear);
4996     cc2->set(UCAL_EXTENDED_YEAR, leapMarchYear);
4997     cc3->set(UCAL_EXTENDED_YEAR, leapMarchYear);
4998 
4999     cc1->set(UCAL_MONTH, UCAL_MARCH); cc1->set(UCAL_IS_LEAP_MONTH, 1);
5000     cc2->set(UCAL_ORDINAL_MONTH, 3);
5001     cc3->setTemporalMonthCode("M03L", status);
5002     if (failure(status, "setTemporalMonthCode failure")) return;
5003     cc1->set(UCAL_DATE, 1);
5004     cc2->set(UCAL_DATE, 1);
5005     cc3->set(UCAL_DATE, 1);
5006     assertTrue("4288 M03L cc2==cc1 set month by UCAL_MONTH and UCAL_UCAL_ORDINAL_MONTH", cc2->equals(*cc1, status));
5007     assertTrue("4288 M03L cc2==cc3 set month by UCAL_MONTH and setTemporalMonthCode", cc2->equals(*cc3, status));
5008     if (failure(status, "equals failure")) return;
5009     VerifyMonth(this, "4288 M03L cc1", cc1.getAlias(), UCAL_MARCH, 3, true, "M03L");
5010     VerifyMonth(this, "4288 M03L cc2", cc2.getAlias(), UCAL_MARCH, 3, true, "M03L");
5011     VerifyMonth(this, "4288 M03L cc3", cc3.getAlias(), UCAL_MARCH, 3, true, "M03L");
5012 
5013     cc1->set(UCAL_EXTENDED_YEAR, notLeapYear);
5014     cc2->set(UCAL_EXTENDED_YEAR, notLeapYear);
5015     cc3->set(UCAL_EXTENDED_YEAR, notLeapYear);
5016     cc1->set(UCAL_ORDINAL_MONTH, 5);
5017     cc2->setTemporalMonthCode("M06", status);
5018     if (failure(status, "setTemporalMonthCode failure")) return;
5019     cc3->set(UCAL_MONTH, UCAL_JUNE); cc3->set(UCAL_IS_LEAP_MONTH, 0);
5020     assertTrue("4287 M06 cc2==cc1 set month by UCAL_MONTH and UCAL_UCAL_ORDINAL_MONTH", cc2->equals(*cc1, status));
5021     assertTrue("4287 M06 cc2==cc3 set month by UCAL_MONTH and setTemporalMonthCode", cc2->equals(*cc3, status));
5022     if (failure(status, "equals failure")) return;
5023     VerifyMonth(this, "4287 M06 cc1", cc1.getAlias(), UCAL_JUNE, 5, false, "M06");
5024     VerifyMonth(this, "4287 M06 cc2", cc2.getAlias(), UCAL_JUNE, 5, false, "M06");
5025     VerifyMonth(this, "4287 M06 cc3", cc3.getAlias(), UCAL_JUNE, 5, false, "M06");
5026 
5027     cc1->set(UCAL_EXTENDED_YEAR, leapMarchYear);
5028     cc2->set(UCAL_EXTENDED_YEAR, leapMarchYear);
5029     cc3->set(UCAL_EXTENDED_YEAR, leapMarchYear);
5030     cc1->setTemporalMonthCode("M04", status);
5031     if (failure(status, "setTemporalMonthCode failure")) return;
5032     cc2->set(UCAL_MONTH, UCAL_APRIL); cc2->set(UCAL_IS_LEAP_MONTH, 0);
5033     cc3->set(UCAL_ORDINAL_MONTH, 4);
5034     assertTrue("4288 M04 cc2==cc1 set month by UCAL_MONTH and UCAL_UCAL_ORDINAL_MONTH", cc2->equals(*cc1, status));
5035     assertTrue("4288 M04 cc2==cc3 set month by UCAL_MONTH and setTemporalMonthCode", cc2->equals(*cc3, status));
5036     if (failure(status, "equals failure")) return;
5037     // 4592 has leap March so April is the 5th month in that year.
5038     VerifyMonth(this, "4288 M04 cc1", cc1.getAlias(), UCAL_APRIL, 4, false, "M04");
5039     VerifyMonth(this, "4288 M04 cc2", cc2.getAlias(), UCAL_APRIL, 4, false, "M04");
5040     VerifyMonth(this, "4288 M04 cc3", cc3.getAlias(), UCAL_APRIL, 4, false, "M04");
5041 
5042     cc1->set(UCAL_EXTENDED_YEAR, notLeapYear);
5043     cc2->set(UCAL_EXTENDED_YEAR, notLeapYear);
5044     cc3->set(UCAL_EXTENDED_YEAR, notLeapYear);
5045     assertTrue("4287 M04 no leap month before cc2==cc1 set month by UCAL_MONTH and UCAL_UCAL_ORDINAL_MONTH", cc2->equals(*cc1, status));
5046     assertTrue("4287 M04 no leap month before cc2==cc3 set month by UCAL_MONTH and setTemporalMonthCode", cc2->equals(*cc3, status));
5047     if (failure(status, "equals failure")) return;
5048     // 4592 has no leap month before April so April is the 4th month in that year.
5049     VerifyMonth(this, "4287 M04 cc1", cc1.getAlias(), UCAL_APRIL, 3, false, "M04");
5050     VerifyMonth(this, "4287 M04 cc2", cc2.getAlias(), UCAL_APRIL, 3, false, "M04");
5051     VerifyMonth(this, "4287 M04 cc3", cc3.getAlias(), UCAL_APRIL, 3, false, "M04");
5052 
5053     // Out of bound monthCodes should return error.
5054     // These are not valid for calendar do not have a leap month
5055     UErrorCode expectedStatus = U_ILLEGAL_ARGUMENT_ERROR;
5056     const char* kInvalidMonthCodes[] = { "M00", "M13", "M14" };
5057 
5058     for (auto& cas : kInvalidMonthCodes) {
5059        cc1->setTemporalMonthCode(cas, status);
5060        if (status != expectedStatus) {
5061            errln("setTemporalMonthCode(%s) should return U_ILLEGAL_ARGUMENT_ERROR", cas);
5062        }
5063        status = U_ZERO_ERROR;
5064     }
5065 }
5066 
TestHebrewCalendarOrdinalMonthSet()5067 void CalendarTest::TestHebrewCalendarOrdinalMonthSet() {
5068     UErrorCode status = U_ZERO_ERROR;
5069     Locale l(Locale::getRoot());
5070     l.setKeywordValue("calendar", "hebrew", status);
5071     LocalPointer<Calendar> cc1(Calendar::createInstance(l, status));
5072     if (failure(status, "Construct Calendar")) return;
5073 
5074     LocalPointer<Calendar> cc2(cc1->clone());
5075     LocalPointer<Calendar> cc3(cc1->clone());
5076 
5077     // 5782 is leap year, 5781 is NOT.
5078     cc1->set(UCAL_EXTENDED_YEAR, 5782);
5079     cc2->set(UCAL_EXTENDED_YEAR, 5782);
5080     cc3->set(UCAL_EXTENDED_YEAR, 5782);
5081     cc1->set(UCAL_MONTH, icu::HebrewCalendar::ADAR_1);
5082     cc2->set(UCAL_ORDINAL_MONTH, 5);
5083     cc3->setTemporalMonthCode("M05L", status);
5084     if (failure(status, "setTemporalMonthCode failure")) return;
5085     cc1->set(UCAL_DATE, 1);
5086     cc2->set(UCAL_DATE, 1);
5087     cc3->set(UCAL_DATE, 1);
5088     assertTrue("5782 M05L cc2==cc1 set month by UCAL_MONTH and UCAL_UCAL_ORDINAL_MONTH", cc2->equals(*cc1, status));
5089     assertTrue("5782 M05L cc2==cc3 set month by UCAL_MONTH and setTemporalMonthCode", cc2->equals(*cc3, status));
5090     if (failure(status, "equals failure")) return;
5091     VerifyMonth(this, "cc1", cc1.getAlias(), icu::HebrewCalendar::ADAR_1, 5, false, "M05L");
5092     VerifyMonth(this, "cc2", cc2.getAlias(), icu::HebrewCalendar::ADAR_1, 5, false, "M05L");
5093     VerifyMonth(this, "cc3", cc3.getAlias(), icu::HebrewCalendar::ADAR_1, 5, false, "M05L");
5094 
5095     cc1->set(UCAL_ORDINAL_MONTH, 4);
5096     cc2->setTemporalMonthCode("M05", status);
5097     if (failure(status, "setTemporalMonthCode failure")) return;
5098     cc3->set(UCAL_MONTH, icu::HebrewCalendar::SHEVAT);
5099     assertTrue("5782 M05 cc2==cc1 set month by UCAL_MONTH and UCAL_UCAL_ORDINAL_MONTH", cc2->equals(*cc1, status));
5100     assertTrue("5782 M05 cc2==cc3 set month by UCAL_MONTH and setTemporalMonthCode", cc2->equals(*cc3, status));
5101     if (failure(status, "equals failure")) return;
5102     VerifyMonth(this, "cc1", cc1.getAlias(), icu::HebrewCalendar::SHEVAT, 4, false, "M05");
5103     VerifyMonth(this, "cc2", cc2.getAlias(), icu::HebrewCalendar::SHEVAT, 4, false, "M05");
5104     VerifyMonth(this, "cc3", cc3.getAlias(), icu::HebrewCalendar::SHEVAT, 4, false, "M05");
5105 
5106     cc1->set(UCAL_EXTENDED_YEAR, 5781);
5107     cc2->set(UCAL_EXTENDED_YEAR, 5781);
5108     cc3->set(UCAL_EXTENDED_YEAR, 5781);
5109     cc1->setTemporalMonthCode("M06", status);
5110     if (failure(status, "setTemporalMonthCode failure")) return;
5111     cc2->set(UCAL_MONTH, icu::HebrewCalendar::ADAR);
5112     cc3->set(UCAL_ORDINAL_MONTH, 5);
5113     assertTrue("5781 M06 cc2==cc1 set month by UCAL_MONTH and UCAL_UCAL_ORDINAL_MONTH", cc2->equals(*cc1, status));
5114     assertTrue("5781 M06 cc2==cc3 set month by UCAL_MONTH and setTemporalMonthCode", cc2->equals(*cc3, status));
5115     if (failure(status, "equals failure")) return;
5116     VerifyMonth(this, "cc1", cc1.getAlias(), icu::HebrewCalendar::ADAR, 5, false, "M06");
5117     VerifyMonth(this, "cc2", cc2.getAlias(), icu::HebrewCalendar::ADAR, 5, false, "M06");
5118     VerifyMonth(this, "cc3", cc3.getAlias(), icu::HebrewCalendar::ADAR, 5, false, "M06");
5119 
5120     cc1->set(UCAL_EXTENDED_YEAR, 5782);
5121     cc2->set(UCAL_EXTENDED_YEAR, 5782);
5122     cc3->set(UCAL_EXTENDED_YEAR, 5782);
5123     assertTrue("5782 M06 cc2==cc1 set month by UCAL_MONTH and UCAL_UCAL_ORDINAL_MONTH", cc2->equals(*cc1, status));
5124     assertTrue("5782 M06 cc2==cc3 set month by UCAL_MONTH and setTemporalMonthCode", cc2->equals(*cc3, status));
5125     if (failure(status, "equals failure")) return;
5126     VerifyMonth(this, "cc1", cc1.getAlias(), icu::HebrewCalendar::ADAR, 6, false, "M06");
5127     VerifyMonth(this, "cc2", cc2.getAlias(), icu::HebrewCalendar::ADAR, 6, false, "M06");
5128     VerifyMonth(this, "cc3", cc3.getAlias(), icu::HebrewCalendar::ADAR, 6, false, "M06");
5129 
5130     cc1->set(UCAL_ORDINAL_MONTH, 6);
5131     cc2->setTemporalMonthCode("M07", status);
5132     if (failure(status, "setTemporalMonthCode failure")) return;
5133     cc3->set(UCAL_MONTH, icu::HebrewCalendar::NISAN);
5134     assertTrue("5782 M07 cc2==cc1 set month by UCAL_MONTH and UCAL_UCAL_ORDINAL_MONTH", cc2->equals(*cc1, status));
5135     assertTrue("5782 M07 cc2==cc3 set month by UCAL_MONTH and setTemporalMonthCode", cc2->equals(*cc3, status));
5136     if (failure(status, "equals failure")) return;
5137     VerifyMonth(this, "cc1", cc1.getAlias(), icu::HebrewCalendar::NISAN, 7, false, "M07");
5138     VerifyMonth(this, "cc2", cc2.getAlias(), icu::HebrewCalendar::NISAN, 7, false, "M07");
5139     VerifyMonth(this, "cc3", cc3.getAlias(), icu::HebrewCalendar::NISAN, 7, false, "M07");
5140 
5141     // Out of bound monthCodes should return error.
5142     // These are not valid for calendar do not have a leap month
5143     UErrorCode expectedStatus = U_ILLEGAL_ARGUMENT_ERROR;
5144     const char* kInvalidMonthCodes[] = { "M00", "M13", "M14",
5145       "M01L", "M02L", "M03L", "M04L",
5146       /* M05L could be legal */
5147       "M06L", "M07L", "M08L", "M09L", "M10L", "M11L", "M12L",
5148     };
5149 
5150     for (auto& cas : kInvalidMonthCodes) {
5151        cc1->setTemporalMonthCode(cas, status);
5152        if (status != expectedStatus) {
5153            errln("setTemporalMonthCode(%s) should return U_ILLEGAL_ARGUMENT_ERROR", cas);
5154        }
5155        status = U_ZERO_ERROR;
5156     }
5157 }
5158 
TestCalendarAddOrdinalMonth()5159 void CalendarTest::TestCalendarAddOrdinalMonth() {
5160     UErrorCode status = U_ZERO_ERROR;
5161     GregorianCalendar gc(status);
5162     gc.set(2022, UCAL_DECEMBER, 16);
5163     Locale l(Locale::getRoot());
5164     std::unique_ptr<icu::StringEnumeration> enumeration(
5165         Calendar::getKeywordValuesForLocale("calendar", l, false, status));
5166     for (const char* name = enumeration->next(nullptr, status);
5167         U_SUCCESS(status) && name != nullptr;
5168         name = enumeration->next(nullptr, status)) {
5169 
5170         l.setKeywordValue("calendar", name, status);
5171         LocalPointer<Calendar> cc1(Calendar::createInstance(l, status));
5172         if (failure(status, "Construct Calendar")) return;
5173 
5174         cc1->setTime(gc.getTime(status), status);
5175         LocalPointer<Calendar> cc2(cc1->clone());
5176 
5177         for (int i = 0; i < 8; i++) {
5178             for (int j = 1; j < 8; j++) {
5179                 cc1->add(UCAL_MONTH, j, status);
5180                 cc2->add(UCAL_ORDINAL_MONTH, j, status);
5181                 if (failure(status, "add j")) return;
5182                 assertTrue("two add produce the same result", cc2->equals(*cc1, status));
5183             }
5184             for (int j = 1; j < 8; j++) {
5185                 cc1->add(UCAL_MONTH, -j, status);
5186                 cc2->add(UCAL_ORDINAL_MONTH, -j, status);
5187                 if (failure(status, "add -j")) return;
5188                 assertTrue("two add produce the same result", cc2->equals(*cc1, status));
5189             }
5190         }
5191     }
5192 }
5193 
TestCalendarRollOrdinalMonth()5194 void CalendarTest::TestCalendarRollOrdinalMonth() {
5195     UErrorCode status = U_ZERO_ERROR;
5196     GregorianCalendar gc(status);
5197     gc.set(2022, UCAL_DECEMBER, 16);
5198     Locale l(Locale::getRoot());
5199     std::unique_ptr<icu::StringEnumeration> enumeration(
5200         Calendar::getKeywordValuesForLocale("calendar", l, false, status));
5201     for (const char* name = enumeration->next(nullptr, status);
5202         U_SUCCESS(status) && name != nullptr;
5203         name = enumeration->next(nullptr, status)) {
5204 
5205         l.setKeywordValue("calendar", name, status);
5206         LocalPointer<Calendar> cc1(Calendar::createInstance(l, status));
5207         if (failure(status, "Construct Calendar")) return;
5208 
5209         cc1->setTime(gc.getTime(status), status);
5210         LocalPointer<Calendar> cc2(cc1->clone());
5211 
5212         for (int i = 0; i < 8; i++) {
5213             for (int j = 1; j < 8; j++) {
5214                 cc1->roll(UCAL_MONTH, j, status);
5215                 cc2->roll(UCAL_ORDINAL_MONTH, j, status);
5216                 if (failure(status, "roll j")) return;
5217                 assertTrue("two add produce the same result", cc2->equals(*cc1, status));
5218             }
5219             for (int j = 1; j < 8; j++) {
5220                 cc1->roll(UCAL_MONTH, -j, status);
5221                 cc2->roll(UCAL_ORDINAL_MONTH, -j, status);
5222                 if (failure(status, "roll -j")) return;
5223                 assertTrue("two add produce the same result", cc2->equals(*cc1, status));
5224             }
5225             for (int j = 1; j < 3; j++) {
5226                 cc1->roll(UCAL_MONTH, true, status);
5227                 cc2->roll(UCAL_ORDINAL_MONTH, true, status);
5228                 if (failure(status, "roll true")) return;
5229                 assertTrue("two add produce the same result", cc2->equals(*cc1, status));
5230             }
5231             for (int j = 1; j < 3; j++) {
5232                 cc1->roll(UCAL_MONTH, false, status);
5233                 cc2->roll(UCAL_ORDINAL_MONTH, false, status);
5234                 if (failure(status, "roll false")) return;
5235                 assertTrue("two add produce the same result", cc2->equals(*cc1, status));
5236             }
5237         }
5238     }
5239 }
5240 
TestLimitsOrdinalMonth()5241 void CalendarTest::TestLimitsOrdinalMonth() {
5242     UErrorCode status = U_ZERO_ERROR;
5243     GregorianCalendar gc(status);
5244     gc.set(2022, UCAL_DECEMBER, 16);
5245     Locale l(Locale::getRoot());
5246     std::unique_ptr<icu::StringEnumeration> enumeration(
5247         Calendar::getKeywordValuesForLocale("calendar", l, false, status));
5248 
5249     struct Expectation {
5250       const char* calendar;
5251       int32_t min;
5252       int32_t max;
5253       int32_t greatestMin;
5254       int32_t leastMax;
5255     } kExpectations[] = {
5256         { "gregorian", 0, 11, 0, 11 },
5257         { "japanese", 0, 11, 0, 11 },
5258         { "buddhist", 0, 11, 0, 11 },
5259         { "roc", 0, 11, 0, 11 },
5260         { "persian", 0, 11, 0, 11 },
5261         { "islamic-civil", 0, 11, 0, 11 },
5262         { "islamic", 0, 11, 0, 11 },
5263         { "hebrew", 0, 12, 0, 11 },
5264         { "chinese", 0, 12, 0, 11 },
5265         { "indian", 0, 11, 0, 11 },
5266         { "coptic", 0, 12, 0, 12 },
5267         { "ethiopic", 0, 12, 0, 12 },
5268         { "ethiopic-amete-alem", 0, 12, 0, 12 },
5269         { "iso8601", 0, 11, 0, 11 },
5270         { "dangi", 0, 12, 0, 11 },
5271         { "islamic-umalqura", 0, 11, 0, 11 },
5272         { "islamic-tbla", 0, 11, 0, 11 },
5273         { "islamic-rgsa", 0, 11, 0, 11 },
5274     };
5275 
5276     for (const char* name = enumeration->next(nullptr, status);
5277         U_SUCCESS(status) && name != nullptr;
5278         name = enumeration->next(nullptr, status)) {
5279         l.setKeywordValue("calendar", name, status);
5280         LocalPointer<Calendar> cc1(Calendar::createInstance(l, status));
5281         if (failure(status, "Construct Calendar")) return;
5282         bool found = false;
5283         for (auto& exp : kExpectations) {
5284             if (uprv_strcmp(exp.calendar, name) == 0) {
5285                 found = true;
5286                 assertEquals("getMinimum(UCAL_ORDINAL_MONTH)",
5287                              exp.min, cc1->getMinimum(UCAL_ORDINAL_MONTH));
5288                 assertEquals("getMaximum(UCAL_ORDINAL_MONTH)",
5289                              exp.max, cc1->getMaximum(UCAL_ORDINAL_MONTH));
5290                 assertEquals("getMinimum(UCAL_ORDINAL_MONTH)",
5291                              exp.greatestMin, cc1->getGreatestMinimum(UCAL_ORDINAL_MONTH));
5292                 assertEquals("getMinimum(UCAL_ORDINAL_MONTH)",
5293                              exp.leastMax, cc1->getLeastMaximum(UCAL_ORDINAL_MONTH));
5294                 break;
5295             }
5296         }
5297         if (!found) {
5298             errln("Cannot find expectation");
5299         }
5300     }
5301 }
5302 
TestActualLimitsOrdinalMonth()5303 void CalendarTest::TestActualLimitsOrdinalMonth() {
5304     UErrorCode status = U_ZERO_ERROR;
5305     GregorianCalendar gc(status);
5306     gc.set(2022, UCAL_DECEMBER, 16);
5307     Locale l(Locale::getRoot());
5308     std::unique_ptr<icu::StringEnumeration> enumeration(
5309         Calendar::getKeywordValuesForLocale("calendar", l, false, status));
5310 
5311     struct TestCases {
5312       const char* calendar;
5313       int32_t extended_year;
5314       int32_t actualMinOrdinalMonth;
5315       int32_t actualMaxOrdinalMonth;
5316     } cases[] = {
5317         { "gregorian", 2021, 0, 11 },
5318         { "gregorian", 2022, 0, 11 },
5319         { "gregorian", 2023, 0, 11 },
5320         { "japanese", 2021, 0, 11 },
5321         { "japanese", 2022, 0, 11 },
5322         { "japanese", 2023, 0, 11 },
5323         { "buddhist", 2021, 0, 11 },
5324         { "buddhist", 2022, 0, 11 },
5325         { "buddhist", 2023, 0, 11 },
5326         { "roc", 2021, 0, 11 },
5327         { "roc", 2022, 0, 11 },
5328         { "roc", 2023, 0, 11 },
5329         { "persian", 1400, 0, 11 },
5330         { "persian", 1401, 0, 11 },
5331         { "persian", 1402, 0, 11 },
5332         { "hebrew", 5782, 0, 12 },
5333         { "hebrew", 5783, 0, 11 },
5334         { "hebrew", 5789, 0, 11 },
5335         { "hebrew", 5790, 0, 12 },
5336         { "chinese", 4645, 0, 11 },
5337         { "chinese", 4646, 0, 12 },
5338         { "chinese", 4647, 0, 11 },
5339         { "dangi", 4645 + 304, 0, 11 },
5340         { "dangi", 4646 + 304, 0, 12 },
5341         { "dangi", 4647 + 304, 0, 11 },
5342         { "indian", 1944, 0, 11 },
5343         { "indian", 1945, 0, 11 },
5344         { "indian", 1946, 0, 11 },
5345         { "coptic", 1737, 0, 12 },
5346         { "coptic", 1738, 0, 12 },
5347         { "coptic", 1739, 0, 12 },
5348         { "ethiopic", 2013, 0, 12 },
5349         { "ethiopic", 2014, 0, 12 },
5350         { "ethiopic", 2015, 0, 12 },
5351         { "ethiopic-amete-alem", 2014, 0, 12 },
5352         { "ethiopic-amete-alem", 2015, 0, 12 },
5353         { "ethiopic-amete-alem", 2016, 0, 12 },
5354         { "iso8601", 2022, 0, 11 },
5355         { "islamic-civil", 1443, 0, 11 },
5356         { "islamic-civil", 1444, 0, 11 },
5357         { "islamic-civil", 1445, 0, 11 },
5358         { "islamic", 1443, 0, 11 },
5359         { "islamic", 1444, 0, 11 },
5360         { "islamic", 1445, 0, 11 },
5361         { "islamic-umalqura", 1443, 0, 11 },
5362         { "islamic-umalqura", 1444, 0, 11 },
5363         { "islamic-umalqura", 1445, 0, 11 },
5364         { "islamic-tbla", 1443, 0, 11 },
5365         { "islamic-tbla", 1444, 0, 11 },
5366         { "islamic-tbla", 1445, 0, 11 },
5367         { "islamic-rgsa", 1443, 0, 11 },
5368         { "islamic-rgsa", 1444, 0, 11 },
5369         { "islamic-rgsa", 1445, 0, 11 },
5370     };
5371 
5372     for (auto& cas : cases) {
5373         l.setKeywordValue("calendar", cas.calendar, status);
5374         LocalPointer<Calendar> cc1(Calendar::createInstance(l, status));
5375         if (failure(status, "Construct Calendar")) return;
5376         cc1->set(UCAL_EXTENDED_YEAR, cas.extended_year);
5377         cc1->set(UCAL_ORDINAL_MONTH, 0);
5378         cc1->set(UCAL_DATE, 1);
5379         assertEquals("getActualMinimum(UCAL_ORDINAL_MONTH)",
5380                      cas.actualMinOrdinalMonth, cc1->getActualMinimum(UCAL_ORDINAL_MONTH, status));
5381         assertEquals("getActualMaximum(UCAL_ORDINAL_MONTH)",
5382                      cas.actualMaxOrdinalMonth, cc1->getActualMaximum(UCAL_ORDINAL_MONTH, status));
5383     }
5384 }
5385 
5386 // The Lunar year which majorty part fall into 1889 and the early part of 1890
5387 // should have no leap months, but currently ICU calculate and show there is
5388 // a Leap month after the 12th month and before the first month of the Chinese
5389 // Calendar which overlapping most of the 1890 year in Gregorian.
5390 //
5391 // We use the value from
5392 // https://ytliu0.github.io/ChineseCalendar/table_period.html?period=qing
5393 // and https://ytliu0.github.io/ChineseCalendar/index_chinese.html
5394 // as the expected value. The same results were given by many several other
5395 // sites not just his one.
5396 //
5397 // There should be a Leap month after the 2nd month of the Chinese Calendar year
5398 // mostly overlapping with 1890 and should have no leap month in the Chinese
5399 // Calendar year mostly overlapping with 1889.
TestChineseCalendarMonthInSpecialYear()5400 void CalendarTest::TestChineseCalendarMonthInSpecialYear() {
5401     UErrorCode status = U_ZERO_ERROR;
5402     GregorianCalendar gc(status);
5403     ChineseCalendar cal(Locale::getRoot(), status);
5404     if (failure(status, "Constructor failed")) return;
5405     struct TestCase {
5406       int32_t gyear;
5407       int32_t gmonth;
5408       int32_t gdate;
5409       int32_t cmonth; // 0-based month number: 1st month = 0, 2nd month = 1.
5410       int32_t cdate;
5411       bool cleapmonth;
5412     } cases[] = {
5413         // Gregorian             Chinese Calendar
5414         // First some recent date
5415         // From https://www.hko.gov.hk/tc/gts/time/calendar/pdf/files/2022.pdf
5416         { 2022, UCAL_DECEMBER, 15, 11-1, 22, false},
5417         //                          ^-- m-1 to convert to 0-based month from 1-based.
5418         // From https://www.hko.gov.hk/tc/gts/time/calendar/pdf/files/2023.pdf
5419         { 2023, UCAL_MARCH, 21, 2-1, 30, false},
5420         { 2023, UCAL_MARCH, 22, 2-1, 1, true},
5421         // We know there are some problematic year, especially those involved
5422         // the rare cases of M11L and M12L.
5423         // Check 1890 and 2033.
5424         //
5425         // 2033 has M11L
5426         // From https://www.hko.gov.hk/tc/gts/time/calendar/pdf/files/2033.pdf
5427         { 2033, UCAL_DECEMBER, 21, 11-1, 30, false},
5428         { 2033, UCAL_DECEMBER, 22, 11-1, 1, true},
5429         // Here are the date we get from multiple external sources
5430         // https://ytliu0.github.io/ChineseCalendar/index_chinese.html
5431         // https://ytliu0.github.io/ChineseCalendar/table_period.html?period=qing
5432         // There should have no leap 12th month in the year mostly overlapping
5433         // 1889 but should have a leap 2th month in the year mostly overlapping
5434         // with 1890.
5435         { 1890, UCAL_JANUARY, 1, 12-1, 11, false},
5436         { 1890, UCAL_JANUARY, 20, 12-1, 30, false},
5437         { 1890, UCAL_JANUARY, 21, 1-1, 1, false},
5438         { 1890, UCAL_FEBRUARY, 1, 1-1, 12, false},
5439         { 1890, UCAL_FEBRUARY, 19, 2-1, 1, false},
5440         { 1890, UCAL_MARCH, 1, 2-1, 11, false},
5441         { 1890, UCAL_MARCH, 21, 2-1, 1, true},
5442         { 1890, UCAL_APRIL, 1, 2-1, 12, true},
5443         { 1890, UCAL_APRIL, 18, 2-1, 29, true},
5444         { 1890, UCAL_APRIL, 19, 3-1, 1, false},
5445         { 1890, UCAL_APRIL, 20, 3-1, 2, false},
5446     };
5447     for (auto& cas : cases) {
5448         gc.set(cas.gyear, cas.gmonth, cas.gdate);
5449         cal.setTime(gc.getTime(status), status);
5450         if (failure(status, "getTime/setTime failed")) return;
5451         int32_t actual_month = cal.get(UCAL_MONTH, status);
5452         int32_t actual_date = cal.get(UCAL_DATE, status);
5453         int32_t actual_in_leap_month = cal.get(UCAL_IS_LEAP_MONTH, status);
5454         if (failure(status, "get failed")) return;
5455         if (cas.cmonth != actual_month ||
5456             cas.cdate != actual_date ||
5457             cas.cleapmonth != (actual_in_leap_month != 0)) {
5458             if (cas.gyear == 1890 &&
5459                 logKnownIssue("ICU-22230", "Problem between 1890/1/21 and 1890/4/18")) {
5460                   continue;
5461             }
5462             errln("Fail: Gregorian(%d/%d/%d) should be Chinese %d%s/%d but got %d%s/%d",
5463                   cas.gyear, cas.gmonth+1, cas.gdate,
5464                   cas.cmonth+1, cas.cleapmonth ? "L" : "" , cas.cdate,
5465                   actual_month+1, ((actual_in_leap_month != 0) ? "L" : ""), actual_date );
5466         }
5467     }
5468 }
5469 #endif /* #if !UCONFIG_NO_FORMATTING */
5470 
5471 //eof
5472