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