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