ICU-10752 Spread (s|g)etRelativeYear to subclass

Remove the switch statment implementaiton in
Calendar::(g|s)etRelatedYear
and move the code into each subclass as proper OOP style.
This commit is contained in:
Frank Tang 2022-09-21 21:11:38 -07:00 committed by Frank Yung-Fong Tang
parent b00562e989
commit b0ab1171ad
17 changed files with 283 additions and 117 deletions

View file

@ -1267,130 +1267,14 @@ Calendar::set(int32_t year, int32_t month, int32_t date, int32_t hour, int32_t m
}
// -------------------------------------
// For now the full getRelatedYear implementation is here;
// per #10752 move the non-default implementation to subclasses
// (default implementation will do no year adjustment)
static int32_t gregoYearFromIslamicStart(int32_t year) {
// ad hoc conversion, improve under #10752
// rough est for now, ok for grego 1846-2138,
// otherwise occasionally wrong (for 3% of years)
int cycle, offset, shift = 0;
if (year >= 1397) {
cycle = (year - 1397) / 67;
offset = (year - 1397) % 67;
shift = 2*cycle + ((offset >= 33)? 1: 0);
} else {
cycle = (year - 1396) / 67 - 1;
offset = -(year - 1396) % 67;
shift = 2*cycle + ((offset <= 33)? 1: 0);
}
return year + 579 - shift;
}
int32_t Calendar::getRelatedYear(UErrorCode &status) const
{
if (U_FAILURE(status)) {
return 0;
}
int32_t year = get(UCAL_EXTENDED_YEAR, status);
if (U_FAILURE(status)) {
return 0;
}
// modify for calendar type
ECalType type = getCalendarType(getType());
switch (type) {
case CALTYPE_PERSIAN:
year += 622; break;
case CALTYPE_HEBREW:
year -= 3760; break;
case CALTYPE_CHINESE:
year -= 2637; break;
case CALTYPE_INDIAN:
year += 79; break;
case CALTYPE_COPTIC:
year += 284; break;
case CALTYPE_ETHIOPIC:
year += 8; break;
case CALTYPE_ETHIOPIC_AMETE_ALEM:
year -=5492; break;
case CALTYPE_DANGI:
year -= 2333; break;
case CALTYPE_ISLAMIC_CIVIL:
case CALTYPE_ISLAMIC:
case CALTYPE_ISLAMIC_UMALQURA:
case CALTYPE_ISLAMIC_TBLA:
case CALTYPE_ISLAMIC_RGSA:
year = gregoYearFromIslamicStart(year); break;
default:
// CALTYPE_GREGORIAN
// CALTYPE_JAPANESE
// CALTYPE_BUDDHIST
// CALTYPE_ROC
// CALTYPE_ISO8601
// do nothing, EXTENDED_YEAR same as Gregorian
break;
}
return year;
return get(UCAL_EXTENDED_YEAR, status);
}
// -------------------------------------
// For now the full setRelatedYear implementation is here;
// per #10752 move the non-default implementation to subclasses
// (default implementation will do no year adjustment)
static int32_t firstIslamicStartYearFromGrego(int32_t year) {
// ad hoc conversion, improve under #10752
// rough est for now, ok for grego 1846-2138,
// otherwise occasionally wrong (for 3% of years)
int cycle, offset, shift = 0;
if (year >= 1977) {
cycle = (year - 1977) / 65;
offset = (year - 1977) % 65;
shift = 2*cycle + ((offset >= 32)? 1: 0);
} else {
cycle = (year - 1976) / 65 - 1;
offset = -(year - 1976) % 65;
shift = 2*cycle + ((offset <= 32)? 1: 0);
}
return year - 579 + shift;
}
void Calendar::setRelatedYear(int32_t year)
{
// modify for calendar type
ECalType type = getCalendarType(getType());
switch (type) {
case CALTYPE_PERSIAN:
year -= 622; break;
case CALTYPE_HEBREW:
year += 3760; break;
case CALTYPE_CHINESE:
year += 2637; break;
case CALTYPE_INDIAN:
year -= 79; break;
case CALTYPE_COPTIC:
year -= 284; break;
case CALTYPE_ETHIOPIC:
year -= 8; break;
case CALTYPE_ETHIOPIC_AMETE_ALEM:
year +=5492; break;
case CALTYPE_DANGI:
year += 2333; break;
case CALTYPE_ISLAMIC_CIVIL:
case CALTYPE_ISLAMIC:
case CALTYPE_ISLAMIC_UMALQURA:
case CALTYPE_ISLAMIC_TBLA:
case CALTYPE_ISLAMIC_RGSA:
year = firstIslamicStartYearFromGrego(year); break;
default:
// CALTYPE_GREGORIAN
// CALTYPE_JAPANESE
// CALTYPE_BUDDHIST
// CALTYPE_ROC
// CALTYPE_ISO8601
// do nothing, EXTENDED_YEAR same as Gregorian
break;
}
// set extended year
set(UCAL_EXTENDED_YEAR, year);
}

View file

@ -825,6 +825,22 @@ void ChineseCalendar::offsetMonth(int32_t newMoon, int32_t dom, int32_t delta) {
}
}
constexpr uint32_t kChineseRelatedYearDiff = -2637;
int32_t ChineseCalendar::getRelatedYear(UErrorCode &status) const
{
int32_t year = get(UCAL_EXTENDED_YEAR, status);
if (U_FAILURE(status)) {
return 0;
}
return year + kChineseRelatedYearDiff;
}
void ChineseCalendar::setRelatedYear(int32_t year)
{
// set extended year
set(UCAL_EXTENDED_YEAR, year - kChineseRelatedYearDiff);
}
// default century

View file

@ -175,6 +175,20 @@ class U_I18N_API ChineseCalendar : public Calendar {
virtual void roll(UCalendarDateFields field, int32_t amount, UErrorCode &status) override;
virtual void roll(EDateFields field, int32_t amount, UErrorCode &status) override;
/**
* @return The related Gregorian year; will be obtained by modifying the value
* obtained by get from UCAL_EXTENDED_YEAR field
* @internal
*/
virtual int32_t getRelatedYear(UErrorCode &status) const override;
/**
* @param year The related Gregorian year to set; will be modified as necessary then
* set in UCAL_EXTENDED_YEAR field
* @internal
*/
virtual void setRelatedYear(int32_t year) override;
//----------------------------------------------------------------------
// Internal methods & astronomical calculations
//----------------------------------------------------------------------

View file

@ -96,6 +96,23 @@ CopticCalendar::handleComputeFields(int32_t julianDay, UErrorCode &/*status*/)
internalSet(UCAL_DAY_OF_YEAR, (30 * month) + day);
}
constexpr uint32_t kCopticRelatedYearDiff = 284;
int32_t CopticCalendar::getRelatedYear(UErrorCode &status) const
{
int32_t year = get(UCAL_EXTENDED_YEAR, status);
if (U_FAILURE(status)) {
return 0;
}
return year + kCopticRelatedYearDiff;
}
void CopticCalendar::setRelatedYear(int32_t year)
{
// set extended year
set(UCAL_EXTENDED_YEAR, year - kCopticRelatedYearDiff);
}
/**
* The system maintains a static default century start date and Year. They are
* initialized the first time they are used. Once the system default century date

View file

@ -154,6 +154,20 @@ public:
*/
const char * getType() const override;
/**
* @return The related Gregorian year; will be obtained by modifying the value
* obtained by get from UCAL_EXTENDED_YEAR field
* @internal
*/
virtual int32_t getRelatedYear(UErrorCode &status) const override;
/**
* @param year The related Gregorian year to set; will be modified as necessary then
* set in UCAL_EXTENDED_YEAR field
* @internal
*/
virtual void setRelatedYear(int32_t year) override;
protected:
//-------------------------------------------------------------------------
// Calendar framework

View file

@ -141,6 +141,23 @@ const TimeZone* DangiCalendar::getDangiCalZoneAstroCalc(UErrorCode &status) cons
return gDangiCalendarZoneAstroCalc;
}
constexpr uint32_t kDangiRelatedYearDiff = -2333;
int32_t DangiCalendar::getRelatedYear(UErrorCode &status) const
{
int32_t year = get(UCAL_EXTENDED_YEAR, status);
if (U_FAILURE(status)) {
return 0;
}
return year + kDangiRelatedYearDiff;
}
void DangiCalendar::setRelatedYear(int32_t year)
{
// set extended year
set(UCAL_EXTENDED_YEAR, year - kDangiRelatedYearDiff);
}
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DangiCalendar)

View file

@ -72,6 +72,20 @@ class DangiCalendar : public ChineseCalendar {
// Internal methods & astronomical calculations
//----------------------------------------------------------------------
/**
* @return The related Gregorian year; will be obtained by modifying the value
* obtained by get from UCAL_EXTENDED_YEAR field
* @internal
*/
virtual int32_t getRelatedYear(UErrorCode &status) const override;
/**
* @param year The related Gregorian year to set; will be modified as necessary then
* set in UCAL_EXTENDED_YEAR field
* @internal
*/
virtual void setRelatedYear(int32_t year) override;
private:
const TimeZone* getDangiCalZoneAstroCalc(UErrorCode &status) const;

View file

@ -136,6 +136,26 @@ EthiopicCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType
return CECalendar::handleGetLimit(field, limitType);
}
constexpr uint32_t kEthiopicRelatedYearDiff = 8;
constexpr uint32_t kEthiopicAmeteAlemRelatedYearDiff = -5492;
int32_t EthiopicCalendar::getRelatedYear(UErrorCode &status) const
{
int32_t year = get(UCAL_EXTENDED_YEAR, status);
if (U_FAILURE(status)) {
return 0;
}
return year + (isAmeteAlemEra() ? kEthiopicAmeteAlemRelatedYearDiff : kEthiopicRelatedYearDiff);
}
void EthiopicCalendar::setRelatedYear(int32_t year)
{
// set extended year
set(UCAL_EXTENDED_YEAR, year -
(isAmeteAlemEra() ? kEthiopicAmeteAlemRelatedYearDiff : kEthiopicRelatedYearDiff));
}
/**
* The system maintains a static default century start date and Year. They are
* initialized the first time they are used. Once the system default century date

View file

@ -164,6 +164,20 @@ public:
*/
UBool isAmeteAlemEra() const;
/**
* @return The related Gregorian year; will be obtained by modifying the value
* obtained by get from UCAL_EXTENDED_YEAR field
* @internal
*/
virtual int32_t getRelatedYear(UErrorCode &status) const override;
/**
* @param year The related Gregorian year to set; will be modified as necessary then
* set in UCAL_EXTENDED_YEAR field
* @internal
*/
virtual void setRelatedYear(int32_t year) override;
protected:
//-------------------------------------------------------------------------
// Calendar framework

View file

@ -666,6 +666,23 @@ int32_t HebrewCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, UB
return (int) (day + 347997);
}
constexpr uint32_t kHebrewRelatedYearDiff = -3760;
int32_t HebrewCalendar::getRelatedYear(UErrorCode &status) const
{
int32_t year = get(UCAL_EXTENDED_YEAR, status);
if (U_FAILURE(status)) {
return 0;
}
return year + kHebrewRelatedYearDiff;
}
void HebrewCalendar::setRelatedYear(int32_t year)
{
// set extended year
set(UCAL_EXTENDED_YEAR, year - kHebrewRelatedYearDiff);
}
/**
* The system maintains a static default century start date and Year. They are
* initialized the first time they are used. Once the system default century date

View file

@ -273,6 +273,20 @@ public:
*/
static UBool isLeapYear(int32_t year) ;
/**
* @return The related Gregorian year; will be obtained by modifying the value
* obtained by get from UCAL_EXTENDED_YEAR field
* @internal
*/
virtual int32_t getRelatedYear(UErrorCode &status) const override;
/**
* @param year The related Gregorian year to set; will be modified as necessary then
* set in UCAL_EXTENDED_YEAR field
* @internal
*/
virtual void setRelatedYear(int32_t year) override;
protected:
/**

View file

@ -297,6 +297,23 @@ void IndianCalendar::handleComputeFields(int32_t julianDay, UErrorCode& /* stat
internalSet(UCAL_DAY_OF_YEAR, yday + 1); // yday is 0-based
}
constexpr uint32_t kIndianRelatedYearDiff = 79;
int32_t IndianCalendar::getRelatedYear(UErrorCode &status) const
{
int32_t year = get(UCAL_EXTENDED_YEAR, status);
if (U_FAILURE(status)) {
return 0;
}
return year + kIndianRelatedYearDiff;
}
void IndianCalendar::setRelatedYear(int32_t year)
{
// set extended year
set(UCAL_EXTENDED_YEAR, year - kIndianRelatedYearDiff);
}
/**
* The system maintains a static default century start date and Year. They are
* initialized the first time they are used. Once the system default century date

View file

@ -284,6 +284,21 @@ public:
*/
virtual const char * getType() const override;
/**
* @return The related Gregorian year; will be obtained by modifying the value
* obtained by get from UCAL_EXTENDED_YEAR field
* @internal
*/
virtual int32_t getRelatedYear(UErrorCode &status) const override;
/**
* @param year The related Gregorian year to set; will be modified as necessary then
* set in UCAL_EXTENDED_YEAR field
* @internal
*/
virtual void setRelatedYear(int32_t year) override;
private:
IndianCalendar() = delete; // default constructor not implemented

View file

@ -692,6 +692,54 @@ void IslamicCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status)
internalSet(UCAL_DAY_OF_YEAR, dayOfYear);
}
static int32_t gregoYearFromIslamicStart(int32_t year) {
// ad hoc conversion, improve under #10752
// rough est for now, ok for grego 1846-2138,
// otherwise occasionally wrong (for 3% of years)
int cycle, offset, shift = 0;
if (year >= 1397) {
cycle = (year - 1397) / 67;
offset = (year - 1397) % 67;
shift = 2*cycle + ((offset >= 33)? 1: 0);
} else {
cycle = (year - 1396) / 67 - 1;
offset = -(year - 1396) % 67;
shift = 2*cycle + ((offset <= 33)? 1: 0);
}
return year + 579 - shift;
}
int32_t IslamicCalendar::getRelatedYear(UErrorCode &status) const
{
int32_t year = get(UCAL_EXTENDED_YEAR, status);
if (U_FAILURE(status)) {
return 0;
}
return gregoYearFromIslamicStart(year);
}
static int32_t firstIslamicStartYearFromGrego(int32_t year) {
// ad hoc conversion, improve under #10752
// rough est for now, ok for grego 1846-2138,
// otherwise occasionally wrong (for 3% of years)
int cycle, offset, shift = 0;
if (year >= 1977) {
cycle = (year - 1977) / 65;
offset = (year - 1977) % 65;
shift = 2*cycle + ((offset >= 32)? 1: 0);
} else {
cycle = (year - 1976) / 65 - 1;
offset = -(year - 1976) % 65;
shift = 2*cycle + ((offset <= 32)? 1: 0);
}
return year - 579 + shift;
}
void IslamicCalendar::setRelatedYear(int32_t year)
{
set(UCAL_EXTENDED_YEAR, firstIslamicStartYearFromGrego(year));
}
/**
* The system maintains a static default century start date and Year. They are
* initialized the first time they are used. Once the system default century date

View file

@ -376,6 +376,20 @@ class U_I18N_API IslamicCalendar : public Calendar {
*/
virtual const char * getType() const override;
/**
* @return The related Gregorian year; will be obtained by modifying the value
* obtained by get from UCAL_EXTENDED_YEAR field
* @internal
*/
virtual int32_t getRelatedYear(UErrorCode &status) const override;
/**
* @param year The related Gregorian year to set; will be modified as necessary then
* set in UCAL_EXTENDED_YEAR field
* @internal
*/
virtual void setRelatedYear(int32_t year) override;
private:
IslamicCalendar() = delete; // default constructor not implemented

View file

@ -233,6 +233,23 @@ void PersianCalendar::handleComputeFields(int32_t julianDay, UErrorCode &/*statu
internalSet(UCAL_DAY_OF_YEAR, dayOfYear);
}
constexpr uint32_t kPersianRelatedYearDiff = 622;
int32_t PersianCalendar::getRelatedYear(UErrorCode &status) const
{
int32_t year = get(UCAL_EXTENDED_YEAR, status);
if (U_FAILURE(status)) {
return 0;
}
return year + kPersianRelatedYearDiff;
}
void PersianCalendar::setRelatedYear(int32_t year)
{
// set extended year
set(UCAL_EXTENDED_YEAR, year - kPersianRelatedYearDiff);
}
// default century
static UDate gSystemDefaultCenturyStart = DBL_MIN;

View file

@ -278,6 +278,20 @@ class PersianCalendar : public Calendar {
*/
virtual const char * getType() const override;
/**
* @return The related Gregorian year; will be obtained by modifying the value
* obtained by get from UCAL_EXTENDED_YEAR field
* @internal
*/
virtual int32_t getRelatedYear(UErrorCode &status) const override;
/**
* @param year The related Gregorian year to set; will be modified as necessary then
* set in UCAL_EXTENDED_YEAR field
* @internal
*/
virtual void setRelatedYear(int32_t year) override;
private:
PersianCalendar(); // default constructor not implemented