+ * TaiwanCalendar
is a subclass of GregorianCalendar
+ * that numbers years since 1912
+ *
+ * The Taiwan calendar is identical to the Gregorian calendar in all respects + * except for the year and era. Years are numbered since 1912 AD (Gregorian), + * so that 1912 AD (Gregorian) is equivalent to 1 MINGUO (Minguo Era) and 1998 AD is 87 MINGUO. + *
+ * The Taiwan Calendar has only one allowable era: MINGUO
. If the
+ * calendar is not in lenient mode (see setLenient
), dates before
+ * 1/1/1 MINGUO are rejected as an illegal argument.
+ *
+ * @internal
+ */
+class TaiwanCalendar : public GregorianCalendar {
+public:
+
+ /**
+ * Useful constants for TaiwanCalendar. Only one Era.
+ * @internal
+ */
+ enum EEras {
+ MINGUO
+ };
+
+ /**
+ * Constructs a TaiwanCalendar 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 TaiwanCalendar object construction.
+ * Returns U_ZERO_ERROR if constructed successfully.
+ * @internal
+ */
+ TaiwanCalendar(const Locale& aLocale, UErrorCode& success);
+
+
+ /**
+ * Destructor
+ * @internal
+ */
+ virtual ~TaiwanCalendar();
+
+ /**
+ * Copy constructor
+ * @param source the object to be copied.
+ * @internal
+ */
+ TaiwanCalendar(const TaiwanCalendar& source);
+
+ /**
+ * Default assignment operator
+ * @param right the object to be copied.
+ * @internal
+ */
+ TaiwanCalendar& operator=(const TaiwanCalendar& right);
+
+ /**
+ * Create and return a polymorphic copy of this calendar.
+ * @return return a polymorphic copy of this calendar.
+ * @internal
+ */
+ virtual Calendar* clone(void) const;
+
+public:
+ /**
+ * 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;
+
+ /**
+ * 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, "Taiwan".
+ *
+ * @return calendar type
+ * @internal
+ */
+ virtual const char * getType() const;
+
+ /**
+ * (Overrides Calendar) UDate Arithmetic function. Adds the specified (signed) amount
+ * of time to the given time field, based on the calendar's rules. For more
+ * information, see the documentation for Calendar::add().
+ *
+ * @param field The time field.
+ * @param amount The amount of date or time to be added to the field.
+ * @param status Output param set to success/failure code on exit. If any value
+ * previously set in the time field is invalid, this will be set to
+ * an error status.
+ * @draft ICU 2.6
+ */
+ virtual void add(UCalendarDateFields field, int32_t amount, UErrorCode& status);
+
+ /**
+ * Gets the maximum value for the given time field. e.g. for DAY_OF_MONTH,
+ * 31.
+ *
+ * @param field The given time field.
+ * @return The maximum value for the given time field.
+ * @draft ICU 2.6
+ */
+ int32_t getMaximum(UCalendarDateFields field) const;
+
+ /**
+ * Gets the lowest maximum value for the given field if varies. Otherwise same as
+ * getMaximum(). e.g., for Gregorian DAY_OF_MONTH, 28.
+ *
+ * @param field The given time field.
+ * @return The lowest maximum value for the given time field.
+ * @draft ICU 2.6
+ */
+ int32_t getLeastMaximum(UCalendarDateFields field) const;
+
+ /**
+ * @deprecated ICU 2.6 use UCalendarDateFields instead of EDateFields
+ */
+ inline virtual int32_t getMaximum(EDateFields field) const { return getMaximum((UCalendarDateFields)field); }
+ /**
+ * @deprecated ICU 2.6 use UCalendarDateFields instead of EDateFields
+ */
+ inline virtual int32_t getLeastMaximum(EDateFields field) const { return getLeastMaximum((UCalendarDateFields)field); }
+ /**
+ * @deprecated ICU 2.6 use UCalendarDateFields instead of EDateFields
+ */
+ inline virtual void add(EDateFields field, int32_t amount, UErrorCode& status) { add((UCalendarDateFields)field, amount, status); }
+
+private:
+ TaiwanCalendar(); // default constructor not implemented
+
+ protected:
+ /**
+ * Return the extended year defined by the current fields. This will
+ * use the UCAL_EXTENDED_YEAR field or the UCAL_YEAR and supra-year fields (such
+ * as UCAL_ERA) specific to the calendar system, depending on which set of
+ * fields is newer.
+ * @return the extended year
+ * @internal
+ */
+ virtual int32_t handleGetExtendedYear();
+ /**
+ * Subclasses may override this method to compute several fields
+ * specific to each calendar system.
+ * @internal
+ */
+ virtual void handleComputeFields(int32_t julianDay, UErrorCode& status);
+ /**
+ * Subclass API for defining limits of different types.
+ * @param field one of the field numbers
+ * @param limitType one of MINIMUM
, GREATEST_MINIMUM
,
+ * LEAST_MAXIMUM
, or MAXIMUM
+ * @internal
+ */
+ virtual int32_t handleGetLimit(UCalendarDateFields field, ELimitType limitType) const;
+ /**
+ * Return the Julian day number of day before the first day of the
+ * given month in the given extended year. Subclasses should override
+ * this method to implement their calendar system.
+ * @param eyear the extended year
+ * @param month the zero-based month, or 0 if useMonth is false
+ * @param useMonth if false, compute the day before the first day of
+ * the given year, otherwise, compute the day before the first day of
+ * the given month
+ * @param return the Julian day number of the day before the first
+ * day of the given month and year
+ * @internal
+ */
+ virtual int32_t handleComputeMonthStart(int32_t eyear, int32_t month,
+ UBool useMonth) const;
+
+ /**
+ * month length of current month
+ * @internal
+ */
+ virtual int32_t monthLength(int32_t month) const;
+ /**
+ * month length of month
+ * @internal
+ */
+ virtual int32_t monthLength(int32_t month, int32_t year) const;
+
+ /**
+ * month length of current month
+ * @internal
+ */
+ int32_t getGregorianYear(UErrorCode& status) const;
+
+ /**
+ * Calculate the era for internal computation
+ * @internal
+ */
+ virtual int32_t internalGetEra() const;
+
+ /**
+ * Returns TRUE because the Taiwan Calendar does have a default century
+ * @internal
+ */
+ virtual UBool haveDefaultCentury() const;
+
+ /**
+ * Returns the date of the start of the default century
+ * @return start of century - in milliseconds since epoch, 1970
+ * @internal
+ */
+ virtual UDate defaultCenturyStart() const;
+
+ /**
+ * Returns the year in which the default century begins
+ * @internal
+ */
+ virtual int32_t defaultCenturyStartYear() const;
+
+ private: // default century stuff.
+ /**
+ * The system maintains a static default century start date. This is initialized
+ * the first time it is used. Before then, it is set to SYSTEM_DEFAULT_CENTURY to
+ * indicate an uninitialized state. Once the system default century date and year
+ * are set, they do not change.
+ */
+ static UDate fgSystemDefaultCenturyStart;
+
+ /**
+ * See documentation for systemDefaultCenturyStart.
+ */
+ static int32_t fgSystemDefaultCenturyStartYear;
+
+ /**
+ * Default value that indicates the defaultCenturyStartYear is unitialized
+ */
+ static const int32_t fgSystemDefaultCenturyYear;
+
+ /**
+ * start of default century, as a date
+ */
+ static const UDate fgSystemDefaultCentury;
+
+ /**
+ * Returns the beginning date of the 100-year window that dates
+ * with 2-digit years are considered to fall within.
+ */
+ UDate internalGetDefaultCenturyStart(void) const;
+
+ /**
+ * Returns the first year of the 100-year window that dates with
+ * 2-digit years are considered to fall within.
+ */
+ int32_t internalGetDefaultCenturyStartYear(void) const;
+
+ /**
+ * Initializes the 100-year window that dates with 2-digit years
+ * are considered to fall within so that its start date is 80 years
+ * before the current time.
+ */
+ static void initializeSystemDefaultCentury(void);
+};
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _TAIWNCAL
+//eof
+
diff --git a/icu4c/source/test/intltest/incaltst.cpp b/icu4c/source/test/intltest/incaltst.cpp
index bbaa139b050..b843012da11 100644
--- a/icu4c/source/test/intltest/incaltst.cpp
+++ b/icu4c/source/test/intltest/incaltst.cpp
@@ -77,6 +77,8 @@ void IntlCalendarTest::runIndexedTest( int32_t index, UBool exec, const char* &n
CASE(6,TestJapanese3860);
CASE(7,TestPersian);
CASE(8,TestPersianFormat);
+ CASE(9,TestTaiwan);
+ CASE(10,TestTaiwanFormat);
default: name = ""; break;
}
}
@@ -293,6 +295,52 @@ void IntlCalendarTest::TestBuddhist() {
delete cal;
}
+
+/**
+ * Verify that TaiWanCalendar shifts years to Minguo Era but otherwise
+ * behaves like GregorianCalendar.
+ */
+void IntlCalendarTest::TestTaiwan() {
+ // MG 1 == 1912 AD
+ UDate timeA = Calendar::getNow();
+
+ int32_t data[] = {
+ 0, // B. era [928479600000]
+ 1, // B. year
+ 1912, // G. year
+ UCAL_JUNE, // month
+ 4, // day
+
+ 0, // B. era [-79204842000000]
+ 3, // B. year
+ 1914, // G. year
+ UCAL_FEBRUARY, // month
+ 12, // day
+
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1
+ };
+ Calendar *cal;
+ UErrorCode status = U_ZERO_ERROR;
+ cal = Calendar::createInstance("en_US@calendar=taiwan", status);
+ CHECK(status, UnicodeString("Creating en_US@calendar=taiwan calendar"));
+
+ // Sanity check the calendar
+ UDate timeB = Calendar::getNow();
+ UDate timeCal = cal->getTime(status);
+
+ if(!(timeA <= timeCal) || !(timeCal <= timeB)) {
+ errln((UnicodeString)"Error: Calendar time " + timeCal +
+ " is not within sampled times [" + timeA + " to " + timeB + "]!");
+ }
+ // end sanity check
+
+
+ quasiGregorianTest(*cal,Locale("en_US"),data);
+ delete cal;
+}
+
+
+
/**
* Verify that JapaneseCalendar shifts years to Japanese Eras but otherwise
* behaves like GregorianCalendar.
@@ -342,6 +390,8 @@ void IntlCalendarTest::TestJapanese() {
delete cal;
}
+
+
void IntlCalendarTest::TestBuddhistFormat() {
UErrorCode status = U_ZERO_ERROR;
@@ -420,6 +470,87 @@ void IntlCalendarTest::TestBuddhistFormat() {
}
+void IntlCalendarTest::TestTaiwanFormat() {
+// TODO: need some more data
+#if 0
+ UErrorCode status = U_ZERO_ERROR;
+
+ // Test simple parse/format with adopt
+
+ // First, a contrived english test..
+ UDate aDate = 999932400000.0;
+ SimpleDateFormat *fmt = new SimpleDateFormat(UnicodeString("MMMM d, yyyy G"), Locale("en_US@calendar=buddhist"), status);
+ CHECK(status, "creating date format instance");
+ SimpleDateFormat *fmt2 = new SimpleDateFormat(UnicodeString("MMMM d, yyyy G"), Locale("en_US@calendar=gregorian"), status);
+ CHECK(status, "creating gregorian date format instance");
+ if(!fmt) {
+ errln("Coudln't create en_US instance");
+ } else {
+ UnicodeString str;
+ fmt2->format(aDate, str);
+ logln(UnicodeString() + "Test Date: " + str);
+ str.remove();
+ fmt->format(aDate, str);
+ logln(UnicodeString() + "as Buddhist Calendar: " + escape(str));
+ UnicodeString expected("September 8, 2544 BE");
+ if(str != expected) {
+ errln("Expected " + escape(expected) + " but got " + escape(str));
+ }
+ UDate otherDate = fmt->parse(expected, status);
+ if(otherDate != aDate) {
+ UnicodeString str3;
+ fmt->format(otherDate, str3);
+ errln("Parse incorrect of " + escape(expected) + " - wanted " + aDate + " but got " + otherDate + ", " + escape(str3));
+ } else {
+ logln("Parsed OK: " + expected);
+ }
+ delete fmt;
+ }
+ delete fmt2;
+
+ CHECK(status, "Error occured testing Buddhist Calendar in English ");
+
+ status = U_ZERO_ERROR;
+ // Now, try in Thai
+ {
+ UnicodeString expect = CharsToUnicodeString("\\u0E27\\u0E31\\u0E19\\u0E40\\u0E2A\\u0E32\\u0E23\\u0E4C\\u0E17\\u0E35\\u0E48"
+ " 8 \\u0E01\\u0E31\\u0e19\\u0e22\\u0e32\\u0e22\\u0e19 \\u0e1e.\\u0e28. 2544");
+ UDate expectDate = 999932400000.0;
+ Locale loc("th_TH_TRADITIONAL"); // legacy
+
+ simpleTest(loc, expect, expectDate, status);
+ }
+ status = U_ZERO_ERROR;
+ {
+ UnicodeString expect = CharsToUnicodeString("\\u0E27\\u0E31\\u0E19\\u0E40\\u0E2A\\u0E32\\u0E23\\u0E4C\\u0E17\\u0E35\\u0E48"
+ " 8 \\u0E01\\u0E31\\u0e19\\u0e22\\u0e32\\u0e22\\u0e19 \\u0e1e.\\u0e28. 2544");
+ UDate expectDate = 999932400000.0;
+ Locale loc("th_TH@calendar=buddhist");
+
+ simpleTest(loc, expect, expectDate, status);
+ }
+ status = U_ZERO_ERROR;
+ {
+ UnicodeString expect = CharsToUnicodeString("\\u0E27\\u0E31\\u0E19\\u0E40\\u0E2A\\u0E32\\u0E23\\u0E4C\\u0E17\\u0E35\\u0E48"
+ " 8 \\u0E01\\u0E31\\u0e19\\u0e22\\u0e32\\u0e22\\u0e19 \\u0e04.\\u0e28. 2001");
+ UDate expectDate = 999932400000.0;
+ Locale loc("th_TH@calendar=gregorian");
+
+ simpleTest(loc, expect, expectDate, status);
+ }
+ status = U_ZERO_ERROR;
+ {
+ UnicodeString expect = CharsToUnicodeString("\\u0E27\\u0E31\\u0E19\\u0E40\\u0E2A\\u0E32\\u0E23\\u0E4C\\u0E17\\u0E35\\u0E48"
+ " 8 \\u0E01\\u0E31\\u0e19\\u0e22\\u0e32\\u0e22\\u0e19 \\u0e04.\\u0e28. 2001");
+ UDate expectDate = 999932400000.0;
+ Locale loc("th_TH_TRADITIONAL@calendar=gregorian");
+
+ simpleTest(loc, expect, expectDate, status);
+ }
+#endif
+}
+
+
void IntlCalendarTest::TestJapaneseFormat() {
Calendar *cal;
UErrorCode status = U_ZERO_ERROR;
diff --git a/icu4c/source/test/intltest/incaltst.h b/icu4c/source/test/intltest/incaltst.h
index 81fd574e4b1..5319ae85c6d 100644
--- a/icu4c/source/test/intltest/incaltst.h
+++ b/icu4c/source/test/intltest/incaltst.h
@@ -27,6 +27,9 @@ public:
void TestBuddhist(void);
void TestBuddhistFormat(void);
+ void TestTaiwan(void);
+ void TestTaiwanFormat(void);
+
void TestJapanese(void);
void TestJapaneseFormat(void);
void TestJapanese3860(void);