1 /* 2 ***************************************************************************** 3 * Copyright (C) 2007-2013, International Business Machines Corporation 4 * and others. All Rights Reserved. 5 ***************************************************************************** 6 * 7 * File CHNSECAL.H 8 * 9 * Modification History: 10 * 11 * Date Name Description 12 * 9/18/2007 ajmacher ported from java ChineseCalendar 13 ***************************************************************************** 14 */ 15 16 #ifndef CHNSECAL_H 17 #define CHNSECAL_H 18 19 #include "unicode/utypes.h" 20 21 #if !UCONFIG_NO_FORMATTING 22 23 #include "unicode/calendar.h" 24 #include "unicode/timezone.h" 25 26 U_NAMESPACE_BEGIN 27 28 /** 29 * <code>ChineseCalendar</code> is a concrete subclass of {@link Calendar} 30 * that implements a traditional Chinese calendar. The traditional Chinese 31 * calendar is a lunisolar calendar: Each month starts on a new moon, and 32 * the months are numbered according to solar events, specifically, to 33 * guarantee that month 11 always contains the winter solstice. In order 34 * to accomplish this, leap months are inserted in certain years. Leap 35 * months are numbered the same as the month they follow. The decision of 36 * which month is a leap month depends on the relative movements of the sun 37 * and moon. 38 * 39 * <p>This class defines one addition field beyond those defined by 40 * <code>Calendar</code>: The <code>IS_LEAP_MONTH</code> field takes the 41 * value of 0 for normal months, or 1 for leap months. 42 * 43 * <p>All astronomical computations are performed with respect to a time 44 * zone of GMT+8:00 and a longitude of 120 degrees east. Although some 45 * calendars implement a historically more accurate convention of using 46 * Beijing's local longitude (116 degrees 25 minutes east) and time zone 47 * (GMT+7:45:40) for dates before 1929, we do not implement this here. 48 * 49 * <p>Years are counted in two different ways in the Chinese calendar. The 50 * first method is by sequential numbering from the 61st year of the reign 51 * of Huang Di, 2637 BCE, which is designated year 1 on the Chinese 52 * calendar. The second method uses 60-year cycles from the same starting 53 * point, which is designated year 1 of cycle 1. In this class, the 54 * <code>EXTENDED_YEAR</code> field contains the sequential year count. 55 * The <code>ERA</code> field contains the cycle number, and the 56 * <code>YEAR</code> field contains the year of the cycle, a value between 57 * 1 and 60. 58 * 59 * <p>There is some variation in what is considered the starting point of 60 * the calendar, with some sources starting in the first year of the reign 61 * of Huang Di, rather than the 61st. This gives continuous year numbers 62 * 60 years greater and cycle numbers one greater than what this class 63 * implements. 64 * 65 * <p>Because <code>ChineseCalendar</code> defines an additional field and 66 * redefines the way the <code>ERA</code> field is used, it requires a new 67 * format class, <code>ChineseDateFormat</code>. As always, use the 68 * methods <code>DateFormat.getXxxInstance(Calendar cal,...)</code> to 69 * obtain a formatter for this calendar. 70 * 71 * <p>References:<ul> 72 * 73 * <li>Dershowitz and Reingold, <i>Calendrical Calculations</i>, 74 * Cambridge University Press, 1997</li> 75 * 76 * <li>Helmer Aslaksen's 77 * <a href="http://www.math.nus.edu.sg/aslaksen/calendar/chinese.shtml"> 78 * Chinese Calendar page</a></li> 79 * 80 * <li>The <a href="http://www.tondering.dk/claus/calendar.html"> 81 * Calendar FAQ</a></li> 82 * 83 * </ul> 84 * 85 * <p> 86 * This class should only be subclassed to implement variants of the Chinese lunar calendar.</p> 87 * <p> 88 * ChineseCalendar usually should be instantiated using 89 * {@link com.ibm.icu.util.Calendar#getInstance(ULocale)} passing in a <code>ULocale</code> 90 * with the tag <code>"@calendar=chinese"</code>.</p> 91 * 92 * @see com.ibm.icu.text.ChineseDateFormat 93 * @see com.ibm.icu.util.Calendar 94 * @author Alan Liu 95 * @internal 96 */ 97 class U_I18N_API ChineseCalendar : public Calendar { 98 public: 99 //------------------------------------------------------------------------- 100 // Constructors... 101 //------------------------------------------------------------------------- 102 103 /** 104 * Constructs a ChineseCalendar based on the current time in the default time zone 105 * with the given locale. 106 * 107 * @param aLocale The given locale. 108 * @param success Indicates the status of ChineseCalendar object construction. 109 * Returns U_ZERO_ERROR if constructed successfully. 110 * @internal 111 */ 112 ChineseCalendar(const Locale& aLocale, UErrorCode &success); 113 114 protected: 115 116 /** 117 * Constructs a ChineseCalendar based on the current time in the default time zone 118 * with the given locale, using the specified epoch year and time zone for 119 * astronomical calculations. 120 * 121 * @param aLocale The given locale. 122 * @param epochYear The epoch year to use for calculation. 123 * @param zoneAstroCalc The TimeZone to use for astronomical calculations. If null, 124 * will be set appropriately for Chinese calendar (UTC + 8:00). 125 * @param success Indicates the status of ChineseCalendar object construction; 126 * if successful, will not be changed to an error value. 127 * @internal 128 */ 129 ChineseCalendar(const Locale& aLocale, int32_t epochYear, const TimeZone* zoneAstroCalc, UErrorCode &success); 130 131 public: 132 /** 133 * Copy Constructor 134 * @internal 135 */ 136 ChineseCalendar(const ChineseCalendar& other); 137 138 /** 139 * Destructor. 140 * @internal 141 */ 142 virtual ~ChineseCalendar(); 143 144 // clone 145 virtual Calendar* clone() const; 146 147 private: 148 149 //------------------------------------------------------------------------- 150 // Internal data.... 151 //------------------------------------------------------------------------- 152 153 UBool isLeapYear; 154 int32_t fEpochYear; // Start year of this Chinese calendar instance. 155 const TimeZone* fZoneAstroCalc; // Zone used for the astronomical calculation 156 // of this Chinese calendar instance. 157 158 //---------------------------------------------------------------------- 159 // Calendar framework 160 //---------------------------------------------------------------------- 161 162 protected: 163 virtual int32_t handleGetLimit(UCalendarDateFields field, ELimitType limitType) const; 164 virtual int32_t handleGetMonthLength(int32_t extendedYear, int32_t month) const; 165 virtual int32_t handleComputeMonthStart(int32_t eyear, int32_t month, UBool useMonth) const; 166 virtual int32_t handleGetExtendedYear(); 167 virtual void handleComputeFields(int32_t julianDay, UErrorCode &status); 168 virtual const UFieldResolutionTable* getFieldResolutionTable() const; 169 170 public: 171 virtual void add(UCalendarDateFields field, int32_t amount, UErrorCode &status); 172 virtual void add(EDateFields field, int32_t amount, UErrorCode &status); 173 virtual void roll(UCalendarDateFields field, int32_t amount, UErrorCode &status); 174 virtual void roll(EDateFields field, int32_t amount, UErrorCode &status); 175 176 //---------------------------------------------------------------------- 177 // Internal methods & astronomical calculations 178 //---------------------------------------------------------------------- 179 180 private: 181 182 static const UFieldResolutionTable CHINESE_DATE_PRECEDENCE[]; 183 184 double daysToMillis(double days) const; 185 double millisToDays(double millis) const; 186 virtual int32_t winterSolstice(int32_t gyear) const; 187 virtual int32_t newMoonNear(double days, UBool after) const; 188 virtual int32_t synodicMonthsBetween(int32_t day1, int32_t day2) const; 189 virtual int32_t majorSolarTerm(int32_t days) const; 190 virtual UBool hasNoMajorSolarTerm(int32_t newMoon) const; 191 virtual UBool isLeapMonthBetween(int32_t newMoon1, int32_t newMoon2) const; 192 virtual void computeChineseFields(int32_t days, int32_t gyear, 193 int32_t gmonth, UBool setAllFields); 194 virtual int32_t newYear(int32_t gyear) const; 195 virtual void offsetMonth(int32_t newMoon, int32_t dom, int32_t delta); 196 const TimeZone* getChineseCalZoneAstroCalc(void) const; 197 198 // UObject stuff 199 public: 200 /** 201 * @return The class ID for this object. All objects of a given class have the 202 * same class ID. Objects of other classes have different class IDs. 203 * @internal 204 */ 205 virtual UClassID getDynamicClassID(void) const; 206 207 /** 208 * Return the class ID for this class. This is useful only for comparing to a return 209 * value from getDynamicClassID(). For example: 210 * 211 * Base* polymorphic_pointer = createPolymorphicObject(); 212 * if (polymorphic_pointer->getDynamicClassID() == 213 * Derived::getStaticClassID()) ... 214 * 215 * @return The class ID for all objects of this class. 216 * @internal 217 */ 218 static UClassID U_EXPORT2 getStaticClassID(void); 219 220 /** 221 * return the calendar type, "chinese". 222 * 223 * @return calendar type 224 * @internal 225 */ 226 virtual const char * getType() const; 227 228 229 protected: 230 /** 231 * (Overrides Calendar) Return true if the current date for this Calendar is in 232 * Daylight Savings Time. Recognizes DST_OFFSET, if it is set. 233 * 234 * @param status Fill-in parameter which receives the status of this operation. 235 * @return True if the current date for this Calendar is in Daylight Savings Time, 236 * false, otherwise. 237 * @internal 238 */ 239 virtual UBool inDaylightTime(UErrorCode& status) const; 240 241 242 /** 243 * Returns TRUE because the Islamic Calendar does have a default century 244 * @internal 245 */ 246 virtual UBool haveDefaultCentury() const; 247 248 /** 249 * Returns the date of the start of the default century 250 * @return start of century - in milliseconds since epoch, 1970 251 * @internal 252 */ 253 virtual UDate defaultCenturyStart() const; 254 255 /** 256 * Returns the year in which the default century begins 257 * @internal 258 */ 259 virtual int32_t defaultCenturyStartYear() const; 260 261 private: // default century stuff. 262 /** 263 * The system maintains a static default century start date. This is initialized 264 * the first time it is used. Before then, it is set to SYSTEM_DEFAULT_CENTURY to 265 * indicate an uninitialized state. Once the system default century date and year 266 * are set, they do not change. 267 */ 268 static UDate fgSystemDefaultCenturyStart; 269 270 /** 271 * See documentation for systemDefaultCenturyStart. 272 */ 273 static int32_t fgSystemDefaultCenturyStartYear; 274 275 /** 276 * Default value that indicates the defaultCenturyStartYear is unitialized 277 */ 278 static const int32_t fgSystemDefaultCenturyYear; 279 280 /** 281 * start of default century, as a date 282 */ 283 static const UDate fgSystemDefaultCentury; 284 285 /** 286 * Returns the beginning date of the 100-year window that dates 287 * with 2-digit years are considered to fall within. 288 */ 289 UDate internalGetDefaultCenturyStart(void) const; 290 291 /** 292 * Returns the first year of the 100-year window that dates with 293 * 2-digit years are considered to fall within. 294 */ 295 int32_t internalGetDefaultCenturyStartYear(void) const; 296 297 /** 298 * Initializes the 100-year window that dates with 2-digit years 299 * are considered to fall within so that its start date is 80 years 300 * before the current time. 301 */ 302 static void initializeSystemDefaultCentury(void); 303 304 ChineseCalendar(); // default constructor not implemented 305 }; 306 307 U_NAMESPACE_END 308 309 #endif 310 #endif 311