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