1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html#License
3/*
4 *******************************************************************************
5 * Copyright (C) 1996-2016, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 *******************************************************************************
8 */
9package com.ibm.icu.util;
10import java.util.Date;
11import java.util.Locale;
12
13import com.ibm.icu.impl.CalendarCache;
14import com.ibm.icu.util.ULocale.Category;
15
16/**
17 * <code>HebrewCalendar</code> is a subclass of <code>Calendar</code>
18 * that that implements the traditional Hebrew calendar.
19 * This is the civil calendar in Israel and the liturgical calendar
20 * of the Jewish faith worldwide.
21 * <p>
22 * The Hebrew calendar is lunisolar and thus has a number of interesting
23 * properties that distinguish it from the Gregorian.  Months start
24 * on the day of (an arithmetic approximation of) each new moon.  Since the
25 * solar year (approximately 365.24 days) is not an even multiple of
26 * the lunar month (approximately 29.53 days) an extra "leap month" is
27 * inserted in 7 out of every 19 years.  To make matters even more
28 * interesting, the start of a year can be delayed by up to three days
29 * in order to prevent certain holidays from falling on the Sabbath and
30 * to prevent certain illegal year lengths.  Finally, the lengths of certain
31 * months can vary depending on the number of days in the year.
32 * <p>
33 * The leap month is known as "Adar 1" and is inserted between the
34 * months of Shevat and Adar in leap years.  Since the leap month does
35 * not come at the end of the year, calculations involving
36 * month numbers are particularly complex.  Users of this class should
37 * make sure to use the {@link #roll roll} and {@link #add add} methods
38 * rather than attempting to perform date arithmetic by manipulating
39 * the fields directly.
40 * <p>
41 * <b>Note:</b> In the traditional Hebrew calendar, days start at sunset.
42 * However, in order to keep the time fields in this class
43 * synchronized with those of the other calendars and with local clock time,
44 * we treat days and months as beginning at midnight,
45 * roughly 6 hours after the corresponding sunset.
46 * <p>
47 * If you are interested in more information on the rules behind the Hebrew
48 * calendar, see one of the following references:
49 * <ul>
50 * <li>"<a href="http://www.amazon.com/exec/obidos/ASIN/0521564743">Calendrical Calculations</a>",
51 *      by Nachum Dershowitz &amp; Edward Reingold, Cambridge University Press, 1997, pages 85-91.
52 *
53 * <li>Hebrew Calendar Science and Myths,
54 *      <a href="http://web.archive.org/web/20090423084613/http://www.geocities.com/Athens/1584/">
55 *      http://web.archive.org/web/20090423084613/http://www.geocities.com/Athens/1584/</a>
56 *
57 * <li>The Calendar FAQ,
58 *      <a href="http://www.faqs.org/faqs/calendars/faq/">
59 *      http://www.faqs.org/faqs/calendars/faq/</a>
60 * </ul>
61 *
62 * <p>
63 * This class should not be subclassed.</p>
64 * <p>
65 * HebrewCalendar usually should be instantiated using
66 * {@link com.ibm.icu.util.Calendar#getInstance(ULocale)} passing in a <code>ULocale</code>
67 * with the tag <code>"@calendar=hebrew"</code>.</p>
68 *
69 * @see com.ibm.icu.util.GregorianCalendar
70 * @see com.ibm.icu.util.Calendar
71 *
72 * @author Laura Werner
73 * @author Alan Liu
74 * @stable ICU 2.8
75 */
76public class HebrewCalendar extends Calendar {
77    // jdk1.4.2 serialver
78    private static final long serialVersionUID = -1952524560588825816L;
79
80    //-------------------------------------------------------------------------
81    // Tons o' Constants...
82    //-------------------------------------------------------------------------
83
84
85    /**
86     * Constant for Tishri, the 1st month of the Hebrew year.
87     * @stable ICU 2.8
88     */
89    public static final int TISHRI = 0;
90
91    /**
92     * Constant for Heshvan, the 2nd month of the Hebrew year.
93     * @stable ICU 2.8
94     */
95    public static final int HESHVAN = 1;
96
97    /**
98     * Constant for Kislev, the 3rd month of the Hebrew year.
99     * @stable ICU 2.8
100     */
101    public static final int KISLEV = 2;
102
103    /**
104     * Constant for Tevet, the 4th month of the Hebrew year.
105     * @stable ICU 2.8
106     */
107    public static final int TEVET = 3;
108
109    /**
110     * Constant for Shevat, the 5th month of the Hebrew year.
111     * @stable ICU 2.8
112     */
113    public static final int SHEVAT = 4;
114
115    /**
116     * Constant for Adar I, the 6th month of the Hebrew year
117     * (present in leap years only). In non-leap years, the calendar
118     * jumps from Shevat (5th month) to Adar (7th month).
119     * @stable ICU 2.8
120     */
121    public static final int ADAR_1 = 5;
122
123    /**
124     * Constant for the Adar, the 7th month of the Hebrew year.
125     * @stable ICU 2.8
126     */
127    public static final int ADAR = 6;
128
129    /**
130     * Constant for Nisan, the 8th month of the Hebrew year.
131     * @stable ICU 2.8
132     */
133    public static final int NISAN = 7;
134
135    /**
136     * Constant for Iyar, the 9th month of the Hebrew year.
137     * @stable ICU 2.8
138     */
139    public static final int IYAR = 8;
140
141    /**
142     * Constant for Sivan, the 10th month of the Hebrew year.
143     * @stable ICU 2.8
144     */
145    public static final int SIVAN = 9;
146
147    /**
148     * Constant for Tammuz, the 11th month of the Hebrew year.
149     * @stable ICU 2.8
150     */
151    public static final int TAMUZ = 10;
152
153    /**
154     * Constant for Av, the 12th month of the Hebrew year.
155     * @stable ICU 2.8
156     */
157    public static final int AV = 11;
158
159    /**
160     * Constant for Elul, the 13th month of the Hebrew year.
161     * @stable ICU 2.8
162     */
163    public static final int ELUL = 12;
164
165    /**
166     * The absolute date, in milliseconds since 1/1/1970 AD, Gregorian,
167     * of the start of the Hebrew calendar.  In order to keep this calendar's
168     * time of day in sync with that of the Gregorian calendar, we use
169     * midnight, rather than sunset the day before.
170     */
171    //private static final long EPOCH_MILLIS = -180799862400000L; // 1/1/1 HY
172
173    private static final int LIMITS[][] = {
174        // Minimum  Greatest    Least  Maximum
175        //           Minimum  Maximum
176        {        0,        0,       0,       0 }, // ERA
177        { -5000000, -5000000, 5000000, 5000000 }, // YEAR
178        {        0,        0,      12,      12 }, // MONTH
179        {        1,        1,      51,      56 }, // WEEK_OF_YEAR
180        {/*                                  */}, // WEEK_OF_MONTH
181        {        1,        1,      29,      30 }, // DAY_OF_MONTH
182        {        1,        1,     353,     385 }, // DAY_OF_YEAR
183        {/*                                  */}, // DAY_OF_WEEK
184        {       -1,       -1,       5,       5 }, // DAY_OF_WEEK_IN_MONTH
185        {/*                                  */}, // AM_PM
186        {/*                                  */}, // HOUR
187        {/*                                  */}, // HOUR_OF_DAY
188        {/*                                  */}, // MINUTE
189        {/*                                  */}, // SECOND
190        {/*                                  */}, // MILLISECOND
191        {/*                                  */}, // ZONE_OFFSET
192        {/*                                  */}, // DST_OFFSET
193        { -5000000, -5000000, 5000000, 5000000 }, // YEAR_WOY
194        {/*                                  */}, // DOW_LOCAL
195        { -5000000, -5000000, 5000000, 5000000 }, // EXTENDED_YEAR
196        {/*                                  */}, // JULIAN_DAY
197        {/*                                  */}, // MILLISECONDS_IN_DAY
198    };
199
200    /**
201     * The lengths of the Hebrew months.  This is complicated, because there
202     * are three different types of years, or six if you count leap years.
203     * Due to the rules for postponing the start of the year to avoid having
204     * certain holidays fall on the sabbath, the year can end up being three
205     * different lengths, called "deficient", "normal", and "complete".
206     */
207    private static final int MONTH_LENGTH[][] = {
208        // Deficient  Normal     Complete
209        {   30,         30,         30     },           //Tishri
210        {   29,         29,         30     },           //Heshvan
211        {   29,         30,         30     },           //Kislev
212        {   29,         29,         29     },           //Tevet
213        {   30,         30,         30     },           //Shevat
214        {   30,         30,         30     },           //Adar I (leap years only)
215        {   29,         29,         29     },           //Adar
216        {   30,         30,         30     },           //Nisan
217        {   29,         29,         29     },           //Iyar
218        {   30,         30,         30     },           //Sivan
219        {   29,         29,         29     },           //Tammuz
220        {   30,         30,         30     },           //Av
221        {   29,         29,         29     },           //Elul
222    };
223
224    /**
225     * The cumulative # of days to the end of each month in a non-leap year
226     * Although this can be calculated from the MONTH_LENGTH table,
227     * keeping it around separately makes some calculations a lot faster
228     */
229    private static final int MONTH_START[][] = {
230        // Deficient  Normal     Complete
231        {    0,          0,          0  },          // (placeholder)
232        {   30,         30,         30  },          // Tishri
233        {   59,         59,         60  },          // Heshvan
234        {   88,         89,         90  },          // Kislev
235        {  117,        118,        119  },          // Tevet
236        {  147,        148,        149  },          // Shevat
237        {  147,        148,        149  },          // (Adar I placeholder)
238        {  176,        177,        178  },          // Adar
239        {  206,        207,        208  },          // Nisan
240        {  235,        236,        237  },          // Iyar
241        {  265,        266,        267  },          // Sivan
242        {  294,        295,        296  },          // Tammuz
243        {  324,        325,        326  },          // Av
244        {  353,        354,        355  },          // Elul
245    };
246
247    /**
248     * The cumulative # of days to the end of each month in a leap year
249     */
250    private static final int LEAP_MONTH_START[][] = {
251        // Deficient  Normal     Complete
252        {    0,          0,          0  },          // (placeholder)
253        {   30,         30,         30  },          // Tishri
254        {   59,         59,         60  },          // Heshvan
255        {   88,         89,         90  },          // Kislev
256        {  117,        118,        119  },          // Tevet
257        {  147,        148,        149  },          // Shevat
258        {  177,        178,        179  },          // Adar I
259        {  206,        207,        208  },          // Adar II
260        {  236,        237,        238  },          // Nisan
261        {  265,        266,        267  },          // Iyar
262        {  295,        296,        297  },          // Sivan
263        {  324,        325,        326  },          // Tammuz
264        {  354,        355,        356  },          // Av
265        {  383,        384,        385  },          // Elul
266    };
267
268    //-------------------------------------------------------------------------
269    // Data Members...
270    //-------------------------------------------------------------------------
271
272    private static CalendarCache cache = new CalendarCache();
273
274    //-------------------------------------------------------------------------
275    // Constructors...
276    //-------------------------------------------------------------------------
277
278    /**
279     * Constructs a default <code>HebrewCalendar</code> using the current time
280     * in the default time zone with the default <code>FORMAT</code> locale.
281     * @see Category#FORMAT
282     * @stable ICU 2.8
283     */
284    public HebrewCalendar() {
285        this(TimeZone.getDefault(), ULocale.getDefault(Category.FORMAT));
286    }
287
288    /**
289     * Constructs a <code>HebrewCalendar</code> based on the current time
290     * in the given time zone with the default <code>FORMAT</code> locale.
291     *
292     * @param zone The time zone for the new calendar.
293     * @see Category#FORMAT
294     * @stable ICU 2.8
295     */
296    public HebrewCalendar(TimeZone zone) {
297        this(zone, ULocale.getDefault(Category.FORMAT));
298    }
299
300    /**
301     * Constructs a <code>HebrewCalendar</code> based on the current time
302     * in the default time zone with the given locale.
303     *
304     * @param aLocale The locale for the new calendar.
305     * @stable ICU 2.8
306     */
307    public HebrewCalendar(Locale aLocale) {
308        this(TimeZone.getDefault(), aLocale);
309    }
310
311    /**
312     * Constructs a <code>HebrewCalendar</code> based on the current time
313     * in the default time zone with the given locale.
314     *
315     * @param locale The locale for the new calendar.
316     * @stable ICU 3.2
317     */
318    public HebrewCalendar(ULocale locale) {
319        this(TimeZone.getDefault(), locale);
320    }
321
322    /**
323     * Constructs a <code>HebrewCalendar</code> based on the current time
324     * in the given time zone with the given locale.
325     *
326     * @param zone The time zone for the new calendar.
327     *
328     * @param aLocale The locale for the new calendar.
329     * @stable ICU 2.8
330     */
331    public HebrewCalendar(TimeZone zone, Locale aLocale) {
332        super(zone, aLocale);
333        setTimeInMillis(System.currentTimeMillis());
334    }
335
336    /**
337     * Constructs a <code>HebrewCalendar</code> based on the current time
338     * in the given time zone with the given locale.
339     *
340     * @param zone The time zone for the new calendar.
341     *
342     * @param locale The locale for the new calendar.
343     * @stable ICU 3.2
344     */
345    public HebrewCalendar(TimeZone zone, ULocale locale) {
346        super(zone, locale);
347        setTimeInMillis(System.currentTimeMillis());
348    }
349
350    /**
351     * Constructs a <code>HebrewCalendar</code> with the given date set
352     * in the default time zone with the default <code>FORMAT</code> locale.
353     *
354     * @param year      The value used to set the calendar's {@link #YEAR YEAR} time field.
355     *
356     * @param month     The value used to set the calendar's {@link #MONTH MONTH} time field.
357     *                  The value is 0-based. e.g., 0 for Tishri.
358     *
359     * @param date      The value used to set the calendar's {@link #DATE DATE} time field.
360     * @see Category#FORMAT
361     * @stable ICU 2.8
362     */
363    public HebrewCalendar(int year, int month, int date) {
364        super(TimeZone.getDefault(), ULocale.getDefault(Category.FORMAT));
365        this.set(YEAR, year);
366        this.set(MONTH, month);
367        this.set(DATE, date);
368    }
369
370    /**
371     * Constructs a <code>HebrewCalendar</code> with the given date set
372     * in the default time zone with the default <code>FORMAT</code> locale.
373     *
374     * @param date      The date to which the new calendar is set.
375     * @see Category#FORMAT
376     * @stable ICU 2.8
377     */
378    public HebrewCalendar(Date date) {
379        super(TimeZone.getDefault(), ULocale.getDefault(Category.FORMAT));
380        this.setTime(date);
381    }
382
383    /**
384     * Constructs a <code>HebrewCalendar</code> with the given date
385     * and time set for the default time zone with the default <code>FORMAT</code> locale.
386     *
387     * @param year      The value used to set the calendar's {@link #YEAR YEAR} time field.
388     *
389     * @param month     The value used to set the calendar's {@link #MONTH MONTH} time field.
390     *                  The value is 0-based. e.g., 0 for Tishri.
391     *
392     * @param date      The value used to set the calendar's {@link #DATE DATE} time field.
393     *
394     * @param hour      The value used to set the calendar's {@link #HOUR_OF_DAY HOUR_OF_DAY} time field.
395     *
396     * @param minute    The value used to set the calendar's {@link #MINUTE MINUTE} time field.
397     *
398     * @param second    The value used to set the calendar's {@link #SECOND SECOND} time field.
399     * @see Category#FORMAT
400     * @stable ICU 2.8
401     */
402    public HebrewCalendar(int year, int month, int date, int hour,
403                             int minute, int second)
404    {
405        super(TimeZone.getDefault(), ULocale.getDefault(Category.FORMAT));
406        this.set(YEAR, year);
407        this.set(MONTH, month);
408        this.set(DATE, date);
409        this.set(HOUR_OF_DAY, hour);
410        this.set(MINUTE, minute);
411        this.set(SECOND, second);
412    }
413
414    //-------------------------------------------------------------------------
415    // Rolling and adding functions overridden from Calendar
416    //
417    // These methods call through to the default implementation in IBMCalendar
418    // for most of the fields and only handle the unusual ones themselves.
419    //-------------------------------------------------------------------------
420
421    /**
422     * Add a signed amount to a specified field, using this calendar's rules.
423     * For example, to add three days to the current date, you can call
424     * <code>add(Calendar.DATE, 3)</code>.
425     * <p>
426     * When adding to certain fields, the values of other fields may conflict and
427     * need to be changed.  For example, when adding one to the {@link #MONTH MONTH} field
428     * for the date "30 Av 5758", the {@link #DAY_OF_MONTH DAY_OF_MONTH} field
429     * must be adjusted so that the result is "29 Elul 5758" rather than the invalid
430     * "30 Elul 5758".
431     * <p>
432     * This method is able to add to
433     * all fields except for {@link #ERA ERA}, {@link #DST_OFFSET DST_OFFSET},
434     * and {@link #ZONE_OFFSET ZONE_OFFSET}.
435     * <p>
436     * <b>Note:</b> You should always use {@link #roll roll} and add rather
437     * than attempting to perform arithmetic operations directly on the fields
438     * of a <tt>HebrewCalendar</tt>.  Since the {@link #MONTH MONTH} field behaves
439     * discontinuously in non-leap years, simple arithmetic can give invalid results.
440     * <p>
441     * @param field     the time field.
442     * @param amount    the amount to add to the field.
443     *
444     * @exception   IllegalArgumentException if the field is invalid or refers
445     *              to a field that cannot be handled by this method.
446     * @stable ICU 2.8
447     */
448    public void add(int field, int amount)
449    {
450        switch (field) {
451        case MONTH:
452            {
453                // We can't just do a set(MONTH, get(MONTH) + amount).  The
454                // reason is ADAR_1.  Suppose amount is +2 and we land in
455                // ADAR_1 -- then we have to bump to ADAR_2 aka ADAR.  But
456                // if amount is -2 and we land in ADAR_1, then we have to
457                // bump the other way -- down to SHEVAT.  - Alan 11/00
458                int month = get(MONTH);
459                int year = get(YEAR);
460                boolean acrossAdar1;
461                if (amount > 0) {
462                    acrossAdar1 = (month < ADAR_1); // started before ADAR_1?
463                    month += amount;
464                    for (;;) {
465                        if (acrossAdar1 && month>=ADAR_1 && !isLeapYear(year)) {
466                            ++month;
467                        }
468                        if (month <= ELUL) {
469                            break;
470                        }
471                        month -= ELUL+1;
472                        ++year;
473                        acrossAdar1 = true;
474                    }
475                } else {
476                    acrossAdar1 = (month > ADAR_1); // started after ADAR_1?
477                    month += amount;
478                    for (;;) {
479                        if (acrossAdar1 && month<=ADAR_1 && !isLeapYear(year)) {
480                            --month;
481                        }
482                        if (month >= 0) {
483                            break;
484                        }
485                        month += ELUL+1;
486                        --year;
487                        acrossAdar1 = true;
488                    }
489                }
490                set(MONTH, month);
491                set(YEAR, year);
492                pinField(DAY_OF_MONTH);
493                break;
494            }
495
496        default:
497            super.add(field, amount);
498            break;
499        }
500    }
501
502    /**
503     * Rolls (up/down) a specified amount time on the given field.  For
504     * example, to roll the current date up by three days, you can call
505     * <code>roll(Calendar.DATE, 3)</code>.  If the
506     * field is rolled past its maximum allowable value, it will "wrap" back
507     * to its minimum and continue rolling.
508     * For example, calling <code>roll(Calendar.DATE, 10)</code>
509     * on a Hebrew calendar set to "25 Av 5758" will result in the date "5 Av 5758".
510     * <p>
511     * When rolling certain fields, the values of other fields may conflict and
512     * need to be changed.  For example, when rolling the {@link #MONTH MONTH} field
513     * upward by one for the date "30 Av 5758", the {@link #DAY_OF_MONTH DAY_OF_MONTH} field
514     * must be adjusted so that the result is "29 Elul 5758" rather than the invalid
515     * "30 Elul".
516     * <p>
517     * This method is able to roll
518     * all fields except for {@link #ERA ERA}, {@link #DST_OFFSET DST_OFFSET},
519     * and {@link #ZONE_OFFSET ZONE_OFFSET}.  Subclasses may, of course, add support for
520     * additional fields in their overrides of <code>roll</code>.
521     * <p>
522     * <b>Note:</b> You should always use roll and {@link #add add} rather
523     * than attempting to perform arithmetic operations directly on the fields
524     * of a <tt>HebrewCalendar</tt>.  Since the {@link #MONTH MONTH} field behaves
525     * discontinuously in non-leap years, simple arithmetic can give invalid results.
526     * <p>
527     * @param field     the time field.
528     * @param amount    the amount by which the field should be rolled.
529     *
530     * @exception   IllegalArgumentException if the field is invalid or refers
531     *              to a field that cannot be handled by this method.
532     * @stable ICU 2.8
533     */
534    public void roll(int field, int amount)
535    {
536        switch (field) {
537        case MONTH:
538            {
539                int month = get(MONTH);
540                int year = get(YEAR);
541
542                boolean leapYear = isLeapYear(year);
543                int yearLength = monthsInYear(year);
544                int newMonth = month + (amount % yearLength);
545                //
546                // If it's not a leap year and we're rolling past the missing month
547                // of ADAR_1, we need to roll an extra month to make up for it.
548                //
549                if (!leapYear) {
550                    if (amount > 0 && month < ADAR_1 && newMonth >= ADAR_1) {
551                        newMonth++;
552                    } else if (amount < 0 && month > ADAR_1 && newMonth <= ADAR_1) {
553                        newMonth--;
554                    }
555                }
556                set(MONTH, (newMonth + 13) % 13);
557                pinField(DAY_OF_MONTH);
558                return;
559            }
560        default:
561            super.roll(field, amount);
562        }
563    }
564
565    //-------------------------------------------------------------------------
566    // Support methods
567    //-------------------------------------------------------------------------
568
569    // Hebrew date calculations are performed in terms of days, hours, and
570    // "parts" (or halakim), which are 1/1080 of an hour, or 3 1/3 seconds.
571    private static final long HOUR_PARTS = 1080;
572    private static final long DAY_PARTS  = 24*HOUR_PARTS;
573
574    // An approximate value for the length of a lunar month.
575    // It is used to calculate the approximate year and month of a given
576    // absolute date.
577    static private final int  MONTH_DAYS = 29;
578    static private final long MONTH_FRACT = 12*HOUR_PARTS + 793;
579    static private final long MONTH_PARTS = MONTH_DAYS*DAY_PARTS + MONTH_FRACT;
580
581    // The time of the new moon (in parts) on 1 Tishri, year 1 (the epoch)
582    // counting from noon on the day before.  BAHARAD is an abbreviation of
583    // Bet (Monday), Hey (5 hours from sunset), Resh-Daled (204).
584    static private final long BAHARAD = 11*HOUR_PARTS + 204;
585
586    /**
587     * Finds the day # of the first day in the given Hebrew year.
588     * To do this, we want to calculate the time of the Tishri 1 new moon
589     * in that year.
590     * <p>
591     * The algorithm here is similar to ones described in a number of
592     * references, including:
593     * <ul>
594     * <li>"Calendrical Calculations", by Nachum Dershowitz & Edward Reingold,
595     *     Cambridge University Press, 1997, pages 85-91.
596     *
597     * <li>Hebrew Calendar Science and Myths,
598     *     <a href="http://www.geocities.com/Athens/1584/">
599     *     http://www.geocities.com/Athens/1584/</a>
600     *
601     * <li>The Calendar FAQ,
602     *      <a href="http://www.faqs.org/faqs/calendars/faq/">
603     *      http://www.faqs.org/faqs/calendars/faq/</a>
604     * </ul>
605     */
606    private static long startOfYear(int year)
607    {
608        long day = cache.get(year);
609
610        if (day == CalendarCache.EMPTY) {
611            int months = (235 * year - 234) / 19;           // # of months before year
612
613            long frac = months * MONTH_FRACT + BAHARAD;     // Fractional part of day #
614            day  = months * 29 + (frac / DAY_PARTS);        // Whole # part of calculation
615            frac = frac % DAY_PARTS;                        // Time of day
616
617            int wd = (int)(day % 7);                        // Day of week (0 == Monday)
618
619            if (wd == 2 || wd == 4 || wd == 6) {
620                // If the 1st is on Sun, Wed, or Fri, postpone to the next day
621                day += 1;
622                wd = (int)(day % 7);
623            }
624            if (wd == 1 && frac > 15*HOUR_PARTS+204 && !isLeapYear(year) ) {
625                // If the new moon falls after 3:11:20am (15h204p from the previous noon)
626                // on a Tuesday and it is not a leap year, postpone by 2 days.
627                // This prevents 356-day years.
628                day += 2;
629            }
630            else if (wd == 0 && frac > 21*HOUR_PARTS+589 && isLeapYear(year-1) ) {
631                // If the new moon falls after 9:32:43 1/3am (21h589p from yesterday noon)
632                // on a Monday and *last* year was a leap year, postpone by 1 day.
633                // Prevents 382-day years.
634                day += 1;
635            }
636            cache.put(year, day);
637        }
638        return day;
639    }
640
641    /*
642     * Find the day of the week for a given day
643     *
644     * @param day   The # of days since the start of the Hebrew calendar,
645     *              1-based (i.e. 1/1/1 AM is day 1).
646     */
647    /*private static int absoluteDayToDayOfWeek(long day)
648    {
649        // We know that 1/1/1 AM is a Monday, which makes the math easy...
650        return (int)(day % 7) + 1;
651    }*/
652
653    /**
654     * Returns the the type of a given year.
655     *  0   "Deficient" year with 353 or 383 days
656     *  1   "Normal"    year with 354 or 384 days
657     *  2   "Complete"  year with 355 or 385 days
658     */
659    private final int yearType(int year)
660    {
661        int yearLength = handleGetYearLength(year);
662
663        if (yearLength > 380) {
664           yearLength -= 30;        // Subtract length of leap month.
665        }
666
667        int type = 0;
668
669        switch (yearLength) {
670            case 353:
671                type = 0; break;
672            case 354:
673                type = 1; break;
674            case 355:
675                type = 2; break;
676            default:
677                throw new IllegalArgumentException("Illegal year length " + yearLength + " in year " + year);
678
679        }
680        return type;
681    }
682
683    /**
684     * Determine whether a given Hebrew year is a leap year
685     *
686     * The rule here is that if (year % 19) == 0, 3, 6, 8, 11, 14, or 17.
687     * The formula below performs the same test, believe it or not.
688     * @internal
689     * @deprecated This API is ICU internal only.
690     */
691    @Deprecated
692    public static boolean isLeapYear(int year) {
693        //return (year * 12 + 17) % 19 >= 12;
694        int x = (year*12 + 17) % 19;
695        return x >= ((x < 0) ? -7 : 12);
696    }
697
698    private static int monthsInYear(int year) {
699        return isLeapYear(year) ? 13 : 12;
700    }
701
702    //-------------------------------------------------------------------------
703    // Calendar framework
704    //-------------------------------------------------------------------------
705
706    /**
707     * @stable ICU 2.8
708     */
709    protected int handleGetLimit(int field, int limitType) {
710        return LIMITS[field][limitType];
711    }
712
713    /**
714     * Returns the length of the given month in the given year
715     * @stable ICU 2.8
716     */
717    protected int handleGetMonthLength(int extendedYear, int month) {
718        // Resolve out-of-range months.  This is necessary in order to
719        // obtain the correct year.  We correct to
720        // a 12- or 13-month year (add/subtract 12 or 13, depending
721        // on the year) but since we _always_ number from 0..12, and
722        // the leap year determines whether or not month 5 (Adar 1)
723        // is present, we allow 0..12 in any given year.
724        while (month < 0) {
725            month += monthsInYear(--extendedYear);
726        }
727        // Careful: allow 0..12 in all years
728        while (month > 12) {
729            month -= monthsInYear(extendedYear++);
730        }
731
732        switch (month) {
733            case HESHVAN:
734            case KISLEV:
735                // These two month lengths can vary
736                return MONTH_LENGTH[month][yearType(extendedYear)];
737
738            default:
739                // The rest are a fixed length
740                return MONTH_LENGTH[month][0];
741        }
742    }
743
744    /**
745     * Returns the number of days in the given Hebrew year
746     * @stable ICU 2.8
747     */
748    protected int handleGetYearLength(int eyear) {
749        return (int)(startOfYear(eyear+1) - startOfYear(eyear));
750    }
751
752    /**
753     * {@inheritDoc}
754     * <p>
755     * Overrides {@link Calendar#validateField(int)} to provide
756     * special handling for month validation for Hebrew calendar.
757     * @internal
758     * @deprecated This API is ICU internal only.
759     */
760    @Deprecated
761    protected void validateField(int field) {
762        if (field == MONTH && !isLeapYear(handleGetExtendedYear()) && internalGet(MONTH) == ADAR_1) {
763            throw new IllegalArgumentException("MONTH cannot be ADAR_1(5) except leap years");
764        }
765
766        super.validateField(field);
767    }
768
769    //-------------------------------------------------------------------------
770    // Functions for converting from milliseconds to field values
771    //-------------------------------------------------------------------------
772
773    /**
774     * Subclasses may override this method to compute several fields
775     * specific to each calendar system.  These are:
776     *
777     * <ul><li>ERA
778     * <li>YEAR
779     * <li>MONTH
780     * <li>DAY_OF_MONTH
781     * <li>DAY_OF_YEAR
782     * <li>EXTENDED_YEAR</ul>
783     *
784     * Subclasses can refer to the DAY_OF_WEEK and DOW_LOCAL fields,
785     * which will be set when this method is called.  Subclasses can
786     * also call the getGregorianXxx() methods to obtain Gregorian
787     * calendar equivalents for the given Julian day.
788     *
789     * <p>In addition, subclasses should compute any subclass-specific
790     * fields, that is, fields from BASE_FIELD_COUNT to
791     * getFieldCount() - 1.
792     * @stable ICU 2.8
793     */
794    protected void handleComputeFields(int julianDay) {
795        long d = julianDay - 347997;
796        long m = (d * DAY_PARTS) / MONTH_PARTS;         // Months (approx)
797        int year = (int)((19 * m + 234) / 235) + 1;     // Years (approx)
798        long ys  = startOfYear(year);                   // 1st day of year
799        int dayOfYear = (int)(d - ys);
800
801        // Because of the postponement rules, it's possible to guess wrong.  Fix it.
802        while (dayOfYear < 1) {
803            year--;
804            ys  = startOfYear(year);
805            dayOfYear = (int)(d - ys);
806        }
807
808        // Now figure out which month we're in, and the date within that month
809        int yearType = yearType(year);
810        int monthStart[][] = isLeapYear(year) ? LEAP_MONTH_START : MONTH_START;
811
812        int month = 0;
813        while (dayOfYear > monthStart[month][yearType]) {
814            month++;
815        }
816        month--;
817        int dayOfMonth = dayOfYear - monthStart[month][yearType];
818
819        internalSet(ERA, 0);
820        internalSet(YEAR, year);
821        internalSet(EXTENDED_YEAR, year);
822        internalSet(MONTH, month);
823        internalSet(DAY_OF_MONTH, dayOfMonth);
824        internalSet(DAY_OF_YEAR, dayOfYear);
825    }
826
827    //-------------------------------------------------------------------------
828    // Functions for converting from field values to milliseconds
829    //-------------------------------------------------------------------------
830
831    /**
832     * @stable ICU 2.8
833     */
834    protected int handleGetExtendedYear() {
835        int year;
836        if (newerField(EXTENDED_YEAR, YEAR) == EXTENDED_YEAR) {
837            year = internalGet(EXTENDED_YEAR, 1); // Default to year 1
838        } else {
839            year = internalGet(YEAR, 1); // Default to year 1
840        }
841        return year;
842    }
843
844    /**
845     * Return JD of start of given month/year.
846     * @stable ICU 2.8
847     */
848    protected int handleComputeMonthStart(int eyear, int month, boolean useMonth) {
849
850        // Resolve out-of-range months.  This is necessary in order to
851        // obtain the correct year.  We correct to
852        // a 12- or 13-month year (add/subtract 12 or 13, depending
853        // on the year) but since we _always_ number from 0..12, and
854        // the leap year determines whether or not month 5 (Adar 1)
855        // is present, we allow 0..12 in any given year.
856        while (month < 0) {
857            month += monthsInYear(--eyear);
858        }
859        // Careful: allow 0..12 in all years
860        while (month > 12) {
861            month -= monthsInYear(eyear++);
862        }
863
864        long day = startOfYear(eyear);
865
866        if (month != 0) {
867            if (isLeapYear(eyear)) {
868                day += LEAP_MONTH_START[month][yearType(eyear)];
869            } else {
870                day += MONTH_START[month][yearType(eyear)];
871            }
872        }
873
874        return (int) (day + 347997);
875    }
876
877    /**
878     * {@inheritDoc}
879     * @stable ICU 3.8
880     */
881    public String getType() {
882        return "hebrew";
883    }
884
885    /*
886    private static CalendarFactory factory;
887    public static CalendarFactory factory() {
888        if (factory == null) {
889            factory = new CalendarFactory() {
890                public Calendar create(TimeZone tz, ULocale loc) {
891                    return new HebrewCalendar(tz, loc);
892                }
893
894                public String factoryName() {
895                    return "Hebrew";
896                }
897            };
898        }
899        return factory;
900    }
901    */
902}
903