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 /** 31 * <code>ChineseCalendar</code> is a concrete subclass of {@link Calendar} 32 * that implements a traditional Chinese calendar. The traditional Chinese 33 * calendar is a lunisolar calendar: Each month starts on a new moon, and 34 * the months are numbered according to solar events, specifically, to 35 * guarantee that month 11 always contains the winter solstice. In order 36 * to accomplish this, leap months are inserted in certain years. Leap 37 * months are numbered the same as the month they follow. The decision of 38 * which month is a leap month depends on the relative movements of the sun 39 * and moon. 40 * 41 * <p>This class defines one addition field beyond those defined by 42 * <code>Calendar</code>: The <code>IS_LEAP_MONTH</code> field takes the 43 * value of 0 for normal months, or 1 for leap months. 44 * 45 * <p>All astronomical computations are performed with respect to a time 46 * zone of GMT+8:00 and a longitude of 120 degrees east. Although some 47 * calendars implement a historically more accurate convention of using 48 * Beijing's local longitude (116 degrees 25 minutes east) and time zone 49 * (GMT+7:45:40) for dates before 1929, we do not implement this here. 50 * 51 * <p>Years are counted in two different ways in the Chinese calendar. The 52 * first method is by sequential numbering from the 61st year of the reign 53 * of Huang Di, 2637 BCE, which is designated year 1 on the Chinese 54 * calendar. The second method uses 60-year cycles from the same starting 55 * point, which is designated year 1 of cycle 1. In this class, the 56 * <code>EXTENDED_YEAR</code> field contains the sequential year count. 57 * The <code>ERA</code> field contains the cycle number, and the 58 * <code>YEAR</code> field contains the year of the cycle, a value between 59 * 1 and 60. 60 * 61 * <p>There is some variation in what is considered the starting point of 62 * the calendar, with some sources starting in the first year of the reign 63 * of Huang Di, rather than the 61st. This gives continuous year numbers 64 * 60 years greater and cycle numbers one greater than what this class 65 * implements. 66 * 67 * <p>Because <code>ChineseCalendar</code> defines an additional field and 68 * redefines the way the <code>ERA</code> field is used, it requires a new 69 * format class, <code>ChineseDateFormat</code>. As always, use the 70 * methods <code>DateFormat.getXxxInstance(Calendar cal,...)</code> to 71 * obtain a formatter for this calendar. 72 * 73 * <p>References:<ul> 74 * 75 * <li>Dershowitz and Reingold, <i>Calendrical Calculations</i>, 76 * Cambridge University Press, 1997</li> 77 * 78 * <li>Helmer Aslaksen's 79 * <a href="http://www.math.nus.edu.sg/aslaksen/calendar/chinese.shtml"> 80 * Chinese Calendar page</a></li> 81 * 82 * <li>The <a href="http://www.tondering.dk/claus/calendar.html"> 83 * Calendar FAQ</a></li> 84 * 85 * </ul> 86 * 87 * <p> 88 * This class should only be subclassed to implement variants of the Chinese lunar calendar.</p> 89 * <p> 90 * ChineseCalendar usually should be instantiated using 91 * {@link com.ibm.icu.util.Calendar#getInstance(ULocale)} passing in a <code>ULocale</code> 92 * with the tag <code>"@calendar=chinese"</code>.</p> 93 * 94 * @see com.ibm.icu.text.ChineseDateFormat 95 * @see com.ibm.icu.util.Calendar 96 * @author Alan Liu 97 * @internal 98 */ 99 class U_I18N_API ChineseCalendar : public Calendar { 100 public: 101 //------------------------------------------------------------------------- 102 // Constructors... 103 //------------------------------------------------------------------------- 104 105 /** 106 * Constructs a ChineseCalendar based on the current time in the default time zone 107 * with the given locale. 108 * 109 * @param aLocale The given locale. 110 * @param success Indicates the status of ChineseCalendar object construction. 111 * Returns U_ZERO_ERROR if constructed successfully. 112 * @internal 113 */ 114 ChineseCalendar(const Locale& aLocale, UErrorCode &success); 115 116 /** 117 * Returns true if the date is in a leap year. 118 * 119 * @param status ICU Error Code 120 * @return True if the date in the fields is in a Temporal proposal 121 * defined leap year. False otherwise. 122 */ 123 virtual bool inTemporalLeapYear(UErrorCode &status) const override; 124 125 /** 126 * Gets The Temporal monthCode value corresponding to the month for the date. 127 * The value is a string identifier that starts with the literal grapheme 128 * "M" followed by two graphemes representing the zero-padded month number 129 * of the current month in a normal (non-leap) year and suffixed by an 130 * optional literal grapheme "L" if this is a leap month in a lunisolar 131 * calendar. For Chinese calendars (including Dangi), the values are 132 * "M01" .. "M12" for non-leap year, and "M01" .. "M12" with one of 133 * "M01L" .. "M12L" for leap year. 134 * 135 * @param status ICU Error Code 136 * @return One of 24 possible strings in 137 * {"M01" .. "M12", "M01L" .. "M12L"}. 138 * @draft ICU 73 139 */ 140 virtual const char* getTemporalMonthCode(UErrorCode &status) const override; 141 142 /** 143 * Sets The Temporal monthCode which is a string identifier that starts 144 * with the literal grapheme "M" followed by two graphemes representing 145 * the zero-padded month number of the current month in a normal 146 * (non-leap) year and suffixed by an optional literal grapheme "L" if this 147 * is a leap month in a lunisolar calendar. For Chinese calendars, the values 148 * are "M01" .. "M12" for non-leap years, and "M01" .. "M12" plus one in 149 * "M01L" .. "M12L" for leap year. 150 * 151 * @param temporalMonth The value to be set for temporal monthCode. One of 152 * 24 possible strings in {"M01" .. "M12", "M01L" .. "M12L"}. 153 * @param status ICU Error Code 154 * 155 * @draft ICU 73 156 */ 157 virtual void setTemporalMonthCode(const char* code, UErrorCode& status) override; 158 159 protected: 160 161 /** 162 * Constructs a ChineseCalendar based on the current time in the default time zone 163 * with the given locale, using the specified epoch year and time zone for 164 * astronomical calculations. 165 * 166 * @param aLocale The given locale. 167 * @param epochYear The epoch year to use for calculation. 168 * @param zoneAstroCalc The TimeZone to use for astronomical calculations. If null, 169 * will be set appropriately for Chinese calendar (UTC + 8:00). 170 * @param success Indicates the status of ChineseCalendar object construction; 171 * if successful, will not be changed to an error value. 172 * @internal 173 */ 174 ChineseCalendar(const Locale& aLocale, int32_t epochYear, const TimeZone* zoneAstroCalc, UErrorCode &success); 175 176 public: 177 /** 178 * Copy Constructor 179 * @internal 180 */ 181 ChineseCalendar(const ChineseCalendar& other); 182 183 /** 184 * Destructor. 185 * @internal 186 */ 187 virtual ~ChineseCalendar(); 188 189 // clone 190 virtual ChineseCalendar* clone() const override; 191 192 private: 193 194 //------------------------------------------------------------------------- 195 // Internal data.... 196 //------------------------------------------------------------------------- 197 198 // There is a leap month between the Winter Solstice before and after the 199 // current date.This is different from leap year because in some year, such as 200 // 1813 and 2033, the leap month is after the Winter Solstice of that year. So 201 // this value could be false for a date prior to the Winter Solstice of that 202 // year but that year still has a leap month and therefor is a leap year. 203 UBool hasLeapMonthBetweenWinterSolstices; 204 int32_t fEpochYear; // Start year of this Chinese calendar instance. 205 const TimeZone* fZoneAstroCalc; // Zone used for the astronomical calculation 206 // of this Chinese calendar instance. 207 208 //---------------------------------------------------------------------- 209 // Calendar framework 210 //---------------------------------------------------------------------- 211 212 protected: 213 virtual int32_t handleGetLimit(UCalendarDateFields field, ELimitType limitType) const override; 214 virtual int32_t handleGetMonthLength(int32_t extendedYear, int32_t month) const override; 215 virtual int32_t handleComputeMonthStart(int32_t eyear, int32_t month, UBool useMonth) const override; 216 virtual int32_t handleGetExtendedYear() override; 217 virtual void handleComputeFields(int32_t julianDay, UErrorCode &status) override; 218 virtual const UFieldResolutionTable* getFieldResolutionTable() const override; 219 220 public: 221 virtual void add(UCalendarDateFields field, int32_t amount, UErrorCode &status) override; 222 virtual void add(EDateFields field, int32_t amount, UErrorCode &status) override; 223 virtual void roll(UCalendarDateFields field, int32_t amount, UErrorCode &status) override; 224 virtual void roll(EDateFields field, int32_t amount, UErrorCode &status) override; 225 226 /** 227 * @return The related Gregorian year; will be obtained by modifying the value 228 * obtained by get from UCAL_EXTENDED_YEAR field 229 * @internal 230 */ 231 virtual int32_t getRelatedYear(UErrorCode &status) const override; 232 233 /** 234 * @param year The related Gregorian year to set; will be modified as necessary then 235 * set in UCAL_EXTENDED_YEAR field 236 * @internal 237 */ 238 virtual void setRelatedYear(int32_t year) override; 239 240 //---------------------------------------------------------------------- 241 // Internal methods & astronomical calculations 242 //---------------------------------------------------------------------- 243 244 private: 245 246 static const UFieldResolutionTable CHINESE_DATE_PRECEDENCE[]; 247 248 double daysToMillis(double days) const; 249 double millisToDays(double millis) const; 250 virtual int32_t winterSolstice(int32_t gyear) const; 251 virtual int32_t newMoonNear(double days, UBool after) const; 252 virtual int32_t synodicMonthsBetween(int32_t day1, int32_t day2) const; 253 virtual int32_t majorSolarTerm(int32_t days) const; 254 virtual UBool hasNoMajorSolarTerm(int32_t newMoon) const; 255 virtual UBool isLeapMonthBetween(int32_t newMoon1, int32_t newMoon2) const; 256 virtual void computeChineseFields(int32_t days, int32_t gyear, 257 int32_t gmonth, UBool setAllFields); 258 virtual int32_t newYear(int32_t gyear) const; 259 virtual void offsetMonth(int32_t newMoon, int32_t dom, int32_t delta); 260 const TimeZone* getChineseCalZoneAstroCalc() const; 261 262 // UObject stuff 263 public: 264 /** 265 * @return The class ID for this object. All objects of a given class have the 266 * same class ID. Objects of other classes have different class IDs. 267 * @internal 268 */ 269 virtual UClassID getDynamicClassID() const override; 270 271 /** 272 * Return the class ID for this class. This is useful only for comparing to a return 273 * value from getDynamicClassID(). For example: 274 * 275 * Base* polymorphic_pointer = createPolymorphicObject(); 276 * if (polymorphic_pointer->getDynamicClassID() == 277 * Derived::getStaticClassID()) ... 278 * 279 * @return The class ID for all objects of this class. 280 * @internal 281 */ 282 static UClassID U_EXPORT2 getStaticClassID(); 283 284 /** 285 * return the calendar type, "chinese". 286 * 287 * @return calendar type 288 * @internal 289 */ 290 virtual const char * getType() const override; 291 292 protected: 293 virtual int32_t internalGetMonth(int32_t defaultValue) const override; 294 295 virtual int32_t internalGetMonth() const override; 296 297 protected: 298 /** 299 * Returns true because the Islamic Calendar does have a default century 300 * @internal 301 */ 302 virtual UBool haveDefaultCentury() const override; 303 304 /** 305 * Returns the date of the start of the default century 306 * @return start of century - in milliseconds since epoch, 1970 307 * @internal 308 */ 309 virtual UDate defaultCenturyStart() const override; 310 311 /** 312 * Returns the year in which the default century begins 313 * @internal 314 */ 315 virtual int32_t defaultCenturyStartYear() const override; 316 317 private: // default century stuff. 318 319 /** 320 * Returns the beginning date of the 100-year window that dates 321 * with 2-digit years are considered to fall within. 322 */ 323 UDate internalGetDefaultCenturyStart() const; 324 325 /** 326 * Returns the first year of the 100-year window that dates with 327 * 2-digit years are considered to fall within. 328 */ 329 int32_t internalGetDefaultCenturyStartYear() const; 330 331 ChineseCalendar() = delete; // default constructor not implemented 332 }; 333 334 U_NAMESPACE_END 335 336 #endif 337 #endif 338