]> granicus.if.org Git - icu/commitdiff
ICU-22164 Replace switch+getType with subclass
authorFrank Tang <ftang@chromium.org>
Thu, 10 Nov 2022 01:22:16 +0000 (01:22 +0000)
committerFrank Yung-Fong Tang <ftang@google.com>
Fri, 11 Nov 2022 22:49:16 +0000 (14:49 -0800)
See #2215

fix

15 files changed:
icu4c/source/i18n/calendar.cpp
icu4c/source/i18n/ethpccal.cpp
icu4c/source/i18n/ethpccal.h
icu4c/source/i18n/i18n.vcxproj
icu4c/source/i18n/i18n.vcxproj.filters
icu4c/source/i18n/i18n_uwp.vcxproj
icu4c/source/i18n/islamcal.cpp
icu4c/source/i18n/islamcal.h
icu4c/source/i18n/iso8601cal.cpp [new file with mode: 0644]
icu4c/source/i18n/iso8601cal.h [new file with mode: 0644]
icu4c/source/i18n/sources.txt
icu4c/source/test/depstest/dependencies.txt
icu4c/source/test/intltest/caltest.cpp
icu4c/source/test/intltest/caltest.h
icu4c/source/test/intltest/dtfmttst.cpp

index f5a40e48395a2cbaddb3384f74acb2fc326d4768..6e2278ba686e7a525a42aaf319fc77bf975903db 100644 (file)
@@ -45,6 +45,7 @@
 #include "hebrwcal.h"
 #include "persncal.h"
 #include "indiancal.h"
+#include "iso8601cal.h"
 #include "chnsecal.h"
 #include "coptccal.h"
 #include "dangical.h"
@@ -354,18 +355,19 @@ static Calendar *createStandardCalendar(ECalType calType, const Locale &loc, UEr
             cal.adoptInsteadAndCheckErrorCode(new PersianCalendar(loc, status), status);
             break;
         case CALTYPE_ISLAMIC_TBLA:
-            cal.adoptInsteadAndCheckErrorCode(new IslamicCalendar(loc, status, IslamicCalendar::TBLA), status);
+            cal.adoptInsteadAndCheckErrorCode(new IslamicTBLACalendar(loc, status), status);
             break;
         case CALTYPE_ISLAMIC_CIVIL:
-            cal.adoptInsteadAndCheckErrorCode(new IslamicCalendar(loc, status, IslamicCalendar::CIVIL), status);
+            cal.adoptInsteadAndCheckErrorCode(new IslamicCivilCalendar(loc, status), status);
             break;
         case CALTYPE_ISLAMIC_RGSA:
-            // default any region specific not handled individually to islamic
+            cal.adoptInsteadAndCheckErrorCode(new IslamicRGSACalendar(loc, status), status);
+            break;
         case CALTYPE_ISLAMIC:
-            cal.adoptInsteadAndCheckErrorCode(new IslamicCalendar(loc, status, IslamicCalendar::ASTRONOMICAL), status);
+            cal.adoptInsteadAndCheckErrorCode(new IslamicCalendar(loc, status), status);
             break;
         case CALTYPE_ISLAMIC_UMALQURA:
-            cal.adoptInsteadAndCheckErrorCode(new IslamicCalendar(loc, status, IslamicCalendar::UMALQURA), status);
+            cal.adoptInsteadAndCheckErrorCode(new IslamicUmalquraCalendar(loc, status), status);
             break;
         case CALTYPE_HEBREW:
             cal.adoptInsteadAndCheckErrorCode(new HebrewCalendar(loc, status), status);
@@ -380,17 +382,13 @@ static Calendar *createStandardCalendar(ECalType calType, const Locale &loc, UEr
             cal.adoptInsteadAndCheckErrorCode(new CopticCalendar(loc, status), status);
             break;
         case CALTYPE_ETHIOPIC:
-            cal.adoptInsteadAndCheckErrorCode(new EthiopicCalendar(loc, status, EthiopicCalendar::AMETE_MIHRET_ERA), status);
+            cal.adoptInsteadAndCheckErrorCode(new EthiopicCalendar(loc, status), status);
             break;
         case CALTYPE_ETHIOPIC_AMETE_ALEM:
-            cal.adoptInsteadAndCheckErrorCode(new EthiopicCalendar(loc, status, EthiopicCalendar::AMETE_ALEM_ERA), status);
+            cal.adoptInsteadAndCheckErrorCode(new EthiopicAmeteAlemCalendar(loc, status), status);
             break;
         case CALTYPE_ISO8601:
-            cal.adoptInsteadAndCheckErrorCode(new GregorianCalendar(loc, status), status);
-            if (cal.isValid()) {
-                cal->setFirstDayOfWeek(UCAL_MONDAY);
-                cal->setMinimalDaysInFirstWeek(4);
-            }
+            cal.adoptInsteadAndCheckErrorCode(new ISO8601Calendar(loc, status), status);
             break;
         case CALTYPE_DANGI:
             cal.adoptInsteadAndCheckErrorCode(new DangiCalendar(loc, status), status);
index 9b97b1ca33caa87316b15b8c4955b3db7f8bbd99..b9ec17b46feefe6a6b273f8c7864a06917c7e6e5 100644 (file)
@@ -19,6 +19,7 @@
 U_NAMESPACE_BEGIN
 
 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(EthiopicCalendar)
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(EthiopicAmeteAlemCalendar)
 
 //static const int32_t JD_EPOCH_OFFSET_AMETE_ALEM = -285019;
 static const int32_t JD_EPOCH_OFFSET_AMETE_MIHRET = 1723856;
@@ -29,16 +30,8 @@ static const int32_t AMETE_MIHRET_DELTA = 5500; // 5501 - 1 (Amete Alem 5501 = A
 //-------------------------------------------------------------------------
 
 EthiopicCalendar::EthiopicCalendar(const Locale& aLocale,
-                                   UErrorCode& success,
-                                   EEraType type /*= AMETE_MIHRET_ERA*/)
-:   CECalendar(aLocale, success),
-    eraType(type)
-{
-}
-
-EthiopicCalendar::EthiopicCalendar(const EthiopicCalendar& other)
-:   CECalendar(other),
-    eraType(other.eraType)
+                                   UErrorCode& success)
+:   CECalendar(aLocale, success)
 {
 }
 
@@ -55,24 +48,9 @@ EthiopicCalendar::clone() const
 const char *
 EthiopicCalendar::getType() const
 {
-    if (isAmeteAlemEra()) {
-        return "ethiopic-amete-alem";
-    }
     return "ethiopic";
 }
 
-void
-EthiopicCalendar::setAmeteAlemEra(UBool onOff)
-{
-    eraType = onOff ? AMETE_ALEM_ERA : AMETE_MIHRET_ERA;
-}
-    
-UBool
-EthiopicCalendar::isAmeteAlemEra() const
-{
-    return (eraType == AMETE_ALEM_ERA);
-}
-
 //-------------------------------------------------------------------------
 // Calendar framework
 //-------------------------------------------------------------------------
@@ -82,63 +60,31 @@ EthiopicCalendar::handleGetExtendedYear()
 {
     // Ethiopic calendar uses EXTENDED_YEAR aligned to
     // Amelete Hihret year always.
-    int32_t eyear;
     if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR) {
-        eyear = internalGet(UCAL_EXTENDED_YEAR, 1); // Default to year 1
-    } else if (isAmeteAlemEra()) {
-        eyear = internalGet(UCAL_YEAR, 1 + AMETE_MIHRET_DELTA)
-            - AMETE_MIHRET_DELTA; // Default to year 1 of Amelete Mihret
-    } else {
-        // The year defaults to the epoch start, the era to AMETE_MIHRET
-        int32_t era = internalGet(UCAL_ERA, AMETE_MIHRET);
-        if (era == AMETE_MIHRET) {
-            eyear = internalGet(UCAL_YEAR, 1); // Default to year 1
-        } else {
-            eyear = internalGet(UCAL_YEAR, 1) - AMETE_MIHRET_DELTA;
-        }
+        return internalGet(UCAL_EXTENDED_YEAR, 1); // Default to year 1
     }
-    return eyear;
+    // The year defaults to the epoch start, the era to AMETE_MIHRET
+    if (internalGet(UCAL_ERA, AMETE_MIHRET) == AMETE_MIHRET) {
+        return internalGet(UCAL_YEAR, 1); // Default to year 1
+    }
+    return internalGet(UCAL_YEAR, 1) - AMETE_MIHRET_DELTA;
 }
 
 void
 EthiopicCalendar::handleComputeFields(int32_t julianDay, UErrorCode &/*status*/)
 {
-    int32_t eyear, month, day, era, year;
+    int32_t eyear, month, day;
     jdToCE(julianDay, getJDEpochOffset(), eyear, month, day);
 
-    if (isAmeteAlemEra()) {
-        era = AMETE_ALEM;
-        year = eyear + AMETE_MIHRET_DELTA;
-    } else {
-        if (eyear > 0) {
-            era = AMETE_MIHRET;
-            year = eyear;
-        } else {
-            era = AMETE_ALEM;
-            year = eyear + AMETE_MIHRET_DELTA;
-        }
-    }
-
     internalSet(UCAL_EXTENDED_YEAR, eyear);
-    internalSet(UCAL_ERA, era);
-    internalSet(UCAL_YEAR, year);
+    internalSet(UCAL_ERA, (eyear > 0) ? AMETE_MIHRET : AMETE_ALEM);
+    internalSet(UCAL_YEAR, (eyear > 0) ? eyear : (eyear + AMETE_MIHRET_DELTA));
     internalSet(UCAL_MONTH, month);
     internalSet(UCAL_DATE, day);
     internalSet(UCAL_DAY_OF_YEAR, (30 * month) + day);
 }
 
-int32_t
-EthiopicCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const
-{
-    if (isAmeteAlemEra() && field == UCAL_ERA) {
-        return 0; // Only one era in this mode, era is always 0
-    }
-    return CECalendar::handleGetLimit(field, limitType);
-}
-
-
 constexpr uint32_t kEthiopicRelatedYearDiff = 8;
-constexpr uint32_t kEthiopicAmeteAlemRelatedYearDiff = -5492;
 
 int32_t EthiopicCalendar::getRelatedYear(UErrorCode &status) const
 {
@@ -146,14 +92,13 @@ int32_t EthiopicCalendar::getRelatedYear(UErrorCode &status) const
     if (U_FAILURE(status)) {
         return 0;
     }
-    return year + (isAmeteAlemEra() ? kEthiopicAmeteAlemRelatedYearDiff : kEthiopicRelatedYearDiff);
+    return year + kEthiopicRelatedYearDiff;
 }
 
 void EthiopicCalendar::setRelatedYear(int32_t year)
 {
     // set extended year
-    set(UCAL_EXTENDED_YEAR, year -
-        (isAmeteAlemEra() ? kEthiopicAmeteAlemRelatedYearDiff : kEthiopicRelatedYearDiff));
+    set(UCAL_EXTENDED_YEAR, year - kEthiopicRelatedYearDiff);
 }
 
 /**
@@ -193,9 +138,6 @@ EthiopicCalendar::defaultCenturyStartYear() const
 {
     // lazy-evaluate systemDefaultCenturyStartYear
     umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury);
-    if (isAmeteAlemEra()) {
-        return gSystemDefaultCenturyStartYear + AMETE_MIHRET_DELTA;
-    }
     return gSystemDefaultCenturyStartYear;
 }
 
@@ -222,6 +164,94 @@ EthiopicCalendar::ethiopicToJD(int32_t year, int32_t month, int32_t date)
 }
 #endif
 
+//-------------------------------------------------------------------------
+// Constructors...
+//-------------------------------------------------------------------------
+
+EthiopicAmeteAlemCalendar::EthiopicAmeteAlemCalendar(const Locale& aLocale,
+                                   UErrorCode& success)
+:   EthiopicCalendar(aLocale, success)
+{
+}
+
+EthiopicAmeteAlemCalendar::~EthiopicAmeteAlemCalendar()
+{
+}
+
+EthiopicAmeteAlemCalendar*
+EthiopicAmeteAlemCalendar::clone() const
+{
+    return new EthiopicAmeteAlemCalendar(*this);
+}
+
+//-------------------------------------------------------------------------
+// Calendar framework
+//-------------------------------------------------------------------------
+
+const char *
+EthiopicAmeteAlemCalendar::getType() const
+{
+    return "ethiopic-amete-alem";
+}
+
+int32_t
+EthiopicAmeteAlemCalendar::handleGetExtendedYear()
+{
+    // Ethiopic calendar uses EXTENDED_YEAR aligned to
+    // Amelete Hihret year always.
+    if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR) {
+        return internalGet(UCAL_EXTENDED_YEAR, 1); // Default to year 1
+    }
+    return internalGet(UCAL_YEAR, 1 + AMETE_MIHRET_DELTA)
+            - AMETE_MIHRET_DELTA; // Default to year 1 of Amelete Mihret
+}
+
+void
+EthiopicAmeteAlemCalendar::handleComputeFields(int32_t julianDay, UErrorCode &/*status*/)
+{
+    int32_t eyear, month, day;
+    jdToCE(julianDay, getJDEpochOffset(), eyear, month, day);
+
+    internalSet(UCAL_EXTENDED_YEAR, eyear);
+    internalSet(UCAL_ERA, AMETE_ALEM);
+    internalSet(UCAL_YEAR, eyear + AMETE_MIHRET_DELTA);
+    internalSet(UCAL_MONTH, month);
+    internalSet(UCAL_DATE, day);
+    internalSet(UCAL_DAY_OF_YEAR, (30 * month) + day);
+}
+
+int32_t
+EthiopicAmeteAlemCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const
+{
+    if (field == UCAL_ERA) {
+        return 0; // Only one era in this mode, era is always 0
+    }
+    return EthiopicCalendar::handleGetLimit(field, limitType);
+}
+
+constexpr uint32_t kEthiopicAmeteAlemRelatedYearDiff = -5492;
+
+int32_t EthiopicAmeteAlemCalendar::getRelatedYear(UErrorCode &status) const
+{
+    int32_t year = get(UCAL_EXTENDED_YEAR, status);
+    if (U_FAILURE(status)) {
+        return 0;
+    }
+    return year + kEthiopicAmeteAlemRelatedYearDiff;
+}
+
+void EthiopicAmeteAlemCalendar::setRelatedYear(int32_t year)
+{
+    // set extended year
+    set(UCAL_EXTENDED_YEAR, year - kEthiopicAmeteAlemRelatedYearDiff);
+}
+
+int32_t
+EthiopicAmeteAlemCalendar::defaultCenturyStartYear() const
+{
+    return EthiopicCalendar::defaultCenturyStartYear() + AMETE_MIHRET_DELTA;
+}
+
 U_NAMESPACE_END
 
 #endif
index 736ae1c565ad21cd0cef11eff1466986d9746d6a..c5828d57706f0dff9256f21276586c4348b3aa57 100644 (file)
@@ -26,15 +26,6 @@ U_NAMESPACE_BEGIN
 class EthiopicCalendar : public CECalendar {
 
 public:
-    /**
-     * Calendar type - use Amete Alem era for all the time or not
-     * @internal 
-     */
-    enum EEraType {
-        AMETE_MIHRET_ERA,
-        AMETE_ALEM_ERA
-    };
-
     /**
      * Useful constants for EthiopicCalendar.
      * @internal
@@ -122,13 +113,13 @@ public:
      *                 only use Amete Alem for all the time.
      * @internal
      */
-    EthiopicCalendar(const Locale& aLocale, UErrorCode& success, EEraType type = AMETE_MIHRET_ERA);
+    EthiopicCalendar(const Locale& aLocale, UErrorCode& success);
 
     /**
      * Copy Constructor
      * @internal
      */
-    EthiopicCalendar(const EthiopicCalendar& other);
+    EthiopicCalendar(const EthiopicCalendar& other) = default;
 
     /**
      * Destructor.
@@ -144,26 +135,12 @@ public:
     virtual EthiopicCalendar* clone() const override;
 
     /**
-     * return the calendar type, "ethiopic"
+     * Return the calendar type, "ethiopic"
      * @return calendar type
      * @internal
      */
     virtual const char * getType() const override;
 
-    /**
-     * Set Alem or Mihret era.
-     * @param onOff Set Amete Alem era if true, otherwise set Amete Mihret era.
-     * @internal
-     */
-    void setAmeteAlemEra (UBool onOff);
-
-    /**
-     * Return true if this calendar is set to the Amete Alem era.
-     * @return true if set to the Amete Alem era.
-     * @internal
-     */
-    UBool isAmeteAlemEra() const;
-
     /**
      * @return      The related Gregorian year; will be obtained by modifying the value
      *              obtained by get from UCAL_EXTENDED_YEAR field
@@ -185,6 +162,11 @@ protected:
 
     /**
      * Return the extended year defined by the current fields.
+     * This calendar uses both AMETE_ALEM and AMETE_MIHRET.
+     *
+     * EXTENDED_YEAR       ERA           YEAR
+     *             0       AMETE_ALEM    5500
+     *             1       AMETE_MIHRET     1
      * @internal
      */
     virtual int32_t handleGetExtendedYear() override;
@@ -195,12 +177,6 @@ protected:
      */
     virtual void handleComputeFields(int32_t julianDay, UErrorCode &status) override;
 
-    /**
-     * Calculate the limit for a specified type of limit and field
-     * @internal
-     */
-    virtual int32_t handleGetLimit(UCalendarDateFields field, ELimitType limitType) const override;
-
     /**
      * Returns the date of the start of the default century
      * @return start of century - in milliseconds since epoch, 1970
@@ -220,18 +196,6 @@ protected:
      */
     virtual int32_t getJDEpochOffset() const override;
 
-private:
-    /**
-     * When eraType is AMETE_ALEM_ERA, then this calendar use only AMETE_ALEM
-     * for the era. Otherwise (default), this calendar uses both AMETE_ALEM
-     * and AMETE_MIHRET.
-     *
-     * EXTENDED_YEAR        AMETE_ALEM_ERA     AMETE_MIHRET_ERA
-     *             0       Amete Alem 5500      Amete Alem 5500
-     *             1        Amete Mihret 1      Amete Alem 5501
-     */
-    EEraType eraType;
-
 public:
     /**
      * Override Calendar Returns a unique class ID POLYMORPHICALLY. Pure virtual
@@ -280,6 +244,123 @@ public:
 #endif
 };
 
+/**
+ * Implement the Ethiopic Amete Alem calendar system.
+ * @internal
+ */
+class EthiopicAmeteAlemCalendar : public EthiopicCalendar {
+
+public:
+    /**
+     * Constructs a EthiopicAmeteAlemCalendar based on the current time in the default time zone
+     * with the given locale.
+     *
+     * @param aLocale  The given locale.
+     * @param success  Indicates the status of EthiopicCalendar object construction.
+     *                 Returns U_ZERO_ERROR if constructed successfully.
+     * @internal
+     */
+    EthiopicAmeteAlemCalendar(const Locale& aLocale, UErrorCode& success);
+
+    /**
+     * Copy Constructor
+     * @internal
+     */
+    EthiopicAmeteAlemCalendar(const EthiopicAmeteAlemCalendar& other) = default;
+
+    /**
+     * Destructor.
+     * @internal
+     */
+    virtual ~EthiopicAmeteAlemCalendar();
+
+    /**
+     * Create and return a polymorphic copy of this calendar.
+     * @return    return a polymorphic copy of this calendar.
+     * @internal
+     */
+    virtual EthiopicAmeteAlemCalendar* clone() const override;
+
+    /**
+     * Return the calendar type, "ethiopic-amete-alem"
+     * @return calendar type
+     * @internal
+     */
+    virtual const char * getType() const override;
+
+    /**
+     * Override Calendar Returns a unique class ID POLYMORPHICALLY. Pure virtual
+     * override. This method is to implement a simple version of RTTI, since not all C++
+     * compilers support genuine RTTI. Polymorphic operator==() and clone() methods call
+     * this method.
+     *
+     * @return   The class ID for this object. All objects of a given class have the
+     *           same class ID. Objects of other classes have different class IDs.
+     * @internal
+     */
+    virtual UClassID getDynamicClassID(void) const override;
+
+    /**
+     * Return the class ID for this class. This is useful only for comparing to a return
+     * value from getDynamicClassID(). For example:
+     *
+     *      Base* polymorphic_pointer = createPolymorphicObject();
+     *      if (polymorphic_pointer->getDynamicClassID() ==
+     *          Derived::getStaticClassID()) ...
+     *
+     * @return   The class ID for all objects of this class.
+     * @internal
+     */
+    U_I18N_API static UClassID U_EXPORT2 getStaticClassID(void); 
+
+    /**
+     * @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
+    //-------------------------------------------------------------------------
+
+    /**
+     * Return the extended year defined by the current fields.
+     * This calendar use only AMETE_ALEM for the era.
+     *
+     * EXTENDED_YEAR       ERA         YEAR
+     *             0       AMETE_ALEM  5500
+     *             1       AMETE_ALEM  5501
+     * @internal
+     */
+    virtual int32_t handleGetExtendedYear() override;
+
+    /**
+     * Compute fields from the JD
+     * @internal
+     */
+    virtual void handleComputeFields(int32_t julianDay, UErrorCode &status) override;
+
+    /**
+     * Calculate the limit for a specified type of limit and field
+     * @internal
+     */
+    virtual int32_t handleGetLimit(UCalendarDateFields field, ELimitType limitType) const override;
+    /**
+     * Returns the year in which the default century begins
+     * @internal
+     */
+    virtual int32_t defaultCenturyStartYear() const override;
+};
+
 U_NAMESPACE_END
 #endif /* #if !UCONFIG_NO_FORMATTING */
 #endif /* ETHPCCAL_H */
index 60bbe0f89ee47a215adbd6f495dd1ea7357133d8..eef2dd190e6eaed33c0d97452eaf20ed5c5a844a 100644 (file)
     <ClCompile Include="hebrwcal.cpp" />
     <ClCompile Include="indiancal.cpp" />
     <ClCompile Include="islamcal.cpp" />
+    <ClCompile Include="iso8601cal.cpp" />
     <ClCompile Include="japancal.cpp" />
     <ClCompile Include="listformatter.cpp" />
     <ClCompile Include="ulistformatter.cpp" />
     <ClInclude Include="hebrwcal.h" />
     <ClInclude Include="indiancal.h" />
     <ClInclude Include="islamcal.h" />
+    <ClInclude Include="iso8601cal.h" />
     <ClInclude Include="japancal.h" />
     <ClInclude Include="measunit_impl.h" />
     <ClInclude Include="msgfmt_impl.h" />
index 74fd8c486145408b8496f7ca14918cb867516653..d2175c7c768d8dcb6b2fc2584dc81693d44cb757 100644 (file)
     <ClCompile Include="indiancal.cpp">
       <Filter>formatting</Filter>
     </ClCompile>
+    <ClCompile Include="iso8601cal.cpp">
+      <Filter>formatting</Filter>
+    </ClCompile>
     <ClCompile Include="islamcal.cpp">
       <Filter>formatting</Filter>
     </ClCompile>
     <ClInclude Include="indiancal.h">
       <Filter>formatting</Filter>
     </ClInclude>
+    <ClInclude Include="iso8601cal.h">
+      <Filter>formatting</Filter>
+    </ClInclude>
     <ClInclude Include="islamcal.h">
       <Filter>formatting</Filter>
     </ClInclude>
index 7ce4ae64f9695df77917f0c525645c14b6af59ee..25c6c333d7bb23464fc85015aafb0536ed1b4c93 100644 (file)
     <ClCompile Include="hebrwcal.cpp" />
     <ClCompile Include="indiancal.cpp" />
     <ClCompile Include="islamcal.cpp" />
+    <ClCompile Include="iso8601cal.cpp" />
     <ClCompile Include="japancal.cpp" />
     <ClCompile Include="listformatter.cpp" />
     <ClCompile Include="ulistformatter.cpp" />
     <ClInclude Include="hebrwcal.h" />
     <ClInclude Include="indiancal.h" />
     <ClInclude Include="islamcal.h" />
+    <ClInclude Include="iso8601cal.h" />
     <ClInclude Include="japancal.h" />
     <ClInclude Include="measunit_impl.h" />
     <ClInclude Include="msgfmt_impl.h" />
index 54b2a97ff49447f33042d2549a487c55f52c808b..2b6d32210beafa32d54c31379d0a6ff81c1cf30a 100644 (file)
@@ -206,67 +206,22 @@ int32_t getUmalqura_MonthLength(int32_t y, int32_t m) {
 //-------------------------------------------------------------------------
 
 const char *IslamicCalendar::getType() const {
-    const char *sType = NULL;
-
-    switch (cType) {
-    case CIVIL:
-        sType = "islamic-civil";
-        break;
-    case ASTRONOMICAL:
-        sType = "islamic";
-        break;
-    case TBLA:
-        sType = "islamic-tbla";
-        break;
-    case UMALQURA:
-        sType = "islamic-umalqura";
-        break;
-    default:
-        UPRV_UNREACHABLE_EXIT; // out of range
-    }
-    return sType;
+    return "islamic";
 }
 
 IslamicCalendar* IslamicCalendar::clone() const {
     return new IslamicCalendar(*this);
 }
 
-IslamicCalendar::IslamicCalendar(const Locale& aLocale, UErrorCode& success, ECalculationType type)
-:   Calendar(TimeZone::forLocaleOrDefault(aLocale), aLocale, success),
-cType(type)
+IslamicCalendar::IslamicCalendar(const Locale& aLocale, UErrorCode& success)
+:   Calendar(TimeZone::forLocaleOrDefault(aLocale), aLocale, success)
 {
     setTimeInMillis(getNow(), success); // Call this again now that the vtable is set up properly.
 }
 
-IslamicCalendar::IslamicCalendar(const IslamicCalendar& other) : Calendar(other), cType(other.cType) {
-}
-
 IslamicCalendar::~IslamicCalendar()
 {
 }
-
-void IslamicCalendar::setCalculationType(ECalculationType type, UErrorCode &status)
-{
-    if (cType != type) {
-        // The fields of the calendar will become invalid, because the calendar
-        // rules are different
-        UDate m = getTimeInMillis(status);
-        cType = type;
-        clear();
-        setTimeInMillis(m, status);
-    }
-}
-
-/**
-* Returns <code>true</code> if this object is using the fixed-cycle civil
-* calendar, or <code>false</code> if using the religious, astronomical
-* calendar.
-* @draft ICU 2.4
-*/
-UBool IslamicCalendar::isCivil() {
-    return (cType == CIVIL);
-}
-
 //-------------------------------------------------------------------------
 // Minimum / Maximum access functions
 //-------------------------------------------------------------------------
@@ -365,19 +320,7 @@ UBool IslamicCalendar::civilLeapYear(int32_t year)
 * from the Hijri epoch, origin 0.
 */
 int32_t IslamicCalendar::yearStart(int32_t year) const{
-    if (cType == CIVIL || cType == TBLA ||
-        (cType == UMALQURA && (year < UMALQURA_YEAR_START || year > UMALQURA_YEAR_END))) 
-    {
-        return (year-1)*354 + ClockMath::floorDivide((3+11*(int64_t)year),(int64_t)30);
-    } else if(cType==ASTRONOMICAL){
-        return trueMonthStart(12*(year-1));
-    } else {
-        year -= UMALQURA_YEAR_START;
-        // rounded least-squares fit of the dates previously calculated from UMALQURA_MONTHLENGTH iteration
-        int32_t yrStartLinearEstimate = (int32_t)((354.36720 * (double)year) + 460322.05 + 0.5);
-        // need a slight correction to some
-        return yrStartLinearEstimate + umAlQuraYrStartEstimateFix[year];
-    }
+    return trueMonthStart(12*(year-1));
 }
 
 /**
@@ -388,19 +331,7 @@ int32_t IslamicCalendar::yearStart(int32_t year) const{
 * @param month The hijri month, 0-based (assumed to be in range 0..11)
 */
 int32_t IslamicCalendar::monthStart(int32_t year, int32_t month) const {
-    if (cType == CIVIL || cType == TBLA) {
-        // This does not handle months out of the range 0..11
-        return (int32_t)uprv_ceil(29.5*month)
-            + (year-1)*354 + (int32_t)ClockMath::floorDivide((3+11*(int64_t)year),(int64_t)30);
-    } else if(cType==ASTRONOMICAL){
-        return trueMonthStart(12*(year-1) + month);
-    } else {
-        int32_t ms = yearStart(year);
-        for(int i=0; i< month; i++){
-            ms+= handleGetMonthLength(year, i);
-        }
-        return ms;
-    }
+    return trueMonthStart(12*(year-1) + month);
 }
 
 /**
@@ -506,22 +437,8 @@ double IslamicCalendar::moonAge(UDate time, UErrorCode &status)
 * @draft ICU 2.4
 */
 int32_t IslamicCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month) const {
-
-    int32_t length = 0;
-
-    if (cType == CIVIL || cType == TBLA ||
-        (cType == UMALQURA && (extendedYear<UMALQURA_YEAR_START || extendedYear>UMALQURA_YEAR_END)) ) {
-        length = 29 + (month+1) % 2;
-        if (month == DHU_AL_HIJJAH && civilLeapYear(extendedYear)) {
-            length++;
-        }
-    } else if(cType == ASTRONOMICAL){
-        month = 12*(extendedYear-1) + month;
-        length =  trueMonthStart(month+1) - trueMonthStart(month) ;
-    } else {
-        length = getUmalqura_MonthLength(extendedYear - UMALQURA_YEAR_START, month);
-    }
-    return length;
+    month = 12*(extendedYear-1) + month;
+    return trueMonthStart(month+1) - trueMonthStart(month) ;
 }
 
 /**
@@ -529,19 +446,8 @@ int32_t IslamicCalendar::handleGetMonthLength(int32_t extendedYear, int32_t mont
 * @draft ICU 2.4
 */
 int32_t IslamicCalendar::handleGetYearLength(int32_t extendedYear) const {
-    if (cType == CIVIL || cType == TBLA ||
-        (cType == UMALQURA && (extendedYear<UMALQURA_YEAR_START || extendedYear>UMALQURA_YEAR_END)) ) {
-        return 354 + (civilLeapYear(extendedYear) ? 1 : 0);
-    } else if(cType == ASTRONOMICAL){
-        int32_t month = 12*(extendedYear-1);
-        return (trueMonthStart(month + 12) - trueMonthStart(month));
-    } else {
-        int len = 0;
-        for(int i=0; i<12; i++) {
-            len += handleGetMonthLength(extendedYear, i);
-        }
-        return len;
-    }
+    int32_t month = 12*(extendedYear-1);
+    return (trueMonthStart(month + 12) - trueMonthStart(month));
 }
 
 //-------------------------------------------------------------------------
@@ -567,8 +473,8 @@ int32_t IslamicCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, U
         eyear += (month / 12) - 1;
         month = (month % 12) + 11;
     }
-    return monthStart(eyear, month) + ((cType == TBLA)? ASTRONOMICAL_EPOC: CIVIL_EPOC) - 1;
-}    
+    return monthStart(eyear, month) + getEpoc() - 1;
+}
 
 //-------------------------------------------------------------------------
 // Functions for converting from milliseconds to field values
@@ -604,93 +510,49 @@ int32_t IslamicCalendar::handleGetExtendedYear() {
 * @draft ICU 2.4
 */
 void IslamicCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status) {
-    int32_t year, month, dayOfMonth, dayOfYear;
-    int32_t startDate;
-    int32_t days = julianDay - CIVIL_EPOC;
+    if (U_FAILURE(status)) return;
+    int32_t days = julianDay - getEpoc();
 
-    if (cType == CIVIL || cType == TBLA) {
-        if(cType == TBLA) {
-            days = julianDay - ASTRONOMICAL_EPOC;
-        }
-        // Use the civil calendar approximation, which is just arithmetic
-        year  = (int32_t)ClockMath::floorDivide(30 * (int64_t)days + 10646, (int64_t)10631);
-        month = (int32_t)uprv_ceil((days - 29 - yearStart(year)) / 29.5 );
-        month = month<11?month:11;
-        startDate = monthStart(year, month);
-    } else if(cType == ASTRONOMICAL){
-        // Guess at the number of elapsed full months since the epoch
-        int32_t months = (int32_t)uprv_floor((double)days / CalendarAstronomer::SYNODIC_MONTH);
+    // Guess at the number of elapsed full months since the epoch
+    int32_t month = (int32_t)uprv_floor((double)days / CalendarAstronomer::SYNODIC_MONTH);
 
-        startDate = (int32_t)uprv_floor(months * CalendarAstronomer::SYNODIC_MONTH);
+    int32_t startDate = (int32_t)uprv_floor(month * CalendarAstronomer::SYNODIC_MONTH);
 
-        double age = moonAge(internalGetTime(), status);
-        if (U_FAILURE(status)) {
-            status = U_MEMORY_ALLOCATION_ERROR;
-            return;
-        }
-        if ( days - startDate >= 25 && age > 0) {
-            // If we're near the end of the month, assume next month and search backwards
-            months++;
-        }
-
-        // Find out the last time that the new moon was actually visible at this longitude
-        // This returns midnight the night that the moon was visible at sunset.
-        while ((startDate = trueMonthStart(months)) > days) {
-            // If it was after the date in question, back up a month and try again
-            months--;
-        }
+    double age = moonAge(internalGetTime(), status);
+    if (U_FAILURE(status)) {
+        status = U_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
+    if ( days - startDate >= 25 && age > 0) {
+        // If we're near the end of the month, assume next month and search backwards
+        month++;
+    }
 
-        year = months >=  0 ? ((months / 12) + 1) : ((months + 1 ) / 12);
-        month = ((months % 12) + 12 ) % 12;
-    } else if(cType == UMALQURA) {
-        int32_t umalquraStartdays = yearStart(UMALQURA_YEAR_START) ;
-        if( days < umalquraStartdays){
-                //Use Civil calculation
-                year  = (int32_t)ClockMath::floorDivide(
-                    (30 * (int64_t)days + 10646) , (int64_t)10631.0 );
-                month = (int32_t)uprv_ceil((days - 29 - yearStart(year)) / 29.5 );
-                month = month<11?month:11;
-                startDate = monthStart(year, month);
-            }else{
-                int y =UMALQURA_YEAR_START-1, m =0;
-                long d = 1;
-                while(d > 0){ 
-                    y++; 
-                    d = days - yearStart(y) +1;
-                    if(d == handleGetYearLength(y)){
-                        m=11;
-                        break;
-                    }else if(d < handleGetYearLength(y) ){
-                        int monthLen = handleGetMonthLength(y, m); 
-                        m=0;
-                        while(d > monthLen){
-                            d -= monthLen;
-                            m++;
-                            monthLen = handleGetMonthLength(y, m);
-                        }
-                        break;
-                    }
-                }
-                year = y;
-                month = m;
-            }
-    } else { // invalid 'civil'
-      UPRV_UNREACHABLE_EXIT; // should not get here, out of range
+    // Find out the last time that the new moon was actually visible at this longitude
+    // This returns midnight the night that the moon was visible at sunset.
+    while ((startDate = trueMonthStart(month)) > days) {
+        // If it was after the date in question, back up a month and try again
+        month--;
     }
 
-    dayOfMonth = (days - monthStart(year, month)) + 1;
+    int32_t year = month >=  0 ? ((month / 12) + 1) : ((month + 1 ) / 12);
+    month = ((month % 12) + 12 ) % 12;
+    int32_t dayOfMonth = (days - monthStart(year, month)) + 1;
 
     // Now figure out the day of the year.
-    dayOfYear = (days - monthStart(year, 0)) + 1;
-
+    int32_t dayOfYear = (days - monthStart(year, 0)) + 1;
 
     internalSet(UCAL_ERA, 0);
     internalSet(UCAL_YEAR, year);
     internalSet(UCAL_EXTENDED_YEAR, year);
     internalSet(UCAL_MONTH, month);
     internalSet(UCAL_DAY_OF_MONTH, dayOfMonth);
-    internalSet(UCAL_DAY_OF_YEAR, dayOfYear);       
-}    
+    internalSet(UCAL_DAY_OF_YEAR, dayOfYear);
+}
+
+int32_t IslamicCalendar::getEpoc() const {
+    return CIVIL_EPOC;
+}
 
 static int32_t gregoYearFromIslamicStart(int32_t year) {
     // ad hoc conversion, improve under #10752
@@ -789,9 +651,315 @@ IslamicCalendar::initializeSystemDefaultCentury()
     // out.
 }
 
+/*****************************************************************************
+ * IslamicCivilCalendar
+ *****************************************************************************/
+IslamicCivilCalendar::IslamicCivilCalendar(const Locale& aLocale, UErrorCode& success)
+    : IslamicCalendar(aLocale, success)
+{
+}
+
+IslamicCivilCalendar::~IslamicCivilCalendar()
+{
+}
+
+const char *IslamicCivilCalendar::getType() const {
+    return "islamic-civil";
+}
+
+IslamicCivilCalendar* IslamicCivilCalendar::clone() const {
+    return new IslamicCivilCalendar(*this);
+}
+
+/**
+* Return the day # on which the given year starts.  Days are counted
+* from the Hijri epoch, origin 0.
+*/
+int32_t IslamicCivilCalendar::yearStart(int32_t year) const{
+    return static_cast<int32_t>(
+        (year-1)*354 + ClockMath::floorDivide((3+11*static_cast<int64_t>(year)),
+                                                 static_cast<int64_t>(30)));
+}
+
+/**
+* Return the day # on which the given month starts.  Days are counted
+* from the Hijri epoch, origin 0.
+*
+* @param year  The hijri year
+* @param month The hijri month, 0-based (assumed to be in range 0..11)
+*/
+int32_t IslamicCivilCalendar::monthStart(int32_t year, int32_t month) const {
+    // This does not handle months out of the range 0..11
+    return static_cast<int32_t>(
+        uprv_ceil(29.5*month) + (year-1)*354 +
+        static_cast<int32_t>(ClockMath::floorDivide(
+             3+11*static_cast<int64_t>(year),
+             static_cast<int64_t>(30))));
+}
+
+/**
+* Return the length (in days) of the given month.
+*
+* @param year  The hijri year
+* @param year  The hijri month, 0-based
+* @draft ICU 2.4
+*/
+int32_t IslamicCivilCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month) const {
+    int32_t length = 29 + (month+1) % 2;
+    if (month == DHU_AL_HIJJAH && civilLeapYear(extendedYear)) {
+        length++;
+    }
+    return length;
+}
+
+/**
+* Return the number of days in the given Islamic year
+* @draft ICU 2.4
+*/
+int32_t IslamicCivilCalendar::handleGetYearLength(int32_t extendedYear) const {
+    return 354 + (civilLeapYear(extendedYear) ? 1 : 0);
+}
+
+/**
+* Override Calendar to compute several fields specific to the Islamic
+* calendar system.  These are:
+*
+* <ul><li>ERA
+* <li>YEAR
+* <li>MONTH
+* <li>DAY_OF_MONTH
+* <li>DAY_OF_YEAR
+* <li>EXTENDED_YEAR</ul>
+* 
+* The DAY_OF_WEEK and DOW_LOCAL fields are already set when this
+* method is called. The getGregorianXxx() methods return Gregorian
+* calendar equivalents for the given Julian day.
+* @draft ICU 2.4
+*/
+void IslamicCivilCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status) {
+    if (U_FAILURE(status)) return;
+    int32_t days = julianDay - getEpoc();
+
+    // Use the civil calendar approximation, which is just arithmetic
+    int32_t year  = static_cast<int32_t>(
+        ClockMath::floorDivide(30 * static_cast<int64_t>(days) + 10646,
+                               static_cast<int64_t>(10631)));
+    int32_t month = static_cast<int32_t>(
+        uprv_ceil((days - 29 - yearStart(year)) / 29.5 ));
+    month = month<11?month:11;
+
+    int32_t dayOfMonth = (days - monthStart(year, month)) + 1;
+
+    // Now figure out the day of the year.
+    int32_t dayOfYear = (days - monthStart(year, 0)) + 1;
+
+    internalSet(UCAL_ERA, 0);
+    internalSet(UCAL_YEAR, year);
+    internalSet(UCAL_EXTENDED_YEAR, year);
+    internalSet(UCAL_MONTH, month);
+    internalSet(UCAL_DAY_OF_MONTH, dayOfMonth);
+    internalSet(UCAL_DAY_OF_YEAR, dayOfYear);
+}
+/*****************************************************************************
+ * IslamicTBLACalendar
+ *****************************************************************************/
+IslamicTBLACalendar::IslamicTBLACalendar(const Locale& aLocale, UErrorCode& success)
+    : IslamicCivilCalendar(aLocale, success)
+{
+}
+
+IslamicTBLACalendar::~IslamicTBLACalendar()
+{
+}
+
+const char *IslamicTBLACalendar::getType() const {
+    return "islamic-tbla";
+}
+
+IslamicTBLACalendar* IslamicTBLACalendar::clone() const {
+    return new IslamicTBLACalendar(*this);
+}
+
+int32_t IslamicTBLACalendar::getEpoc() const {
+    return ASTRONOMICAL_EPOC;
+}
+
+/*****************************************************************************
+ * IslamicUmalquraCalendar
+ *****************************************************************************/
+IslamicUmalquraCalendar::IslamicUmalquraCalendar(const Locale& aLocale, UErrorCode& success)
+    : IslamicCalendar(aLocale, success)
+{
+}
+
+IslamicUmalquraCalendar::~IslamicUmalquraCalendar()
+{
+}
+
+const char *IslamicUmalquraCalendar::getType() const {
+    return "islamic-umalqura";
+}
+
+IslamicUmalquraCalendar* IslamicUmalquraCalendar::clone() const {
+    return new IslamicUmalquraCalendar(*this);
+}
+
+/**
+* Return the day # on which the given year starts.  Days are counted
+* from the Hijri epoch, origin 0.
+*/
+int32_t IslamicUmalquraCalendar::yearStart(int32_t year) const {
+    if (year < UMALQURA_YEAR_START || year > UMALQURA_YEAR_END) {
+        return static_cast<int32_t>(
+            (year-1)*354 + ClockMath::floorDivide((3+11*static_cast<int64_t>(year)),
+                                                  static_cast<int64_t>(30)));
+    }
+    year -= UMALQURA_YEAR_START;
+    // rounded least-squares fit of the dates previously calculated from UMALQURA_MONTHLENGTH iteration
+    int32_t yrStartLinearEstimate = static_cast<int32_t>(
+        (354.36720 * (double)year) + 460322.05 + 0.5);
+    // need a slight correction to some
+    return yrStartLinearEstimate + umAlQuraYrStartEstimateFix[year];
+}
 
+/**
+* Return the day # on which the given month starts.  Days are counted
+* from the Hijri epoch, origin 0.
+*
+* @param year  The hijri year
+* @param month The hijri month, 0-based (assumed to be in range 0..11)
+*/
+int32_t IslamicUmalquraCalendar::monthStart(int32_t year, int32_t month) const {
+    int32_t ms = yearStart(year);
+    for(int i=0; i< month; i++){
+        ms+= handleGetMonthLength(year, i);
+    }
+    return ms;
+}
+
+/**
+* Return the length (in days) of the given month.
+*
+* @param year  The hijri year
+* @param year  The hijri month, 0-based
+*/
+int32_t IslamicUmalquraCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month) const {
+    int32_t length = 0;
+    if (extendedYear<UMALQURA_YEAR_START || extendedYear>UMALQURA_YEAR_END) {
+        length = 29 + (month+1) % 2;
+        if (month == DHU_AL_HIJJAH && civilLeapYear(extendedYear)) {
+            length++;
+        }
+        return length;
+    }
+    return getUmalqura_MonthLength(extendedYear - UMALQURA_YEAR_START, month);
+}
+
+/**
+* Return the number of days in the given Islamic year
+* @draft ICU 2.4
+*/
+int32_t IslamicUmalquraCalendar::handleGetYearLength(int32_t extendedYear) const {
+    if (extendedYear<UMALQURA_YEAR_START || extendedYear>UMALQURA_YEAR_END) {
+        return 354 + (civilLeapYear(extendedYear) ? 1 : 0);
+    }
+    int len = 0;
+    for(int i=0; i<12; i++) {
+        len += handleGetMonthLength(extendedYear, i);
+    }
+    return len;
+}
+
+/**
+* Override Calendar to compute several fields specific to the Islamic
+* calendar system.  These are:
+*
+* <ul><li>ERA
+* <li>YEAR
+* <li>MONTH
+* <li>DAY_OF_MONTH
+* <li>DAY_OF_YEAR
+* <li>EXTENDED_YEAR</ul>
+* 
+* The DAY_OF_WEEK and DOW_LOCAL fields are already set when this
+* method is called. The getGregorianXxx() methods return Gregorian
+* calendar equivalents for the given Julian day.
+* @draft ICU 2.4
+*/
+void IslamicUmalquraCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status) {
+    if (U_FAILURE(status)) return;
+    int32_t year, month, dayOfMonth, dayOfYear;
+    int32_t days = julianDay - getEpoc();
+
+    int32_t umalquraStartdays = yearStart(UMALQURA_YEAR_START) ;
+    if (days < umalquraStartdays) {
+        //Use Civil calculation
+        year  = (int32_t)ClockMath::floorDivide(
+            (30 * (int64_t)days + 10646) , (int64_t)10631.0 );
+        month = (int32_t)uprv_ceil((days - 29 - yearStart(year)) / 29.5 );
+        month = month < 11 ? month : 11;
+    } else {
+        int y =UMALQURA_YEAR_START-1, m =0;
+        long d = 1;
+        while (d > 0) {
+            y++;
+            d = days - yearStart(y) +1;
+            if (d == handleGetYearLength(y)) {
+                m=11;
+                break;
+            }
+            if (d < handleGetYearLength(y)){
+                int monthLen = handleGetMonthLength(y, m);
+                m=0;
+                while(d > monthLen){
+                    d -= monthLen;
+                    m++;
+                    monthLen = handleGetMonthLength(y, m);
+                }
+                break;
+            }
+        }
+        year = y;
+        month = m;
+    }
+
+    dayOfMonth = (days - monthStart(year, month)) + 1;
+
+    // Now figure out the day of the year.
+    dayOfYear = (days - monthStart(year, 0)) + 1;
+
+    internalSet(UCAL_ERA, 0);
+    internalSet(UCAL_YEAR, year);
+    internalSet(UCAL_EXTENDED_YEAR, year);
+    internalSet(UCAL_MONTH, month);
+    internalSet(UCAL_DAY_OF_MONTH, dayOfMonth);
+    internalSet(UCAL_DAY_OF_YEAR, dayOfYear);
+}
+/*****************************************************************************
+ * IslamicRGSACalendar
+ *****************************************************************************/
+IslamicRGSACalendar::IslamicRGSACalendar(const Locale& aLocale, UErrorCode& success)
+    : IslamicCalendar(aLocale, success)
+{
+}
+
+IslamicRGSACalendar::~IslamicRGSACalendar()
+{
+}
+
+const char *IslamicRGSACalendar::getType() const {
+    return "islamic-rgsa";
+}
+
+IslamicRGSACalendar* IslamicRGSACalendar::clone() const {
+    return new IslamicRGSACalendar(*this);
+}
 
 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IslamicCalendar)
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IslamicCivilCalendar)
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IslamicUmalquraCalendar)
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IslamicTBLACalendar)
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IslamicRGSACalendar)
 
 U_NAMESPACE_END
 
index 5ff212485e0aa36a6c57015e3f4a9ca0d4b9d13c..6d7c0503a2cc0ce77a72f0809e3492c490c702ec 100644 (file)
@@ -53,7 +53,8 @@ U_NAMESPACE_BEGIN
  * every 30 years.  This calendar is easily calculated and thus predictable in
  * advance, so it is used as the civil calendar in a number of Arab countries.
  * This is the default behavior of a newly-created <code>IslamicCalendar</code>
- * object.
+ * object. This calendar variant is implemented in the IslamicCivilCalendar
+ * class.
  * <p>
  * The Islamic <em>religious</em> calendar, however, is based on the <em>observation</em>
  * of the crescent moon.  It is thus affected by the position at which the
@@ -71,10 +72,6 @@ U_NAMESPACE_BEGIN
  * calculations.  At present, the approximations used in this class are fairly
  * simplistic; they will be improved in later versions of the code.
  * <p>
- * The {@link #setCivil setCivil} method determines
- * which approach is used to determine the start of a month.  By default, the
- * fixed-cycle civil calendar is used.  However, if <code>setCivil(false)</code>
- * is called, an approximation of the true lunar calendar will be used.
  *
  * @see GregorianCalendar
  *
@@ -88,18 +85,6 @@ class U_I18N_API IslamicCalendar : public Calendar {
   //-------------------------------------------------------------------------
   // Constants...
   //-------------------------------------------------------------------------
-  
-  /**
-   * Calendar type - civil or religious or um alqura
-   * @internal 
-   */
-  enum ECalculationType {
-    ASTRONOMICAL,
-    CIVIL,
-    UMALQURA,
-    TBLA
-  };
-  
   /**
    * Constants for the months
    * @internal
@@ -192,16 +177,15 @@ class U_I18N_API IslamicCalendar : public Calendar {
    * @param aLocale  The given locale.
    * @param success  Indicates the status of IslamicCalendar object construction.
    *                 Returns U_ZERO_ERROR if constructed successfully.
-   * @param type     The Islamic calendar calculation type. The default value is CIVIL.
    * @internal
    */
-  IslamicCalendar(const Locale& aLocale, UErrorCode &success, ECalculationType type = CIVIL);
+  IslamicCalendar(const Locale& aLocale, UErrorCode &success);
 
   /**
    * Copy Constructor
    * @internal
    */
-  IslamicCalendar(const IslamicCalendar& other);
+  IslamicCalendar(const IslamicCalendar& other) = default;
 
   /**
    * Destructor.
@@ -209,40 +193,20 @@ class U_I18N_API IslamicCalendar : public Calendar {
    */
   virtual ~IslamicCalendar();
 
-  /**
-   * Sets Islamic calendar calculation type used by this instance.
-   *
-   * @param type    The calendar calculation type, <code>CIVIL</code> to use the civil
-   *                calendar, <code>ASTRONOMICAL</code> to use the astronomical calendar.
-   * @internal
-   */
-  void setCalculationType(ECalculationType type, UErrorCode &status);
-    
-  /**
-   * Returns <code>true</code> if this object is using the fixed-cycle civil
-   * calendar, or <code>false</code> if using the religious, astronomical
-   * calendar.
-   * @internal
-   */
-  UBool isCivil();
-
-
-  // TODO: copy c'tor, etc
-
   // clone
   virtual IslamicCalendar* clone() const override;
 
- private:
+ protected:
   /**
    * Determine whether a year is a leap year in the Islamic civil calendar
    */
   static UBool civilLeapYear(int32_t year);
-    
+
   /**
    * Return the day # on which the given year starts.  Days are counted
    * from the Hijri epoch, origin 0.
    */
-  int32_t yearStart(int32_t year) const;
+  virtual int32_t yearStart(int32_t year) const;
 
   /**
    * Return the day # on which the given month starts.  Days are counted
@@ -251,7 +215,7 @@ class U_I18N_API IslamicCalendar : public Calendar {
    * @param year  The hijri year
    * @param year  The hijri month, 0-based
    */
-  int32_t monthStart(int32_t year, int32_t month) const;
+  virtual int32_t monthStart(int32_t year, int32_t month) const;
     
   /**
    * Find the day number on which a particular month of the true/lunar
@@ -263,6 +227,7 @@ class U_I18N_API IslamicCalendar : public Calendar {
    */
   int32_t trueMonthStart(int32_t month) const;
 
+ private:
   /**
    * Return the "age" of the moon at the given time; this is the difference
    * in ecliptic latitude between the moon and the sun.  This method simply
@@ -274,17 +239,6 @@ class U_I18N_API IslamicCalendar : public Calendar {
    */
   static double moonAge(UDate time, UErrorCode &status);
 
-  //-------------------------------------------------------------------------
-  // Internal data....
-  //
-    
-  /**
-   * <code>CIVIL</code> if this object uses the fixed-cycle Islamic civil calendar,
-   * and <code>ASTRONOMICAL</code> if it approximates the true religious calendar using
-   * astronomical calculations for the time of the new moon.
-   */
-  ECalculationType cType;
-
   //----------------------------------------------------------------------
   // Calendar framework
   //----------------------------------------------------------------------
@@ -346,6 +300,12 @@ class U_I18N_API IslamicCalendar : public Calendar {
    */
   virtual void handleComputeFields(int32_t julianDay, UErrorCode &status) override;
 
+  /**
+   * Return the epoc.
+   * @internal
+   */
+  virtual int32_t getEpoc() const;
+
   // UObject stuff
  public: 
   /**
@@ -369,7 +329,7 @@ class U_I18N_API IslamicCalendar : public Calendar {
   /*U_I18N_API*/ static UClassID U_EXPORT2 getStaticClassID(void);
 
   /**
-   * return the calendar type, "buddhist".
+   * return the calendar type, "islamic".
    *
    * @return calendar type
    * @internal
@@ -423,10 +383,372 @@ class U_I18N_API IslamicCalendar : public Calendar {
   static void U_CALLCONV initializeSystemDefaultCentury(void);
 };
 
-U_NAMESPACE_END
+/*
+ * IslamicCivilCalendar is one of the two main variants of the Islamic calendar.
+ * The <em>civil</em> calendar, which uses a fixed cycle of alternating 29-
+ * and 30-day months, with a leap day added to the last month of 11 out of
+ * every 30 years.  This calendar is easily calculated and thus predictable in
+ * advance, so it is used as the civil calendar in a number of Arab countries.
+ * This calendar is referring as "Islamic calendar, tabular (intercalary years
+ * [2,5,7,10,13,16,18,21,24,26,29]- civil epoch" in CLDR.
+ */
+class U_I18N_API IslamicCivilCalendar : public IslamicCalendar {
+ public:
+  /**
+   * Constructs an IslamicCivilCalendar based on the current time in the default time zone
+   * with the given locale.
+   *
+   * @param aLocale  The given locale.
+   * @param success  Indicates the status of IslamicCivilCalendar object construction.
+   *                 Returns U_ZERO_ERROR if constructed successfully.
+   * @internal
+   */
+  IslamicCivilCalendar(const Locale& aLocale, UErrorCode &success);
 
-#endif
-#endif
+  /**
+   * Copy Constructor
+   * @internal
+   */
+  IslamicCivilCalendar(const IslamicCivilCalendar& other) = default;
+
+  /**
+   * Destructor.
+   * @internal
+   */
+  virtual ~IslamicCivilCalendar();
+
+  // clone
+  virtual IslamicCivilCalendar* clone() const override;
+
+  /**
+   * @return   The class ID for this object. All objects of a given class have the
+   *           same class ID. Objects of other classes have different class IDs.
+   * @internal
+   */
+  virtual UClassID getDynamicClassID(void) const override;
+
+  /**
+   * Return the class ID for this class. This is useful only for comparing to a return
+   * value from getDynamicClassID(). For example:
+   *
+   *      Base* polymorphic_pointer = createPolymorphicObject();
+   *      if (polymorphic_pointer->getDynamicClassID() ==
+   *          Derived::getStaticClassID()) ...
+   *
+   * @return   The class ID for all objects of this class.
+   * @internal
+   */
+  static UClassID U_EXPORT2 getStaticClassID(void);
+
+  /**
+   * return the calendar type, "islamic-civil".
+   *
+   * @return calendar type
+   * @internal
+   */
+  virtual const char * getType() const override;
+
+ protected:
+  /**
+   * Return the day # on which the given year starts.  Days are counted
+   * from the Hijri epoch, origin 0.
+   * @internal
+   */
+  virtual int32_t yearStart(int32_t year) const override;
+
+  /**
+   * Return the day # on which the given month starts.  Days are counted
+   * from the Hijri epoch, origin 0.
+   *
+   * @param year  The hijri year
+   * @param year  The hijri month, 0-based
+   * @internal
+   */
+  virtual int32_t monthStart(int32_t year, int32_t month) const override;
 
+  /**
+   * Return the length (in days) of the given month.
+   *
+   * @param year  The hijri year
+   * @param year  The hijri month, 0-based
+   * @internal
+   */
+  virtual int32_t handleGetMonthLength(int32_t extendedYear, int32_t month) const override;
 
+  /**
+   * Return the number of days in the given Islamic year
+   * @internal
+   */
+  virtual int32_t handleGetYearLength(int32_t extendedYear) const override;
+
+  /**
+   * Override Calendar to compute several fields specific to the Islamic
+   * calendar system.  These are:
+   *
+   * <ul><li>ERA
+   * <li>YEAR
+   * <li>MONTH
+   * <li>DAY_OF_MONTH
+   * <li>DAY_OF_YEAR
+   * <li>EXTENDED_YEAR</ul>
+   * 
+   * The DAY_OF_WEEK and DOW_LOCAL fields are already set when this
+   * method is called. The getGregorianXxx() methods return Gregorian
+   * calendar equivalents for the given Julian day.
+   * @internal
+   */
+  virtual void handleComputeFields(int32_t julianDay, UErrorCode &status) override;
+};
+
+/*
+ * IslamicTBLACalendar calendar.
+ * This is a subclass of IslamicCivilCalendar. The only differences in the
+ * calendar math is it uses different epoch.
+ * This calendar is referring as "Islamic calendar, tabular (intercalary years
+ * [2,5,7,10,13,16,18,21,24,26,29] - astronomical epoch" in CLDR.
+ */
+class U_I18N_API IslamicTBLACalendar : public IslamicCivilCalendar {
+ public:
+  /**
+   * Constructs an IslamicTBLACalendar based on the current time in the default time zone
+   * with the given locale.
+   *
+   * @param aLocale  The given locale.
+   * @param success  Indicates the status of IslamicTBLACalendar object construction.
+   *                 Returns U_ZERO_ERROR if constructed successfully.
+   * @internal
+   */
+  IslamicTBLACalendar(const Locale& aLocale, UErrorCode &success);
+
+  /**
+   * Copy Constructor
+   * @internal
+   */
+  IslamicTBLACalendar(const IslamicTBLACalendar& other) = default;
+
+  /**
+   * Destructor.
+   * @internal
+   */
+  virtual ~IslamicTBLACalendar();
+
+  /**
+   * @return   The class ID for this object. All objects of a given class have the
+   *           same class ID. Objects of other classes have different class IDs.
+   * @internal
+   */
+  virtual UClassID getDynamicClassID(void) const override;
+
+  /**
+   * Return the class ID for this class. This is useful only for comparing to a return
+   * value from getDynamicClassID(). For example:
+   *
+   *      Base* polymorphic_pointer = createPolymorphicObject();
+   *      if (polymorphic_pointer->getDynamicClassID() ==
+   *          Derived::getStaticClassID()) ...
+   *
+   * @return   The class ID for all objects of this class.
+   * @internal
+   */
+  static UClassID U_EXPORT2 getStaticClassID(void);
 
+  /**
+   * return the calendar type, "islamic-tbla".
+   *
+   * @return calendar type
+   * @internal
+   */
+  virtual const char * getType() const override;
+
+  // clone
+  virtual IslamicTBLACalendar* clone() const override;
+
+ protected:
+  /**
+   * Return the epoc.
+   * @internal
+   */
+  virtual int32_t getEpoc() const override;
+};
+
+/*
+ * IslamicUmalquraCalendar
+ * This calendar is referred as "Islamic calendar, Umm al-Qura" in CLDR.
+ */
+class U_I18N_API IslamicUmalquraCalendar : public IslamicCalendar {
+ public:
+  /**
+   * Constructs an IslamicUmalquraCalendar based on the current time in the default time zone
+   * with the given locale.
+   *
+   * @param aLocale  The given locale.
+   * @param success  Indicates the status of IslamicUmalquraCalendar object construction.
+   *                 Returns U_ZERO_ERROR if constructed successfully.
+   * @internal
+   */
+  IslamicUmalquraCalendar(const Locale& aLocale, UErrorCode &success);
+
+  /**
+   * Copy Constructor
+   * @internal
+   */
+  IslamicUmalquraCalendar(const IslamicUmalquraCalendar& other) = default;
+
+  /**
+   * Destructor.
+   * @internal
+   */
+  virtual ~IslamicUmalquraCalendar();
+
+  /**
+   * @return   The class ID for this object. All objects of a given class have the
+   *           same class ID. Objects of other classes have different class IDs.
+   * @internal
+   */
+  virtual UClassID getDynamicClassID(void) const override;
+
+  /**
+   * Return the class ID for this class. This is useful only for comparing to a return
+   * value from getDynamicClassID(). For example:
+   *
+   *      Base* polymorphic_pointer = createPolymorphicObject();
+   *      if (polymorphic_pointer->getDynamicClassID() ==
+   *          Derived::getStaticClassID()) ...
+   *
+   * @return   The class ID for all objects of this class.
+   * @internal
+   */
+  static UClassID U_EXPORT2 getStaticClassID(void);
+
+  /**
+   * return the calendar type, "islamic-umalqura".
+   *
+   * @return calendar type
+   * @internal
+   */
+  virtual const char * getType() const override;
+
+  // clone
+  virtual IslamicUmalquraCalendar* clone() const override;
+
+ protected:
+  /**
+   * Return the day # on which the given year starts.  Days are counted
+   * from the Hijri epoch, origin 0.
+   * @internal
+   */
+  virtual int32_t yearStart(int32_t year) const override;
+
+  /**
+   * Return the day # on which the given month starts.  Days are counted
+   * from the Hijri epoch, origin 0.
+   *
+   * @param year  The hijri year
+   * @param year  The hijri month, 0-based
+   * @internal
+   */
+  virtual int32_t monthStart(int32_t year, int32_t month) const override;
+
+  /**
+   * Return the length (in days) of the given month.
+   *
+   * @param year  The hijri year
+   * @param year  The hijri month, 0-based
+   * @internal
+   */
+  virtual int32_t handleGetMonthLength(int32_t extendedYear, int32_t month) const override;
+
+  /**
+   * Return the number of days in the given Islamic year
+   * @internal
+   */
+  virtual int32_t handleGetYearLength(int32_t extendedYear) const override;
+
+  /**
+   * Override Calendar to compute several fields specific to the Islamic
+   * calendar system.  These are:
+   *
+   * <ul><li>ERA
+   * <li>YEAR
+   * <li>MONTH
+   * <li>DAY_OF_MONTH
+   * <li>DAY_OF_YEAR
+   * <li>EXTENDED_YEAR</ul>
+   * 
+   * The DAY_OF_WEEK and DOW_LOCAL fields are already set when this
+   * method is called. The getGregorianXxx() methods return Gregorian
+   * calendar equivalents for the given Julian day.
+   * @internal
+   */
+  virtual void handleComputeFields(int32_t julianDay, UErrorCode &status) override;
+};
+
+
+/*
+ * IslamicRGSACalendar
+ * Islamic calendar, Saudi Arabia sighting. Since the calendar depends on the
+ * sighting, it is impossible to implement by algorithm ahead of time. It is
+ * currently identical to IslamicCalendar except the getType will return
+ * "islamic-rgsa".
+ */
+class U_I18N_API IslamicRGSACalendar : public IslamicCalendar {
+ public:
+  /**
+   * Constructs an IslamicRGSACalendar based on the current time in the default time zone
+   * with the given locale.
+   *
+   * @param aLocale  The given locale.
+   * @param success  Indicates the status of IslamicRGSACalendar object construction.
+   *                 Returns U_ZERO_ERROR if constructed successfully.
+   * @internal
+   */
+  IslamicRGSACalendar(const Locale& aLocale, UErrorCode &success);
+
+  /**
+   * Copy Constructor
+   * @internal
+   */
+  IslamicRGSACalendar(const IslamicRGSACalendar& other) = default;
+
+  /**
+   * Destructor.
+   * @internal
+   */
+  virtual ~IslamicRGSACalendar();
+
+  /**
+   * @return   The class ID for this object. All objects of a given class have the
+   *           same class ID. Objects of other classes have different class IDs.
+   * @internal
+   */
+  virtual UClassID getDynamicClassID(void) const override;
+
+  /**
+   * Return the class ID for this class. This is useful only for comparing to a return
+   * value from getDynamicClassID(). For example:
+   *
+   *      Base* polymorphic_pointer = createPolymorphicObject();
+   *      if (polymorphic_pointer->getDynamicClassID() ==
+   *          Derived::getStaticClassID()) ...
+   *
+   * @return   The class ID for all objects of this class.
+   * @internal
+   */
+  static UClassID U_EXPORT2 getStaticClassID(void);
+
+  /**
+   * return the calendar type, "islamic-rgsa".
+   *
+   * @return calendar type
+   * @internal
+   */
+  virtual const char * getType() const override;
+
+  // clone
+  virtual IslamicRGSACalendar* clone() const override;
+};
+
+U_NAMESPACE_END
+
+#endif
+#endif
diff --git a/icu4c/source/i18n/iso8601cal.cpp b/icu4c/source/i18n/iso8601cal.cpp
new file mode 100644 (file)
index 0000000..1bc81fa
--- /dev/null
@@ -0,0 +1,37 @@
+// Â© 2022 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "iso8601cal.h"
+#include "unicode/gregocal.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ISO8601Calendar)
+
+ISO8601Calendar::ISO8601Calendar(const Locale& aLocale, UErrorCode& success)
+:   GregorianCalendar(aLocale, success)
+{
+    setFirstDayOfWeek(UCAL_MONDAY);
+    setMinimalDaysInFirstWeek(4);
+}
+
+ISO8601Calendar::~ISO8601Calendar()
+{
+}
+
+ISO8601Calendar* ISO8601Calendar::clone() const
+{
+    return new ISO8601Calendar(*this);
+}
+
+const char *ISO8601Calendar::getType() const
+{
+    return "iso8601";
+}
+
+U_NAMESPACE_END
+
+#endif
diff --git a/icu4c/source/i18n/iso8601cal.h b/icu4c/source/i18n/iso8601cal.h
new file mode 100644 (file)
index 0000000..48dff5a
--- /dev/null
@@ -0,0 +1,102 @@
+// Â© 2022 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+#ifndef ISO8601CAL_H
+#define ISO8601CAL_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/calendar.h"
+#include "unicode/gregocal.h"
+#include "unicode/timezone.h"
+
+U_NAMESPACE_BEGIN
+
+/**
+ * Concrete class which provides the ISO8601 calendar.
+ * <P>
+ * <code>ISO8601Calendar</code> is a subclass of <code>GregorianCalendar</code>
+ * that the first day of a week is Monday and the minimal days in the first
+ * week of a year or month is four days.
+ * <p>
+ * The ISO8601 calendar is identical to the Gregorian calendar in all respects
+ * except for the first day of week and the minimal days in the first week
+ * of a year. 
+ * @internal
+ */
+class ISO8601Calendar : public GregorianCalendar {
+ public:
+  //-------------------------------------------------------------------------
+  // Constructors...
+  //-------------------------------------------------------------------------
+
+  /**
+   * Constructs a DangiCalendar based on the current time in the default time zone
+   * with the given locale.
+   *
+   * @param aLocale  The given locale.
+   * @param success  Indicates the status of ISO8601Calendar object construction.
+   *                 Returns U_ZERO_ERROR if constructed successfully.
+   * @internal
+   */
+  ISO8601Calendar(const Locale& aLocale, UErrorCode &success);
+
+  /**
+   * Copy Constructor
+   * @internal
+   */
+  ISO8601Calendar(const ISO8601Calendar& other) = default;
+
+  /**
+   * Destructor.
+   * @internal
+   */
+  virtual ~ISO8601Calendar();
+
+  /**
+   * Clone.
+   * @internal
+   */
+  virtual ISO8601Calendar* clone() const override;
+
+  // UObject stuff
+ public: 
+  /**
+   * @return   The class ID for this object. All objects of a given class have the
+   *           same class ID. Objects of other classes have different class IDs.
+   * @internal
+   */
+  virtual UClassID getDynamicClassID(void) const override;
+
+  /**
+   * Return the class ID for this class. This is useful only for comparing to a return
+   * value from getDynamicClassID(). For example:
+   *
+   *      Base* polymorphic_pointer = createPolymorphicObject();
+   *      if (polymorphic_pointer->getDynamicClassID() ==
+   *          Derived::getStaticClassID()) ...
+   *
+   * @return   The class ID for all objects of this class.
+   * @internal
+   */
+  U_I18N_API static UClassID U_EXPORT2 getStaticClassID(void);
+
+  /**
+   * return the calendar type, "iso8601".
+   *
+   * @return calendar type
+   * @internal
+   */
+  virtual const char * getType() const override;
+
+
+ private:
+  ISO8601Calendar(); // default constructor not implemented
+};
+
+U_NAMESPACE_END
+
+#endif
+#endif
index b882b0464a9f80a7d280652128cf6586b489e853..69705c87b4e25f8b366c2873d49abb32988872d3 100644 (file)
@@ -86,6 +86,7 @@ hebrwcal.cpp
 indiancal.cpp
 inputext.cpp
 islamcal.cpp
+iso8601cal.cpp
 japancal.cpp
 listformatter.cpp
 measfmt.cpp
index d0cb8a80a2299bbb565d0dd4ad166794d4bcd96b..878dd95860aec42f468d81fe6daf9416adac1699 100644 (file)
@@ -1078,7 +1078,7 @@ group: formatting
     measfmt.o quantityformatter.o
     # dateformat
     astro.o buddhcal.o calendar.o cecal.o chnsecal.o coptccal.o dangical.o ethpccal.o
-    gregocal.o gregoimp.o hebrwcal.o indiancal.o islamcal.o japancal.o persncal.o taiwncal.o
+    gregocal.o gregoimp.o hebrwcal.o indiancal.o islamcal.o iso8601cal.o japancal.o persncal.o taiwncal.o
     erarules.o  # mostly for Japanese eras
     ucal.o
     basictz.o olsontz.o rbtz.o simpletz.o timezone.o tzrule.o tztrans.o
index 9fc46ef1d4c40a022c0d0dfc0a9546ffe853eee9..96c1ff9c80e22b26dd2ecaa7991f50e1ce535692 100644 (file)
@@ -353,6 +353,34 @@ void CalendarTest::runIndexedTest( int32_t index, UBool exec, const char* &name,
             TestTimeZoneInLocale();
           }
           break;
+#define CASE(num, NAME) \
+        case num: \
+          name = #NAME; \
+          if(exec) { \
+            logln(#NAME "---"); logln(""); \
+            NAME(); \
+          } \
+          break;
+
+        CASE(38, TestBasicConversionISO8601);
+        CASE(39, TestBasicConversionJapanese);
+        CASE(40, TestBasicConversionBuddhist);
+        CASE(41, TestBasicConversionTaiwan);
+        CASE(42, TestBasicConversionPersian);
+        CASE(43, TestBasicConversionIslamic);
+        CASE(44, TestBasicConversionIslamicTBLA);
+        CASE(45, TestBasicConversionIslamicCivil);
+        CASE(46, TestBasicConversionIslamicRGSA);
+        CASE(47, TestBasicConversionIslamicUmalqura);
+        CASE(48, TestBasicConversionHebrew);
+        CASE(49, TestBasicConversionChinese);
+        CASE(50, TestBasicConversionDangi);
+        CASE(51, TestBasicConversionIndian);
+        CASE(52, TestBasicConversionCoptic);
+        CASE(53, TestBasicConversionEthiopic);
+        CASE(54, TestBasicConversionEthiopicAmeteAlem);
+
+#undef CASE
         default: name = ""; break;
     }
 }
@@ -2390,8 +2418,8 @@ void CalendarTest::TestISO8601() {
             errln("Error: Failed to create a calendar for locale: %s", TEST_LOCALES[i]);
             continue;
         }
-        if (uprv_strcmp(cal->getType(), "gregorian") != 0) {
-            errln("Error: Gregorian calendar is not used for locale: %s", TEST_LOCALES[i]);
+        if (uprv_strcmp(cal->getType(), "iso8601") != 0) {
+            errln("Error: iso8601 calendar is not used for locale: %s", TEST_LOCALES[i]);
             continue;
         }
         for (int j = 0; TEST_DATA[j][0] != 0; j++) {
@@ -2833,8 +2861,8 @@ void CalendarTest::TestTimeZoneInLocale(void) {
         { "my-u-ca-islamic-umalqura-tz-kzala", "Asia/Almaty",                "islamic-umalqura" },
         { "lo-u-ca-islamic-tbla-tz-bmbda",     "Atlantic/Bermuda",           "islamic-tbla" },
         { "km-u-ca-islamic-civil-tz-aqplm",    "Antarctica/Palmer",          "islamic-civil" },
-        { "kk-u-ca-islamic-rgsa-tz-usanc",     "America/Anchorage",          "islamic" },
-        { "ar-u-ca-iso8601-tz-bjptn",          "Africa/Porto-Novo",          "gregorian" },
+        { "kk-u-ca-islamic-rgsa-tz-usanc",     "America/Anchorage",          "islamic-rgsa" },
+        { "ar-u-ca-iso8601-tz-bjptn",          "Africa/Porto-Novo",          "iso8601" },
         { "he-u-ca-japanese-tz-tzdar",         "Africa/Dar_es_Salaam",       "japanese" },
         { "bs-u-ca-persian-tz-etadd",          "Africa/Addis_Ababa",         "persian" },
         { "it-u-ca-roc-tz-aruaq",              "America/Argentina/San_Juan", "roc" },
@@ -2859,6 +2887,286 @@ void CalendarTest::TestTimeZoneInLocale(void) {
     }
 }
 
+void CalendarTest::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) {
+
+    UErrorCode status = U_ZERO_ERROR;
+    cal->setTime(time, status);
+    assertEquals("getType", type, cal->getType());
+
+    assertEquals("UCAL_ERA", era, cal->get(UCAL_ERA, status));
+    assertEquals("UCAL_YEAR", year, cal->get(UCAL_YEAR, status));
+    assertEquals("UCAL_MONTH", month, cal->get(UCAL_MONTH, status));
+    assertEquals("UCAL_WEEK_OF_YEAR", week_of_year, cal->get(UCAL_WEEK_OF_YEAR, status));
+    assertEquals("UCAL_WEEK_OF_MONTH", week_of_month, cal->get(UCAL_WEEK_OF_MONTH, status));
+    assertEquals("UCAL_DATE", date, cal->get(UCAL_DATE, status));
+    assertEquals("UCAL_DAY_OF_YEAR", day_of_year, cal->get(UCAL_DAY_OF_YEAR, status));
+    assertEquals("UCAL_DAY_OF_WEEK", day_of_week, cal->get(UCAL_DAY_OF_WEEK, status));
+    assertEquals("UCAL_DAY_OF_WEEK_IN_MONTH", day_of_week_in_month, cal->get(UCAL_DAY_OF_WEEK_IN_MONTH, status));
+    assertEquals("UCAL_AM_PM", am_pm, cal->get(UCAL_AM_PM, status));
+    assertEquals("UCAL_HOUR", hour, cal->get(UCAL_HOUR, status));
+    assertEquals("UCAL_HOUR_OF_DAY", hour_of_day, cal->get(UCAL_HOUR_OF_DAY, status));
+    assertEquals("UCAL_MINUTE", minute, cal->get(UCAL_MINUTE, status));
+    assertEquals("UCAL_SECOND", second, cal->get(UCAL_SECOND, status));
+    assertEquals("UCAL_MILLISECOND", millisecond, cal->get(UCAL_MILLISECOND, status));
+    assertEquals("UCAL_ZONE_OFFSET", zone_offset, cal->get(UCAL_ZONE_OFFSET, status));
+    assertEquals("UCAL_DST_OFFSET", dst_offset, cal->get(UCAL_DST_OFFSET, status));
+    assertEquals("UCAL_YEAR_WOY", year_woy, cal->get(UCAL_YEAR_WOY, status));
+    assertEquals("UCAL_DOW_LOCAL", dow_local, cal->get(UCAL_DOW_LOCAL, status));
+    assertEquals("UCAL_EXTENDED_YEAR", extended_year, cal->get(UCAL_EXTENDED_YEAR, status));
+    assertEquals("UCAL_JULIAN_DAY", julian_day, cal->get(UCAL_JULIAN_DAY, status));
+    assertEquals("UCAL_MILLISECONDS_IN_DAY", milliseconds_in_day, cal->get(UCAL_MILLISECONDS_IN_DAY, status));
+    assertEquals("UCAL_IS_LEAP_MONTH", is_leap_month, cal->get(UCAL_IS_LEAP_MONTH, status));
+}
+
+static constexpr double test_time = 1667277891323; // Nov 1, 2022 4:44:51 GMT
+
+void CalendarTest::TestBasicConversionGregorian(void) {
+    UErrorCode status = U_ZERO_ERROR;
+    LocalPointer<Calendar> cal(icu::Calendar::createInstance(
+        *TimeZone::getGMT(), Locale("en@calendar=gregorian"), status));
+    if (U_FAILURE(status)) {
+        errln("Fail: Cannot get Gregorian calendar");
+        return;
+    }
+    AsssertCalendarFieldValue(
+        cal.getAlias(), test_time, "gregorian",
+        1, 2022, 10, 45, 1, 1, 305, 3, 1, 0, 4, 4, 44, 51,
+        323, 0, 0, 2022, 3, 2022, 2459885, 17091323, 0);
+}
+void CalendarTest::TestBasicConversionISO8601(void) {
+    UErrorCode status = U_ZERO_ERROR;
+    LocalPointer<Calendar> cal(icu::Calendar::createInstance(
+        *TimeZone::getGMT(), Locale("en@calendar=iso8601"), status));
+    if (U_FAILURE(status)) {
+        errln("Fail: Cannot get ISO8601 calendar");
+        return;
+    }
+    AsssertCalendarFieldValue(
+        cal.getAlias(), test_time, "iso8601",
+        1, 2022, 10, 44, 1, 1, 305, 3, 1, 0, 4, 4, 44, 51,
+        323, 0, 0, 2022, 2, 2022, 2459885, 17091323, 0);
+}
+void CalendarTest::TestBasicConversionJapanese(void) {
+    UErrorCode status = U_ZERO_ERROR;
+    LocalPointer<Calendar> cal(icu::Calendar::createInstance(
+        *TimeZone::getGMT(), Locale("en@calendar=japanese"), status));
+    if (U_FAILURE(status)) {
+        errln("Fail: Cannot get Japanese calendar");
+        return;
+    }
+    AsssertCalendarFieldValue(
+        cal.getAlias(), test_time, "japanese",
+        236, 4, 10, 45, 1, 1, 305, 3, 1, 0, 4, 4, 44, 51,
+        323, 0, 0, 2022, 3, 2022, 2459885, 17091323, 0);
+}
+void CalendarTest::TestBasicConversionBuddhist(void) {
+    UErrorCode status = U_ZERO_ERROR;
+    LocalPointer<Calendar> cal(icu::Calendar::createInstance(
+        *TimeZone::getGMT(), Locale("en@calendar=buddhist"), status));
+    if (U_FAILURE(status)) {
+        errln("Fail: Cannot get Buddhist calendar");
+        return;
+    }
+    AsssertCalendarFieldValue(
+        cal.getAlias(), test_time, "buddhist",
+        0, 2565, 10, 45, 1, 1, 305, 3, 1, 0, 4, 4, 44, 51,
+        323, 0, 0, 2022, 3, 2022, 2459885, 17091323, 0);
+}
+void CalendarTest::TestBasicConversionTaiwan(void) {
+    UErrorCode status = U_ZERO_ERROR;
+    LocalPointer<Calendar> cal(icu::Calendar::createInstance(
+        *TimeZone::getGMT(), Locale("en@calendar=roc"), status));
+    if (U_FAILURE(status)) {
+        errln("Fail: Cannot get Taiwan calendar");
+        return;
+    }
+    AsssertCalendarFieldValue(
+        cal.getAlias(), test_time, "roc",
+        1, 111, 10, 45, 1, 1, 305, 3, 1, 0, 4, 4, 44, 51,
+        323, 0, 0, 2022, 3, 2022, 2459885, 17091323, 0);
+
+}
+void CalendarTest::TestBasicConversionPersian(void) {
+    UErrorCode status = U_ZERO_ERROR;
+    LocalPointer<Calendar> cal(icu::Calendar::createInstance(
+        *TimeZone::getGMT(), Locale("en@calendar=persian"), status));
+    if (U_FAILURE(status)) {
+        errln("Fail: Cannot get Persian calendar");
+        return;
+    }
+    AsssertCalendarFieldValue(
+        cal.getAlias(), test_time, "persian",
+        0, 1401, 7, 33, 2, 10, 226, 3, 2, 0, 4, 4, 44, 51,
+        323, 0, 0, 1401, 3, 1401, 2459885, 17091323, 0);
+}
+void CalendarTest::TestBasicConversionIslamic(void) {
+    UErrorCode status = U_ZERO_ERROR;
+    LocalPointer<Calendar> cal(icu::Calendar::createInstance(
+        *TimeZone::getGMT(), Locale("en@calendar=islamic"), status));
+    if (U_FAILURE(status)) {
+        errln("Fail: Cannot get Islamic calendar");
+        return;
+    }
+    AsssertCalendarFieldValue(
+        cal.getAlias(), test_time, "islamic",
+        0, 1444, 3, 15, 2, 7, 96, 3, 1, 0, 4, 4, 44, 51,
+        323, 0, 0, 1444, 3, 1444, 2459885, 17091323, 0);
+}
+void CalendarTest::TestBasicConversionIslamicTBLA(void) {
+    UErrorCode status = U_ZERO_ERROR;
+    LocalPointer<Calendar> cal(icu::Calendar::createInstance(
+        *TimeZone::getGMT(), Locale("en@calendar=islamic-tbla"), status));
+    if (U_FAILURE(status)) {
+        errln("Fail: Cannot get IslamicTBLA calendar");
+        return;
+    }
+    AsssertCalendarFieldValue(
+        cal.getAlias(), test_time, "islamic-tbla",
+        0, 1444, 3, 15, 2, 7, 96, 3, 1, 0, 4, 4, 44, 51,
+        323, 0, 0, 1444, 3, 1444, 2459885, 17091323, 0);
+
+}
+void CalendarTest::TestBasicConversionIslamicCivil(void) {
+    UErrorCode status = U_ZERO_ERROR;
+    LocalPointer<Calendar> cal(icu::Calendar::createInstance(
+        *TimeZone::getGMT(), Locale("en@calendar=islamic-civil"), status));
+    if (U_FAILURE(status)) {
+        errln("Fail: Cannot get IslamicCivil calendar");
+        return;
+    }
+    AsssertCalendarFieldValue(
+        cal.getAlias(), test_time, "islamic-civil",
+        0, 1444, 3, 15, 2, 6, 95, 3, 1, 0, 4, 4, 44, 51,
+        323, 0, 0, 1444, 3, 1444, 2459885, 17091323, 0);
+
+}
+void CalendarTest::TestBasicConversionIslamicRGSA(void) {
+    UErrorCode status = U_ZERO_ERROR;
+    LocalPointer<Calendar> cal(icu::Calendar::createInstance(
+        *TimeZone::getGMT(), Locale("en@calendar=islamic-rgsa"), status));
+    if (U_FAILURE(status)) {
+        errln("Fail: Cannot get IslamicRGSA calendar");
+        return;
+    }
+    AsssertCalendarFieldValue(
+        cal.getAlias(), test_time, "islamic-rgsa",
+        0, 1444, 3, 15, 2, 7, 96, 3, 1, 0, 4, 4, 44, 51,
+        323, 0, 0, 1444, 3, 1444, 2459885, 17091323, 0);
+
+}
+void CalendarTest::TestBasicConversionIslamicUmalqura(void) {
+    UErrorCode status = U_ZERO_ERROR;
+    LocalPointer<Calendar> cal(icu::Calendar::createInstance(
+        *TimeZone::getGMT(), Locale("en@calendar=islamic-umalqura"), status));
+    if (U_FAILURE(status)) {
+        errln("Fail: Cannot get IslamicUmalqura calendar");
+        return;
+    }
+    AsssertCalendarFieldValue(
+        cal.getAlias(), test_time, "islamic-umalqura",
+        0, 1444, 3, 15, 2, 7, 95, 3, 1, 0, 4, 4, 44, 51,
+        323, 0, 0, 1444, 3, 1444, 2459885, 17091323, 0);
+}
+void CalendarTest::TestBasicConversionHebrew(void) {
+    UErrorCode status = U_ZERO_ERROR;
+    LocalPointer<Calendar> cal(icu::Calendar::createInstance(
+        *TimeZone::getGMT(), Locale("en@calendar=hebrew"), status));
+    if (U_FAILURE(status)) {
+        errln("Fail: Cannot get Hebrew calendar");
+        return;
+    }
+    AsssertCalendarFieldValue(
+        cal.getAlias(), test_time, "hebrew",
+        0, 5783, 1, 6, 2, 7, 37, 3, 1, 0, 4, 4, 44, 51,
+        323, 0, 0, 5783, 3, 5783, 2459885, 17091323, 0);
+}
+void CalendarTest::TestBasicConversionChinese(void) {
+    UErrorCode status = U_ZERO_ERROR;
+    LocalPointer<Calendar> cal(icu::Calendar::createInstance(
+        *TimeZone::getGMT(), Locale("en@calendar=chinese"), status));
+    if (U_FAILURE(status)) {
+        errln("Fail: Cannot get Chinese calendar");
+        return;
+    }
+    AsssertCalendarFieldValue(
+        cal.getAlias(), test_time, "chinese",
+        78, 39, 9, 40, 2, 8, 274, 3, 2, 0, 4, 4, 44, 51,
+        323, 0, 0, 4659, 3, 4659, 2459885, 17091323, 0);
+}
+void CalendarTest::TestBasicConversionDangi(void) {
+    UErrorCode status = U_ZERO_ERROR;
+    LocalPointer<Calendar> cal(icu::Calendar::createInstance(
+        *TimeZone::getGMT(), Locale("en@calendar=dangi"), status));
+    if (U_FAILURE(status)) {
+        errln("Fail: Cannot get Dangi calendar");
+        return;
+    }
+    AsssertCalendarFieldValue(
+        cal.getAlias(), test_time, "dangi",
+        78, 39, 9, 40, 2, 8, 274, 3, 2, 0, 4, 4, 44, 51,
+        323, 0, 0, 4355, 3, 4355, 2459885, 17091323, 0);
+}
+void CalendarTest::TestBasicConversionIndian(void) {
+    UErrorCode status = U_ZERO_ERROR;
+    LocalPointer<Calendar> cal(icu::Calendar::createInstance(
+        *TimeZone::getGMT(), Locale("en@calendar=indian"), status));
+    if (U_FAILURE(status)) {
+        errln("Fail: Cannot get Indian calendar");
+        return;
+    }
+    AsssertCalendarFieldValue(
+        cal.getAlias(), test_time, "indian",
+        0, 1944, 7, 33, 2, 10, 225, 3, 2, 0, 4, 4, 44, 51,
+        323, 0, 0, 1944, 3, 1944, 2459885, 17091323, 0);
+}
+void CalendarTest::TestBasicConversionCoptic(void) {
+    UErrorCode status = U_ZERO_ERROR;
+    LocalPointer<Calendar> cal(icu::Calendar::createInstance(
+        *TimeZone::getGMT(), Locale("en@calendar=coptic"), status));
+    if (U_FAILURE(status)) {
+        errln("Fail: Cannot get Coptic calendar");
+        return;
+    }
+    AsssertCalendarFieldValue(
+        cal.getAlias(), test_time, "coptic",
+        1, 1739, 1, 8, 4, 22, 52, 3, 4, 0, 4, 4, 44, 51,
+        323, 0, 0, 1739, 3, 1739, 2459885, 17091323, 0);
+}
+void CalendarTest::TestBasicConversionEthiopic(void) {
+    UErrorCode status = U_ZERO_ERROR;
+    LocalPointer<Calendar> cal(icu::Calendar::createInstance(
+        *TimeZone::getGMT(), Locale("en@calendar=ethiopic"), status));
+    if (U_FAILURE(status)) {
+        errln("Fail: Cannot get Ethiopic calendar");
+        return;
+    }
+    AsssertCalendarFieldValue(
+        cal.getAlias(), test_time, "ethiopic",
+        1, 2015, 1, 8, 4, 22, 52, 3, 4, 0, 4, 4, 44, 51,
+        323, 0, 0, 2015, 3, 2015, 2459885, 17091323, 0);
+}
+void CalendarTest::TestBasicConversionEthiopicAmeteAlem(void) {
+    UErrorCode status = U_ZERO_ERROR;
+    LocalPointer<Calendar> cal(icu::Calendar::createInstance(
+        *TimeZone::getGMT(), Locale("en@calendar=ethiopic-amete-alem"), status));
+    if (U_FAILURE(status)) {
+        errln("Fail: Cannot get EthiopicAmeteAlem calendar");
+        return;
+    }
+    AsssertCalendarFieldValue(
+        cal.getAlias(), test_time, "ethiopic-amete-alem",
+        0, 7515, 1, 8, 4, 22, 52, 3, 4, 0, 4, 4, 44, 51,
+        323, 0, 0, 2015, 3, 2015, 2459885, 17091323, 0);
+}
+
+
 void CalendarTest::setAndTestCalendar(Calendar* cal, int32_t initMonth, int32_t initDay, int32_t initYear, UErrorCode& status) {
         cal->clear();
         cal->setLenient(false);
index 7f14c89b1510b65961a2fe24976180281066a51e..55225ac828d5c324f03140a6e6625d1c06b11bbc 100644 (file)
@@ -257,6 +257,34 @@ public: // package
     void TestAddAcrossZoneTransition(void);
 
     void TestChineseCalendarMapping(void);
+
+    void TestBasicConversionGregorian(void);
+    void TestBasicConversionISO8601(void);
+    void TestBasicConversionJapanese(void);
+    void TestBasicConversionBuddhist(void);
+    void TestBasicConversionTaiwan(void);
+    void TestBasicConversionPersian(void);
+    void TestBasicConversionIslamic(void);
+    void TestBasicConversionIslamicTBLA(void);
+    void TestBasicConversionIslamicCivil(void);
+    void TestBasicConversionIslamicRGSA(void);
+    void TestBasicConversionIslamicUmalqura(void);
+    void TestBasicConversionHebrew(void);
+    void TestBasicConversionChinese(void);
+    void TestBasicConversionDangi(void);
+    void TestBasicConversionIndian(void);
+    void TestBasicConversionCoptic(void);
+    void TestBasicConversionEthiopic(void);
+    void TestBasicConversionEthiopicAmeteAlem(void);
+
+    void 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);
 };
 
 #endif /* #if !UCONFIG_NO_FORMATTING */
index 317ae437ba29bf04d71b724fd838faa40783cc05..e29c7a16f362b77ff30d1d48d43fafc5ad97ab2b 100644 (file)
@@ -3477,8 +3477,8 @@ void DateFormatTest::TestTimeZoneInLocale()
         { "my-u-ca-islamic-umalqura-tz-kzala", "Asia/Almaty",                "islamic-umalqura" },
         { "lo-u-ca-islamic-tbla-tz-bmbda",     "Atlantic/Bermuda",           "islamic-tbla" },
         { "km-u-ca-islamic-civil-tz-aqplm",    "Antarctica/Palmer",          "islamic-civil" },
-        { "kk-u-ca-islamic-rgsa-tz-usanc",     "America/Anchorage",          "islamic" },
-        { "ar-u-ca-iso8601-tz-bjptn",          "Africa/Porto-Novo",          "gregorian" },
+        { "kk-u-ca-islamic-rgsa-tz-usanc",     "America/Anchorage",          "islamic-rgsa" },
+        { "ar-u-ca-iso8601-tz-bjptn",          "Africa/Porto-Novo",          "iso8601" },
         { "he-u-ca-japanese-tz-tzdar",         "Africa/Dar_es_Salaam",       "japanese" },
         { "bs-u-ca-persian-tz-etadd",          "Africa/Addis_Ababa",         "persian" },
         { "it-u-ca-roc-tz-aruaq",              "America/Argentina/San_Juan", "roc" },