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