1 // © 2016 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html 3 /* 4 ***************************************************************************** 5 * Copyright (C) 2007-2013, International Business Machines Corporation 6 * and others. All Rights Reserved. 7 ***************************************************************************** 8 * 9 * File CHNSECAL.H 10 * 11 * Modification History: 12 * 13 * Date Name Description 14 * 9/18/2007 ajmacher ported from java ChineseCalendar 15 ***************************************************************************** 16 */ 17 18 #ifndef CHNSECAL_H 19 #define CHNSECAL_H 20 21 #include "unicode/utypes.h" 22 23 #if !UCONFIG_NO_FORMATTING 24 25 #include "unicode/calendar.h" 26 #include "unicode/timezone.h" 27 28 U_NAMESPACE_BEGIN 29 30 class CalendarCache; 31 /** 32 * <code>ChineseCalendar</code> is a concrete subclass of {@link Calendar} 33 * that implements a traditional Chinese calendar. The traditional Chinese 34 * calendar is a lunisolar calendar: Each month starts on a new moon, and 35 * the months are numbered according to solar events, specifically, to 36 * guarantee that month 11 always contains the winter solstice. In order 37 * to accomplish this, leap months are inserted in certain years. Leap 38 * months are numbered the same as the month they follow. The decision of 39 * which month is a leap month depends on the relative movements of the sun 40 * and moon. 41 * 42 * <p>This class defines one addition field beyond those defined by 43 * <code>Calendar</code>: The <code>IS_LEAP_MONTH</code> field takes the 44 * value of 0 for normal months, or 1 for leap months. 45 * 46 * <p>All astronomical computations are performed with respect to a time 47 * zone of GMT+8:00 and a longitude of 120 degrees east. Although some 48 * calendars implement a historically more accurate convention of using 49 * Beijing's local longitude (116 degrees 25 minutes east) and time zone 50 * (GMT+7:45:40) for dates before 1929, we do not implement this here. 51 * 52 * <p>Years are counted in two different ways in the Chinese calendar. The 53 * first method is by sequential numbering from the 61st year of the reign 54 * of Huang Di, 2637 BCE, which is designated year 1 on the Chinese 55 * calendar. The second method uses 60-year cycles from the same starting 56 * point, which is designated year 1 of cycle 1. In this class, the 57 * <code>EXTENDED_YEAR</code> field contains the sequential year count. 58 * The <code>ERA</code> field contains the cycle number, and the 59 * <code>YEAR</code> field contains the year of the cycle, a value between 60 * 1 and 60. 61 * 62 * <p>There is some variation in what is considered the starting point of 63 * the calendar, with some sources starting in the first year of the reign 64 * of Huang Di, rather than the 61st. This gives continuous year numbers 65 * 60 years greater and cycle numbers one greater than what this class 66 * implements. 67 * 68 * <p>Because <code>ChineseCalendar</code> defines an additional field and 69 * redefines the way the <code>ERA</code> field is used, it requires a new 70 * format class, <code>ChineseDateFormat</code>. As always, use the 71 * methods <code>DateFormat.getXxxInstance(Calendar cal,...)</code> to 72 * obtain a formatter for this calendar. 73 * 74 * <p>References:<ul> 75 * 76 * <li>Dershowitz and Reingold, <i>Calendrical Calculations</i>, 77 * Cambridge University Press, 1997</li> 78 * 79 * <li>The <a href="http://www.tondering.dk/claus/calendar.html"> 80 * Calendar FAQ</a></li> 81 * 82 * </ul> 83 * 84 * <p> 85 * This class should only be subclassed to implement variants of the Chinese lunar calendar.</p> 86 * <p> 87 * ChineseCalendar usually should be instantiated using 88 * {@link com.ibm.icu.util.Calendar#getInstance(ULocale)} passing in a <code>ULocale</code> 89 * with the tag <code>"@calendar=chinese"</code>.</p> 90 * 91 * @see com.ibm.icu.text.ChineseDateFormat 92 * @see com.ibm.icu.util.Calendar 93 * @author Alan Liu 94 * @internal 95 */ 96 class U_I18N_API ChineseCalendar : public Calendar { 97 public: 98 //------------------------------------------------------------------------- 99 // Constructors... 100 //------------------------------------------------------------------------- 101 102 /** 103 * Constructs a ChineseCalendar based on the current time in the default time zone 104 * with the given locale. 105 * 106 * @param aLocale The given locale. 107 * @param success Indicates the status of ChineseCalendar object construction. 108 * Returns U_ZERO_ERROR if constructed successfully. 109 * @internal 110 */ 111 ChineseCalendar(const Locale& aLocale, UErrorCode &success); 112 113 /** 114 * Returns true if the date is in a leap year. 115 * 116 * @param status ICU Error Code 117 * @return True if the date in the fields is in a Temporal proposal 118 * defined leap year. False otherwise. 119 */ 120 virtual bool inTemporalLeapYear(UErrorCode &status) const override; 121 122 /** 123 * Gets The Temporal monthCode value corresponding to the month for the date. 124 * The value is a string identifier that starts with the literal grapheme 125 * "M" followed by two graphemes representing the zero-padded month number 126 * of the current month in a normal (non-leap) year and suffixed by an 127 * optional literal grapheme "L" if this is a leap month in a lunisolar 128 * calendar. For Chinese calendars (including Dangi), the values are 129 * "M01" .. "M12" for non-leap year, and "M01" .. "M12" with one of 130 * "M01L" .. "M12L" for leap year. 131 * 132 * @param status ICU Error Code 133 * @return One of 24 possible strings in 134 * {"M01" .. "M12", "M01L" .. "M12L"}. 135 * @draft ICU 73 136 */ 137 virtual const char* getTemporalMonthCode(UErrorCode &status) const override; 138 139 /** 140 * Sets The Temporal monthCode which is a string identifier that starts 141 * with the literal grapheme "M" followed by two graphemes representing 142 * the zero-padded month number of the current month in a normal 143 * (non-leap) year and suffixed by an optional literal grapheme "L" if this 144 * is a leap month in a lunisolar calendar. For Chinese calendars, the values 145 * are "M01" .. "M12" for non-leap years, and "M01" .. "M12" plus one in 146 * "M01L" .. "M12L" for leap year. 147 * 148 * @param temporalMonth The value to be set for temporal monthCode. One of 149 * 24 possible strings in {"M01" .. "M12", "M01L" .. "M12L"}. 150 * @param status ICU Error Code 151 * 152 * @draft ICU 73 153 */ 154 virtual void setTemporalMonthCode(const char* code, UErrorCode& status) override; 155 156 public: 157 /** 158 * Copy Constructor 159 * @internal 160 */ 161 ChineseCalendar(const ChineseCalendar& other); 162 163 /** 164 * Destructor. 165 * @internal 166 */ 167 virtual ~ChineseCalendar(); 168 169 // clone 170 virtual ChineseCalendar* clone() const override; 171 172 private: 173 174 //------------------------------------------------------------------------- 175 // Internal data.... 176 //------------------------------------------------------------------------- 177 178 // There is a leap month between the Winter Solstice before and after the 179 // current date.This is different from leap year because in some year, such as 180 // 1813 and 2033, the leap month is after the Winter Solstice of that year. So 181 // this value could be false for a date prior to the Winter Solstice of that 182 // year but that year still has a leap month and therefor is a leap year. 183 UBool hasLeapMonthBetweenWinterSolstices; 184 185 //---------------------------------------------------------------------- 186 // Calendar framework 187 //---------------------------------------------------------------------- 188 189 protected: 190 virtual int32_t handleGetLimit(UCalendarDateFields field, ELimitType limitType) const override; 191 virtual int32_t handleGetMonthLength(int32_t extendedYear, int32_t month, UErrorCode& status) const override; 192 virtual int64_t handleComputeMonthStart(int32_t eyear, int32_t month, UBool useMonth, UErrorCode& status) const override; 193 virtual int32_t handleGetExtendedYear(UErrorCode& status) override; 194 virtual void handleComputeFields(int32_t julianDay, UErrorCode &status) override; 195 virtual const UFieldResolutionTable* getFieldResolutionTable() const override; 196 197 public: 198 virtual void add(UCalendarDateFields field, int32_t amount, UErrorCode &status) override; 199 virtual void add(EDateFields field, int32_t amount, UErrorCode &status) override; 200 virtual void roll(UCalendarDateFields field, int32_t amount, UErrorCode &status) override; 201 virtual void roll(EDateFields field, int32_t amount, UErrorCode &status) override; 202 203 /** 204 * @return The related Gregorian year; will be obtained by modifying the value 205 * obtained by get from UCAL_EXTENDED_YEAR field 206 * @internal 207 */ 208 virtual int32_t getRelatedYear(UErrorCode &status) const override; 209 210 /** 211 * @param year The related Gregorian year to set; will be modified as necessary then 212 * set in UCAL_EXTENDED_YEAR field 213 * @internal 214 */ 215 virtual void setRelatedYear(int32_t year) override; 216 217 //---------------------------------------------------------------------- 218 // Internal methods & astronomical calculations 219 //---------------------------------------------------------------------- 220 221 private: 222 223 static const UFieldResolutionTable CHINESE_DATE_PRECEDENCE[]; 224 225 virtual void offsetMonth(int32_t newMoon, int32_t dom, int32_t delta, UErrorCode& status); 226 227 // UObject stuff 228 public: 229 /** 230 * @return The class ID for this object. All objects of a given class have the 231 * same class ID. Objects of other classes have different class IDs. 232 * @internal 233 */ 234 virtual UClassID getDynamicClassID() const override; 235 236 /** 237 * Return the class ID for this class. This is useful only for comparing to a return 238 * value from getDynamicClassID(). For example: 239 * 240 * Base* polymorphic_pointer = createPolymorphicObject(); 241 * if (polymorphic_pointer->getDynamicClassID() == 242 * Derived::getStaticClassID()) ... 243 * 244 * @return The class ID for all objects of this class. 245 * @internal 246 */ 247 static UClassID U_EXPORT2 getStaticClassID(); 248 249 /** 250 * return the calendar type, "chinese". 251 * 252 * @return calendar type 253 * @internal 254 */ 255 virtual const char * getType() const override; 256 257 struct Setting { 258 int32_t epochYear; 259 const TimeZone* zoneAstroCalc; 260 CalendarCache** winterSolsticeCache; 261 CalendarCache** newYearCache; 262 }; 263 protected: 264 virtual Setting getSetting(UErrorCode& status) const; 265 virtual int32_t internalGetMonth(int32_t defaultValue, UErrorCode& status) const override; 266 267 virtual int32_t internalGetMonth(UErrorCode& status) const override; 268 269 protected: 270 271 DECLARE_OVERRIDE_SYSTEM_DEFAULT_CENTURY 272 273 private: // default century stuff. 274 275 ChineseCalendar() = delete; // default constructor not implemented 276 277 #ifdef __CalendarTest__ 278 friend void CalendarTest::TestChineseCalendarComputeMonthStart(); 279 #endif 280 }; 281 282 U_NAMESPACE_END 283 284 #endif 285 #endif 286