001    /*
002     * Zmanim Java API
003     * Copyright (C) 2004-2008 Eliyahu Hershfeld
004     *
005     * This program is free software; you can redistribute it and/or modify it under the terms of the
006     * GNU General Public License as published by the Free Software Foundation; either version 2 of the
007     * License, or (at your option) any later version.
008     *
009     * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
010     * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
011     * General Public License for more details.
012     *
013     * You should have received a copy of the GNU General Public License along with this program; if
014     * not, write to the Free Software Foundation, Inc. 59 Temple Place - Suite 330, Boston, MA
015     * 02111-1307, USA or connect to: http://www.fsf.org/copyleft/gpl.html
016     */
017    package net.sourceforge.zmanim;
018    
019    import java.util.Calendar;
020    import java.util.Date;
021    
022    import net.sourceforge.zmanim.util.AstronomicalCalculator;
023    import net.sourceforge.zmanim.util.GeoLocation;
024    
025    /**
026     * <p>
027     * Description: A Java library for calculating zmanim.
028     * </p>
029     * The zmanim library is an API is a specialized calendar that can calculate
030     * sunrise and sunset and Jewish <em>zmanim</em> (religious times) for prayers
031     * and other Jewish religious duties. For a much more extensive list of zmanim
032     * use the {@link ComplexZmanimCalendar} that extends this class. This class
033     * contains the main functionality of the Zmanim library.
034     * <h2>Disclaimer:</h2>
035     * While I did my best to get accurate results please do not rely on these
036     * zmanim for <em>halacha lemaaseh</em>
037     *
038     * @author &copy; Eliyahu Hershfeld 2004 - 2008
039     * @version 1.1
040     */
041    public class ZmanimCalendar extends AstronomicalCalendar {
042            private static final long serialVersionUID = 1;
043    
044            /**
045             * The zenith of 16.1&deg; below geometric zenith (90&deg;). This
046             * calculation is used for calculating <em>alos</em> (dawn) and
047             * <em>tzais</em> (nightfall) in some opinions. This calculation is based
048             * on the calculation that the time between dawn and sunrise (and sunset to
049             * nightfall) is the time that is takes to walk 4 <em>mil</em> at 18
050             * minutes a mil (<em>Ramba"m</em> and others). The sun's position at 72
051             * minutes before {@link #getSunrise sunrise} in Jerusalem on the equinox is
052             * 16.1&deg; below {@link #GEOMETRIC_ZENITH geometric zenith}.
053             *
054             * @see #getAlosHashachar()
055             * @see ComplexZmanimCalendar#getAlos16Point1Degrees()
056             * @see ComplexZmanimCalendar#getTzais16Point1Degrees()
057             * @see ComplexZmanimCalendar#getSofZmanShmaMGA16Point1Degrees()
058             * @see ComplexZmanimCalendar#getSofZmanTfilaMGA16Point1Degrees()
059             * @see ComplexZmanimCalendar#getMinchaGedola16Point1Degrees()
060             * @see ComplexZmanimCalendar#getMinchaKetana16Point1Degrees()
061             * @see ComplexZmanimCalendar#getPlagHamincha16Point1Degrees()
062             * @see ComplexZmanimCalendar#getPlagAlos16Point1ToTzaisGeonim7Point083Degrees()
063             * @see ComplexZmanimCalendar#getSofZmanShmaAlos16Point1ToSunset()
064             */
065            protected static final double ZENITH_16_POINT_1 = GEOMETRIC_ZENITH + 16.1;
066    
067            /**
068             * The zenith of 8.5&deg; below geometric zenith (90&deg;). This calculation
069             * is used for calculating <em>alos</em> (dawn) and <em>tzais</em>
070             * (nightfall) in some opinions. This calculation is based on the position
071             * of the sun 36 minutes after {@link #getSunset sunset} in Jerusalem in the
072             * equinox which is 8.5&deg; below
073             * {@link #GEOMETRIC_ZENITH geometric zenith}
074             *
075             * @see #getTzais()
076             * @see ComplexZmanimCalendar#getTzaisGeonim8Point5Degrees()
077             */
078            protected static final double ZENITH_8_POINT_5 = GEOMETRIC_ZENITH + 8.5;
079    
080            // private AstronomicalCalculator astronomicalGeometryCalculator;
081    
082            private double candleLightingOffset = 18;
083    
084            /**
085             * Returns <em>tzais</em> (nightfall) when the sun is 8.5&deg; below the
086             * western geometric horizon (90&deg;) after {@link #getSunset sunset}. For
087             * information on the source of this calculation see
088             * {@link #ZENITH_8_POINT_5}.
089             *
090             * @return The <code>Date</code> of nightfall.
091             * @see #ZENITH_8_POINT_5
092             */
093            public Date getTzais() {
094                    return this.getSunsetOffsetByDegrees(ZENITH_8_POINT_5);
095            }
096    
097            /**
098             * Returns <em>alos</em> (dawn) based on the time when the sun is
099             * 16.1&deg; below the eastern {@link #GEOMETRIC_ZENITH geometric horizon}
100             * before {@link #getSunrise sunrise}. For more information the source of
101             * 16.1&deg; see {@link #ZENITH_16_POINT_1}.
102             *
103             * @see net.sourceforge.zmanim.ZmanimCalendar#ZENITH_16_POINT_1
104             * @return The <code>Date</code> of dawn.
105             */
106            public Date getAlosHashachar() {
107                    return getSunriseOffsetByDegrees(ZENITH_16_POINT_1);
108            }
109    
110            /**
111             * Method to return <em>alos</em> (dawn) calculated using 72 minutes
112             * before {@link #getSeaLevelSunrise() sea level sunrise} (no adjustment for
113             * elevation) based on the time to walk the distance of 4 <em>Mil</em> at
114             * 18 minutes a <em>Mil</em>. This is based on the opinion of most
115             * <em>Rishonim</em> who stated that the time of the <em>Neshef</em>
116             * (time between dawn and sunrise) does not vary by the time of year or
117             * location but purely depends on the time it takes to walk the distance of
118             * 4 <em>Mil</em>.
119             *
120             * @return the <code>Date</code> representing the time.
121             */
122            public Date getAlos72() {
123                    return getTimeOffset(getSeaLevelSunrise(), -72 * MINUTE_MILLIS);
124            }
125    
126            /**
127             * This method returns <em>chatzos</em> (midday) following the opinion of
128             * the GRA that the day for Jewish halachic times start at
129             * {@link #getSunrise sunrise} and ends at {@link #getSunset sunset}. The
130             * returned value is identical to {@link #getSunTransit()}
131             *
132             * @see AstronomicalCalendar#getSunTransit()
133             * @return the <code>Date</code> of chatzos.
134             */
135            public Date getChatzos() {
136                    return getSunTransit();
137            }
138    
139            /**
140             * A method that returns "solar" midnight, or the time when the sun is at
141             * it's <a href="http://en.wikipedia.org/wiki/Nadir">nadir</a>.
142             * <br/><br/><b>Note:</b> this method is experimental and might be removed (or moved)
143             *
144             * @return the <code>Date</code> of Solar Midnight (chatzos layla).
145             */
146            public Date getSolarMidnight() {
147                    ZmanimCalendar clonedCal = (ZmanimCalendar) clone();
148                    clonedCal.getCalendar().add(Calendar.DAY_OF_MONTH, 1);
149                    Date sunset = getSunset();
150                    Date sunrise = clonedCal.getSunrise();
151                    return getTimeOffset(sunset, getTemporalHour(sunset, sunrise) * 6);
152            }
153    
154    //      public Date getChatzosLaylaRSZ() {
155    //              ZmanimCalendar clonedCal = (ZmanimCalendar)clone();
156    //              clonedCal.getCalendar().add(Calendar.DAY_OF_MONTH, 1);
157    //              Date sunset = getSunset();
158    //              Date sunrise = clonedCal.getAlosHashachar();
159    //              return getTimeOffset(sunset, getTemporalHour(sunset, sunrise) * 6);
160    //      }
161    
162            /**
163             * This method returns the latest <em>zman krias shema</em> (time to say
164             * Shema in the morning). This time is 3
165             * <em>{@link #getShaahZmanisGra() shaos zmaniyos}</em> (solar hours)
166             * after {@link #getSunrise() sunrise} based on the opinion of the
167             * <em>GR"A</em> and the <em>Baal Hatanya</em> that the day is
168             * calculated from sunrise to sunset. This returns the time 3 *{@link #getShaahZmanisGra()}
169             * after {@link #getSunrise() sunrise}.
170             *
171             * @see net.sourceforge.zmanim.ZmanimCalendar#getShaahZmanisGra()
172             * @return the <code>Date</code> of the latest zman shema.
173             */
174            public Date getSofZmanShmaGRA() {
175                    return getTimeOffset(getSunrise(), getShaahZmanisGra() * 3);
176            }
177    
178            /**
179             * This method returns the latest <em>zman krias shema</em> (time to say
180             * Shema in the morning) in the opinion of the <em>MG"A</em> based on
181             * <em>alos</em> being 72 minutes before {@link #getSunrise() sunrise}.
182             * This time is 3 <em> shaos zmaniyos</em> (solar hours) after dawn based
183             * on the opinion of the <em>MG"A</em> that the day is calculated from a
184             * dawn of 72 minutes before sunrise to nightfall of 72 minutes after
185             * sunset. This returns the time of 3 * <em>shaos zmaniyos</em> after
186             * dawn.
187             *
188             * @return the <code>Date</code> of the latest zman shema.
189             * @see ComplexZmanimCalendar#getShaahZmanis72Minutes()
190             * @see ComplexZmanimCalendar#getAlos72()
191             * @see ComplexZmanimCalendar#getSofZmanShmaMGA72Minutes()
192             */
193            public Date getSofZmanShmaMGA() {
194                    return getTimeOffset(getAlos72(), getShaahZmanisMGA() * 3);
195            }
196    
197            /**
198             * This method returns the <em>tzais</em> (nightfall) based on the opinion
199             * of the <em>Ramba"m</em> and <em>Rabainu Tam</em> that <em>tzais</em>
200             * is calculated as the time it takes to walk 4 <em>Mil</em> at 18 minutes
201             * a <em>Mil</em> for a total of 72 minutes. Even for locations above sea
202             * level, this is calculated at sea level, since the darkness level is not
203             * affected by elevation.
204             *
205             * @return the <code>Date</code> representing 72 minutes after sea level
206             *         sunset.
207             */
208            public Date getTzais72() {
209                    return getTimeOffset(getSeaLevelSunset(), 72 * MINUTE_MILLIS);
210            }
211    
212            /**
213             * A method to return candle lighting time. This is calculated as
214             * {@link #getCandleLightingOffset()} minutes before sunset. This will
215             * return the time for any day of the week, since it can be used to
216             * calculate candle lighting time for <em>yom tov</em> (holidays) as well.
217             *
218             * @return candle lighting time.
219             * @see #getCandleLightingOffset()
220             * @see #setCandleLightingOffset(double)
221             */
222            public Date getCandelLighting() {
223                    return getTimeOffset(getSunset(), -getCandleLightingOffset()
224                                    * MINUTE_MILLIS);
225            }
226    
227            /**
228             * This method returns the latest
229             * <em>zman tefilah<em> (time to pray morning prayers). This time is 4
230             * hours into the day based on the opinion of the <em>GR"A</em> and the </em>Baal Hatanya</em>
231             * that the day is calculated from sunrise to sunset. This returns the time
232             * 4 * {@link #getShaahZmanisGra()} after {@link #getSunrise() sunrise}.
233             *
234             * @see net.sourceforge.zmanim.ZmanimCalendar#getShaahZmanisGra()
235             * @return the <code>Date</code> of the latest zman tefilah.
236             */
237            public Date getSofZmanTfilaGRA() {
238                    return getTimeOffset(getSunrise(), getShaahZmanisGra() * 4);
239            }
240    
241            /**
242             * This method returns the latest <em>zman tfila</em> (time to say the
243             * morning prayers) in the opinion of the <em>MG"A</em> based on
244             * <em>alos</em> being {@link #getAlos72() 72} minutes before
245             * {@link #getSunrise() sunrise}. This time is 4
246             * <em>{@link #getShaahZmanisMGA() shaos zmaniyos}</em> (temporal hours)
247             * after {@link #getAlos72() dawn} based on the opinion of the <em>MG"A</em>
248             * that the day is calculated from a {@link #getAlos72() dawn} of 72 minutes
249             * before sunrise to {@link #getTzais72() nightfall} of 72 minutes after
250             * sunset. This returns the time of 4 * {@link #getShaahZmanisMGA()} after
251             * {@link #getAlos72() dawn}.
252             *
253             * @return the <code>Date</code> of the latest zman tfila.
254             * @see #getShaahZmanisMGA()
255             * @see #getAlos72()
256             */
257            public Date getSofZmanTfilaMGA() {
258                    return getTimeOffset(getAlos72(), getShaahZmanisMGA() * 4);
259            }
260    
261            /**
262             * This method returns the time of <em>mincha gedola</em>.<em>Mincha gedola</em>
263             * is the earliest time one can pray mincha. The Ramba"m is of the opinion
264             * that it is better to delay <em>mincha</em> until
265             * <em>{@link #getMinchaKetana() mincha ketana}</em> while the <em>Ra"sh,
266             * Tur, GR"A</em>
267             * and others are of the opinion that <em>mincha</em> can be prayed
268             * <em>lechatchila</em> starting at <em>mincha gedola</em>. This is
269             * calculated as 6.5 {@link #getTemporalHour() solar hours} after sunrise.
270             * This calculation is calculated based on the opinion of the <em>GR"A</em>
271             * and the <em>Baal Hatanya</em> that the day is calculated from sunrise
272             * to sunset. This returns the time 6.5 *{@link #getShaahZmanisGra()} after
273             * {@link #getSunrise() sunrise}.
274             *
275             * @see #getShaahZmanisGra()
276             * @see #getMinchaKetana()
277             * @return the <code>Date</code> of the time of mincha gedola.
278             */
279            public Date getMinchaGedola() {
280                    return getTimeOffset(getSunrise(), getShaahZmanisGra() * 6.5);
281            }
282    
283            /**
284             * This method returns the time of <em>mincha ketana</em>. This is the
285             * perfered earliest time to pray <em>mincha</em> in the opinion of the
286             * Ramba"m and others. For more information on this see the documentation on
287             * <em>{@link #getMinchaGedola() mincha gedola}</em>. This is calculated
288             * as 9.5 {@link #getTemporalHour() solar hours}after sunrise. This
289             * calculation is calculated based on the opinion of the <em>GR"A</em> and
290             * the <em>Baal Hatanya</em> that the day is calculated from sunrise to
291             * sunset. This returns the time 9.5 * {@link #getShaahZmanisGra()} after
292             * {@link #getSunrise() sunrise}.
293             *
294             * @see #getShaahZmanisGra()
295             * @see #getMinchaGedola()
296             * @return the <code>Date</code> of the time of mincha gedola.
297             */
298            public Date getMinchaKetana() {
299                    return getTimeOffset(getSunrise(), getShaahZmanisGra() * 9.5);
300            }
301    
302            /**
303             * This method returns he time of <em>plag hamincha</em>. This is
304             * calculated as 10.75 hours after sunrise. This calculation is calculated
305             * based on the opinion of the <em>GR"A</em> and the <em>Baal Hatanya</em>
306             * that the day is calculated from sunrise to sunset. This returns the time
307             * 10.75 *{@link #getShaahZmanisGra()} after {@link #getSunrise() sunrise}.
308             *
309             * @return the <code>Date</code> of the time of <em>plag hamincha</em>.
310             */
311            public Date getPlagHamincha() {
312                    return getTimeOffset(getSunrise(), getShaahZmanisGra() * 10.75);
313            }
314    
315            /**
316             * Method to return a <em>shaah zmanis</em> ({@link #getTemporalHour temporal hour})
317             * according to the opinion of the <em>GR"A</em> and the
318             * <em>Baal Hatanya</em>. This calculation divides the day based on the
319             * opinion of the <em>GR"A</em> and the <em>Baal Hatanya</em> that the
320             * day runs from {@link #getSunrise() sunrise} to {@link #getSunset sunset}.
321             * The day is split into 12 equal parts each part with each one being a
322             * <em>shaah zmanis</em>. This method is identical to
323             * {@link #getTemporalHour} (it is actually a wrapper that calls that
324             * method) and is provided for clarity.
325             *
326             * @return the <code>long</code> millisecond length of a
327             *         <em>shaah zmanis</em>.
328             * @see #getTemporalHour()
329             */
330            public long getShaahZmanisGra() {
331                    return getTemporalHour();
332            }
333    
334            /**
335             * Method to return a <em>shaah zmanis</em> (temporal hour) according to
336             * the opinion of the MGA. This calculation divides the day based on the
337             * opinion of the <em>MGA</em> that the day runs from dawn to dusk (for
338             * sof zman krias shema and tfila). Dawn for this calculation is 72 minutes
339             * before sunrise and dusk is 72 minutes after sunset. This day is split
340             * into 12 equal parts with each part being a <em>shaah zmanis</em>.
341             * Alternate mothods of calculating a <em>shaah zmanis</em> are available
342             * in the subclass {@link ComplexZmanimCalendar}.
343             *
344             * @return the <code>long</code> millisecond length of a
345             *         <em>shaah zmanis</em>.
346             */
347            public long getShaahZmanisMGA() {
348                    return getTemporalHour(getAlos72(), getTzais72());
349            }
350    
351            /**
352             * Default constructor will set a default {@link GeoLocation#GeoLocation()},
353             * a default
354             * {@link AstronomicalCalculator#getDefault() AstronomicalCalculator} and
355             * default the calendar to the current date.
356             *
357             * @see AstronomicalCalendar#AstronomicalCalendar()
358             */
359            public ZmanimCalendar() {
360                    super();
361            }
362    
363            /**
364             * A constructor that takes a {@link GeoLocation} as a parameter.
365             *
366             * @param location
367             *            the location
368             */
369            public ZmanimCalendar(GeoLocation location) {
370                    super(location);
371            }
372    
373            /**
374             * @see java.lang.Object#equals(Object)
375             */
376            public boolean equals(Object object) {
377                    if (this == object) {
378                            return true;
379                    }
380                    if (!(object instanceof ZmanimCalendar)) {
381                            return false;
382                    }
383                    ZmanimCalendar zCal = (ZmanimCalendar) object;
384                    // return getCalendar().getTime().equals(zCal.getCalendar().getTime())
385                    return getCalendar().equals(zCal.getCalendar())
386                                    && getGeoLocation().equals(zCal.getGeoLocation())
387                                    && getAstronomicalCalculator().equals(
388                                                    zCal.getAstronomicalCalculator());
389            }
390    
391            /**
392             * @see java.lang.Object#hashCode()
393             */
394            public int hashCode() {
395                    int result = 17;
396                    // needed or this and subclasses will return identical hash
397                    result = 37 * result + getClass().hashCode();
398                    result += 37 * result + getCalendar().hashCode();
399                    result += 37 * result + getGeoLocation().hashCode();
400                    result += 37 * result + getAstronomicalCalculator().hashCode();
401                    return result;
402            }
403    
404            /**
405             * A method to get the offset in minutes before
406             * {@link AstronomicalCalendar#getSunset() sunset} that is used in
407             * calculating candle lighting time. The default time used is 18 minutes
408             * before sunset. Some calendars use 15 minutes, while the custom in
409             * Jerusalem is to use a 40 minute offset. Please check the local custom for
410             * candel lighting time.
411             *
412             * @return Returns the candle lighting offset to set in minutes..
413             * @see #getCandelLighting()
414             */
415            public double getCandleLightingOffset() {
416                    return candleLightingOffset;
417            }
418    
419            /**
420             * A method to set the offset in minutes before
421             * {@link AstronomicalCalendar#getSunset() sunset} that is used in
422             * calculating candle lighting time. The default time used is 18 minutes
423             * before sunset. Some calendars use 15 minutes, while the custom in
424             * Jerusalem is to use a 40 minute offset.
425             *
426             * @param candleLightingOffset
427             *            The candle lighting offset to set in minutes.
428             * @see #getCandelLighting()
429             */
430            public void setCandleLightingOffset(double candleLightingOffset) {
431                    this.candleLightingOffset = candleLightingOffset;
432            }
433    }