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