From 7a3dfe877d9b39c025920fe457639496ac431ca1 Mon Sep 17 00:00:00 2001 From: Frank Tang Date: Mon, 18 Mar 2024 00:02:16 -0700 Subject: [PATCH] ICU-22679 Remove getType and string comparsion Change the logic of handling year in era 0 counting backwards to depend on a boolean virtual function instead of adding string comparsion code in the base class to have specific knowledge of behavior of subclass. --- icu4c/source/i18n/buddhcal.h | 2 ++ icu4c/source/i18n/calendar.cpp | 29 +++++++------------ icu4c/source/i18n/coptccal.h | 2 +- icu4c/source/i18n/iso8601cal.h | 2 ++ icu4c/source/i18n/japancal.h | 2 ++ icu4c/source/i18n/unicode/calendar.h | 7 +++++ icu4c/source/i18n/unicode/gregocal.h | 9 ++++++ .../com/ibm/icu/util/BuddhistCalendar.java | 11 +++++++ .../main/java/com/ibm/icu/util/Calendar.java | 29 ++++++++++--------- .../java/com/ibm/icu/util/CopticCalendar.java | 11 +++++++ .../com/ibm/icu/util/GregorianCalendar.java | 11 +++++++ .../com/ibm/icu/util/JapaneseCalendar.java | 10 +++++++ 12 files changed, 92 insertions(+), 33 deletions(-) diff --git a/icu4c/source/i18n/buddhcal.h b/icu4c/source/i18n/buddhcal.h index a92c9bb0fc8..a78ac633343 100644 --- a/icu4c/source/i18n/buddhcal.h +++ b/icu4c/source/i18n/buddhcal.h @@ -177,6 +177,8 @@ private: * @internal */ virtual int32_t defaultCenturyStartYear() const override; + + virtual bool isEra0CountingBackward() const override { return false; } }; U_NAMESPACE_END diff --git a/icu4c/source/i18n/calendar.cpp b/icu4c/source/i18n/calendar.cpp index 640f3dd8731..8d5246966e2 100644 --- a/icu4c/source/i18n/calendar.cpp +++ b/icu4c/source/i18n/calendar.cpp @@ -1826,16 +1826,11 @@ void Calendar::roll(UCalendarDateFields field, int32_t amount, UErrorCode& statu // * If era==0 and years go backwards in time, change sign of amount. // * Until we have new API per #9393, we temporarily hardcode knowledge of // which calendars have era 0 years that go backwards. - UBool era0WithYearsThatGoBackwards = false; - int32_t era = get(UCAL_ERA, status); - if (era == 0) { - const char * calType = getType(); - if ( uprv_strcmp(calType,"gregorian")==0 || uprv_strcmp(calType,"roc")==0 || uprv_strcmp(calType,"coptic")==0 ) { - if (uprv_mul32_overflow(amount, -1, &amount)) { - status = U_ILLEGAL_ARGUMENT_ERROR; - return; - } - era0WithYearsThatGoBackwards = true; + int32_t era = internalGet(UCAL_ERA); + if (era == 0 && isEra0CountingBackward()) { + if (uprv_mul32_overflow(amount, -1, &amount)) { + status = U_ILLEGAL_ARGUMENT_ERROR; + return; } } int32_t newYear; @@ -1860,7 +1855,7 @@ void Calendar::roll(UCalendarDateFields field, int32_t amount, UErrorCode& statu // else we are in era 0 with newYear < 1; // calendars with years that go backwards must pin the year value at 0, // other calendars can have years < 0 in era 0 - } else if (era0WithYearsThatGoBackwards) { + } else if (era == 0 && isEra0CountingBackward()) { newYear = 1; } set(field, newYear); @@ -2175,14 +2170,10 @@ void Calendar::add(UCalendarDateFields field, int32_t amount, UErrorCode& status // this by applying the amount to the UCAL_EXTENDED_YEAR field; but since // we would still need to handle UCAL_YEAR_WOY as below, might as well // also handle UCAL_YEAR the same way. - int32_t era = get(UCAL_ERA, status); - if (era == 0) { - const char * calType = getType(); - if ( uprv_strcmp(calType,"gregorian")==0 || uprv_strcmp(calType,"roc")==0 || uprv_strcmp(calType,"coptic")==0 ) { - if (uprv_mul32_overflow(amount, -1, &amount)) { - status = U_ILLEGAL_ARGUMENT_ERROR; - return; - } + if (get(UCAL_ERA, status) == 0 && isEra0CountingBackward()) { + if (uprv_mul32_overflow(amount, -1, &amount)) { + status = U_ILLEGAL_ARGUMENT_ERROR; + return; } } } diff --git a/icu4c/source/i18n/coptccal.h b/icu4c/source/i18n/coptccal.h index aabb4a5f305..377a045168d 100644 --- a/icu4c/source/i18n/coptccal.h +++ b/icu4c/source/i18n/coptccal.h @@ -204,7 +204,7 @@ protected: */ virtual int32_t getJDEpochOffset() const override; - + virtual bool isEra0CountingBackward() const override { return true; } public: /** * Override Calendar Returns a unique class ID POLYMORPHICALLY. Pure virtual diff --git a/icu4c/source/i18n/iso8601cal.h b/icu4c/source/i18n/iso8601cal.h index 688fac3588b..957f12e4f23 100644 --- a/icu4c/source/i18n/iso8601cal.h +++ b/icu4c/source/i18n/iso8601cal.h @@ -90,6 +90,8 @@ class ISO8601Calendar : public GregorianCalendar { */ virtual const char * getType() const override; + protected: + virtual bool isEra0CountingBackward() const override { return false; } private: diff --git a/icu4c/source/i18n/japancal.h b/icu4c/source/i18n/japancal.h index 018df4c6b42..ae48095e091 100644 --- a/icu4c/source/i18n/japancal.h +++ b/icu4c/source/i18n/japancal.h @@ -223,6 +223,8 @@ protected: * @internal */ virtual int32_t getDefaultDayInMonth(int32_t eyear, int32_t month) override; + + virtual bool isEra0CountingBackward() const override { return false; } }; U_NAMESPACE_END diff --git a/icu4c/source/i18n/unicode/calendar.h b/icu4c/source/i18n/unicode/calendar.h index f1f29a1d7aa..22ccf2e6e13 100644 --- a/icu4c/source/i18n/unicode/calendar.h +++ b/icu4c/source/i18n/unicode/calendar.h @@ -1547,6 +1547,13 @@ protected: * @internal */ inline int32_t internalGet(UCalendarDateFields field) const {return fFields[field];} + + /** + * The year in this calendar is counting from 1 backward if the era is 0. + * @return The year in era 0 of this calendar is counting backward from 1. + * @internal + */ + virtual bool isEra0CountingBackward() const { return false; } #endif /* U_HIDE_INTERNAL_API */ /** diff --git a/icu4c/source/i18n/unicode/gregocal.h b/icu4c/source/i18n/unicode/gregocal.h index 4f0a7ec2d9f..df5c987ab03 100644 --- a/icu4c/source/i18n/unicode/gregocal.h +++ b/icu4c/source/i18n/unicode/gregocal.h @@ -619,6 +619,15 @@ public: */ virtual void handleComputeFields(int32_t julianDay, UErrorCode &status) override; +#ifndef U_HIDE_INTERNAL_API + /** + * The year in this calendar is counting from 1 backward if the era is 0. + * @return The year in era 0 of this calendar is counting backward from 1. + * @internal + */ + virtual bool isEra0CountingBackward() const override { return true; } +#endif // U_HIDE_INTERNAL_API + private: /** * Compute the julian day number of the given year. diff --git a/icu4j/main/core/src/main/java/com/ibm/icu/util/BuddhistCalendar.java b/icu4j/main/core/src/main/java/com/ibm/icu/util/BuddhistCalendar.java index 2073860977c..0abeffffb73 100644 --- a/icu4j/main/core/src/main/java/com/ibm/icu/util/BuddhistCalendar.java +++ b/icu4j/main/core/src/main/java/com/ibm/icu/util/BuddhistCalendar.java @@ -244,4 +244,15 @@ public class BuddhistCalendar extends GregorianCalendar { public String getType() { return "buddhist"; } + + /* + * {@inheritDoc} + * @internal + * @deprecated This API is ICU internal only. + */ + @Override + @Deprecated + protected boolean isEra0CountingBackward() { + return false; + } } diff --git a/icu4j/main/core/src/main/java/com/ibm/icu/util/Calendar.java b/icu4j/main/core/src/main/java/com/ibm/icu/util/Calendar.java index fd53ab5c081..1ab0f72dfbd 100644 --- a/icu4j/main/core/src/main/java/com/ibm/icu/util/Calendar.java +++ b/icu4j/main/core/src/main/java/com/ibm/icu/util/Calendar.java @@ -3072,14 +3072,9 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable 0 || newYear >= 1) { @@ -3098,7 +3093,7 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable