mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-10 07:39:16 +00:00
ICU-22639 Clone the calendar so we don't mess with the real one.
This commit is contained in:
parent
ca53838b83
commit
c5160765d4
4 changed files with 50 additions and 18 deletions
|
@ -325,8 +325,6 @@ const UFieldResolutionTable* ChineseCalendar::getFieldResolutionTable() const {
|
|||
* @stable ICU 2.8
|
||||
*/
|
||||
int32_t ChineseCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, UBool useMonth) const {
|
||||
ChineseCalendar *nonConstThis = (ChineseCalendar*)this; // cast away const
|
||||
|
||||
// If the month is out of range, adjust it into range, and
|
||||
// modify the extended year value accordingly.
|
||||
if (month < 0 || month > 11) {
|
||||
|
@ -341,32 +339,29 @@ int32_t ChineseCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, U
|
|||
|
||||
int32_t julianDay = newMoon + kEpochStartAsJulianDay;
|
||||
|
||||
// Save fields for later restoration
|
||||
int32_t saveMonth = internalGet(UCAL_MONTH);
|
||||
int32_t saveOrdinalMonth = internalGet(UCAL_ORDINAL_MONTH);
|
||||
int32_t saveIsLeapMonth = internalGet(UCAL_IS_LEAP_MONTH);
|
||||
|
||||
// Ignore IS_LEAP_MONTH field if useMonth is false
|
||||
int32_t isLeapMonth = useMonth ? saveIsLeapMonth : 0;
|
||||
int32_t isLeapMonth = useMonth ? internalGet(UCAL_IS_LEAP_MONTH) : 0;
|
||||
|
||||
// Clone the calendar so we don't mess with the real one.
|
||||
LocalPointer<ChineseCalendar> work(clone());
|
||||
if (work.isNull())
|
||||
return 0;
|
||||
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
nonConstThis->computeGregorianFields(julianDay, status);
|
||||
work->computeGregorianFields(julianDay, status);
|
||||
if (U_FAILURE(status))
|
||||
return 0;
|
||||
|
||||
// This will modify the MONTH and IS_LEAP_MONTH fields (only)
|
||||
nonConstThis->computeChineseFields(newMoon, getGregorianYear(),
|
||||
getGregorianMonth(), false);
|
||||
|
||||
if (month != internalGet(UCAL_MONTH) ||
|
||||
isLeapMonth != internalGet(UCAL_IS_LEAP_MONTH)) {
|
||||
// This will modify the MONTH and IS_LEAP_MONTH fields (only)
|
||||
work->computeChineseFields(newMoon, work->getGregorianYear(),
|
||||
work->getGregorianMonth(), false);
|
||||
|
||||
if (month != work->internalGet(UCAL_MONTH) ||
|
||||
isLeapMonth != work->internalGet(UCAL_IS_LEAP_MONTH)) {
|
||||
newMoon = newMoonNear(newMoon + SYNODIC_GAP, true);
|
||||
julianDay = newMoon + kEpochStartAsJulianDay;
|
||||
}
|
||||
|
||||
nonConstThis->internalSet(UCAL_MONTH, saveMonth);
|
||||
nonConstThis->internalSet(UCAL_ORDINAL_MONTH, saveOrdinalMonth);
|
||||
nonConstThis->internalSet(UCAL_IS_LEAP_MONTH, saveIsLeapMonth);
|
||||
return julianDay - 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -325,6 +325,10 @@ class U_I18N_API ChineseCalendar : public Calendar {
|
|||
int32_t internalGetDefaultCenturyStartYear() const;
|
||||
|
||||
ChineseCalendar() = delete; // default constructor not implemented
|
||||
|
||||
#ifdef __CalendarTest__
|
||||
friend void CalendarTest::TestChineseCalendarComputeMonthStart();
|
||||
#endif
|
||||
};
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
|
|
@ -191,6 +191,8 @@ void CalendarTest::runIndexedTest( int32_t index, UBool exec, const char* &name,
|
|||
TESTCASE_AUTO(TestRollWeekOfYear);
|
||||
TESTCASE_AUTO(TestFirstDayOfWeek);
|
||||
|
||||
TESTCASE_AUTO(TestChineseCalendarComputeMonthStart);
|
||||
|
||||
TESTCASE_AUTO_END;
|
||||
}
|
||||
|
||||
|
@ -5628,6 +5630,35 @@ void CalendarTest::TestFirstDayOfWeek() {
|
|||
|
||||
verifyFirstDayOfWeek("zxx", UCAL_MONDAY);
|
||||
}
|
||||
|
||||
void CalendarTest::TestChineseCalendarComputeMonthStart() { // ICU-22639
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
|
||||
// An extended year for which hasLeapMonthBetweenWinterSolstices is true.
|
||||
constexpr int32_t eyear = 4643;
|
||||
constexpr int32_t monthStart = 2453764;
|
||||
|
||||
LocalPointer<Calendar> calendar(
|
||||
Calendar::createInstance(Locale("en_US@calendar=chinese"), status),
|
||||
status);
|
||||
if (failure(status, "Calendar::createInstance")) return;
|
||||
|
||||
// This test case is a friend of ChineseCalendar and may access internals.
|
||||
const ChineseCalendar& chinese =
|
||||
*dynamic_cast<ChineseCalendar*>(calendar.getAlias());
|
||||
|
||||
// The initial value of hasLeapMonthBetweenWinterSolstices should be false.
|
||||
assertFalse("hasLeapMonthBetweenWinterSolstices [#1]",
|
||||
chinese.hasLeapMonthBetweenWinterSolstices);
|
||||
|
||||
assertEquals("monthStart", monthStart,
|
||||
chinese.handleComputeMonthStart(eyear, 0, false));
|
||||
|
||||
// Calling a const method must not haved changed the state of the object.
|
||||
assertFalse("hasLeapMonthBetweenWinterSolstices [#2]",
|
||||
chinese.hasLeapMonthBetweenWinterSolstices);
|
||||
}
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||
|
||||
//eof
|
||||
|
|
|
@ -337,6 +337,8 @@ public: // package
|
|||
void verifyFirstDayOfWeek(const char* locale, UCalendarDaysOfWeek expected);
|
||||
void TestFirstDayOfWeek();
|
||||
|
||||
void TestChineseCalendarComputeMonthStart();
|
||||
|
||||
void RunChineseCalendarInTemporalLeapYearTest(Calendar* cal);
|
||||
void RunIslamicCalendarInTemporalLeapYearTest(Calendar* cal);
|
||||
void Run366DaysIsLeapYearCalendarInTemporalLeapYearTest(Calendar* cal);
|
||||
|
|
Loading…
Add table
Reference in a new issue