summaryrefslogtreecommitdiffstats
path: root/intl/icu/source/i18n/chnsecal.h
blob: 9b5a629fad4c35ba60fcb4a551c99f7fe1dc09e0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
 *****************************************************************************
 * Copyright (C) 2007-2013, International Business Machines Corporation
 * and others. All Rights Reserved.
 *****************************************************************************
 *
 * File CHNSECAL.H
 *
 * Modification History:
 *
 *   Date        Name        Description
 *   9/18/2007  ajmacher         ported from java ChineseCalendar
 *****************************************************************************
 */

#ifndef CHNSECAL_H
#define CHNSECAL_H

#include "unicode/utypes.h"

#if !UCONFIG_NO_FORMATTING

#include "unicode/calendar.h"
#include "unicode/timezone.h"

U_NAMESPACE_BEGIN

/**
 * <code>ChineseCalendar</code> is a concrete subclass of {@link Calendar}
 * that implements a traditional Chinese calendar.  The traditional Chinese
 * calendar is a lunisolar calendar: Each month starts on a new moon, and
 * the months are numbered according to solar events, specifically, to
 * guarantee that month 11 always contains the winter solstice.  In order
 * to accomplish this, leap months are inserted in certain years.  Leap
 * months are numbered the same as the month they follow.  The decision of
 * which month is a leap month depends on the relative movements of the sun
 * and moon.
 *
 * <p>This class defines one addition field beyond those defined by
 * <code>Calendar</code>: The <code>IS_LEAP_MONTH</code> field takes the
 * value of 0 for normal months, or 1 for leap months.
 *
 * <p>All astronomical computations are performed with respect to a time
 * zone of GMT+8:00 and a longitude of 120 degrees east.  Although some
 * calendars implement a historically more accurate convention of using
 * Beijing's local longitude (116 degrees 25 minutes east) and time zone
 * (GMT+7:45:40) for dates before 1929, we do not implement this here.
 *
 * <p>Years are counted in two different ways in the Chinese calendar.  The
 * first method is by sequential numbering from the 61st year of the reign
 * of Huang Di, 2637 BCE, which is designated year 1 on the Chinese
 * calendar.  The second method uses 60-year cycles from the same starting
 * point, which is designated year 1 of cycle 1.  In this class, the
 * <code>EXTENDED_YEAR</code> field contains the sequential year count.
 * The <code>ERA</code> field contains the cycle number, and the
 * <code>YEAR</code> field contains the year of the cycle, a value between
 * 1 and 60.
 *
 * <p>There is some variation in what is considered the starting point of
 * the calendar, with some sources starting in the first year of the reign
 * of Huang Di, rather than the 61st.  This gives continuous year numbers
 * 60 years greater and cycle numbers one greater than what this class
 * implements.
 *
 * <p>Because <code>ChineseCalendar</code> defines an additional field and
 * redefines the way the <code>ERA</code> field is used, it requires a new
 * format class, <code>ChineseDateFormat</code>.  As always, use the
 * methods <code>DateFormat.getXxxInstance(Calendar cal,...)</code> to
 * obtain a formatter for this calendar.
 *
 * <p>References:<ul>
 * 
 * <li>Dershowitz and Reingold, <i>Calendrical Calculations</i>,
 * Cambridge University Press, 1997</li>
 * 
 * <li>Helmer Aslaksen's
 * <a href="http://www.math.nus.edu.sg/aslaksen/calendar/chinese.shtml">
 * Chinese Calendar page</a></li>
 *
 * <li>The <a href="http://www.tondering.dk/claus/calendar.html">
 * Calendar FAQ</a></li>
 *
 * </ul>
 *
 * <p>
 * This class should only be subclassed to implement variants of the Chinese lunar calendar.</p>
 * <p>
 * ChineseCalendar usually should be instantiated using 
 * {@link com.ibm.icu.util.Calendar#getInstance(ULocale)} passing in a <code>ULocale</code>
 * with the tag <code>"@calendar=chinese"</code>.</p>
 *
 * @see com.ibm.icu.text.ChineseDateFormat
 * @see com.ibm.icu.util.Calendar
 * @author Alan Liu
 * @internal
 */
class U_I18N_API ChineseCalendar : public Calendar {
 public:
  //-------------------------------------------------------------------------
  // Constructors...
  //-------------------------------------------------------------------------

  /**
   * Constructs a ChineseCalendar 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 ChineseCalendar object construction.
   *                 Returns U_ZERO_ERROR if constructed successfully.
   * @internal
   */
  ChineseCalendar(const Locale& aLocale, UErrorCode &success);

  /**
   * Returns true if the date is in a leap year.
   *
   * @param status        ICU Error Code
   * @return       True if the date in the fields is in a Temporal proposal
   *               defined leap year. False otherwise.
   */
  virtual bool inTemporalLeapYear(UErrorCode &status) const override;

  /**
   * Gets The Temporal monthCode value corresponding to the month for the date.
   * The value is a string identifier that starts with the literal grapheme
   * "M" followed by two graphemes representing the zero-padded month number
   * of the current month in a normal (non-leap) year and suffixed by an
   * optional literal grapheme "L" if this is a leap month in a lunisolar
   * calendar. For Chinese calendars (including Dangi), the values are
   * "M01" .. "M12" for non-leap year, and "M01" .. "M12" with one of
   * "M01L" .. "M12L" for leap year.
   *
   * @param status        ICU Error Code
   * @return       One of 24 possible strings in
   *               {"M01" .. "M12", "M01L" .. "M12L"}.
   * @draft ICU 73
   */
  virtual const char* getTemporalMonthCode(UErrorCode &status) const override;

  /**
   * Sets The Temporal monthCode which is a string identifier that starts
   * with the literal grapheme "M" followed by two graphemes representing
   * the zero-padded month number of the current month in a normal
   * (non-leap) year and suffixed by an optional literal grapheme "L" if this
   * is a leap month in a lunisolar calendar. For Chinese calendars, the values
   * are "M01" .. "M12" for non-leap years, and "M01" .. "M12" plus one in
   * "M01L" .. "M12L" for leap year.
   *
   * @param temporalMonth  The value to be set for temporal monthCode. One of
   *                    24 possible strings in {"M01" .. "M12", "M01L" .. "M12L"}.
   * @param status        ICU Error Code
   *
   * @draft ICU 73
   */
  virtual void setTemporalMonthCode(const char* code, UErrorCode& status) override;

 protected:
 
   /**
   * Constructs a ChineseCalendar based on the current time in the default time zone
   * with the given locale, using the specified epoch year and time zone for
   * astronomical calculations.
   *
   * @param aLocale         The given locale.
   * @param epochYear       The epoch year to use for calculation.
   * @param zoneAstroCalc   The TimeZone to use for astronomical calculations. If null,
   *                        will be set appropriately for Chinese calendar (UTC + 8:00).
   * @param success         Indicates the status of ChineseCalendar object construction;
   *                        if successful, will not be changed to an error value.
   * @internal
   */
  ChineseCalendar(const Locale& aLocale, int32_t epochYear, const TimeZone* zoneAstroCalc, UErrorCode &success);

 public:
  /**
   * Copy Constructor
   * @internal
   */
  ChineseCalendar(const ChineseCalendar& other);

  /**
   * Destructor.
   * @internal
   */
  virtual ~ChineseCalendar();

  // clone
  virtual ChineseCalendar* clone() const override;

 private:

  //-------------------------------------------------------------------------
  // Internal data....
  //-------------------------------------------------------------------------
    
  // There is a leap month between the Winter Solstice before and after the
  // current date.This is different from leap year because in some year, such as
  // 1813 and 2033, the leap month is after the Winter Solstice of that year. So
  // this value could be false for a date prior to the Winter Solstice of that
  // year but that year still has a leap month and therefor is a leap year.
  UBool hasLeapMonthBetweenWinterSolstices;
  int32_t fEpochYear;   // Start year of this Chinese calendar instance.
  const TimeZone* fZoneAstroCalc;   // Zone used for the astronomical calculation
                                    // of this Chinese calendar instance.

  //----------------------------------------------------------------------
  // Calendar framework
  //----------------------------------------------------------------------

 protected:
  virtual int32_t handleGetLimit(UCalendarDateFields field, ELimitType limitType) const override;
  virtual int32_t handleGetMonthLength(int32_t extendedYear, int32_t month) const override;
  virtual int32_t handleComputeMonthStart(int32_t eyear, int32_t month, UBool useMonth) const override;
  virtual int32_t handleGetExtendedYear() override;
  virtual void handleComputeFields(int32_t julianDay, UErrorCode &status) override;
  virtual const UFieldResolutionTable* getFieldResolutionTable() const override;

 public:
  virtual void add(UCalendarDateFields field, int32_t amount, UErrorCode &status) override;
  virtual void add(EDateFields field, int32_t amount, UErrorCode &status) override;
  virtual void roll(UCalendarDateFields field, int32_t amount, UErrorCode &status) override;
  virtual void roll(EDateFields field, int32_t amount, UErrorCode &status) override;

  /**
   * @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;

  //----------------------------------------------------------------------
  // Internal methods & astronomical calculations
  //----------------------------------------------------------------------

 private:

  static const UFieldResolutionTable CHINESE_DATE_PRECEDENCE[];

  double daysToMillis(double days) const;
  double millisToDays(double millis) const;
  virtual int32_t winterSolstice(int32_t gyear) const;
  virtual int32_t newMoonNear(double days, UBool after) const;
  virtual int32_t synodicMonthsBetween(int32_t day1, int32_t day2) const;
  virtual int32_t majorSolarTerm(int32_t days) const;
  virtual UBool hasNoMajorSolarTerm(int32_t newMoon) const;
  virtual UBool isLeapMonthBetween(int32_t newMoon1, int32_t newMoon2) const;
  virtual void computeChineseFields(int32_t days, int32_t gyear,
                 int32_t gmonth, UBool setAllFields);
  virtual int32_t newYear(int32_t gyear) const;
  virtual void offsetMonth(int32_t newMoon, int32_t dom, int32_t delta);
  const TimeZone* getChineseCalZoneAstroCalc() const;

  // 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() 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();

  /**
   * return the calendar type, "chinese".
   *
   * @return calendar type
   * @internal
   */
  virtual const char * getType() const override;

 protected:
  virtual int32_t internalGetMonth(int32_t defaultValue) const override;

  virtual int32_t internalGetMonth() const override;

 protected:
  /**
   * Returns true because the Islamic Calendar does have a default century
   * @internal
   */
  virtual UBool haveDefaultCentury() const override;

  /**
   * Returns the date of the start of the default century
   * @return start of century - in milliseconds since epoch, 1970
   * @internal
   */
  virtual UDate defaultCenturyStart() const override;

  /**
   * Returns the year in which the default century begins
   * @internal
   */
  virtual int32_t defaultCenturyStartYear() const override;

 private: // default century stuff.

  /**
   * Returns the beginning date of the 100-year window that dates 
   * with 2-digit years are considered to fall within.
   */
  UDate         internalGetDefaultCenturyStart() const;

  /**
   * Returns the first year of the 100-year window that dates with 
   * 2-digit years are considered to fall within.
   */
  int32_t          internalGetDefaultCenturyStartYear() const;

  ChineseCalendar() = delete; // default constructor not implemented
};

U_NAMESPACE_END

#endif
#endif