001    /*
002     * Zmanim Java API
003     * Copyright (C) 2011 Eliyahu Hershfeld
004     * Copyright (C) September 2002 Avrom Finkelstien
005     *
006     * This program is free software; you can redistribute it and/or modify it under the terms of the
007     * GNU General Public License as published by the Free Software Foundation; either version 2 of the
008     * License, or (at your option) any later version.
009     *
010     * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
011     * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012     * General Public License for more details.
013     *
014     * You should have received a copy of the GNU General Public License along with this program; if
015     * not, write to the Free Software Foundation, Inc. 59 Temple Place - Suite 330, Boston, MA
016     * 02111-1307, USA or connect to: http://www.fsf.org/copyleft/gpl.html
017     */
018    package net.sourceforge.zmanim.hebrewcalendar;
019    
020    import java.util.*;
021    
022    /**
023     * The JewishDate class allows one to maintain an instance of a Gregorian date
024     * along with the corresponding Jewish date. This class can use the standard
025     * Java Date and Calendar classes for setting it, but does not subclass these
026     * classes or use them internally to any extensive use. This class also does not
027     * have a concept of a time (which the Date class does). If you are looking for
028     * a class that implements a Jewish calendar version of the Calendar class, one
029     * is available from <a
030     * href="http://oss.software.ibm.com/developerworks/opensource/icu4j/"
031     * >developerWorks</a> by IBM.
032     * 
033     * This open source Java code was written by <a
034     * href="http://www.facebook.com/avromf">Avrom Finkelstien</a> from his C++
035     * code. it was adapted to the KosherJava Zmanim API with simplification of the
036     * non-core code. The original algorithms were untouched.
037     * 
038     * Some of Avrom's original C++ code was translated from <a
039     * href="http://emr.cs.uiuc.edu/~reingold/calendar.C">C/C++ code</a> in <a
040     * href="http://www.calendarists.com">Calendrical Calculations</a> by Nachum
041     * Dershowitz and Edward M. Reingold, Software-- Practice & Experience, vol. 20,
042     * no. 9 (September, 1990), pp. 899- 928. Any method with the mark "ND+ER"
043     * indicates that the method was taken from this source with minor
044     * modifications.
045     * 
046     * The methods used to obtain the parsha were derived from the source code of <a
047     * href="http://www.sadinoff.com/hebcal/">HebCal</a> by Danny Sadinoff and JCal
048     * for the Mac by Frank Yellin. Both based their code on routines by Nachum
049     * Dershowitz and Edward M. Reingold. The class allows setting whether the
050     * parsha and holiday scheme follows the Israel scheme or outside Israel scheme.
051     * 
052     * <b>TODO:</b> Some do not belong in this class, but here is a partial list of what should still be implementted in some form:
053     * <ol>
054     *   <li>Add special parshiyos (shekalim, parah, zachor and hachodesh</li>
055     *   <li>Molad / shabbos mevarchim)</li>
056     *   <li>Haftorah (various minhagim)</li>
057     *   <li>Daf Yomi (bavli, yerushalmi, mishna yomis etc)</li>
058     *   <li>Support showing the upcoming parsha for the middle of the week</li>
059     * </ol>
060     * 
061     * @see java.util.Date
062     * @see java.util.Calendar
063     * @author &copy; Avrom Finkelstien 2002
064     * @author &copy; Eliyahu Hershfeld 2011
065     * @version 0.2.5
066     */
067    public class JewishDate implements Comparable, Cloneable {
068            private static final int JEWISH_EPOCH = -1373429;
069    
070            private int jewishMonth;
071            private int jewishDay;
072            private int jewishYear;
073    
074            private int gregorianMonth;
075            private int gregorianDayOfMonth;
076            private int gregorianYear;
077    
078            private int dayOfWeek;
079    
080            private int gregorianAbsDate;
081    
082            /**
083             * Use the formatting class for formatting Ashkenazi VS Sephardi English
084             * transliteration. Using the default will use the Ashkenazi pronounciation.
085             */
086            private static final String[] parshios = { "Bereshis", "Noach",
087                            "Lech Lecha", "Vayera", "Chayei Sara", "Toldos", "Vayetzei",
088                            "Vayishlach", "Vayeshev", "Miketz", "Vayigash", "Vayechi",
089                            "Shemos", "Vaera", "Bo", "Beshalach", "Yisro", "Mishpatim",
090                            "Terumah", "Tetzaveh", "Ki Sisa", "Vayakhel", "Pekudei", "Vayikra",
091                            "Tzav", "Shmini", "Tazria", "Metzora", "Achrei Mos", "Kedoshim",
092                            "Emor", "Behar", "Bechukosai", "Bamidbar", "Nasso", "Beha'aloscha",
093                            "Sh'lach", "Korach", "Chukas", "Balak", "Pinchas", "Matos",
094                            "Masei", "Devarim", "Vaeschanan", "Eikev", "Re'eh", "Shoftim",
095                            "Ki Seitzei", "Ki Savo", "Nitzavim", "Vayeilech", "Ha'Azinu",
096                            "Vayakhel Pekudei", "Tazria Metzora", "Achrei Mos Kedoshim",
097                            "Behar Bechukosai", "Chukas Balak", "Matos Masei",
098                            "Nitzavim Vayeilech" };
099            private boolean inIsrael = false;
100    
101            /**
102             * Returns the number of days in a given month in a given year.
103             * 
104             * @param month
105             *            the month
106             * @param year
107             *            the year (only impacts February)
108             * @return the number of days in the month in the given year
109             */
110            private static int getLastDayOfGregorianMonth(int month, int year) {
111                    switch (month) {
112                    case 2:
113                            if ((((year % 4) == 0) && ((year % 100) != 0))
114                                            || ((year % 400) == 0)) {
115                                    return 29;
116                            } else {
117                                    return 28;
118                            }
119                    case 4:
120                    case 6:
121                    case 9:
122                    case 11:
123                            return 30;
124                    default:
125                            return 31;
126                    }
127            }
128    
129            /**
130             * Returns the number of days in a given month for the current year.
131             * Will likely turn into a private method in the future.
132             * @param month
133             *            the month
134             * @return the number of days in the month
135             */
136            int getLastDayOfGregorianMonth(int month) {
137                    return getLastDayOfGregorianMonth(month, gregorianYear);
138            }
139    
140            /**
141             * Computes the Gregorian date from the absolute date. ND+ER
142             */
143            private void absDateToDate() {
144                    // Search forward year by year from approximate year
145                    gregorianYear = gregorianAbsDate / 366;
146                    while (gregorianAbsDate >= gregorianDateToAbsDate(gregorianYear + 1, 1,
147                                    1)) {
148                            gregorianYear++;
149                    }
150                    // Search forward month by month from January
151                    gregorianMonth = 1;
152                    while (gregorianAbsDate > gregorianDateToAbsDate(gregorianYear,
153                                    gregorianMonth, getLastDayOfGregorianMonth(gregorianMonth))) {
154                            gregorianMonth++;
155                    }
156                    gregorianDayOfMonth = gregorianAbsDate
157                                    - gregorianDateToAbsDate(gregorianYear, gregorianMonth, 1) + 1;
158            }
159    
160            /**
161             * Returns the absolute date (days since January 1, 0001 on the Gregorian
162             * calendar).
163             * 
164             * @return the number of days since January 1, 1
165             */
166            private int getAbsDate() {
167                    return gregorianAbsDate;
168            }
169    
170            /**
171             * Computes the absolute date from a Gregorian date. ND+ER
172             * 
173             * @param year
174             *            the Gregorian year
175             * @param month
176             *            the Gregorian month. Unlike the Java Calendar where January
177             *            has the value of 0,This expects a 1 for January
178             * @param absDate
179             *            the Gregorian day of month. If this is > the number of days in
180             *            the month/year, the last valid date of the month will be set
181             * @return the absolute Gregorian day
182             */
183            private static int gregorianDateToAbsDate(int year, int month,
184                            int dayOfMonth) {
185                    int absDate = 0; //dayOfMonth
186                    for (int m = month - 1; m > 0; m--) {
187                            // days in prior months of the year
188                            absDate = dayOfMonth + getLastDayOfGregorianMonth(m, year);
189                    }
190                    return (absDate // days this year //
191                                    + 365 * (year - 1) // days in previous years ignoring leap days
192                                    + (year - 1) / 4 // Julian leap days before this year...
193                                    - (year - 1) / 100 // ...minus prior century years...
194                    + (year - 1) / 400); // ...plus prior years divisible by 400
195            }
196    
197            /**
198             * Returns if the year is a Jewish leap year.
199             * 
200             * @param year
201             *            the Jewish year.
202             * @return true if it is a leap year
203             */
204            public static boolean isJewishLeapYear(int year) {
205                    if ((((7 * year) + 1) % 19) < 7) {
206                            return true;
207                    } else {
208                            return false;
209                    }
210            }
211    
212            /**
213             * Returns the last month of a given Jewish year.
214             * 
215             * @param year
216             *            the Jewish year.
217             * @return 12 on a non leap-year or 13 on a leap-year
218             */
219            private static int getLastMonthOfJewishYear(int year) {
220                    return isJewishLeapYear(year) ? 13 : 12;
221            }
222    
223            /**
224             * Returns the number of days elapsed from the Sunday prior to the start of
225             * the Jewish calendar to the mean conjunction of Tishri of the Jewish
226             * year.ND+ER
227             * 
228             * @param year
229             *            the Jewish year
230             * @return the number of days elapsed from the Sunday prior to the start of
231             *         the Jewish calendar to the mean conjunction of Tishri of Jewish
232             *         year.
233             */
234            private static int getJewishCalendarElapsedDays(int year) {
235                    int monthsElapsed = (235 * ((year - 1) / 19)) // Months in complete
236                                                                                                                    // cycles so far
237                                    + (12 * ((year - 1) % 19)) // Regular months in this cycle
238                                    + (7 * ((year - 1) % 19) + 1) / 19; // Leap months this cycle
239                    int partsElapsed = 204 + 793 * (monthsElapsed % 1080);
240                    int hoursElapsed = 5 + 12 * monthsElapsed + 793
241                                    * (monthsElapsed / 1080) + partsElapsed / 1080;
242                    int conjunctionDay = 1 + 29 * monthsElapsed + hoursElapsed / 24;
243                    int conjunctionParts = 1080 * (hoursElapsed % 24) + partsElapsed % 1080;
244                    int alternativeDay;
245                    if ((conjunctionParts >= 19440) // If new moon is at or after midday,
246                                    || (((conjunctionDay % 7) == 2) // ...or is on a Tuesday...
247                                                    && (conjunctionParts >= 9924) // at 9 hours, 204 parts
248                                                                                                                    // or later...
249                                    && !isJewishLeapYear(year)) // ...of a common year,
250                                    || (((conjunctionDay % 7) == 1) // ...or is on a Monday at...
251                                                    && (conjunctionParts >= 16789) // 15 hours, 589 parts or
252                                                                                                                    // later...
253                                    && (isJewishLeapYear(year - 1)))) { // at the end of a leap year
254                            // Then postpone Rosh HaShanah one day
255                            alternativeDay = conjunctionDay + 1;
256                    } else {
257                            alternativeDay = conjunctionDay;
258                    }
259                    if (((alternativeDay % 7) == 0)// If Rosh HaShanah would occur on
260                                                                                    // Sunday,
261                                    || ((alternativeDay % 7) == 3) // or Wednesday,
262                                    || ((alternativeDay % 7) == 5)) { // or Friday
263                            // Then postpone it one (more) day
264                            return (1 + alternativeDay);
265                    } else {
266                            return alternativeDay;
267                    }
268            }
269    
270            /**
271             * Returns the number of days for a given Jewish year. ND+ER
272             * 
273             * @param year
274             *            the Jewish year
275             * @return the number of days for a given Jewish year.
276             */
277            private static int getDaysInJewishYear(int year) {
278                    return getJewishCalendarElapsedDays(year + 1)
279                                    - getJewishCalendarElapsedDays(year);
280            }
281    
282            /**
283             * Returns if Cheshvan is long in a given Jewish year. ND+ER
284             * 
285             * @param year
286             *            the year
287             * @return true if Cheshvan is long in Jewish year.
288             */
289            public static boolean isCheshvanLong(int year) {
290                    return getDaysInJewishYear(year) % 10 == 5;
291            }
292    
293            /**
294             * Returns if the day is Rosh Chodesh.
295             * 
296             * @return true if it is Rosh Chodesh. Rosh Hashana will return false
297             */
298            public boolean isRoshChodesh() {
299                    // Rosh Hashana is not rosh chodesh. Elul never has 30 days
300                    return (jewishDay == 1 && jewishMonth != 7) || jewishDay == 30;
301            }
302    
303            /**
304             * Returns if Kislev is short in a given Jewish year. ND+ER
305             * 
306             * @param year
307             *            the Jewish year
308             * @return true if Kislev is short for the given Jewish year.
309             */
310            public static boolean isKislevShort(int year) {
311                    return getDaysInJewishYear(year) % 10 == 3;
312            }
313    
314            /**
315             * Returns the number of days of a Jewish month for a given month and year.
316             * 
317             * @param month
318             *            the Jewish month
319             * @param year
320             *            the Jewish Year
321             * @return the number of days for a given Jewish month
322             */
323            public static int getDaysInJewishMonth(int month, int year) {
324                    if ((month == 2) || (month == 4) || (month == 6)
325                                    || ((month == 8) && !(isCheshvanLong(year)))
326                                    || ((month == 9) && isKislevShort(year)) || (month == 10)
327                                    || ((month == 12) && !(isJewishLeapYear(year)))
328                                    || (month == 13)) {
329                            return 29;
330                    } else {
331                            return 30;
332                    }
333            }
334    
335            /**
336             * Computes the Jewish date from the absolute date. ND+ER
337             */
338            private void absDateToJewishDate() {
339                    // Approximation from below
340                    jewishYear = (gregorianAbsDate + JEWISH_EPOCH) / 366;
341                    // Search forward for year from the approximation
342                    while (gregorianAbsDate >= jewishDateToAbsDate(jewishYear + 1, 7, 1)) {
343                            jewishYear++;
344                    }
345                    // Search forward for month from either Tishri or Nisan.
346                    if (gregorianAbsDate < jewishDateToAbsDate(jewishYear, 1, 1)) {
347                            jewishMonth = 7;// Start at Tishri
348                    } else {
349                            jewishMonth = 1;// Start at Nisan
350                    }
351                    while (gregorianAbsDate > jewishDateToAbsDate(jewishYear, jewishMonth,
352                                    getDaysInJewishMonth(jewishMonth, jewishYear))) {
353                            jewishMonth++;
354                    }
355                    // Calculate the day by subtraction
356                    jewishDay = gregorianAbsDate
357                                    - jewishDateToAbsDate(jewishYear, jewishMonth, 1) + 1;
358            }
359    
360            /**
361             * Computes the absolute date of Jewish date. Default is current Jewish
362             * date. ND+ER
363             */
364            // private int hebrewDateToAbsDateBROKEN(int month, int date, int year) {
365            // int m;
366            //
367            // // Before Tishri, so add days in prior months//
368            // if (month < 7) {
369            // // this year before and after Nisan.//
370            // for (m = 7; m <= getLastMonthOfHebrewYear(hebrewYear); m++) {
371            // date = date + getLastDayOfHebrewMonth(m, year);
372            // }
373            // for (m = 1; m < month; m++) {
374            // date = date + getLastDayOfHebrewMonth(m, year);
375            // }
376            // } else { // Add days in prior months this year//
377            // for (m = 7; m < month; m++) {
378            // date = date + getLastDayOfHebrewMonth(m, year);
379            // }
380            // }
381            // // Days in prior years + Days elapsed before absolute date 1
382            // return (date + getHebrewCalendarElapsedDays(year) + HEBREW_EPOCH);
383            // }
384    
385            /**
386             * Returns the absolute date of Jewish date. ND+ER
387             * 
388             * @param year
389             *            the Jewish year. The year can't be negative
390             * @param month
391             *            the Jewish month starting with Nisan. Nisan expects a value of
392             *            1 etc till Adar with a value of 12. For a leap year, 13 will
393             *            be the expected value for Adar II.
394             * @param dayOfMonth
395             *            the Jewish day of month. valid values are 1-30. If the day of
396             *            month is set to 30 for a month that only has 29 days, the day
397             *            will be set as 29.
398             * @return the absolute date of the Jewish date.
399             */
400            private static int jewishDateToAbsDate(int year, int month, int dayOfMonth) {
401                    int m;
402                    // Before Tishri, so add days in prior months
403                    if (month < 7) {
404                            // this year before and after Nisan.
405                            for (m = 7; m <= getLastMonthOfJewishYear(year); m++) {
406                                    dayOfMonth = dayOfMonth + getDaysInJewishMonth(m, year);
407                            }
408                            for (m = 1; m < month; m++) {
409                                    dayOfMonth = dayOfMonth + getDaysInJewishMonth(m, year);
410                            }
411                    } else { // Add days in prior months this year
412                            for (m = 7; m < month; m++) {
413                                    dayOfMonth = dayOfMonth + getDaysInJewishMonth(m, year);
414                            }
415                    }
416                    // Days in prior years + Days elapsed before absolute date 1
417                    return (dayOfMonth + getJewishCalendarElapsedDays(year) + JEWISH_EPOCH);
418            }
419    
420            /**
421             * Creates a Jewish date based on a Gregorian date
422             * 
423             * @param gregorianYear
424             *            the Gregorian year
425             * @param gregorianMonth
426             *            the Gregorian month. Unlike the Java Calendar where January
427             *            has the value of 0,This expects a 1 for January
428             * @param gregorianDayOfMonth
429             *            the Gregorian day of month. If this is > the number of days in
430             *            the month/year, the last valid date of the month will be set
431             * 
432             */
433            public JewishDate(int gregorianYear, int gregorianMonth,
434                            int gregorianDayOfMonth) {
435                    setGregorianDate(gregorianYear, gregorianMonth, gregorianDayOfMonth);
436            }
437    
438            /**
439             * Creates a Jewish date based on Gregorian date and whether in Israel
440             * 
441             * @param gregorianYear
442             *            the Gregorian year
443             * @param gregorianMonth
444             *            the Gregorian month. Unlike the Java Calendar where January
445             *            has the value of 0,This expects a 1 for January
446             * @param gregorianDayOfMonth
447             *            the Gregorian day of month. If this is > the number of days in
448             *            the month/year, the last valid date of the month will be set
449             * @param inIsrael
450             *            whether in Israel. This affects Yom Tov and Parsha
451             *            calculations
452             */
453            public JewishDate(int gregorianYear, int gregorianMonth,
454                            int gregorianDayOfMonth, boolean inIsrael) {
455                    this(gregorianYear, gregorianMonth, gregorianDayOfMonth);
456                    setInIsrael(inIsrael);
457            }
458    
459            /**
460             * Default constructor will set a default date to the current system date.
461             */
462            public JewishDate() {
463                    resetDate();
464            }
465    
466            /**
467             * A constructor that initializes the date to the {@link java.util.Date
468             * Date} paremeter.
469             * 
470             * @param date
471             *            the <code>Date</code> to set the calendar to
472             */
473            public JewishDate(Date date) {
474                    setDate(date);
475            }
476    
477            /**
478             * A constructor that initializes the date to the {@link java.util.Calendar
479             * Calendar} paremeter.
480             * 
481             * @param calendar
482             *            the <code>Calendar</code> to set the calendar to
483             */
484            public JewishDate(Calendar calendar) {
485                    setDate(calendar);
486            }
487    
488            /**
489             * Sets the date based on a {@link java.util.Calendar Calendar} object.
490             * Modifies the Jewish date as well.
491             * 
492             * @param calendar
493             *            the <code>Calendar</code> to set the calendar to
494             */
495            public void setDate(Calendar calendar) {
496                    gregorianMonth = calendar.get(Calendar.MONTH) + 1;
497                    gregorianDayOfMonth = calendar.get(Calendar.DATE);
498                    gregorianYear = calendar.get(Calendar.YEAR);
499    
500                    // init the date
501                    gregorianAbsDate = gregorianDateToAbsDate(gregorianYear,
502                                    gregorianMonth, gregorianDayOfMonth);
503                    absDateToJewishDate();
504    
505                    // set day of week
506                    dayOfWeek = Math.abs(gregorianAbsDate % 7) + 1;
507            }
508    
509            /**
510             * Sets the date based on a {@link java.util.Date Date} object. Modifies the
511             * Jewish date as well.
512             * 
513             * @param date
514             *            the <code>Date</code> to set the calendar to
515             */
516            public void setDate(Date date) {
517                    Calendar cal = Calendar.getInstance();
518                    cal.setTime(date);
519                    setDate(cal);
520            }
521    
522            /**
523             * Sets the Gregorian Date, and updates the Jewish date accordingly.
524             * Confusingly unlike the Java Calendar where January has the value of
525             * 0,This expects a 1 for January this uses a
526             * 
527             * @param year
528             *            the Gregorian year
529             * @param month
530             *            the Gregorian month. Unlike the Java Calendar where January
531             *            has the value of 0,This expects a 1 for January
532             * @param dayOfMonth
533             *            the Gregorian day of month. If this is > the number of days in
534             *            the month/year, the last valid date of the month will be set
535             */
536            public void setGregorianDate(int year, int month, int dayOfMonth) {
537                    // precondition should be 1->12 anyways, but just in case... //
538                    if (month > 12 || month < 1) {
539                            throw new IllegalArgumentException(
540                                            "The Gregorian month has to be between 1 - 12. " + month
541                                                            + " is invalid.");
542                    }
543                    if (dayOfMonth <= 0) {
544                            throw new IllegalArgumentException(
545                                            "The day of month can't be less than 1. " + dayOfMonth
546                                                            + " is invalid.");
547                    }
548    
549                    // make sure date is a valid date for the given month, if not, set to
550                    // last day of month
551                    if (dayOfMonth > getLastDayOfGregorianMonth(month, year)) {
552                            dayOfMonth = getLastDayOfGregorianMonth(month, year);
553                    }
554                    if (year < 0) {
555                            throw new IllegalArgumentException(
556                                            "Years < 0 can't be claculated. " + year + " is invalid.");
557                    }
558                    // init month, date, year
559                    gregorianMonth = month;
560                    gregorianDayOfMonth = dayOfMonth;
561                    gregorianYear = year;
562    
563                    // init date
564                    gregorianAbsDate = gregorianDateToAbsDate(gregorianYear,
565                                    gregorianMonth, gregorianDayOfMonth);
566                    absDateToJewishDate();
567    
568                    // set day of week
569                    dayOfWeek = Math.abs(gregorianAbsDate % 7) + 1;
570            }
571    
572            /**
573             * Sets the Jewish Date and updates the Gregorian date accordingly.
574             * 
575             * @param year
576             *            the Jewish year. The year can't be negative
577             * @param month
578             *            the Jewish month starting with Nisan. Nisan expects a value of
579             *            1 etc till Adar with a value of 12. For a leap year, 13 will
580             *            be the expected value for Adar II.
581             * @param dayOfMonth
582             *            the Jewish day of month. valid values are 1-30. If the day of
583             *            month is set to 30 for a month that only has 29 days, the day
584             *            will be set as 29.
585             */
586            public void setJewishDate(int year, int month, int dayOfMonth) {
587                    if (month < 1 || month > getLastMonthOfJewishYear(year)) {
588                            throw new IllegalArgumentException(
589                                            "The Jewish month has to be between 1 and 12 (or 13 on a leap year). "
590                                                            + month + " is invalid for the year " + year + ".");
591                    }
592                    if (dayOfMonth < 1) {
593                            throw new IllegalArgumentException(
594                                            "The Jewish day of month can't be < 1.  " + dayOfMonth
595                                                            + " is invalid.");
596                    }
597    
598                    if (dayOfMonth > 30) {
599                            throw new IllegalArgumentException(
600                                            "The Jewish day of month can't be > 30.  " + dayOfMonth
601                                                            + " is invalid.");
602                    }
603    
604                    // if 30 is passed for a month that only has 29 days (for example by
605                    // rolling the month from a month that had 30 days to a month that only
606                    // has 29) set the date to 29th
607                    if (dayOfMonth > getDaysInJewishMonth(month, year)) {
608                            dayOfMonth = getDaysInJewishMonth(month, year);
609                    }
610    
611                    if (year < 0) {
612                            throw new IllegalArgumentException(
613                                            "A Jewish years < 0 can't be set. " + year + " is invalid.");
614                    }
615    
616                    jewishMonth = month;
617                    jewishDay = dayOfMonth;
618                    jewishYear = year;
619    
620                    // reset Gregorian date
621                    gregorianAbsDate = jewishDateToAbsDate(jewishYear, jewishMonth,
622                                    jewishDay);
623                    absDateToDate();
624    
625                    // reset day of week
626                    dayOfWeek = Math.abs(gregorianAbsDate % 7) + 1;
627            }
628    
629            /**
630             * Returns this object's date as a java.util.Date object. <b>Note</b>: This
631             * class does not have a concept of time.
632             * 
633             * @return The <code>Date</code>
634             */
635            public Date getTime() {
636                    Calendar cal = Calendar.getInstance();
637                    cal.set(gregorianYear, gregorianMonth - 1, gregorianDayOfMonth);
638                    return cal.getTime();
639            }
640    
641            /**
642             * Resets this date to the current system date.
643             */
644            public void resetDate() {
645                    Calendar calendar = Calendar.getInstance();
646                    setDate(calendar);
647            }
648    
649            /**
650             * Returns a string containing the Jewish date in the form,
651             * "day Month, year" e.g. "21 Shevat, 5729". For more complex formatting,
652             * use the formatter classes.
653             * 
654             * @return the Jewish date in the form "day Month, year" e.g.
655             *         "21 Shevat, 5729"
656             */
657            public String toString() {
658                    return HebrewDateFormatter.getHebrewDateAsString(this);
659            }
660    
661            /**
662             * Rolls the date forward by 1. It modifies both the Gregorian and Jewish
663             * dates accordingly.
664             */
665            public void forward() {
666                    // Change Gregorian date
667                    if (gregorianDayOfMonth == getLastDayOfGregorianMonth(gregorianMonth)) {
668                            // if last day of year
669                            if (gregorianMonth == 12) {
670                                    gregorianYear++;
671                                    gregorianMonth = 1;
672                                    gregorianDayOfMonth = 1;
673                            } else {
674                                    gregorianMonth++;
675                                    gregorianDayOfMonth = 1;
676                            }
677                    } else { // if not last day of month
678                            gregorianDayOfMonth++;
679                    }
680    
681                    // Change the Jewish Date
682                    if (jewishDay == getDaysInJewishMonth(jewishMonth, jewishYear)) {
683                            // if it last day of elul (i.e. last day of Jewish year)
684                            if (jewishMonth == 6) {
685                                    jewishYear++;
686                                    jewishMonth++;
687                                    jewishDay = 1;
688                            } else if (jewishMonth == getLastMonthOfJewishYear(jewishYear)) {
689                                    // if it is the last day of Adar, or Adar II as case may be
690                                    jewishMonth = 1;
691                                    jewishDay = 1;
692                            } else {
693                                    jewishMonth++;
694                                    jewishDay = 1;
695                            }
696                    } else { // if not last date of month
697                            jewishDay++;
698                    }
699                    // if last day of week, loop back to Sunday
700                    if (dayOfWeek == 7) {
701                            dayOfWeek = 1;
702                    } else {
703                            dayOfWeek++;
704                    }
705                    // increment the absolute date
706                    gregorianAbsDate++;
707            }
708    
709            /**
710             * Rolls the date back by 1. It modifies both the Gregorian and Jewish dates
711             * accordingly
712             */
713            public void back() {
714                    // Change Gregorian date
715                    // if first day of month
716                    if (gregorianDayOfMonth == 1) {
717                            // if first day of year
718                            if (gregorianMonth == 1) {
719                                    gregorianMonth = 12;
720                                    gregorianYear--;
721                            } else {
722                                    gregorianMonth--;
723                            }
724                            // change to last day of previous month
725                            gregorianDayOfMonth = getLastDayOfGregorianMonth(gregorianMonth);
726                    } else {
727                            gregorianDayOfMonth--;
728                    }
729                    // change Jewish date
730                    // if first day of the Jewish month
731                    if (jewishDay == 1) {
732                            // if Nissan
733                            if (jewishMonth == 1) {
734                                    jewishMonth = getLastMonthOfJewishYear(jewishYear);
735                            } else if (jewishMonth == 7) { // if Rosh Hashana
736                                    jewishYear--;
737                                    jewishMonth--;
738                            } else {
739                                    jewishMonth--;
740                            }
741                            jewishDay = getDaysInJewishMonth(jewishMonth, jewishYear);
742                    } else {
743                            jewishDay--;
744                    }
745                    // if first day of week, loop back to Saturday
746                    if (dayOfWeek == 1) {
747                            dayOfWeek = 7;
748                    } else {
749                            dayOfWeek--;
750                    }
751                    // change the absolute date
752                    gregorianAbsDate--;
753            }
754    
755            /**
756             * Compares two dates to see if they are equal
757             */
758            public boolean equals(Object object) {
759                    JewishDate hebDate = (JewishDate) object;
760                    if (gregorianAbsDate != hebDate.getAbsDate()) {
761                            return false;
762                    } else {
763                            return true;
764                    }
765            }
766    
767            /**
768             * Compares two dates as per the compareTo() method in the Comparable
769             * interface. Returns a value less than 0 if this date is "less than"
770             * (before) the date, greater than 0 if this date is "greater than" (after)
771             * the date, or 0 if they are equal.
772             */
773            public int compareTo(Object o) {
774                    JewishDate hebDate = (JewishDate) o;
775                    if (gregorianAbsDate < hebDate.getAbsDate()) {
776                            return -1;
777                    } else if (gregorianAbsDate > hebDate.getAbsDate()) {
778                            return 1;
779                    } else {
780                            return 0;
781                    }
782            }
783    
784            /**
785             * Returns the Gregorian month (between 1-12).
786             * 
787             * @return the Gregorian month (between 1-12). Unlike the
788             *         java.util.Calendar, this will be 1 based and not 0 based.
789             */
790            public int getGregorianMonth() {
791                    return gregorianMonth;
792            }
793    
794            /**
795             * Returns the Gregorian day of the month.
796             * 
797             * @return the Gregorian day of the mont
798             */
799            public int getGregorianDayOfMonth() {
800                    return gregorianDayOfMonth;
801            }
802    
803            /**
804             * Returns the Gregotian year.
805             * 
806             * @return the Gregorian year
807             */
808            public int getGregorianYear() {
809                    return gregorianYear;
810            }
811    
812            /**
813             * Returns the Jewish month (1-12 or 13).
814             * 
815             * @return the Jewish month from 1 to 12 (or 13 years in a leap year). The
816             *         month count starts with 1 for Nisan and goes to 13 for Adar II
817             */
818            public int getJewishMonth() {
819                    return jewishMonth;
820            }
821    
822            /**
823             * Returns the Jewish day of month.
824             * 
825             * @return the Jewish day of the month
826             */
827            public int getJewishDayOfMonth() {
828                    return jewishDay;
829            }
830    
831            /**
832             * Returns the Jewish year.
833             * 
834             * @return the Jewish year
835             */
836            public int getJewishYear() {
837                    return jewishYear;
838            }
839    
840            /**
841             * Returns the day of the week as a number between 1-7.
842             * 
843             * @return the day of the week as a number between 1-7.
844             */
845            public int getDayOfWeek() {
846                    return dayOfWeek;
847            }
848    
849            /**
850             * Sets the Gregorian month.
851             * 
852             * @param month
853             *            the Gregorian month
854             * 
855             */
856            public void setGregorianMonth(int month) {
857                    setGregorianDate(gregorianYear, month, gregorianDayOfMonth);
858            }
859    
860            /**
861             * sets the Gregorian year.
862             * 
863             * @param year
864             *            the Gregorian year.
865             */
866            public void setGregorianYear(int year) {
867                    setGregorianDate(year, gregorianMonth, gregorianDayOfMonth);
868            }
869    
870            /**
871             * sets the Gregorian Day of month.
872             * 
873             * @param dayOfMonth
874             *            the Gregorian Day of month.
875             */
876            public void setGregorianDayOfMonth(int dayOfMonth) {
877                    setGregorianDate(gregorianYear, gregorianMonth, dayOfMonth);
878            }
879    
880            /**
881             * sets the Jewish month.
882             * 
883             * @param month
884             *            the Jewish month from 1 to 12 (or 13 years in a leap year).
885             *            The month count starts with 1 for Nisan and goes to 13 for
886             *            Adar II
887             */
888            public void setJewishMonth(int month) {
889                    setJewishDate(jewishYear, month, jewishDay);
890            }
891    
892            /**
893             * sets the Jewish year.
894             * 
895             * @param year
896             *            the Jewish year
897             */
898            public void setJewishYear(int year) {
899                    setJewishDate(year, jewishMonth, jewishDay);
900            }
901    
902            /**
903             * sets the Jewish day of month.
904             * 
905             * @param dayOfMonth
906             *            the Jewish day of month
907             */
908            public void setJewishDayOfMonth(int dayOfMonth) {
909                    setJewishDate(jewishYear, jewishMonth, dayOfMonth);
910            }
911    
912            /**
913             * Returns the int value of the Omer day or {@link Integer#MIN_VALUE} if the
914             * day is not in the omer
915             * 
916             * @return The Omer count as an int or {@link Integer#MIN_VALUE} if it is
917             *         not a day of the Omer.
918             */
919            public int getDayOfOmer() {
920                    // int omer = 0;
921                    // better to use MIN_VALUE that is a better equivalent to null
922                    int omer = Integer.MIN_VALUE;
923    
924                    // if Nissan and second day of Pesach and on
925                    if (jewishMonth == 1 && jewishDay >= 16) {
926                            omer = jewishDay - 15;
927                            // if Iyar
928                    } else if (jewishMonth == 2) {
929                            omer = jewishDay + 15;
930                            // if Sivan and before Shavuos
931                    } else if (jewishMonth == 3 && jewishDay < 6)
932                            omer = jewishDay + 44;
933    
934                    return omer;
935            }
936    
937            /**
938             * Returns a String of the Jewish holiday or fast day for the current day,
939             * or a null if there is no holiday for this day. Has no "modern" holidays.
940             * 
941             * @return A String containing the holiday name or an empty string if it is
942             *         not a holiday.
943             */
944            public String getHoliday() {
945                    // check by month (starts from Nissan)
946                    switch (jewishMonth) {
947                    case 1:
948                            if (jewishDay == 14) {
949                                    return "Erev Pesach";
950                            } else if (jewishDay == 15 || jewishDay == 21
951                                            || (!inIsrael && (jewishDay == 16 || jewishDay == 22))) {
952                                    return "Pesach";
953                            } else if (jewishDay >= 17 && jewishDay <= 20
954                                            || (jewishDay == 16 && inIsrael)) {
955                                    return "Chol Hamoed Pesach";
956                            }
957                            break;
958                    case 2:
959                            if (jewishDay == 14) {
960                                    return "Pesach Sheni";
961                            }
962                            break;
963                    case 3:
964                            if (jewishDay == 5) {
965                                    return "Erev Shavuos";
966                                    // if (ashkenaz) {
967                                    // return "Erev Shavuos";
968                                    // } else {
969                                    // return "Erev Shavuot";
970                                    // }
971                            } else if (jewishDay == 6 || (jewishDay == 7 && !inIsrael)) {
972                                    return "Shavuos";
973                                    // if (ashkenaz) {
974                                    // return "Shavuos";
975                                    // } else {
976                                    // return "Shavuot";
977                                    // }
978                            }
979                            break;
980                    case 4:
981                            // push off the fast day if it falls on Shabbos
982                            if ((jewishDay == 17 && dayOfWeek != 7)
983                                            || (jewishDay == 18 && dayOfWeek == 1)) {
984                                    return "Tzom Tammuz";
985                            }
986                            break;
987                    case 5:
988                            // if Tisha B'av falls on Shabbos, push off until Sunday
989                            if ((dayOfWeek == 1 && jewishDay == 10)
990                                            || (dayOfWeek != 7 && jewishDay == 9)) {
991                                    return "Tisha B'av";
992                            } else if (jewishDay == 15) {
993                                    return "Tu B'Av";
994                            }
995                            break;
996                    case 6:
997                            if (jewishDay == 29) {
998                                    return "Erev Rosh Hashanah";
999                            }
1000                            break;
1001                    case 7:
1002                            if (jewishDay == 1 || jewishDay == 2) {
1003                                    return "Rosh Hashanah";
1004                            } else if ((jewishDay == 3 && dayOfWeek != 7)
1005                                            || (jewishDay == 4 && dayOfWeek == 1)) { // push off Tzom
1006                                                                                                                                    // Gedalia
1007                                    // if it falls on
1008                                    // Shabbos
1009                                    return "Tzom Gedalia";
1010                            } else if (jewishDay == 9) {
1011                                    return "Erev Yom Kippur";
1012                            } else if (jewishDay == 10) {
1013                                    return "Yom Kippur";
1014                            } else if (jewishDay == 14) {
1015                                    return "Erev Sukkos";
1016                                    // if (ashkenaz) {
1017                                    // return "Erev Sukkos";
1018                                    // } else {
1019                                    // return "Erev Sukkot";
1020                                    // }
1021                            }
1022                            if (jewishDay == 15 || (jewishDay == 16 && !inIsrael)) {
1023                                    return "Sukkos";
1024                                    // if (ashkenaz) {
1025                                    // return "Sukkos";
1026                                    // } else {
1027                                    // return "Sukkot";
1028                                    // }
1029                            }
1030                            if (jewishDay >= 17 && jewishDay <= 20
1031                                            || (jewishDay == 16 && inIsrael)) {
1032                                    return "Chol Hamoed Sukkos";
1033                                    // if (ashkenaz) {
1034                                    // return "Chol Hamoed Sukkos";
1035                                    // } else {
1036                                    // return "Chol Hamoed Sukkot";
1037                                    // }
1038                            }
1039                            if (jewishDay == 21) {
1040                                    return "Hoshana Rabah";
1041                            }
1042                            if (jewishDay == 22) {
1043                                    return "Shmini Atzeres";
1044                                    // if (ashkenaz) {
1045                                    // return "Shmini Atzeres";
1046                                    // } else {
1047                                    // return "Shmini Atzeret";
1048                                    // }
1049                            }
1050                            if (jewishDay == 23 && !inIsrael) {
1051                                    return "Simchas Torah";
1052                                    // if (ashkenaz) {
1053                                    // return "Simchas Torah";
1054                                    // } else {
1055                                    // return "Simchat Torah";
1056                                    // }
1057                            }
1058                            break;
1059                    case 9:
1060                            if (jewishDay == 24) {
1061                                    return "Erev Chanukah";
1062                            } else if (jewishDay >= 25) {
1063                                    return "Chanukah";
1064                            }
1065                            break;
1066                    case 10:
1067                            if (jewishDay == 1 || jewishDay == 2
1068                                            || (jewishDay == 3 && isKislevShort(jewishYear))) {
1069                                    return "Chanukah";
1070                            } else if (jewishDay == 10) {
1071                                    return "Asarah BeTeves";
1072                                    // if (ashkenaz) {
1073                                    // return "Tzom Teves";
1074                                    // } else {
1075                                    // return "Tzom Tevet";
1076                                    // }
1077                            }
1078                            break;
1079                    case 11:
1080                            if (jewishDay == 15) {
1081                                    return "Tu B'Shvat";
1082                            }
1083                            break;
1084                    case 12:
1085                            if (!isJewishLeapYear(jewishYear)) {
1086                                    // if 13th Adar falls on Friday or Shabbos, push back to
1087                                    // Thursday
1088                                    if (((jewishDay == 11 || jewishDay == 12) && dayOfWeek == 5)
1089                                                    || (jewishDay == 13 && !(dayOfWeek == 6 || dayOfWeek == 7))) {
1090                                            return "Ta'anis Esther";
1091                                            // if (ashkenaz) {
1092                                            // return "Ta'anis Esther";
1093                                            // } else {
1094                                            // return "Ta'anit Esther";
1095                                            // }
1096                                    }
1097                                    if (jewishDay == 14) {
1098                                            return "Purim";
1099                                    } else if (jewishDay == 15) {
1100                                            return "Shushan Purim";
1101                                    }
1102                            }
1103                            // else if a leap year //
1104                            else {
1105                                    if (jewishDay == 14) {
1106                                            return "Purim Katan";
1107                                    }
1108                            }
1109                            break;
1110                    case 13:
1111                            // if 13th Adar falls on Friday or Shabbos, push back to Thursday
1112                            if (((jewishDay == 11 || jewishDay == 12) && dayOfWeek == 5)
1113                                            || (jewishDay == 13 && !(dayOfWeek == 6 || dayOfWeek == 7))) {
1114                                    return "Ta'anis Esther";
1115                                    // if (ashkenaz) {
1116                                    // return "Ta'anis Esther";
1117                                    // } else {
1118                                    // return "Ta'anit Esther";
1119                                    // }
1120                            }
1121                            if (jewishDay == 14) {
1122                                    return "Purim";
1123                            } else if (jewishDay == 15) {
1124                                    return "Shushan Purim";
1125                            }
1126                            break;
1127                    }
1128                    // if we get to this stage, then there are no holidays for the given
1129                    // date
1130                    // return "";
1131                    return null;
1132            }
1133    
1134            /**
1135             * Sets whether to use Israel parsha and holiday scheme or not. Default is
1136             * false.
1137             * 
1138             * @param inIsrael
1139             *            set to true for calculations for Israel
1140             */
1141            public void setInIsrael(boolean inIsrael) {
1142                    this.inIsrael = inIsrael;
1143            }
1144    
1145            /**
1146             * Gets whether Israel parsha and holiday scheme is used or not. The default
1147             * (if not set) is false.
1148             * 
1149             * @return if the if the calendar is set to Israel
1150             */
1151            public boolean getInIsrael() {
1152                    return inIsrael;
1153            }
1154    
1155            // These indices were originally included in the emacs 19 distribution.
1156            // These arrays determine the correct indices into the parsha names
1157            // -1 means no parsha that week, values > 52 means it is a double parsha
1158            private static final int[] Sat_short = { -1, 52, -1, -1, 0, 1, 2, 3, 4, 5,
1159                            6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 53, 23, 24,
1160                            -1, 25, 54, 55, 30, 56, 33, 34, 35, 36, 37, 38, 39, 40, 58, 43, 44,
1161                            45, 46, 47, 48, 49, 50 };
1162    
1163            private static final int[] Sat_long = { -1, 52, -1, -1, 0, 1, 2, 3, 4, 5,
1164                            6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 53, 23, 24,
1165                            -1, 25, 54, 55, 30, 56, 33, 34, 35, 36, 37, 38, 39, 40, 58, 43, 44,
1166                            45, 46, 47, 48, 49, 59 };
1167    
1168            private static final int[] Mon_short = { 51, 52, -1, 0, 1, 2, 3, 4, 5, 6,
1169                            7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 53, 23, 24,
1170                            -1, 25, 54, 55, 30, 56, 33, 34, 35, 36, 37, 38, 39, 40, 58, 43, 44,
1171                            45, 46, 47, 48, 49, 59 };
1172    
1173            private static final int[] Mon_long = // split
1174            { 51, 52, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
1175                            18, 19, 20, 53, 23, 24, -1, 25, 54, 55, 30, 56, 33, -1, 34, 35, 36,
1176                            37, 57, 40, 58, 43, 44, 45, 46, 47, 48, 49, 59 };
1177    
1178            private static final int[] Thu_normal = { 52, -1, -1, 0, 1, 2, 3, 4, 5, 6,
1179                            7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 53, 23, 24,
1180                            -1, -1, 25, 54, 55, 30, 56, 33, 34, 35, 36, 37, 38, 39, 40, 58, 43,
1181                            44, 45, 46, 47, 48, 49, 50 };
1182            private static final int[] Thu_normal_Israel = { 52, -1, -1, 0, 1, 2, 3, 4,
1183                            5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 53, 23,
1184                            24, -1, 25, 54, 55, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 58,
1185                            43, 44, 45, 46, 47, 48, 49, 50 };
1186    
1187            private static final int[] Thu_long = { 52, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7,
1188                            8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
1189                            -1, 25, 54, 55, 30, 56, 33, 34, 35, 36, 37, 38, 39, 40, 58, 43, 44,
1190                            45, 46, 47, 48, 49, 50 };
1191    
1192            private static final int[] Sat_short_leap = { -1, 52, -1, -1, 0, 1, 2, 3,
1193                            4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
1194                            22, 23, 24, 25, 26, 27, -1, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
1195                            38, 39, 40, 58, 43, 44, 45, 46, 47, 48, 49, 59 };
1196    
1197            private static final int[] Sat_long_leap = { -1, 52, -1, -1, 0, 1, 2, 3, 4,
1198                            5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
1199                            23, 24, 25, 26, 27, -1, 28, 29, 30, 31, 32, 33, -1, 34, 35, 36, 37,
1200                            57, 40, 58, 43, 44, 45, 46, 47, 48, 49, 59 };
1201    
1202            private static final int[] Mon_short_leap = { 51, 52, -1, 0, 1, 2, 3, 4, 5,
1203                            6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
1204                            24, 25, 26, 27, -1, 28, 29, 30, 31, 32, 33, -1, 34, 35, 36, 37, 57,
1205                            40, 58, 43, 44, 45, 46, 47, 48, 49, 59 };
1206            private static final int[] Mon_short_leap_Israel = { 51, 52, -1, 0, 1, 2,
1207                            3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
1208                            21, 22, 23, 24, 25, 26, 27, -1, 28, 29, 30, 31, 32, 33, 34, 35, 36,
1209                            37, 38, 39, 40, 58, 43, 44, 45, 46, 47, 48, 49, 59 };
1210    
1211            private static final int[] Mon_long_leap = { 51, 52, -1, 0, 1, 2, 3, 4, 5,
1212                            6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
1213                            24, 25, 26, 27, -1, -1, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
1214                            39, 40, 58, 43, 44, 45, 46, 47, 48, 49, 50 };
1215            private static final int[] Mon_long_leap_Israel = { 51, 52, -1, 0, 1, 2, 3,
1216                            4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
1217                            22, 23, 24, 25, 26, 27, -1, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
1218                            38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50 };
1219    
1220            private static final int[] Thu_short_leap = { 52, -1, -1, 0, 1, 2, 3, 4, 5,
1221                            6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
1222                            24, 25, 26, 27, 28, -1, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
1223                            40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50 };
1224    
1225            private static final int[] Thu_long_leap = { 52, -1, -1, 0, 1, 2, 3, 4, 5,
1226                            6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
1227                            24, 25, 26, 27, 28, -1, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
1228                            40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 59 };
1229    
1230            /**
1231             * returns a string of today's parsha(ios) or an empty string if there are
1232             * none. FIXME: consider possibly return the parsha of the week for any day
1233             * during the week instead of empty. To do this the simple way, create a new
1234             * instance of the class in the mothod, roll it to the next shabbos. If the
1235             * shabbos has no parsha, keep rolling by a week till a parsha is
1236             * encountered. Possibly turn into static method that takes in a year,
1237             * month, day, roll to next shabbos (not that simple with the API for date
1238             * passed in) and if it is not a shabbos roll forwarde one week at a time to
1239             * get the parsha. I do not think it is possible to have more than 2
1240             * shabbosim in a row without a parsha, but I may be wrong.
1241             * 
1242             * @return the string of the parsha. Will currently return blank for
1243             *         weekdays and a shabbos on a yom tov.
1244             */
1245            public String getParsha() {
1246    
1247                    // if today is not Shabbos, then there is no normal parsha reading. If
1248                    // commented our will return LAST week's parsha for a non shabbos
1249                    if (getDayOfWeek() != 7) {
1250                            return "";
1251                    }
1252    
1253                    // kvia = whether a Jewish year is short/regular/long (0/1/2)
1254                    // roshHashana = Rosh Hashana of this Jewish year
1255                    // roshHashanaDay= day of week Rosh Hashana was on this year
1256                    // week= current week in Jewish calendar from Rosh Hashana
1257                    // array= the correct index array for this Jewish year
1258                    // index= the index number of the parsha name
1259                    int kvia;
1260                    int roshHashanaDay;
1261                    int week;
1262                    int[] array = null;
1263                    int index;
1264                    // create a clone of this date
1265                    JewishDate roshHashana = (JewishDate) this.clone();
1266                    // try {
1267                    // set it to Rosh Hashana of this year
1268                    roshHashana.setJewishDate(jewishYear, 7, 1);
1269                    // } catch (IllegalArgumentException e) {
1270                    // e.printStackTrace();
1271                    // }
1272    
1273                    // get day Rosh Hashana was on
1274                    roshHashanaDay = roshHashana.getDayOfWeek();
1275    
1276                    // week is the week since the first Shabbos on or after Rosh Hashana
1277                    week = (((gregorianAbsDate - roshHashana.getAbsDate()) - (7 - roshHashanaDay)) / 7);
1278    
1279                    // get kvia
1280                    if (isCheshvanLong(jewishYear) && !isKislevShort(jewishYear))
1281                            kvia = 2;
1282                    else if (!isCheshvanLong(jewishYear) && isKislevShort(jewishYear))
1283                            kvia = 0;
1284                    else
1285                            kvia = 1;
1286    
1287                    // determine appropriate array
1288                    if (!isJewishLeapYear(jewishYear)) {
1289                            switch (roshHashanaDay) {
1290                            case 7: // RH was on a Saturday
1291                                    if (kvia == 0)
1292                                            array = Sat_short;
1293                                    else if (kvia == 2)
1294                                            array = Sat_long;
1295                                    break;
1296                            case 2: // RH was on a Monday
1297                                    if (kvia == 0)
1298                                            array = Mon_short;
1299                                    else if (kvia == 2)
1300                                            array = inIsrael ? Mon_short : Mon_long;
1301                                    break;
1302                            case 3: // RH was on a Tuesday
1303                                    if (kvia == 1)
1304                                            array = inIsrael ? Mon_short : Mon_long;
1305                                    break;
1306                            case 5: // RH was on a Thursday
1307                                    if (kvia == 1)
1308                                            array = inIsrael ? Thu_normal_Israel : Thu_normal;
1309                                    else if (kvia == 2)
1310                                            array = Thu_long;
1311                                    break;
1312                            }
1313                    }
1314    
1315                    // if leap year //
1316                    else {
1317                            switch (roshHashanaDay) {
1318                            case 7: // RH was on a Sat
1319                                    if (kvia == 0)
1320                                            array = Sat_short_leap;
1321                                    else if (kvia == 2)
1322                                            array = inIsrael ? Sat_short_leap : Sat_long_leap;
1323                                    break;
1324                            case 2: // RH was on a Mon
1325                                    if (kvia == 0)
1326                                            array = inIsrael ? Mon_short_leap_Israel : Mon_short_leap;
1327                                    else if (kvia == 2)
1328                                            array = inIsrael ? Mon_long_leap_Israel : Mon_long_leap;
1329                                    break;
1330                            case 3: // RH was on a Tue
1331                                    if (kvia == 1)
1332                                            array = inIsrael ? Mon_long_leap_Israel : Mon_long_leap;
1333                                    break;
1334                            case 5: // RH was on a Thu
1335                                    if (kvia == 0)
1336                                            array = Thu_short_leap;
1337                                    else if (kvia == 2)
1338                                            array = Thu_long_leap;
1339                                    break;
1340                            }
1341                    }
1342                    // if something goes wrong
1343                    if (array == null) {
1344                            throw new RuntimeException(
1345                                            "Unable to claculate the parsha. No index array matched any of the known types for the date: "
1346                                                            + toString());
1347                    }
1348                    // get index from array
1349                    index = array[week];
1350    
1351                    // If no Parsha this week
1352                    if (index == -1) {
1353                            return "";
1354                    }
1355    
1356                    // if parsha this week
1357                    // else {
1358                    // if (getDayOfWeek() != 7){//in weekday return next shabbos's parsha
1359                    // System.out.print(" index=" + index + " ");
1360                    // return parshios[index + 1];
1361                    // this code returns odd data for yom tov. See parshas kedoshim display
1362                    // for 2011 for example. It will also break for Sept 25, 2011 where it
1363                    // goes one beyong the index of Nitzavim-Vayelech
1364                    // }
1365                    return parshios[index];
1366                    // }
1367            }
1368    
1369            /** Create a copy of this date. */
1370            // FIXME - create deep clone
1371            public Object clone() {
1372                    return new JewishDate(gregorianYear, gregorianMonth,
1373                                    gregorianDayOfMonth);
1374            }
1375            
1376            /**
1377             * @see java.lang.Object#hashCode()
1378             */
1379            public int hashCode() {
1380                    int result = 17;
1381                    result = 37 * result + getClass().hashCode(); // needed or this and
1382                                                                                                                    // subclasses will
1383                                                                                                                    // return identical hash
1384                    result += 37 * result + gregorianAbsDate;
1385                    return result;
1386            }
1387    }