ICU-22633 Return error if era is out of range

This commit is contained in:
Frank Tang 2024-02-21 16:33:41 -08:00 committed by Frank Yung-Fong Tang
parent 314f03eeaf
commit ec800e7407
26 changed files with 113 additions and 34 deletions

View file

@ -63,8 +63,11 @@ const char *BuddhistCalendar::getType() const
return "buddhist";
}
int32_t BuddhistCalendar::handleGetExtendedYear()
int32_t BuddhistCalendar::handleGetExtendedYear(UErrorCode& status)
{
if (U_FAILURE(status)) {
return 0;
}
// EXTENDED_YEAR in BuddhistCalendar is a Gregorian year.
// The default value of EXTENDED_YEAR is 1970 (Buddhist 2513)
int32_t year;

View file

@ -139,10 +139,11 @@ private:
* use the UCAL_EXTENDED_YEAR field or the UCAL_YEAR and supra-year fields (such
* as UCAL_ERA) specific to the calendar system, depending on which set of
* fields is newer.
* @param status
* @return the extended year
* @internal
*/
virtual int32_t handleGetExtendedYear() override;
virtual int32_t handleGetExtendedYear(UErrorCode& status) override;
/**
* Subclasses may override this method to compute several fields
* specific to each calendar system.

View file

@ -2929,11 +2929,17 @@ void Calendar::validateField(UCalendarDateFields field, UErrorCode &status) {
int32_t y;
switch (field) {
case UCAL_DAY_OF_MONTH:
y = handleGetExtendedYear();
y = handleGetExtendedYear(status);
if (U_FAILURE(status)) {
return;
}
validateField(field, 1, handleGetMonthLength(y, internalGetMonth()), status);
break;
case UCAL_DAY_OF_YEAR:
y = handleGetExtendedYear();
y = handleGetExtendedYear(status);
if (U_FAILURE(status)) {
return;
}
validateField(field, 1, handleGetYearLength(y), status);
break;
case UCAL_DAY_OF_WEEK_IN_MONTH:
@ -3387,7 +3393,10 @@ int32_t Calendar::handleComputeJulianDay(UCalendarDateFields bestField, UErrorCo
if (bestField == UCAL_WEEK_OF_YEAR && newerField(UCAL_YEAR_WOY, UCAL_YEAR) == UCAL_YEAR_WOY) {
year = internalGet(UCAL_YEAR_WOY);
} else {
year = handleGetExtendedYear();
year = handleGetExtendedYear(status);
if (U_FAILURE(status)) {
return 0;
}
}
internalSet(UCAL_EXTENDED_YEAR, year);

View file

@ -222,7 +222,11 @@ int32_t ChineseCalendar::handleGetLimit(UCalendarDateFields field, ELimitType li
* field as the continuous year count, depending on which is newer.
* @stable ICU 2.8
*/
int32_t ChineseCalendar::handleGetExtendedYear() {
int32_t ChineseCalendar::handleGetExtendedYear(UErrorCode& status) {
if (U_FAILURE(status)) {
return 0;
}
int32_t year;
if (newestStamp(UCAL_ERA, UCAL_YEAR, kUnset) <= fStamp[UCAL_EXTENDED_YEAR]) {
year = internalGet(UCAL_EXTENDED_YEAR, 1); // Default to year 1

View file

@ -209,7 +209,7 @@ class U_I18N_API ChineseCalendar : public Calendar {
virtual int32_t handleGetLimit(UCalendarDateFields field, ELimitType limitType) const override;
virtual int32_t handleGetMonthLength(int32_t extendedYear, int32_t month) const override;
virtual int64_t handleComputeMonthStart(int32_t eyear, int32_t month, UBool useMonth) const override;
virtual int32_t handleGetExtendedYear() override;
virtual int32_t handleGetExtendedYear(UErrorCode& status) override;
virtual void handleComputeFields(int32_t julianDay, UErrorCode &status) override;
virtual const UFieldResolutionTable* getFieldResolutionTable() const override;

View file

@ -57,8 +57,11 @@ CopticCalendar::getType() const
//-------------------------------------------------------------------------
int32_t
CopticCalendar::handleGetExtendedYear()
CopticCalendar::handleGetExtendedYear(UErrorCode& status)
{
if (U_FAILURE(status)) {
return 0;
}
int32_t eyear;
if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR) {
eyear = internalGet(UCAL_EXTENDED_YEAR, 1); // Default to year 1
@ -67,8 +70,11 @@ CopticCalendar::handleGetExtendedYear()
int32_t era = internalGet(UCAL_ERA, CE);
if (era == BCE) {
eyear = 1 - internalGet(UCAL_YEAR, 1); // Convert to extended year
} else {
} else if (era == CE){
eyear = internalGet(UCAL_YEAR, 1); // Default to year 1
} else {
status = U_ILLEGAL_ARGUMENT_ERROR;
return 0;
}
}
return eyear;

View file

@ -177,7 +177,7 @@ protected:
* Return the extended year defined by the current fields.
* @internal
*/
virtual int32_t handleGetExtendedYear() override;
virtual int32_t handleGetExtendedYear(UErrorCode& status) override;
/**
* Compute fields from the JD

View file

@ -56,8 +56,11 @@ EthiopicCalendar::getType() const
//-------------------------------------------------------------------------
int32_t
EthiopicCalendar::handleGetExtendedYear()
EthiopicCalendar::handleGetExtendedYear(UErrorCode& status)
{
if (U_FAILURE(status)) {
return 0;
}
// Ethiopic calendar uses EXTENDED_YEAR aligned to
// Amelete Hihret year always.
if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR) {
@ -181,8 +184,11 @@ EthiopicAmeteAlemCalendar::getType() const
}
int32_t
EthiopicAmeteAlemCalendar::handleGetExtendedYear()
EthiopicAmeteAlemCalendar::handleGetExtendedYear(UErrorCode& status)
{
if (U_FAILURE(status)) {
return 0;
}
// Ethiopic calendar uses EXTENDED_YEAR aligned to
// Amelete Hihret year always.
if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR) {

View file

@ -169,7 +169,7 @@ protected:
* 1 AMETE_MIHRET 1
* @internal
*/
virtual int32_t handleGetExtendedYear() override;
virtual int32_t handleGetExtendedYear(UErrorCode& status) override;
/**
* Compute fields from the JD
@ -341,7 +341,7 @@ protected:
* 1 AMETE_ALEM 5501
* @internal
*/
virtual int32_t handleGetExtendedYear() override;
virtual int32_t handleGetExtendedYear(UErrorCode& status) override;
/**
* Compute fields from the JD

View file

@ -1158,7 +1158,10 @@ int32_t GregorianCalendar::getActualMaximum(UCalendarDateFields field, UErrorCod
}
int32_t GregorianCalendar::handleGetExtendedYear() {
int32_t GregorianCalendar::handleGetExtendedYear(UErrorCode& status) {
if (U_FAILURE(status)) {
return 0;
}
// the year to return
int32_t year = kEpochYear;
@ -1184,8 +1187,11 @@ int32_t GregorianCalendar::handleGetExtendedYear() {
int32_t era = internalGet(UCAL_ERA, AD);
if (era == BC) {
year = 1 - internalGet(UCAL_YEAR, 1); // Convert to extended year
} else {
} else if (era == AD) {
year = internalGet(UCAL_YEAR, kEpochYear);
} else {
status = U_ILLEGAL_ARGUMENT_ERROR;
return 0;
}
}
break;

View file

@ -546,7 +546,10 @@ int32_t HebrewCalendar::handleGetYearLength(int32_t eyear) const {
void HebrewCalendar::validateField(UCalendarDateFields field, UErrorCode &status) {
if ((field == UCAL_MONTH || field == UCAL_ORDINAL_MONTH)
&& !isLeapYear(handleGetExtendedYear()) && internalGetMonth() == ADAR_1) {
&& !isLeapYear(handleGetExtendedYear(status)) && internalGetMonth() == ADAR_1) {
if (U_FAILURE(status)) {
return;
}
status = U_ILLEGAL_ARGUMENT_ERROR;
return;
}
@ -636,7 +639,10 @@ void HebrewCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status)
/**
* @internal
*/
int32_t HebrewCalendar::handleGetExtendedYear() {
int32_t HebrewCalendar::handleGetExtendedYear(UErrorCode& status ) {
if (U_FAILURE(status)) {
return 0;
}
int32_t year;
if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR) {
year = internalGet(UCAL_EXTENDED_YEAR, 1); // Default to year 1
@ -783,7 +789,9 @@ int32_t HebrewCalendar::internalGetMonth() const {
int32_t ordinalMonth = internalGet(UCAL_ORDINAL_MONTH);
HebrewCalendar *nonConstThis = (HebrewCalendar*)this; // cast away const
int32_t year = nonConstThis->handleGetExtendedYear();
UErrorCode status = U_ZERO_ERROR;
int32_t year = nonConstThis->handleGetExtendedYear(status);
U_ASSERT(U_SUCCESS(status));
return ordinalMonth + (((!isLeapYear(year)) && (ordinalMonth > ADAR_1)) ? 1: 0);
}
return Calendar::internalGetMonth();

View file

@ -350,10 +350,11 @@ public:
* use the UCAL_EXTENDED_YEAR field or the UCAL_YEAR and supra-year fields (such
* as UCAL_ERA) specific to the calendar system, depending on which set of
* fields is newer.
* @param status
* @return the extended year
* @internal
*/
virtual int32_t handleGetExtendedYear() override;
virtual int32_t handleGetExtendedYear(UErrorCode& status) override;
/**
* Return the Julian day number of day before the first day of the
* given month in the given extended year. Subclasses should override

View file

@ -228,7 +228,10 @@ int64_t IndianCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, UB
// Functions for converting from milliseconds to field values
//-------------------------------------------------------------------------
int32_t IndianCalendar::handleGetExtendedYear() {
int32_t IndianCalendar::handleGetExtendedYear(UErrorCode& status) {
if (U_FAILURE(status)) {
return 0;
}
int32_t year;
if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR) {

View file

@ -234,7 +234,7 @@ public:
/**
* @internal
*/
virtual int32_t handleGetExtendedYear() override;
virtual int32_t handleGetExtendedYear(UErrorCode& status) override;
/**
* Override Calendar to compute several fields specific to the Indian

View file

@ -484,7 +484,10 @@ int64_t IslamicCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, U
/**
* @draft ICU 2.4
*/
int32_t IslamicCalendar::handleGetExtendedYear() {
int32_t IslamicCalendar::handleGetExtendedYear(UErrorCode& status) {
if (U_FAILURE(status)) {
return 0;
}
int32_t year;
if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR) {
year = internalGet(UCAL_EXTENDED_YEAR, 1); // Default to year 1

View file

@ -280,7 +280,7 @@ class U_I18N_API IslamicCalendar : public Calendar {
/**
* @internal
*/
virtual int32_t handleGetExtendedYear() override;
virtual int32_t handleGetExtendedYear(UErrorCode& status) override;
/**
* Override Calendar to compute several fields specific to the Islamic

View file

@ -191,8 +191,11 @@ int32_t JapaneseCalendar::internalGetEra() const
return internalGet(UCAL_ERA, gCurrentEra);
}
int32_t JapaneseCalendar::handleGetExtendedYear()
int32_t JapaneseCalendar::handleGetExtendedYear(UErrorCode& status)
{
if (U_FAILURE(status)) {
return 0;
}
// EXTENDED_YEAR in JapaneseCalendar is a Gregorian year
// The default value of EXTENDED_YEAR is 1970 (Showa 45)
int32_t year;
@ -201,9 +204,10 @@ int32_t JapaneseCalendar::handleGetExtendedYear()
newerField(UCAL_EXTENDED_YEAR, UCAL_ERA) == UCAL_EXTENDED_YEAR) {
year = internalGet(UCAL_EXTENDED_YEAR, kGregorianEpoch);
} else {
UErrorCode status = U_ZERO_ERROR;
int32_t eraStartYear = gJapaneseEraRules->getStartYear(internalGet(UCAL_ERA, gCurrentEra), status);
U_ASSERT(U_SUCCESS(status));
if (U_FAILURE(status)) {
return 0;
}
// extended year is a gregorian year, where 1 = 1AD, 0 = 1BC, -1 = 2BC, etc
year = internalGet(UCAL_YEAR, 1) // pin to minimum of year 1 (first year)

View file

@ -123,7 +123,7 @@ public:
* Japanese calendar case, this is equal to the equivalent extended Gregorian year.
* @internal
*/
virtual int32_t handleGetExtendedYear() override;
virtual int32_t handleGetExtendedYear(UErrorCode& status) override;
/**
* Return the maximum value that this field could have, given the current date.

View file

@ -187,7 +187,10 @@ int64_t PersianCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, U
// Functions for converting from milliseconds to field values
//-------------------------------------------------------------------------
int32_t PersianCalendar::handleGetExtendedYear() {
int32_t PersianCalendar::handleGetExtendedYear(UErrorCode& status) {
if (U_FAILURE(status)) {
return 0;
}
int32_t year;
if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR) {
year = internalGet(UCAL_EXTENDED_YEAR, 1); // Default to year 1

View file

@ -228,7 +228,7 @@ class PersianCalendar : public Calendar {
/**
* @internal
*/
virtual int32_t handleGetExtendedYear() override;
virtual int32_t handleGetExtendedYear(UErrorCode& status) override;
/**
* Override Calendar to compute several fields specific to the Persian

View file

@ -63,8 +63,12 @@ const char *TaiwanCalendar::getType() const
return "roc";
}
int32_t TaiwanCalendar::handleGetExtendedYear()
int32_t TaiwanCalendar::handleGetExtendedYear(UErrorCode& status)
{
if (U_FAILURE(status)) {
return 0;
}
// EXTENDED_YEAR in TaiwanCalendar is a Gregorian year
// The default value of EXTENDED_YEAR is 1970 (Minguo 59)
int32_t year = kGregorianEpoch;
@ -78,6 +82,9 @@ int32_t TaiwanCalendar::handleGetExtendedYear()
year = internalGet(UCAL_YEAR, 1) + kTaiwanEraStart;
} else if(era == BEFORE_MINGUO) {
year = 1 - internalGet(UCAL_YEAR, 1) + kTaiwanEraStart;
} else {
status = U_ILLEGAL_ARGUMENT_ERROR;
return 0;
}
}
return year;

View file

@ -139,7 +139,7 @@ private:
* @return the extended year
* @internal
*/
virtual int32_t handleGetExtendedYear() override;
virtual int32_t handleGetExtendedYear(UErrorCode& status) override;
/**
* Subclasses may override this method to compute several fields
* specific to each calendar system.

View file

@ -1694,10 +1694,11 @@ protected:
* use the UCAL_EXTENDED_YEAR field or the UCAL_YEAR and supra-year fields (such
* as UCAL_ERA) specific to the calendar system, depending on which set of
* fields is newer.
* @param status ICU Error Code
* @return the extended year
* @internal
*/
virtual int32_t handleGetExtendedYear() = 0;
virtual int32_t handleGetExtendedYear(UErrorCode& status) = 0;
/**
* Subclasses may override this. This method calls

View file

@ -583,10 +583,11 @@ public:
* use the UCAL_EXTENDED_YEAR field or the UCAL_YEAR and supra-year fields (such
* as UCAL_ERA) specific to the calendar system, depending on which set of
* fields is newer.
* @param status
* @return the extended year
* @internal
*/
virtual int32_t handleGetExtendedYear() override;
virtual int32_t handleGetExtendedYear(UErrorCode& status) override;
/**
* Subclasses may override this to convert from week fields

View file

@ -106,6 +106,7 @@ void IntlCalendarTest::runIndexedTest( int32_t index, UBool exec, const char* &n
TESTCASE_AUTO(TestConsistencyPersian);
TESTCASE_AUTO(TestConsistencyJapanese);
TESTCASE_AUTO(TestIslamicUmalquraCalendarSlow);
TESTCASE_AUTO(TestJapaneseLargeEra);
TESTCASE_AUTO_END;
}
@ -1135,6 +1136,17 @@ void IntlCalendarTest::TestIslamicUmalquraCalendarSlow() {
status.reset();
}
void IntlCalendarTest::TestJapaneseLargeEra() {
IcuTestErrorCode status(*this, "TestJapaneseLargeEra");
Locale l("ja@calendar=japanese");
std::unique_ptr<Calendar> cal(
Calendar::createInstance(l, status));
cal->clear();
cal->set(UCAL_ERA, 2139062143);
cal->add(UCAL_YEAR, 1229539657, status);
status.expectErrorAndReset(U_ILLEGAL_ARGUMENT_ERROR);
}
void IntlCalendarTest::simpleTest(const Locale& loc, const UnicodeString& expect, UDate expectDate, UErrorCode& status)
{
UnicodeString tmp;

View file

@ -61,6 +61,7 @@ public:
void TestConsistencyPersian();
void TestConsistencyJapanese();
void TestIslamicUmalquraCalendarSlow();
void TestJapaneseLargeEra();
protected:
// Test a Gregorian-Like calendar