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