1/* GENERATED SOURCE. DO NOT MODIFY. */
2// © 2016 and later: Unicode, Inc. and others.
3// License & terms of use: http://www.unicode.org/copyright.html#License
4/*********************************************************************
5 * Copyright (C) 2000-2014, International Business Machines
6 * Corporation and others. All Rights Reserved.
7 *********************************************************************
8 */
9
10package android.icu.util;
11
12import java.io.IOException;
13import java.io.ObjectInputStream;
14import java.util.Date;
15import java.util.Locale;
16
17import android.icu.impl.CalendarAstronomer;
18import android.icu.impl.CalendarCache;
19import android.icu.text.DateFormat;
20import android.icu.util.ULocale.Category;
21
22/**
23 * <code>ChineseCalendar</code> is a concrete subclass of {@link Calendar}
24 * that implements a traditional Chinese calendar.  The traditional Chinese
25 * calendar is a lunisolar calendar: Each month starts on a new moon, and
26 * the months are numbered according to solar events, specifically, to
27 * guarantee that month 11 always contains the winter solstice.  In order
28 * to accomplish this, leap months are inserted in certain years.  Leap
29 * months are numbered the same as the month they follow.  The decision of
30 * which month is a leap month depends on the relative movements of the sun
31 * and moon.
32 *
33 * <p>All astronomical computations are performed with respect to a time
34 * zone of GMT+8:00 and a longitude of 120 degrees east.  Although some
35 * calendars implement a historically more accurate convention of using
36 * Beijing's local longitude (116 degrees 25 minutes east) and time zone
37 * (GMT+7:45:40) for dates before 1929, we do not implement this here.
38 *
39 * <p>Years are counted in two different ways in the Chinese calendar.  The
40 * first method is by sequential numbering from the 61st year of the reign
41 * of Huang Di, 2637 BCE, which is designated year 1 on the Chinese
42 * calendar.  The second method uses 60-year cycles from the same starting
43 * point, which is designated year 1 of cycle 1.  In this class, the
44 * <code>EXTENDED_YEAR</code> field contains the sequential year count.
45 * The <code>ERA</code> field contains the cycle number, and the
46 * <code>YEAR</code> field contains the year of the cycle, a value between
47 * 1 and 60.
48 *
49 * <p>There is some variation in what is considered the starting point of
50 * the calendar, with some sources starting in the first year of the reign
51 * of Huang Di, rather than the 61st.  This gives continuous year numbers
52 * 60 years greater and cycle numbers one greater than what this class
53 * implements.
54 *
55 * <p>Because <code>ChineseCalendar</code> defines an additional field and
56 * redefines the way the <code>ERA</code> field is used, it requires a new
57 * format class, <code>ChineseDateFormat</code>.  As always, use the
58 * methods <code>DateFormat.getXxxInstance(Calendar cal,...)</code> to
59 * obtain a formatter for this calendar.
60 *
61 * <p>References:<ul>
62 *
63 * <li>Dershowitz and Reingold, <i>Calendrical Calculations</i>,
64 * Cambridge University Press, 1997</li>
65 *
66 * <li>Helmer Aslaksen's
67 * <a href="http://www.math.nus.edu.sg/aslaksen/calendar/chinese.shtml">
68 * Chinese Calendar page</a></li>
69 *
70 * <li>The <a href="http://www.tondering.dk/claus/calendar.html">
71 * Calendar FAQ</a></li>
72 *
73 * </ul>
74 *
75 * <p>
76 * This class should not be subclassed.</p>
77 * <p>
78 * ChineseCalendar usually should be instantiated using
79 * {@link android.icu.util.Calendar#getInstance(ULocale)} passing in a <code>ULocale</code>
80 * with the tag <code>"@calendar=chinese"</code>.</p>
81 *
82 * @see android.icu.util.Calendar
83 * @author Alan Liu
84 */
85public class ChineseCalendar extends Calendar {
86    // jdk1.4.2 serialver
87    private static final long serialVersionUID = 7312110751940929420L;
88
89    //------------------------------------------------------------------
90    // Developer Notes
91    //
92    // Time is represented as a scalar in two ways in this class.  One is
93    // the usual UTC epoch millis, that is, milliseconds after January 1,
94    // 1970 Gregorian, 0:00:00.000 UTC.  The other is in terms of 'local
95    // days.'  This is the number of days after January 1, 1970 Gregorian,
96    // local to Beijing, China (since all computations of the Chinese
97    // calendar are done in Beijing).  That is, 0 represents January 1,
98    // 1970 0:00 Asia/Shanghai.  Conversion of local days to and from
99    // standard epoch milliseconds is accomplished by the daysToMillis()
100    // and millisToDays() methods.
101    //
102    // Several methods use caches to improve performance.  Caches are at
103    // the object, not class level, under the assumption that typical
104    // usage will be to have one instance of ChineseCalendar at a time.
105
106    /**
107     * The start year of this Chinese calendar instance.
108     */
109    private int epochYear;
110
111    /**
112     * The zone used for the astronomical calculation of this Chinese
113     * calendar instance.
114     */
115    private TimeZone zoneAstro;
116
117    /**
118     * We have one instance per object, and we don't synchronize it because
119     * Calendar doesn't support multithreaded execution in the first place.
120     */
121    private transient CalendarAstronomer astro = new CalendarAstronomer();
122
123    /**
124     * Cache that maps Gregorian year to local days of winter solstice.
125     * @see #winterSolstice
126     */
127    private transient CalendarCache winterSolsticeCache = new CalendarCache();
128
129    /**
130     * Cache that maps Gregorian year to local days of Chinese new year.
131     * @see #newYear
132     */
133    private transient CalendarCache newYearCache = new CalendarCache();
134
135    /**
136     * True if the current year is a leap year.  Updated with each time to
137     * fields resolution.
138     * @see #computeChineseFields
139     */
140    private transient boolean isLeapYear;
141
142    //------------------------------------------------------------------
143    // Constructors
144    //------------------------------------------------------------------
145
146    /**
147     * Construct a <code>ChineseCalendar</code> with the default time zone and locale.
148     */
149    public ChineseCalendar() {
150        this(TimeZone.getDefault(), ULocale.getDefault(Category.FORMAT), CHINESE_EPOCH_YEAR, CHINA_ZONE);
151    }
152
153    /**
154     * Construct a <code>ChineseCalendar</code> with the give date set in the default time zone
155     * with the default locale.
156     * @param date The date to which the new calendar is set.
157     */
158    public ChineseCalendar(Date date) {
159        this(TimeZone.getDefault(), ULocale.getDefault(Category.FORMAT), CHINESE_EPOCH_YEAR, CHINA_ZONE);
160        setTime(date);
161    }
162
163    /**
164     * Constructs a <code>ChineseCalendar</code> with the given date set
165     * in the default time zone with the default <code>FORMAT</code> locale.
166     *
167     * @param year      The value used to set the calendar's {@link #YEAR YEAR} time field.
168     * @param month     The value used to set the calendar's {@link #MONTH MONTH} time field.
169     *                  The value is 0-based. e.g., 0 for January.
170     * @param isLeapMonth The value used to set the Chinese calendar's {@link #IS_LEAP_MONTH}
171     *                  time field.
172     * @param date      The value used to set the calendar's {@link #DATE DATE} time field.
173     * @see Category#FORMAT
174     */
175    public ChineseCalendar(int year, int month, int isLeapMonth, int date) {
176        this(year, month, isLeapMonth, date, 0, 0, 0);
177    }
178
179    /**
180     * Constructs a <code>ChineseCalendar</code> with the given date
181     * and time set for the default time zone with the default <code>FORMAT</code> locale.
182     *
183     * @param year  the value used to set the {@link #YEAR YEAR} time field in the calendar.
184     * @param month the value used to set the {@link #MONTH MONTH} time field in the calendar.
185     *              Note that the month value is 0-based. e.g., 0 for January.
186     * @param isLeapMonth the value used to set the {@link #IS_LEAP_MONTH} time field
187     *              in the calendar.
188     * @param date  the value used to set the {@link #DATE DATE} time field in the calendar.
189     * @param hour  the value used to set the {@link #HOUR_OF_DAY HOUR_OF_DAY} time field
190     *              in the calendar.
191     * @param minute the value used to set the {@link #MINUTE MINUTE} time field
192     *              in the calendar.
193     * @param second the value used to set the {@link #SECOND SECOND} time field
194     *              in the calendar.
195     * @see Category#FORMAT
196     */
197    public ChineseCalendar(int year, int month, int isLeapMonth, int date, int hour,
198                             int minute, int second)
199    {
200        this(TimeZone.getDefault(), ULocale.getDefault(Category.FORMAT), CHINESE_EPOCH_YEAR, CHINA_ZONE);
201
202        // The current time is set at this point, so ERA field is already
203        // set to the current era.
204
205        // Then we need to clean up time fields
206        this.set(MILLISECOND, 0);
207
208        // Then, set the given field values.
209        this.set(YEAR, year);
210        this.set(MONTH, month);
211        this.set(IS_LEAP_MONTH, isLeapMonth);
212        this.set(DATE, date);
213        this.set(HOUR_OF_DAY, hour);
214        this.set(MINUTE, minute);
215        this.set(SECOND, second);
216    }
217
218    /**
219     * Constructs a <code>ChineseCalendar</code> with the given date set
220     * in the default time zone with the default <code>FORMAT</code> locale.
221     *
222     * @param era       The value used to set the calendar's {@link #ERA ERA} time field.
223     * @param year      The value used to set the calendar's {@link #YEAR YEAR} time field.
224     * @param month     The value used to set the calendar's {@link #MONTH MONTH} time field.
225     *                  The value is 0-based. e.g., 0 for January.
226     * @param isLeapMonth The value used to set the Chinese calendar's {@link #IS_LEAP_MONTH}
227     *                  time field.
228     * @param date      The value used to set the calendar's {@link #DATE DATE} time field.
229     * @see Category#FORMAT
230     */
231    public ChineseCalendar(int era, int year, int month, int isLeapMonth, int date)
232    {
233        this(era, year, month, isLeapMonth, date, 0, 0, 0);
234    }
235
236    /**
237     * Constructs a <code>ChineseCalendar</code> with the given date
238     * and time set for the default time zone with the default <code>FORMAT</code> locale.
239     *
240     * @param era   the value used to set the calendar's {@link #ERA ERA} time field.
241     * @param year  the value used to set the {@link #YEAR YEAR} time field in the calendar.
242     * @param month the value used to set the {@link #MONTH MONTH} time field in the calendar.
243     *              Note that the month value is 0-based. e.g., 0 for January.
244     * @param isLeapMonth the value used to set the {@link #IS_LEAP_MONTH} time field
245     *              in the calendar.
246     * @param date  the value used to set the {@link #DATE DATE} time field in the calendar.
247     * @param hour  the value used to set the {@link #HOUR_OF_DAY HOUR_OF_DAY} time field
248     *              in the calendar.
249     * @param minute the value used to set the {@link #MINUTE MINUTE} time field
250     *              in the calendar.
251     * @param second the value used to set the {@link #SECOND SECOND} time field
252     *              in the calendar.
253     * @see Category#FORMAT
254     */
255    public ChineseCalendar(int era, int year, int month, int isLeapMonth, int date, int hour,
256                           int minute, int second)
257    {
258        this(TimeZone.getDefault(), ULocale.getDefault(Category.FORMAT), CHINESE_EPOCH_YEAR, CHINA_ZONE);
259
260        // Set 0 to millisecond field
261        this.set(MILLISECOND, 0);
262
263        // Then, set the given field values.
264        this.set(ERA, era);
265        this.set(YEAR, year);
266        this.set(MONTH, month);
267        this.set(IS_LEAP_MONTH, isLeapMonth);
268        this.set(DATE, date);
269        this.set(HOUR_OF_DAY, hour);
270        this.set(MINUTE, minute);
271        this.set(SECOND, second);
272    }
273
274    /**
275     * Constructs a <code>ChineseCalendar</code> based on the current time
276     * in the default time zone with the given locale.
277     * @param aLocale The given locale
278     */
279    public ChineseCalendar(Locale aLocale) {
280        this(TimeZone.getDefault(), ULocale.forLocale(aLocale), CHINESE_EPOCH_YEAR, CHINA_ZONE);
281    }
282
283    /**
284     * Construct a <code>ChineseCalendar</code> based on the current time
285     * in the given time zone with the default <code>FORMAT</code> locale.
286     * @param zone the given time zone
287     * @see Category#FORMAT
288     */
289    public ChineseCalendar(TimeZone zone) {
290        this(zone, ULocale.getDefault(Category.FORMAT), CHINESE_EPOCH_YEAR, CHINA_ZONE);
291    }
292
293    /**
294     * Construct a <code>ChineseCalendar</code> based on the current time
295     * in the given time zone with the given locale.
296     * @param zone the given time zone
297     * @param aLocale the given locale
298     */
299    public ChineseCalendar(TimeZone zone, Locale aLocale) {
300        this(zone, ULocale.forLocale(aLocale), CHINESE_EPOCH_YEAR, CHINA_ZONE);
301    }
302
303    /**
304     * Constructs a <code>ChineseCalendar</code> based on the current time
305     * in the default time zone with the given locale.
306     *
307     * @param locale the given ulocale
308     */
309    public ChineseCalendar(ULocale locale) {
310        this(TimeZone.getDefault(), locale, CHINESE_EPOCH_YEAR, CHINA_ZONE);
311    }
312
313    /**
314     * Construct a <code>ChineseCalendar</code>  based on the current time
315     * with the given time zone with the given locale.
316     * @param zone the given time zone
317     * @param locale the given ulocale
318     */
319    public ChineseCalendar(TimeZone zone, ULocale locale) {
320        this(zone, locale, CHINESE_EPOCH_YEAR, CHINA_ZONE);
321    }
322
323    /**
324     * Construct a <code>ChineseCalenar</code> based on the current time
325     * with the given time zone, the locale, the epoch year and the time zone
326     * used for astronomical calculation.
327     * @deprecated This API is ICU internal only.
328     * @hide original deprecated declaration
329     * @hide draft / provisional / internal are hidden on Android
330     */
331    @Deprecated
332    protected ChineseCalendar(TimeZone zone, ULocale locale, int epochYear, TimeZone zoneAstroCalc) {
333        super(zone, locale);
334        this.epochYear = epochYear;
335        this.zoneAstro = zoneAstroCalc;
336        setTimeInMillis(System.currentTimeMillis());
337    }
338
339    //------------------------------------------------------------------
340    // Public constants
341    //------------------------------------------------------------------
342
343    /**
344     * Field indicating whether or not the current month is a leap month.
345     * Should have a value of 0 for non-leap months, and 1 for leap months.
346     * @stable ICU 2.8
347     */
348    // public static int IS_LEAP_MONTH = BASE_FIELD_COUNT;
349
350
351    //------------------------------------------------------------------
352    // Calendar framework
353    //------------------------------------------------------------------
354
355    /**
356     * Array defining the limits of field values for this class.  Field
357     * limits which are invariant with respect to calendar system and
358     * defined by Calendar are left blank.
359     *
360     * Notes:
361     *
362     * ERA 5000000 / 60 = 83333.
363     *
364     * MONTH There are 12 or 13 lunar months in a year.  However, we always
365     * number them 0..11, with an intercalated, identically numbered leap
366     * month, when necessary.
367     *
368     * DAY_OF_YEAR In a non-leap year there are 353, 354, or 355 days.  In
369     * a leap year there are 383, 384, or 385 days.
370     *
371     * WEEK_OF_YEAR The least maximum occurs if there are 353 days in the
372     * year, and the first 6 are the last week of the previous year.  Then
373     * we have 49 full weeks and 4 days in the last week: 6 + 49*7 + 4 =
374     * 353.  So the least maximum is 50.  The maximum occurs if there are
375     * 385 days in the year, and WOY 1 extends 6 days into the prior year.
376     * Then there are 54 full weeks, and 6 days in the last week: 1 + 54*7
377     * + 6 = 385.  The 6 days of the last week will fall into WOY 1 of the
378     * next year.  Maximum is 55.
379     *
380     * WEEK_OF_MONTH In a 29 day month, if the first 7 days make up week 1
381     * that leaves 3 full weeks and 1 day at the end.  The least maximum is
382     * thus 5.  In a 30 days month, if the previous 6 days belong WOM 1 of
383     * this month, we have 4 full weeks and 1 days at the end (which
384     * technically will be WOM 1 of the next month, but will be reported by
385     * time->fields and hence by getActualMaximum as WOM 6 of this month).
386     * Maximum is 6.
387     *
388     * DAY_OF_WEEK_IN_MONTH In a 29 or 30 day month, there are 4 full weeks
389     * plus 1 or 2 days at the end, so the maximum is always 5.
390     */
391    private static final int LIMITS[][] = {
392        // Minimum  Greatest    Least  Maximum
393        //           Minimum  Maximum
394        {        1,        1,   83333,   83333 }, // ERA
395        {        1,        1,      60,      60 }, // YEAR
396        {        0,        0,      11,      11 }, // MONTH
397        {        1,        1,      50,      55 }, // WEEK_OF_YEAR
398        {/*                                  */}, // WEEK_OF_MONTH
399        {        1,        1,      29,      30 }, // DAY_OF_MONTH
400        {        1,        1,     353,     385 }, // DAY_OF_YEAR
401        {/*                                  */}, // DAY_OF_WEEK
402        {       -1,       -1,       5,       5 }, // DAY_OF_WEEK_IN_MONTH
403        {/*                                  */}, // AM_PM
404        {/*                                  */}, // HOUR
405        {/*                                  */}, // HOUR_OF_DAY
406        {/*                                  */}, // MINUTE
407        {/*                                  */}, // SECOND
408        {/*                                  */}, // MILLISECOND
409        {/*                                  */}, // ZONE_OFFSET
410        {/*                                  */}, // DST_OFFSET
411        { -5000000, -5000000, 5000000, 5000000 }, // YEAR_WOY
412        {/*                                  */}, // DOW_LOCAL
413        { -5000000, -5000000, 5000000, 5000000 }, // EXTENDED_YEAR
414        {/*                                  */}, // JULIAN_DAY
415        {/*                                  */}, // MILLISECONDS_IN_DAY
416        {        0,        0,       1,       1 }, // IS_LEAP_MONTH
417    };
418
419    /**
420     * Override Calendar to return the limit value for the given field.
421     */
422    protected int handleGetLimit(int field, int limitType) {
423        return LIMITS[field][limitType];
424    }
425
426    /**
427     * Implement abstract Calendar method to return the extended year
428     * defined by the current fields.  This will use either the ERA and
429     * YEAR field as the cycle and year-of-cycle, or the EXTENDED_YEAR
430     * field as the continuous year count, depending on which is newer.
431     */
432    protected int handleGetExtendedYear() {
433        int year;
434        if (newestStamp(ERA, YEAR, UNSET) <= getStamp(EXTENDED_YEAR)) {
435            year = internalGet(EXTENDED_YEAR, 1); // Default to year 1
436        } else {
437            int cycle = internalGet(ERA, 1) - 1; // 0-based cycle
438            // adjust to the instance specific epoch
439            year = cycle * 60 + internalGet(YEAR, 1) - (epochYear - CHINESE_EPOCH_YEAR);
440        }
441        return year;
442    }
443
444    /**
445     * Override Calendar method to return the number of days in the given
446     * extended year and month.
447     *
448     * <p>Note: This method also reads the IS_LEAP_MONTH field to determine
449     * whether or not the given month is a leap month.
450     */
451    protected int handleGetMonthLength(int extendedYear, int month) {
452        int thisStart = handleComputeMonthStart(extendedYear, month, true) -
453            EPOCH_JULIAN_DAY + 1; // Julian day -> local days
454        int nextStart = newMoonNear(thisStart + SYNODIC_GAP, true);
455        return nextStart - thisStart;
456    }
457
458    /**
459     * {@inheritDoc}
460     */
461    protected DateFormat handleGetDateFormat(String pattern, String override, ULocale locale) {
462        // Note: ICU 50 or later versions no longer use ChineseDateFormat.
463        // The super class's handleGetDateFormat will create an instance of
464        // SimpleDateFormat which supports Chinese calendar date formatting
465        // since ICU 49.
466
467        //return new ChineseDateFormat(pattern, override, locale);
468        return super.handleGetDateFormat(pattern, override, locale);
469    }
470
471    /**
472     * Field resolution table that incorporates IS_LEAP_MONTH.
473     */
474    static final int[][][] CHINESE_DATE_PRECEDENCE = {
475        {
476            { DAY_OF_MONTH },
477            { WEEK_OF_YEAR, DAY_OF_WEEK },
478            { WEEK_OF_MONTH, DAY_OF_WEEK },
479            { DAY_OF_WEEK_IN_MONTH, DAY_OF_WEEK },
480            { WEEK_OF_YEAR, DOW_LOCAL },
481            { WEEK_OF_MONTH, DOW_LOCAL },
482            { DAY_OF_WEEK_IN_MONTH, DOW_LOCAL },
483            { DAY_OF_YEAR },
484            { RESOLVE_REMAP | DAY_OF_MONTH, IS_LEAP_MONTH },
485        },
486        {
487            { WEEK_OF_YEAR },
488            { WEEK_OF_MONTH },
489            { DAY_OF_WEEK_IN_MONTH },
490            { RESOLVE_REMAP | DAY_OF_WEEK_IN_MONTH, DAY_OF_WEEK },
491            { RESOLVE_REMAP | DAY_OF_WEEK_IN_MONTH, DOW_LOCAL },
492        },
493    };
494
495    /**
496     * Override Calendar to add IS_LEAP_MONTH to the field resolution
497     * table.
498     */
499    protected int[][][] getFieldResolutionTable() {
500        return CHINESE_DATE_PRECEDENCE;
501    }
502
503    /**
504     * Adjust this calendar to be delta months before or after a given
505     * start position, pinning the day of month if necessary.  The start
506     * position is given as a local days number for the start of the month
507     * and a day-of-month.  Used by add() and roll().
508     * @param newMoon the local days of the first day of the month of the
509     * start position (days after January 1, 1970 0:00 Asia/Shanghai)
510     * @param dom the 1-based day-of-month of the start position
511     * @param delta the number of months to move forward or backward from
512     * the start position
513     */
514    private void offsetMonth(int newMoon, int dom, int delta) {
515        // Move to the middle of the month before our target month.
516        newMoon += (int) (CalendarAstronomer.SYNODIC_MONTH * (delta - 0.5));
517
518        // Search forward to the target month's new moon
519        newMoon = newMoonNear(newMoon, true);
520
521        // Find the target dom
522        int jd = newMoon + EPOCH_JULIAN_DAY - 1 + dom;
523
524        // Pin the dom.  In this calendar all months are 29 or 30 days
525        // so pinning just means handling dom 30.
526        if (dom > 29) {
527            set(JULIAN_DAY, jd-1);
528            // TODO Fix this.  We really shouldn't ever have to
529            // explicitly call complete().  This is either a bug in
530            // this method, in ChineseCalendar, or in
531            // Calendar.getActualMaximum().  I suspect the last.
532            complete();
533            if (getActualMaximum(DAY_OF_MONTH) >= dom) {
534                set(JULIAN_DAY, jd);
535            }
536        } else {
537            set(JULIAN_DAY, jd);
538        }
539    }
540
541    /**
542     * Override Calendar to handle leap months properly.
543     */
544    public void add(int field, int amount) {
545        switch (field) {
546        case MONTH:
547            if (amount != 0) {
548                int dom = get(DAY_OF_MONTH);
549                int day = get(JULIAN_DAY) - EPOCH_JULIAN_DAY; // Get local day
550                int moon = day - dom + 1; // New moon
551                offsetMonth(moon, dom, amount);
552            }
553            break;
554        default:
555            super.add(field, amount);
556            break;
557        }
558    }
559
560    /**
561     * Override Calendar to handle leap months properly.
562     */
563    public void roll(int field, int amount) {
564        switch (field) {
565        case MONTH:
566            if (amount != 0) {
567                int dom = get(DAY_OF_MONTH);
568                int day = get(JULIAN_DAY) - EPOCH_JULIAN_DAY; // Get local day
569                int moon = day - dom + 1; // New moon (start of this month)
570
571                // Note throughout the following:  Months 12 and 1 are never
572                // followed by a leap month (D&R p. 185).
573
574                // Compute the adjusted month number m.  This is zero-based
575                // value from 0..11 in a non-leap year, and from 0..12 in a
576                // leap year.
577                int m = get(MONTH); // 0-based month
578                if (isLeapYear) { // (member variable)
579                    if (get(IS_LEAP_MONTH) == 1) {
580                        ++m;
581                    } else {
582                        // Check for a prior leap month.  (In the
583                        // following, month 0 is the first month of the
584                        // year.)  Month 0 is never followed by a leap
585                        // month, and we know month m is not a leap month.
586                        // moon1 will be the start of month 0 if there is
587                        // no leap month between month 0 and month m;
588                        // otherwise it will be the start of month 1.
589                        int moon1 = moon -
590                            (int) (CalendarAstronomer.SYNODIC_MONTH * (m - 0.5));
591                        moon1 = newMoonNear(moon1, true);
592                        if (isLeapMonthBetween(moon1, moon)) {
593                            ++m;
594                        }
595                    }
596                }
597
598                // Now do the standard roll computation on m, with the
599                // allowed range of 0..n-1, where n is 12 or 13.
600                int n = isLeapYear ? 13 : 12; // Months in this year
601                int newM = (m + amount) % n;
602                if (newM < 0) {
603                    newM += n;
604                }
605
606                if (newM != m) {
607                    offsetMonth(moon, dom, newM - m);
608                }
609            }
610            break;
611        default:
612            super.roll(field, amount);
613            break;
614        }
615    }
616
617    //------------------------------------------------------------------
618    // Support methods and constants
619    //------------------------------------------------------------------
620
621    /**
622     * The start year of the Chinese calendar, the 61st year of the reign
623     * of Huang Di.  Some sources use the first year of his reign,
624     * resulting in EXTENDED_YEAR values 60 years greater and ERA (cycle)
625     * values one greater.
626     */
627    private static final int CHINESE_EPOCH_YEAR = -2636; // Gregorian year
628
629    /**
630     * The time zone used for performing astronomical computations.
631     * Some sources use a different historically accurate
632     * offset of GMT+7:45:40 for years before 1929; we do not do this.
633     */
634    private static final TimeZone CHINA_ZONE = new SimpleTimeZone(8 * ONE_HOUR, "CHINA_ZONE").freeze();
635
636    /**
637     * Value to be added or subtracted from the local days of a new moon to
638     * get close to the next or prior new moon, but not cross it.  Must be
639     * >= 1 and < CalendarAstronomer.SYNODIC_MONTH.
640     */
641    private static final int SYNODIC_GAP = 25;
642
643    /**
644     * Convert local days to UTC epoch milliseconds.
645     * This is not an accurate conversion in terms that getTimezoneOffset
646     * takes the milliseconds in GMT (not local time).  In theory, more
647     * accurate algorithm can be implemented but practically we do not need
648     * to go through that complication as long as the historically timezone
649     * changes did not happen around the 'tricky' new moon (new moon around
650     * the midnight).
651     *
652     * @param days days after January 1, 1970 0:00 in the astronomical base zone
653     * @return milliseconds after January 1, 1970 0:00 GMT
654     */
655    private final long daysToMillis(int days) {
656        long millis = days * ONE_DAY;
657        return millis - zoneAstro.getOffset(millis);
658    }
659
660    /**
661     * Convert UTC epoch milliseconds to local days.
662     * @param millis milliseconds after January 1, 1970 0:00 GMT
663     * @return days days after January 1, 1970 0:00 in the astronomical base zone
664     */
665    private final int millisToDays(long millis) {
666        return (int) floorDivide(millis + zoneAstro.getOffset(millis), ONE_DAY);
667    }
668
669    //------------------------------------------------------------------
670    // Astronomical computations
671    //------------------------------------------------------------------
672
673    /**
674     * Return the major solar term on or after December 15 of the given
675     * Gregorian year, that is, the winter solstice of the given year.
676     * Computations are relative to Asia/Shanghai time zone.
677     * @param gyear a Gregorian year
678     * @return days after January 1, 1970 0:00 Asia/Shanghai of the
679     * winter solstice of the given year
680     */
681    private int winterSolstice(int gyear) {
682
683        long cacheValue = winterSolsticeCache.get(gyear);
684
685        if (cacheValue == CalendarCache.EMPTY) {
686            // In books December 15 is used, but it fails for some years
687            // using our algorithms, e.g.: 1298 1391 1492 1553 1560.  That
688            // is, winterSolstice(1298) starts search at Dec 14 08:00:00
689            // PST 1298 with a final result of Dec 14 10:31:59 PST 1299.
690            long ms = daysToMillis(computeGregorianMonthStart(gyear, DECEMBER) +
691                                   1 - EPOCH_JULIAN_DAY);
692            astro.setTime(ms);
693
694            // Winter solstice is 270 degrees solar longitude aka Dongzhi
695            long solarLong = astro.getSunTime(CalendarAstronomer.WINTER_SOLSTICE,
696                                              true);
697            cacheValue = millisToDays(solarLong);
698            winterSolsticeCache.put(gyear, cacheValue);
699        }
700        return (int) cacheValue;
701    }
702
703    /**
704     * Return the closest new moon to the given date, searching either
705     * forward or backward in time.
706     * @param days days after January 1, 1970 0:00 Asia/Shanghai
707     * @param after if true, search for a new moon on or after the given
708     * date; otherwise, search for a new moon before it
709     * @return days after January 1, 1970 0:00 Asia/Shanghai of the nearest
710     * new moon after or before <code>days</code>
711     */
712    private int newMoonNear(int days, boolean after) {
713
714        astro.setTime(daysToMillis(days));
715        long newMoon = astro.getMoonTime(CalendarAstronomer.NEW_MOON, after);
716
717        return millisToDays(newMoon);
718    }
719
720    /**
721     * Return the nearest integer number of synodic months between
722     * two dates.
723     * @param day1 days after January 1, 1970 0:00 Asia/Shanghai
724     * @param day2 days after January 1, 1970 0:00 Asia/Shanghai
725     * @return the nearest integer number of months between day1 and day2
726     */
727    private int synodicMonthsBetween(int day1, int day2) {
728        return (int) Math.round((day2 - day1) / CalendarAstronomer.SYNODIC_MONTH);
729    }
730
731    /**
732     * Return the major solar term on or before a given date.  This
733     * will be an integer from 1..12, with 1 corresponding to 330 degrees,
734     * 2 to 0 degrees, 3 to 30 degrees,..., and 12 to 300 degrees.
735     * @param days days after January 1, 1970 0:00 Asia/Shanghai
736     */
737    private int majorSolarTerm(int days) {
738
739        astro.setTime(daysToMillis(days));
740
741        // Compute (floor(solarLongitude / (pi/6)) + 2) % 12
742        int term = ((int) Math.floor(6 * astro.getSunLongitude() / Math.PI) + 2) % 12;
743        if (term < 1) {
744            term += 12;
745        }
746        return term;
747    }
748
749    /**
750     * Return true if the given month lacks a major solar term.
751     * @param newMoon days after January 1, 1970 0:00 Asia/Shanghai of a new
752     * moon
753     */
754    private boolean hasNoMajorSolarTerm(int newMoon) {
755
756        int mst = majorSolarTerm(newMoon);
757        int nmn = newMoonNear(newMoon + SYNODIC_GAP, true);
758        int mstt = majorSolarTerm(nmn);
759        return mst == mstt;
760        /*
761        return majorSolarTerm(newMoon) ==
762            majorSolarTerm(newMoonNear(newMoon + SYNODIC_GAP, true));
763        */
764    }
765
766    //------------------------------------------------------------------
767    // Time to fields
768    //------------------------------------------------------------------
769
770    /**
771     * Return true if there is a leap month on or after month newMoon1 and
772     * at or before month newMoon2.
773     * @param newMoon1 days after January 1, 1970 0:00 astronomical base zone of a
774     * new moon
775     * @param newMoon2 days after January 1, 1970 0:00 astronomical base zone of a
776     * new moon
777     */
778    private boolean isLeapMonthBetween(int newMoon1, int newMoon2) {
779
780        // This is only needed to debug the timeOfAngle divergence bug.
781        // Remove this later. Liu 11/9/00
782        // DEBUG
783        if (synodicMonthsBetween(newMoon1, newMoon2) >= 50) {
784            throw new IllegalArgumentException("isLeapMonthBetween(" + newMoon1 +
785                                               ", " + newMoon2 +
786                                               "): Invalid parameters");
787        }
788
789        return (newMoon2 >= newMoon1) &&
790            (isLeapMonthBetween(newMoon1, newMoonNear(newMoon2 - SYNODIC_GAP, false)) ||
791             hasNoMajorSolarTerm(newMoon2));
792    }
793
794    /**
795     * Override Calendar to compute several fields specific to the Chinese
796     * calendar system.  These are:
797     *
798     * <ul><li>ERA
799     * <li>YEAR
800     * <li>MONTH
801     * <li>DAY_OF_MONTH
802     * <li>DAY_OF_YEAR
803     * <li>EXTENDED_YEAR</ul>
804     *
805     * The DAY_OF_WEEK and DOW_LOCAL fields are already set when this
806     * method is called.  The getGregorianXxx() methods return Gregorian
807     * calendar equivalents for the given Julian day.
808     *
809     * <p>Compute the ChineseCalendar-specific field IS_LEAP_MONTH.
810     */
811    protected void handleComputeFields(int julianDay) {
812
813        computeChineseFields(julianDay - EPOCH_JULIAN_DAY, // local days
814                             getGregorianYear(), getGregorianMonth(),
815                             true); // set all fields
816    }
817
818    /**
819     * Compute fields for the Chinese calendar system.  This method can
820     * either set all relevant fields, as required by
821     * <code>handleComputeFields()</code>, or it can just set the MONTH and
822     * IS_LEAP_MONTH fields, as required by
823     * <code>handleComputeMonthStart()</code>.
824     *
825     * <p>As a side effect, this method sets {@link #isLeapYear}.
826     * @param days days after January 1, 1970 0:00 astronomical base zone of the
827     * date to compute fields for
828     * @param gyear the Gregorian year of the given date
829     * @param gmonth the Gregorian month of the given date
830     * @param setAllFields if true, set the EXTENDED_YEAR, ERA, YEAR,
831     * DAY_OF_MONTH, and DAY_OF_YEAR fields.  In either case set the MONTH
832     * and IS_LEAP_MONTH fields.
833     */
834    private void computeChineseFields(int days, int gyear, int gmonth,
835                                      boolean setAllFields) {
836
837        // Find the winter solstices before and after the target date.
838        // These define the boundaries of this Chinese year, specifically,
839        // the position of month 11, which always contains the solstice.
840        // We want solsticeBefore <= date < solsticeAfter.
841        int solsticeBefore;
842        int solsticeAfter = winterSolstice(gyear);
843        if (days < solsticeAfter) {
844            solsticeBefore = winterSolstice(gyear - 1);
845        } else {
846            solsticeBefore = solsticeAfter;
847            solsticeAfter = winterSolstice(gyear + 1);
848        }
849
850        // Find the start of the month after month 11.  This will be either
851        // the prior month 12 or leap month 11 (very rare).  Also find the
852        // start of the following month 11.
853        int firstMoon = newMoonNear(solsticeBefore + 1, true);
854        int lastMoon = newMoonNear(solsticeAfter + 1, false);
855        int thisMoon = newMoonNear(days + 1, false); // Start of this month
856        // Note: isLeapYear is a member variable
857        isLeapYear = synodicMonthsBetween(firstMoon, lastMoon) == 12;
858
859        int month = synodicMonthsBetween(firstMoon, thisMoon);
860        if (isLeapYear && isLeapMonthBetween(firstMoon, thisMoon)) {
861            month--;
862        }
863        if (month < 1) {
864            month += 12;
865        }
866
867        boolean isLeapMonth = isLeapYear &&
868            hasNoMajorSolarTerm(thisMoon) &&
869            !isLeapMonthBetween(firstMoon, newMoonNear(thisMoon - SYNODIC_GAP, false));
870
871        internalSet(MONTH, month-1); // Convert from 1-based to 0-based
872        internalSet(IS_LEAP_MONTH, isLeapMonth?1:0);
873
874        if (setAllFields) {
875
876            // Extended year and cycle year is based on the epoch year
877            int extended_year = gyear - epochYear;
878            int cycle_year = gyear - CHINESE_EPOCH_YEAR;
879            if (month < 11 ||
880                gmonth >= JULY) {
881                extended_year++;
882                cycle_year++;
883            }
884            int dayOfMonth = days - thisMoon + 1;
885
886            internalSet(EXTENDED_YEAR, extended_year);
887
888            // 0->0,60  1->1,1  60->1,60  61->2,1  etc.
889            int[] yearOfCycle = new int[1];
890            int cycle = floorDivide(cycle_year-1, 60, yearOfCycle);
891            internalSet(ERA, cycle+1);
892            internalSet(YEAR, yearOfCycle[0]+1);
893
894            internalSet(DAY_OF_MONTH, dayOfMonth);
895
896            // Days will be before the first new year we compute if this
897            // date is in month 11, leap 11, 12.  There is never a leap 12.
898            // New year computations are cached so this should be cheap in
899            // the long run.
900            int newYear = newYear(gyear);
901            if (days < newYear) {
902                newYear = newYear(gyear-1);
903            }
904            internalSet(DAY_OF_YEAR, days - newYear + 1);
905        }
906    }
907
908    //------------------------------------------------------------------
909    // Fields to time
910    //------------------------------------------------------------------
911
912    /**
913     * Return the Chinese new year of the given Gregorian year.
914     * @param gyear a Gregorian year
915     * @return days after January 1, 1970 0:00 astronomical base zone of the
916     * Chinese new year of the given year (this will be a new moon)
917     */
918    private int newYear(int gyear) {
919
920        long cacheValue = newYearCache.get(gyear);
921
922        if (cacheValue == CalendarCache.EMPTY) {
923
924            int solsticeBefore= winterSolstice(gyear - 1);
925            int solsticeAfter = winterSolstice(gyear);
926            int newMoon1 = newMoonNear(solsticeBefore + 1, true);
927            int newMoon2 = newMoonNear(newMoon1 + SYNODIC_GAP, true);
928            int newMoon11 = newMoonNear(solsticeAfter + 1, false);
929
930            if (synodicMonthsBetween(newMoon1, newMoon11) == 12 &&
931                (hasNoMajorSolarTerm(newMoon1) || hasNoMajorSolarTerm(newMoon2))) {
932                cacheValue = newMoonNear(newMoon2 + SYNODIC_GAP, true);
933            } else {
934                cacheValue = newMoon2;
935            }
936
937            newYearCache.put(gyear, cacheValue);
938        }
939        return (int) cacheValue;
940    }
941
942    /**
943     * Return the Julian day number of day before the first day of the
944     * given month in the given extended year.
945     *
946     * <p>Note: This method reads the IS_LEAP_MONTH field to determine
947     * whether the given month is a leap month.
948     * @param eyear the extended year
949     * @param month the zero-based month.  The month is also determined
950     * by reading the IS_LEAP_MONTH field.
951     * @return the Julian day number of the day before the first
952     * day of the given month and year
953     */
954    protected int handleComputeMonthStart(int eyear, int month, boolean useMonth) {
955
956        // If the month is out of range, adjust it into range, and
957        // modify the extended year value accordingly.
958        if (month < 0 || month > 11) {
959            int[] rem = new int[1];
960            eyear += floorDivide(month, 12, rem);
961            month = rem[0];
962        }
963
964        int gyear = eyear + epochYear - 1; // Gregorian year
965        int newYear = newYear(gyear);
966        int newMoon = newMoonNear(newYear + month * 29, true);
967
968        int julianDay = newMoon + EPOCH_JULIAN_DAY;
969
970        // Save fields for later restoration
971        int saveMonth = internalGet(MONTH);
972        int saveIsLeapMonth = internalGet(IS_LEAP_MONTH);
973
974        // Ignore IS_LEAP_MONTH field if useMonth is false
975        int isLeapMonth = useMonth ? saveIsLeapMonth : 0;
976
977        computeGregorianFields(julianDay);
978
979        // This will modify the MONTH and IS_LEAP_MONTH fields (only)
980        computeChineseFields(newMoon, getGregorianYear(),
981                             getGregorianMonth(), false);
982
983        if (month != internalGet(MONTH) ||
984            isLeapMonth != internalGet(IS_LEAP_MONTH)) {
985            newMoon = newMoonNear(newMoon + SYNODIC_GAP, true);
986            julianDay = newMoon + EPOCH_JULIAN_DAY;
987        }
988
989        internalSet(MONTH, saveMonth);
990        internalSet(IS_LEAP_MONTH, saveIsLeapMonth);
991
992        return julianDay - 1;
993    }
994
995    /**
996     * {@inheritDoc}
997     */
998    public String getType() {
999        return "chinese";
1000    }
1001
1002    /**
1003     * {@inheritDoc}
1004     * @deprecated This API is ICU internal only.
1005     * @hide original deprecated declaration
1006     * @hide draft / provisional / internal are hidden on Android
1007     */
1008    @Deprecated
1009    public boolean haveDefaultCentury() {
1010        return false;
1011    }
1012
1013    /**
1014     * Override readObject.
1015     */
1016    private void readObject(ObjectInputStream stream)
1017        throws IOException, ClassNotFoundException
1018    {
1019        epochYear = CHINESE_EPOCH_YEAR;
1020        zoneAstro = CHINA_ZONE;
1021
1022        stream.defaultReadObject();
1023
1024        /* set up the transient caches... */
1025        astro = new CalendarAstronomer();
1026        winterSolsticeCache = new CalendarCache();
1027        newYearCache = new CalendarCache();
1028    }
1029
1030    /*
1031    private static CalendarFactory factory;
1032    public static CalendarFactory factory() {
1033        if (factory == null) {
1034            factory = new CalendarFactory() {
1035                public Calendar create(TimeZone tz, ULocale loc) {
1036                    return new ChineseCalendar(tz, loc);
1037                }
1038
1039                public String factoryName() {
1040                    return "Chinese";
1041                }
1042            };
1043        }
1044        return factory;
1045    }
1046    */
1047}
1048