001/*
002 * Zmanim Java API
003 * Copyright (C) 2004-2020 Eliyahu Hershfeld
004 *
005 * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General
006 * Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option)
007 * any later version.
008 *
009 * This library is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied
010 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
011 * details.
012 * You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to
013 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA,
014 * or connect to: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
015 */
016package com.kosherjava.zmanim;
017
018import java.util.Calendar;
019import java.util.Date;
020
021import com.kosherjava.zmanim.hebrewcalendar.JewishCalendar;
022import com.kosherjava.zmanim.util.AstronomicalCalculator;
023import com.kosherjava.zmanim.util.GeoLocation;
024
025/**
026 * The ZmanimCalendar is a specialized calendar that can calculate sunrise and sunset and Jewish <em>zmanim</em>
027 * (religious times) for prayers and other Jewish religious duties. This class contains the main functionality of the
028 * Zmanim library. For a much more extensive list of zmanim use the {@link ComplexZmanimCalendar} that extends this
029 * class. See documentation for the {@link ComplexZmanimCalendar} and {@link AstronomicalCalendar} for simple examples
030 * on using the API. According to Rabbi Dovid Yehudah Bursztyn in his <a href="http://www.worldcat.org/oclc/659793988"
031 * >Zmanim Kehilchasam (second edition published in 2007)</a> chapter 2 (pages 186-187) no zmanim besides sunrise and
032 * sunset should use elevation. However Rabbi Yechiel Avrahom Zilber in the <a href="http://hebrewbooks.org/51654"
033 * >Birur Halacha Vol. 6</a> Ch. 58 Pages <a href="http://hebrewbooks.org/pdfpager.aspx?req=51654&amp;pgnum=42">34</a>
034 * and <a href="http://hebrewbooks.org/pdfpager.aspx?req=51654&amp;pgnum=50">42</a> is of the opinion that elevation
035 * should be accounted for in zmanim calculations. Related to this, Rabbi Yaakov Karp in <a href=
036 * "http://www.worldcat.org/oclc/919472094">Shimush Zekeinim</a>, Ch. 1, page 17 states that obstructing horizons should
037 * be factored into zmanim calculations. The setting defaults to false (elevation will not be used for zmanim calculations),
038 * unless the setting is changed to true in {@link #setUseElevation(boolean)}. This will impact sunrise and sunset based
039 * zmanim such as {@link #getSunrise()}, {@link #getSunset()}, {@link #getSofZmanShmaGRA()}, alos based zmanim such as
040 * {@link #getSofZmanShmaMGA()} that are based on a fixed offset of sunrise or sunset and zmanim based on a percentage of
041 * the day such as {@link ComplexZmanimCalendar#getSofZmanShmaMGA90MinutesZmanis()} that are based on sunrise and sunset.
042 * It will not impact zmanim that are a degree based offset of sunrise and sunset, such as
043 * {@link ComplexZmanimCalendar#getSofZmanShmaMGA16Point1Degrees()} or {@link ComplexZmanimCalendar#getSofZmanShmaBaalHatanya()}.
044 * 
045 * <p><b>Note:</b> It is important to read the technical notes on top of the {@link AstronomicalCalculator} documentation
046 * before using this code.
047 * <p>I would like to thank Rabbi Yaakov Shakow, the author of Luach Ikvei Hayom who spent a considerable amount of time
048 * reviewing, correcting and making suggestions on the documentation in this library.
049 * <h2>Disclaimer:</h2> I did my best to get accurate results, but please double-check before relying on these zmanim for
050 * <em>halacha lemaaseh</em>.
051 * 
052 * 
053 * @author &copy; Eliyahu Hershfeld 2004 - 2020
054 */
055public class ZmanimCalendar extends AstronomicalCalendar {
056        
057        /**
058         * Is elevation factored in for some zmanim (see {@link #isUseElevation()} for additional information).
059         * @see #isUseElevation()
060         * @see #setUseElevation(boolean)
061         */
062        private boolean useElevation;
063
064        /**
065         * Is elevation above sea level calculated for times besides sunrise and sunset. According to Rabbi Dovid Yehuda
066         * Bursztyn in his <a href="http://www.worldcat.org/oclc/659793988">Zmanim Kehilchasam (second edition published
067         * in 2007)</a> chapter 2 (pages 186-187) no zmanim besides sunrise and sunset should use elevation. However Rabbi
068         * Yechiel Avrahom Zilber in the <a href="http://hebrewbooks.org/51654">Birur Halacha Vol. 6</a> Ch. 58 Pages
069         * <a href="http://hebrewbooks.org/pdfpager.aspx?req=51654&amp;pgnum=42">34</a> and <a href=
070         * "http://hebrewbooks.org/pdfpager.aspx?req=51654&amp;pgnum=50">42</a> is of the opinion that elevation should be
071         * accounted for in zmanim calculations. Related to this, Rabbi Yaakov Karp in <a href=
072         * "http://www.worldcat.org/oclc/919472094">Shimush Zekeinim</a>, Ch. 1, page 17 states that obstructing horizons
073         * should be factored into zmanim calculations.The setting defaults to false (elevation will not be used for zmanim
074         * calculations), unless the setting is changed to true in {@link #setUseElevation(boolean)}. This will impact sunrise
075         * and sunset based zmanim such as {@link #getSunrise()}, {@link #getSunset()}, {@link #getSofZmanShmaGRA()}, alos based
076         * zmanim such as {@link #getSofZmanShmaMGA()} that are based on a fixed offset of sunrise or sunset and zmanim based on
077         * a percentage of the day such as {@link ComplexZmanimCalendar#getSofZmanShmaMGA90MinutesZmanis()} that are based on
078         * sunrise and sunset. It will not impact zmanim that are a degree based offset of sunrise and sunset, such as
079         * {@link ComplexZmanimCalendar#getSofZmanShmaMGA16Point1Degrees()} or {@link ComplexZmanimCalendar#getSofZmanShmaBaalHatanya()}.
080         * 
081         * @return if the use of elevation is active
082         * 
083         * @see #setUseElevation(boolean)
084         */
085        public boolean isUseElevation() {
086                return useElevation;
087        }
088
089        /**
090         * Sets whether elevation above sea level is factored into <em>zmanim</em> calculations for times besides sunrise and sunset.
091         * See {@link #isUseElevation()} for more details. 
092         * @see #isUseElevation()
093         * 
094         * @param useElevation set to true to use elevation in zmanim calculations
095         */
096        public void setUseElevation(boolean useElevation) {
097                this.useElevation = useElevation;
098        }
099
100        /**
101         * The zenith of 16.1&deg; below geometric zenith (90&deg;). This calculation is used for determining <em>alos</em>
102         * (dawn) and <em>tzais</em> (nightfall) in some opinions. It is based on the calculation that the time between dawn
103         * and sunrise (and sunset to nightfall) is 72 minutes, the time that is takes to walk 4 <em>mil</em> at 18 minutes
104         * a mil (<em><a href="https://en.wikipedia.org/wiki/Maimonides">Rambam</a></em> and others). The sun's position at
105         * 72 minutes before {@link #getSunrise sunrise} in Jerusalem on the equinox (on March 16, about 4 days before the
106         * astronomical equinox, the day that a solar hour is 60 minutes) is 16.1&deg; below
107         * {@link #GEOMETRIC_ZENITH geometric zenith}.
108         * 
109         * @see #getAlosHashachar()
110         * @see ComplexZmanimCalendar#getAlos16Point1Degrees()
111         * @see ComplexZmanimCalendar#getTzais16Point1Degrees()
112         * @see ComplexZmanimCalendar#getSofZmanShmaMGA16Point1Degrees()
113         * @see ComplexZmanimCalendar#getSofZmanTfilaMGA16Point1Degrees()
114         * @see ComplexZmanimCalendar#getMinchaGedola16Point1Degrees()
115         * @see ComplexZmanimCalendar#getMinchaKetana16Point1Degrees()
116         * @see ComplexZmanimCalendar#getPlagHamincha16Point1Degrees()
117         * @see ComplexZmanimCalendar#getPlagAlos16Point1ToTzaisGeonim7Point083Degrees()
118         * @see ComplexZmanimCalendar#getSofZmanShmaAlos16Point1ToSunset()
119         */
120        protected static final double ZENITH_16_POINT_1 = GEOMETRIC_ZENITH + 16.1;
121
122        /**
123         * The zenith of 8.5&deg; below geometric zenith (90&deg;). This calculation is used for calculating <em>alos</em>
124         * (dawn) and <em>tzais</em> (nightfall) in some opinions. This calculation is based on the position of the sun 36
125         * minutes after {@link #getSunset sunset} in Jerusalem on March 16, about 4 days before the equinox, the day that a
126         * solar hour is 60 minutes, which is 8.5&deg; below {@link #GEOMETRIC_ZENITH geometric zenith}. The <em><a href=
127         * "http://www.worldcat.org/oclc/29283612">Ohr Meir</a></em> considers this the time that 3 small stars are visible,
128         * which is later than the required 3 medium stars.
129         * 
130         * @see #getTzais()
131         * @see ComplexZmanimCalendar#getTzaisGeonim8Point5Degrees()
132         */
133        protected static final double ZENITH_8_POINT_5 = GEOMETRIC_ZENITH + 8.5;
134
135        /**
136         * The default <em>Shabbos</em> candle lighting offset is 18 minutes. This can be changed via the
137         * {@link #setCandleLightingOffset(double)} and retrieved by the {@link #getCandleLightingOffset()}.
138         */
139        private double candleLightingOffset = 18;
140        
141        /**
142         * This method will return {@link #getSeaLevelSunrise() sea level sunrise} if {@link #isUseElevation()} is false
143         * (the default), or elevation adjusted {@link AstronomicalCalendar#getSunrise()} if it is true. This allows relevant zmanim
144         * in this and extending classes (such as the {@link ComplexZmanimCalendar}) to automatically adjust to the elevation setting.
145         * 
146         * @return {@link #getSeaLevelSunrise()} if {@link #isUseElevation()} is false (the default), or elevation adjusted
147         *          {@link AstronomicalCalendar#getSunrise()} if it is true.
148         * @see com.kosherjava.zmanim.AstronomicalCalendar#getSunrise()
149         */
150        protected Date getElevationAdjustedSunrise() {
151                if(isUseElevation()) {
152                        return super.getSunrise();
153                }
154                return getSeaLevelSunrise();
155        }
156        
157        /**
158         * This method will return {@link #getSeaLevelSunrise() sea level sunrise} if {@link #isUseElevation()} is false
159         * (the default), or elevation adjusted {@link AstronomicalCalendar#getSunrise()} if it is true. This allows relevant zmanim
160         * in this and extending classes (such as the {@link ComplexZmanimCalendar}) to automatically adjust to the elevation setting.
161         * 
162         * @return {@link #getSeaLevelSunset()} if {@link #isUseElevation()} is false (the default), or elevation adjusted
163         *          {@link AstronomicalCalendar#getSunset()} if it is true.
164         * @see com.kosherjava.zmanim.AstronomicalCalendar#getSunset()
165         */
166        protected Date getElevationAdjustedSunset() {
167                if(isUseElevation()) {
168                        return super.getSunset();
169                }
170                return getSeaLevelSunset();
171        }
172
173        /**
174         * A method that returns <em>tzais</em> (nightfall) when the sun is {@link #ZENITH_8_POINT_5 8.5&deg;} below the
175         * {@link #GEOMETRIC_ZENITH geometric horizon} (90&deg;) after {@link #getSunset sunset}, a time that Rabbi Meir
176         * Posen in his the <em><a href="http://www.worldcat.org/oclc/29283612">Ohr Meir</a></em> calculated that 3 small
177         * stars are visible, which is later than the required 3 medium stars. See the {@link #ZENITH_8_POINT_5} constant.
178         * 
179         * @see #ZENITH_8_POINT_5
180         * 
181         * @return The <code>Date</code> of nightfall. If the calculation can't be computed such as northern and southern
182         *         locations even south of the Arctic Circle and north of the Antarctic Circle where the sun may not reach
183         *         low enough below the horizon for this calculation, a null will be returned. See detailed explanation on
184         *         top of the {@link AstronomicalCalendar} documentation.
185         * @see #ZENITH_8_POINT_5
186         * ComplexZmanimCalendar#getTzaisGeonim8Point5Degrees() that returns an identical time to this generic <em>tzais</em>
187         */
188        public Date getTzais() {
189                return getSunsetOffsetByDegrees(ZENITH_8_POINT_5);
190        }
191
192        /**
193         * Returns <em>alos</em> (dawn) based on the time when the sun is {@link #ZENITH_16_POINT_1 16.1&deg;} below the
194         * eastern {@link #GEOMETRIC_ZENITH geometric horizon} before {@link #getSunrise sunrise}. This is based on the
195         * calculation that the time between dawn and sunrise (and sunset to nightfall) is 72 minutes, the time that is
196         * takes to walk 4 <em>mil</em> at 18 minutes a mil (<em><a href="https://en.wikipedia.org/wiki/Maimonides"
197         * >Rambam</a></em> and others). The sun's position at 72 minutes before {@link #getSunrise sunrise} in Jerusalem
198         * on the equinox (on March 16, about 4 days before the astronomical equinox, the day that a solar hour is 60
199         * minutes) is 16.1&deg; below. See the {@link #GEOMETRIC_ZENITH} constant.
200         * 
201         * @see #ZENITH_16_POINT_1
202         * @see ComplexZmanimCalendar#getAlos16Point1Degrees()
203         * 
204         * @return The <code>Date</code> of dawn. If the calculation can't be computed such as northern and southern
205         *         locations even south of the Arctic Circle and north of the Antarctic Circle where the sun may not reach
206         *         low enough below the horizon for this calculation, a null will be returned. See detailed explanation on
207         *         top of the {@link AstronomicalCalendar} documentation.
208         */
209        public Date getAlosHashachar() {
210                return getSunriseOffsetByDegrees(ZENITH_16_POINT_1);
211        }
212
213        /**
214         * Method to return <em>alos</em> (dawn) calculated using 72 minutes before {@link #getSunrise() sunrise} or
215         * {@link #getSeaLevelSunrise() sea level sunrise} (depending on the {@link #isUseElevation()} setting). This time
216         * is based on the time to walk the distance of 4 <em>Mil</em> at 18 minutes a <em>Mil</em>. The 72 minute time (but
217         * not the concept of fixed minutes) is based on the opinion that the time of the <em>Neshef</em> (twilight between
218         * dawn and sunrise) does not vary by the time of year or location but depends on the time it takes to walk the
219         * distance of 4 <em>Mil</em>.
220         * 
221         * @return the <code>Date</code> representing the time. If the calculation can't be computed such as in the Arctic
222         *         Circle where there is at least one day a year where the sun does not rise, and one where it does not set,
223         *         a null will be returned. See detailed explanation on top of the {@link AstronomicalCalendar}
224         *         documentation.
225         */
226        public Date getAlos72() {
227                return getTimeOffset(getElevationAdjustedSunrise(), -72 * MINUTE_MILLIS);
228        }
229
230        /**
231         * This method returns <em>chatzos</em> (midday) following most opinions that <em>chatzos</em> is the midpoint
232         * between {@link #getSeaLevelSunrise sea level sunrise} and {@link #getSeaLevelSunset sea level sunset}. A day
233         * starting at <em>alos</em> and ending at <em>tzais</em> using the same time or degree offset will also return
234         * the same time. The returned value is identical to {@link #getSunTransit()}. In reality due to lengthening or
235         * shortening of day, this is not necessarily the exact midpoint of the day, but it is very close.
236         * 
237         * @see AstronomicalCalendar#getSunTransit()
238         * @return the <code>Date</code> of chatzos. If the calculation can't be computed such as in the Arctic Circle
239         *         where there is at least one day where the sun does not rise, and one where it does not set, a null will
240         *         be returned. See detailed explanation on top of the {@link AstronomicalCalendar} documentation.
241         */
242        public Date getChatzos() {
243                return getSunTransit();
244        }
245
246        /**
247         * A generic method for calculating the latest <em>zman krias shema</em> (time to recite shema in the morning)
248         * that is 3 * <em>shaos zmaniyos</em> (temporal hours) after the start of the day, calculated using the start and
249         * end of the day passed to this method.
250         * The time from the start of day to the end of day are divided into 12 <em>shaos zmaniyos</em> (temporal hours),
251         * and the latest <em>zman krias shema</em> is calculated as 3 of those <em>shaos zmaniyos</em> after the beginning of
252         * the day. As an example, passing {@link #getSunrise() sunrise} and {@link #getSunset sunset} or {@link #getSeaLevelSunrise()
253         * sea level sunrise} and {@link #getSeaLevelSunset() sea level sunset} (depending on the {@link #isUseElevation()}
254         * elevation setting) to this method will return <em>sof zman krias shema</em> according to the opinion of the
255         * <em><a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a></em>.
256         * 
257         * @param startOfDay
258         *            the start of day for calculating <em>zman krias shema</em>. This can be sunrise or any alos passed to
259         *            this method.
260         * @param endOfDay
261         *            the end of day for calculating <em>zman krias shema</em>. This can be sunset or any tzais passed to
262         *            this method.
263         * @return the <code>Date</code> of the latest <em>zman shema</em> based on the start and end of day times passed to this
264         *         method. If the calculation can't be computed such as in the Arctic Circle where there is at least one day
265         *         a year where the sun does not rise, and one where it does not set, a null will be returned. See detailed
266         *         explanation on top of the {@link AstronomicalCalendar} documentation.
267         */
268        public Date getSofZmanShma(Date startOfDay, Date endOfDay) {
269                return getShaahZmanisBasedZman(startOfDay, endOfDay, 3);
270        }
271
272        /**
273         * This method returns the latest <em>zman krias shema</em> (time to recite shema in the morning) that is 3 *
274         * <em>{@link #getShaahZmanisGra() shaos zmaniyos}</em> (solar hours) after {@link #getSunrise() sunrise} or
275         * {@link #getSeaLevelSunrise() sea level sunrise} (depending on the {@link #isUseElevation()} setting), according
276         * to the <em><a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a></em>. 
277         *  The day is calculated from {@link #getSeaLevelSunrise() sea level sunrise} to {@link #getSeaLevelSunrise sea level
278         *  sunset} or {@link #getSunrise() sunrise} to {@link #getSunset() sunset} (depending on the {@link #isUseElevation()}
279         *  setting).
280         * 
281         * @see #getSofZmanShma(Date, Date)
282         * @see #getShaahZmanisGra()
283         * @see #isUseElevation()
284         * @see ComplexZmanimCalendar#getSofZmanShmaBaalHatanya()
285         * @return the <code>Date</code> of the latest zman shema according to the GRA. If the calculation can't be computed
286         * such as in the Arctic Circle where there is at least one day a year where the sun does not rise, and one where it
287         * does not set, a null will be returned. See the detailed explanation on top of the {@link AstronomicalCalendar}
288         * documentation.
289         */
290        public Date getSofZmanShmaGRA() {
291                return getSofZmanShma(getElevationAdjustedSunrise(), getElevationAdjustedSunset());
292        }
293
294        /**
295         * This method returns the latest <em>zman krias shema</em> (time to recite shema in the morning) that is 3 *
296         * <em>{@link #getShaahZmanisMGA() shaos zmaniyos}</em> (solar hours) after {@link #getAlos72()}, according to the
297         * <em><a href="https://en.wikipedia.org/wiki/Avraham_Gombinern">Magen Avraham (MGA)</a></em>. The day is calculated
298         * from 72 minutes before {@link #getSeaLevelSunrise() sea level sunrise} to 72 minutes after {@link
299         * #getSeaLevelSunrise sea level sunset} or from 72 minutes before {@link #getSunrise() sunrise} to {@link #getSunset()
300         * sunset} (depending on the {@link #isUseElevation()} setting).
301         * 
302         * @return the <code>Date</code> of the latest <em>zman shema</em>. If the calculation can't be computed such as in
303         *         the Arctic Circle where there is at least one day a year where the sun does not rise, and one where it
304         *         does not set, a null will be returned. See detailed explanation on top of the
305         *         {@link AstronomicalCalendar} documentation.
306         * @see #getSofZmanShma(Date, Date)
307         * @see ComplexZmanimCalendar#getShaahZmanis72Minutes()
308         * @see ComplexZmanimCalendar#getAlos72()
309         * @see ComplexZmanimCalendar#getSofZmanShmaMGA72Minutes() that 
310         */
311        public Date getSofZmanShmaMGA() {
312                return getSofZmanShma(getAlos72(), getTzais72());
313        }
314
315        /**
316         * This method returns the <em>tzais</em> (nightfall) based on the opinion of <em>Rabbeinu Tam</em> that
317         * <em>tzais hakochavim</em> is calculated as 72 minutes, the time it takes to walk 4 <em>Mil</em> at 18 minutes
318         * a <em>Mil</em>. According to the <a href="https://en.wikipedia.org/wiki/Samuel_Loew">Machtzis Hashekel</a> in
319         * Orach Chaim 235:3, the <a href="https://en.wikipedia.org/wiki/Joseph_ben_Meir_Teomim">Pri Megadim</a> in Orach
320         * Chaim 261:2 (see the Biur Halacha) and others (see Hazmanim Bahalacha 17:3 and 17:5) the 72 minutes are standard
321         * clock minutes any time of the year in any location. Depending on the {@link #isUseElevation()} setting) a 72
322         * minute offset from  either {@link #getSunset() sunset} or {@link #getSeaLevelSunset() sea level sunset} is used.
323         * 
324         * @see ComplexZmanimCalendar#getTzais16Point1Degrees()
325         * @return the <code>Date</code> representing 72 minutes after sunset. If the calculation can't be
326         *         computed such as in the Arctic Circle where there is at least one day a year where the sun does not rise,
327         *         and one where it does not set, a null will be returned See detailed explanation on top of the
328         *         {@link AstronomicalCalendar} documentation.
329         */
330        public Date getTzais72() {
331                return getTimeOffset(getElevationAdjustedSunset(), 72 * MINUTE_MILLIS);
332        }
333
334        /**
335         * A method to return candle lighting time, calculated as {@link #getCandleLightingOffset()} minutes before
336         * {@link #getSeaLevelSunset() sea level sunset}. This will return the time for any day of the week, since it can be
337         * used to calculate candle lighting time for <em>Yom Tov</em> (mid-week holidays) as well. Elevation adjustments
338         * are intentionally not performed by this method, but you can calculate it by passing the elevation adjusted sunset
339         * to {@link #getTimeOffset(Date, long)}.
340         * 
341         * @return candle lighting time. If the calculation can't be computed such as in the Arctic Circle where there is at
342         *         least one day a year where the sun does not rise, and one where it does not set, a null will be returned.
343         *         See detailed explanation on top of the {@link AstronomicalCalendar} documentation.
344         * 
345         * @see #getSeaLevelSunset()
346         * @see #getCandleLightingOffset()
347         * @see #setCandleLightingOffset(double)
348         */
349        public Date getCandleLighting() {
350                return getTimeOffset(getSeaLevelSunset(), -getCandleLightingOffset() * MINUTE_MILLIS);
351        }
352
353        /**
354         * A generic method for calculating the latest <em>zman tfilah</em> (time to recite the morning prayers)
355         * that is 4 * <em>shaos zmaniyos</em> (temporal hours) after the start of the day, calculated using the start and
356         * end of the day passed to this method.
357         * The time from the start of day to the end of day are divided into 12 <em>shaos zmaniyos</em> (temporal hours),
358         * and <em>sof zman tfila</em> is calculated as 4 of those <em>shaos zmaniyos</em> after the beginning of the day.
359         * As an example, passing {@link #getSunrise() sunrise} and {@link #getSunset sunset} or {@link #getSeaLevelSunrise()
360         * sea level sunrise} and {@link #getSeaLevelSunset() sea level sunset} (depending on the {@link #isUseElevation()}
361         * elevation setting) to this method will return <em>zman tfilah</em> according to the opinion of the <em><a href=
362         * "https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a></em>.
363         * 
364         * @param startOfDay
365         *            the start of day for calculating <em>zman tfilah</em>. This can be sunrise or any alos passed to
366         *            this method.
367         * @param endOfDay
368         *            the end of day for calculating <em>zman tfilah</em>. This can be sunset or any tzais passed to this
369         *            method.
370         * @return the <code>Date</code> of the latest <em>zman tfilah</em> based on the start and end of day times passed
371         *         to this method. If the calculation can't be computed such as in the Arctic Circle where there is at least
372         *         one day a year where the sun does not rise, and one where it does not set, a null will be returned. See
373         *         detailed explanation on top of the {@link AstronomicalCalendar} documentation.
374         */
375        public Date getSofZmanTfila(Date startOfDay, Date endOfDay) {
376                return getShaahZmanisBasedZman(startOfDay, endOfDay, 4);
377        }
378
379        /**
380         * This method returns the latest <em>zman tfila</em> (time to recite shema in the morning) that is 4 *
381         * <em>{@link #getShaahZmanisGra() shaos zmaniyos}</em> (solar hours) after {@link #getSunrise() sunrise} or
382         * {@link #getSeaLevelSunrise() sea level sunrise} (depending on the {@link #isUseElevation()} setting), according
383         * to the <em><a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a></em>. 
384         * The day is calculated from {@link #getSeaLevelSunrise() sea level sunrise} to {@link #getSeaLevelSunrise sea level
385         * sunset} or {@link #getSunrise() sunrise} to {@link #getSunset() sunset} (depending on the {@link #isUseElevation()}
386         * setting).
387         * 
388         * @see #getSofZmanTfila(Date, Date)
389         * @see #getShaahZmanisGra()
390         * @see ComplexZmanimCalendar#getSofZmanTfilaBaalHatanya()
391         * @return the <code>Date</code> of the latest zman tfilah. If the calculation can't be computed such as in the
392         *         Arctic Circle where there is at least one day a year where the sun does not rise, and one where it does
393         *         not set, a null will be returned. See detailed explanation on top of the {@link AstronomicalCalendar}
394         *         documentation.
395         */
396        public Date getSofZmanTfilaGRA() {
397                return getSofZmanTfila(getElevationAdjustedSunrise(), getElevationAdjustedSunset());
398        }
399
400        /**
401         * This method returns the latest <em>zman tfila</em> (time to recite shema in the morning) that is 4 *
402         * <em>{@link #getShaahZmanisMGA() shaos zmaniyos}</em> (solar hours) after {@link #getAlos72()}, according to the
403         * <em><a href="https://en.wikipedia.org/wiki/Avraham_Gombinern">Magen Avraham (MGA)</a></em>. The day is calculated
404         * from 72 minutes before {@link #getSeaLevelSunrise() sea level sunrise} to 72 minutes after {@link
405         * #getSeaLevelSunrise sea level sunset} or from 72 minutes before {@link #getSunrise() sunrise} to {@link #getSunset()
406         * sunset} (depending on the {@link #isUseElevation()} setting).
407         * 
408         * @return the <code>Date</code> of the latest zman tfila. If the calculation can't be computed such as in the
409         *         Arctic Circle where there is at least one day a year where the sun does not rise, and one where it does
410         *         not set), a null will be returned. See detailed explanation on top of the {@link AstronomicalCalendar}
411         *         documentation.
412         * @see #getSofZmanTfila(Date, Date)
413         * @see #getShaahZmanisMGA()
414         * @see #getAlos72()
415         */
416        public Date getSofZmanTfilaMGA() {
417                return getSofZmanTfila(getAlos72(), getTzais72());
418        }
419
420        /**
421         * A generic method for calculating the latest <em>mincha gedola</em> (the earliest time to recite the mincha  prayers)
422         * that is 6.5 * <em>shaos zmaniyos</em> (temporal hours) after the start of the day, calculated using the start and end
423         * of the day passed to this method.
424         * The time from the start of day to the end of day are divided into 12 <em>shaos zmaniyos</em> (temporal hours), and
425         * <em>mincha gedola</em> is calculated as 6.5 of those <em>shaos zmaniyos</em> after the beginning of the day. As an
426         * example, passing {@link #getSunrise() sunrise} and {@link #getSunset sunset} or {@link #getSeaLevelSunrise() sea level
427         * sunrise} and {@link #getSeaLevelSunset() sea level sunset} (depending on the {@link #isUseElevation()} elevation
428         * setting) to this method will return <em>mincha gedola</em> according to the opinion of the
429         * <em><a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a></em>.
430         * 
431         * @param startOfDay
432         *            the start of day for calculating <em>Mincha gedola</em>. This can be sunrise or any alos passed to
433         *            this method.
434         * @param endOfDay
435         *            the end of day for calculating <em>Mincha gedola</em>. This can be sunrise or any alos passed to
436         *            this method.
437         * @return the <code>Date</code> of the time of <em>Mincha gedola</em> based on the start and end of day times
438         *         passed to this method. If the calculation can't be computed such as in the Arctic Circle where there is
439         *         at least one day a year where the sun does not rise, and one where it does not set, a null will be
440         *         returned. See detailed explanation on top of the {@link AstronomicalCalendar} documentation.
441         */
442        public Date getMinchaGedola(Date startOfDay, Date endOfDay) {
443                return getShaahZmanisBasedZman(startOfDay, endOfDay, 6.5);
444        }
445
446        /**
447         * This method returns the latest <em>mincha gedola</em>,the earliest time one can pray <em>mincha</em> that is 6.5 *
448         * <em>{@link #getShaahZmanisGra() shaos zmaniyos}</em> (solar hours) after {@link #getSunrise() sunrise} or
449         * {@link #getSeaLevelSunrise() sea level sunrise} (depending on the {@link #isUseElevation()} setting), according
450         * to the <em><a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a></em>. <em>Mincha gedola</em> is the earliest
451         * time one can pray <em>mincha</em>. The Ramba"m is of the opinion that it is better to delay <em>mincha</em> until
452         * <em>{@link #getMinchaKetana() mincha ketana}</em> while the <em>Ra"sh, Tur, GRA</em> and others are of the
453         * opinion that <em>mincha</em> can be prayed <em>lechatchila</em> starting at <em>mincha gedola</em>.
454         * The day is calculated from {@link #getSeaLevelSunrise() sea level sunrise} to {@link #getSeaLevelSunrise sea level
455         * sunset} or {@link #getSunrise() sunrise} to {@link #getSunset() sunset} (depending on the {@link #isUseElevation()}
456         * setting).
457         * 
458         * @see #getMinchaGedola(Date, Date)
459         * @see #getShaahZmanisGra()
460         * @see #getMinchaKetana()
461         * @see ComplexZmanimCalendar#getMinchaGedolaBaalHatanya()
462         * @return the <code>Date</code> of the time of mincha gedola. If the calculation can't be computed such as in the
463         *         Arctic Circle where there is at least one day a year where the sun does not rise, and one where it does
464         *         not set, a null will be returned. See detailed explanation on top of the {@link AstronomicalCalendar}
465         *         documentation.
466         */
467        public Date getMinchaGedola() {
468                return getMinchaGedola(getElevationAdjustedSunrise(), getElevationAdjustedSunset());
469        }
470
471        /**
472         * A generic method for calculating <em>mincha ketana</em>, (the preferred time to recite the mincha prayers in
473         * the opinion of the <em><a href="https://en.wikipedia.org/wiki/Maimonides">Rambam</a></em> and others) that is
474         * 9.5 * <em>shaos zmaniyos</em> (temporal hours) after the start of the day, calculated using the start and end
475         * of the day passed to this method.
476         * The time from the start of day to the end of day are divided into 12 <em>shaos zmaniyos</em> (temporal hours), and
477         * <em>mincha ketana</em> is calculated as 9.5 of those <em>shaos zmaniyos</em> after the beginning of the day. As an
478         * example, passing {@link #getSunrise() sunrise} and {@link #getSunset sunset} or {@link #getSeaLevelSunrise() sea level
479         * sunrise} and {@link #getSeaLevelSunset() sea level sunset} (depending on the {@link #isUseElevation()} elevation
480         * setting) to this method will return <em>mincha ketana</em> according to the opinion of the
481         * <em><a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a></em>.
482         * 
483         * @param startOfDay
484         *            the start of day for calculating <em>Mincha ketana</em>. This can be sunrise or any alos passed to
485         *            this method.
486         * @param endOfDay
487         *            the end of day for calculating <em>Mincha ketana</em>. This can be sunrise or any alos passed to
488         *            this method.
489         * @return the <code>Date</code> of the time of <em>Mincha ketana</em> based on the start and end of day times
490         *         passed to this method. If the calculation can't be computed such as in the Arctic Circle where there is
491         *         at least one day a year where the sun does not rise, and one where it does not set, a null will be
492         *         returned. See detailed explanation on top of the {@link AstronomicalCalendar} documentation.
493         *
494         */
495        public Date getMinchaKetana(Date startOfDay, Date endOfDay) {
496                return getShaahZmanisBasedZman(startOfDay, endOfDay, 9.5);
497        }
498
499        /**
500         * This method returns <em>mincha ketana</em>,the preferred earliest time to pray <em>mincha</em> in the
501         * opinion of the <em><a href="https://en.wikipedia.org/wiki/Maimonides">Rambam</a></em> and others, that is 9.5
502         * * <em>{@link #getShaahZmanisGra() shaos zmaniyos}</em> (solar hours) after {@link #getSunrise() sunrise} or
503         * {@link #getSeaLevelSunrise() sea level sunrise} (depending on the {@link #isUseElevation()} setting), according
504         * to the <em><a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a></em>. For more information on this see the
505         * documentation on <em>{@link #getMinchaGedola() mincha gedola}</em>.
506         * The day is calculated from {@link #getSeaLevelSunrise() sea level sunrise} to {@link #getSeaLevelSunrise sea level
507         * sunset} or {@link #getSunrise() sunrise} to {@link #getSunset() sunset} (depending on the {@link #isUseElevation()}
508         * setting.
509         * 
510         * @see #getMinchaKetana(Date, Date)
511         * @see #getShaahZmanisGra()
512         * @see #getMinchaGedola()
513         * @see ComplexZmanimCalendar#getMinchaKetanaBaalHatanya()
514         * @return the <code>Date</code> of the time of mincha ketana. If the calculation can't be computed such as in the
515         *         Arctic Circle where there is at least one day a year where the sun does not rise, and one where it does
516         *         not set, a null will be returned. See detailed explanation on top of the {@link AstronomicalCalendar}
517         *         documentation.
518         */
519        public Date getMinchaKetana() {
520                return getMinchaKetana(getElevationAdjustedSunrise(), getElevationAdjustedSunset());
521        }
522
523        /**
524         * A generic method for calculating <em>plag hamincha</em> (the earliest time that Shabbos can be started) that is
525         * 10.75 hours after the start of the day, (or 1.25 hours before the end of the day) based on the start and end of
526         * the day passed to the method.
527         * The time from the start of day to the end of day are divided into 12 <em>shaos zmaniyos</em> (temporal hours), and
528         * <em>plag hamincha</em> is calculated as 10.75 of those <em>shaos zmaniyos</em> after the beginning of the day. As an
529         * example, passing {@link #getSunrise() sunrise} and {@link #getSunset sunset} or {@link #getSeaLevelSunrise() sea level
530         * sunrise} and {@link #getSeaLevelSunset() sea level sunset} (depending on the {@link #isUseElevation()} elevation
531         * setting) to this method will return <em>plag mincha</em> according to the opinion of the
532         * <em><a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a></em>.
533         * 
534         * @param startOfDay
535         *            the start of day for calculating plag. This can be sunrise or any alos passed to this method.
536         * @param endOfDay
537         *            the end of day for calculating plag. This can be sunrise or any alos passed to this method.
538         * @return the <code>Date</code> of the time of <em>plag hamincha</em> based on the start and end of day times
539         *         passed to this method. If the calculation can't be computed such as in the Arctic Circle where there is
540         *         at least one day a year where the sun does not rise, and one where it does not set, a null will be
541         *         returned. See detailed explanation on top of the {@link AstronomicalCalendar} documentation.
542         */
543        public Date getPlagHamincha(Date startOfDay, Date endOfDay) {
544                return getShaahZmanisBasedZman(startOfDay, endOfDay, 10.75);
545        }
546
547        /**
548         * This method returns <em>plag hamincha</em>, that is 10.75 * <em>{@link #getShaahZmanisGra() shaos zmaniyos}</em>
549         * (solar hours) after {@link #getSunrise() sunrise} or {@link #getSeaLevelSunrise() sea level sunrise} (depending on
550         * the {@link #isUseElevation()} setting), according to the <em><a href="https://en.wikipedia.org/wiki/Vilna_Gaon"
551         * >GRA</a></em>. Plag hamincha is the earliest time that <em>Shabbos</em> can be started.
552         * The day is calculated from {@link #getSeaLevelSunrise() sea level sunrise} to {@link #getSeaLevelSunrise sea level
553         * sunset} or {@link #getSunrise() sunrise} to {@link #getSunset() sunset} (depending on the {@link #isUseElevation()}
554         * 
555         * @see #getPlagHamincha(Date, Date)
556         * @see ComplexZmanimCalendar#getPlagHaminchaBaalHatanya()
557         * @return the <code>Date</code> of the time of <em>plag hamincha</em>. If the calculation can't be computed such as
558         *         in the Arctic Circle where there is at least one day a year where the sun does not rise, and one where it
559         *         does not set, a null will be returned. See detailed explanation on top of the
560         *         {@link AstronomicalCalendar} documentation.
561         */
562        public Date getPlagHamincha() {
563                return getPlagHamincha(getElevationAdjustedSunrise(), getElevationAdjustedSunset());
564        }
565
566        /**
567         * A method that returns a <em>shaah zmanis</em> ({@link #getTemporalHour(Date, Date) temporal hour}) according to
568         * the opinion of the <em><a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a></em>. This calculation divides
569         * the day based on the opinion of the <em>GRA</em> that the day runs from from {@link #getSeaLevelSunrise() sea
570         * level sunrise} to {@link #getSeaLevelSunrise sea level sunset} or {@link #getSunrise() sunrise} to
571         * {@link #getSunset() sunset} (depending on the {@link #isUseElevation()} setting). The day is split into 12 equal
572         * parts with each one being a <em>shaah zmanis</em>. This method is similar to {@link #getTemporalHour}, but can
573         * account for elevation.
574         * 
575         * @return the <code>long</code> millisecond length of a <em>shaah zmanis</em> calculated from sunrise to sunset.
576         *         If the calculation can't be computed such as in the Arctic Circle where there is at least one day a year
577         *         where the sun does not rise, and one where it does not set, {@link Long#MIN_VALUE} will be returned. See
578         *         detailed explanation on top of the {@link AstronomicalCalendar} documentation.
579         * @see #getTemporalHour(Date, Date)
580         * @see #getSeaLevelSunrise()
581         * @see #getSeaLevelSunset()
582         * @see ComplexZmanimCalendar#getShaahZmanisBaalHatanya()
583         */
584        public long getShaahZmanisGra() {
585                return getTemporalHour(getElevationAdjustedSunrise(), getElevationAdjustedSunset());
586        }
587
588        /**
589         * A method that returns a <em>shaah zmanis</em> (temporal hour) according to the opinion of the <em><a href=
590         * "https://en.wikipedia.org/wiki/Avraham_Gombinern">Magen Avraham (MGA)</a></em> based on a 72 minutes <em>alos</em>
591         * and <em>tzais</em>. This calculation divides the day that runs from dawn to dusk (for sof zman krias shema and tfila).
592         * Dawn for this calculation is 72 minutes before {@link #getSunrise() sunrise} or {@link #getSeaLevelSunrise() sea level
593         * sunrise} (depending on the {@link #isUseElevation()} elevation setting) and dusk is 72 minutes after {@link #getSunset
594         * sunset} or {@link #getSeaLevelSunset() sea level sunset} (depending on the {@link #isUseElevation()} elevation setting).
595         * This day is split into 12 equal parts with each part being a <em>shaah zmanis</em>. Alternate methods of calculating a
596         * <em>shaah zmanis</em> according to the Magen Avraham (MGA) are available in the subclass {@link ComplexZmanimCalendar}.
597         * 
598         * @return the <code>long</code> millisecond length of a <em>shaah zmanis</em>. If the calculation can't be computed
599         *         such as in the Arctic Circle where there is at least one day a year where the sun does not rise, and one
600         *         where it does not set, {@link Long#MIN_VALUE} will be returned. See detailed explanation on top of the
601         *         {@link AstronomicalCalendar} documentation.
602         */
603        public long getShaahZmanisMGA() {
604                return getTemporalHour(getAlos72(), getTzais72());
605        }
606
607        /**
608         * Default constructor will set a default {@link GeoLocation#GeoLocation()}, a default
609         * {@link AstronomicalCalculator#getDefault() AstronomicalCalculator} and default the calendar to the current date.
610         * 
611         * @see AstronomicalCalendar#AstronomicalCalendar()
612         */
613        public ZmanimCalendar() {
614                super();
615        }
616
617        /**
618         * A constructor that takes a {@link GeoLocation} as a parameter.
619         * 
620         * @param location
621         *            the location
622         */
623        public ZmanimCalendar(GeoLocation location) {
624                super(location);
625        }
626
627        /**
628         * A method to get the offset in minutes before {@link AstronomicalCalendar#getSeaLevelSunset() sea level sunset} which
629         * is used in calculating candle lighting time. The default time used is 18 minutes before sea level sunset. Some
630         * calendars use 15 minutes, while the custom in Jerusalem is to use a 40 minute offset. Please check the local custom
631         * for candle lighting time.
632         * 
633         * @return Returns the currently set candle lighting offset in minutes.
634         * @see #getCandleLighting()
635         * @see #setCandleLightingOffset(double)
636         */
637        public double getCandleLightingOffset() {
638                return candleLightingOffset;
639        }
640
641        /**
642         * A method to set the offset in minutes before {@link AstronomicalCalendar#getSeaLevelSunset() sea level sunset} that is
643         * used in calculating candle lighting time. The default time used is 18 minutes before sunset. Some calendars use 15
644         * minutes, while the custom in Jerusalem is to use a 40 minute offset.
645         * 
646         * @param candleLightingOffset
647         *            The candle lighting offset to set in minutes.
648         * @see #getCandleLighting()
649         * @see #getCandleLightingOffset()
650         */
651        public void setCandleLightingOffset(double candleLightingOffset) {
652                this.candleLightingOffset = candleLightingOffset;
653        }
654        
655        /**
656         * This is a utility method to determine if the current Date (date-time) passed in has a <em>melacha</em> (work) prohibition.
657         * Since there are many opinions on the time of <em>tzais</em>, the <em>tzais</em> for the current day has to be passed to this
658         * class. Sunset is the classes current day's {@link #getElevationAdjustedSunset() elevation adjusted sunset} that observes the
659         * {@link #isUseElevation()} settings. The {@link JewishCalendar#getInIsrael()} will be set by the inIsrael parameter.
660         * 
661         * @param currentTime the current time
662         * @param tzais the time of tzais
663         * @param inIsrael whether to use Israel holiday scheme or not
664         * 
665         * @return true if <em>melacha</em> is prohibited or false if it is not.
666         * 
667         * @see JewishCalendar#isAssurBemelacha()
668         * @see JewishCalendar#hasCandleLighting()
669         * @see JewishCalendar#setInIsrael(boolean)
670         */
671        public boolean isAssurBemlacha(Date currentTime, Date tzais, boolean inIsrael) {
672                JewishCalendar jewishCalendar = new JewishCalendar();
673                jewishCalendar.setGregorianDate(getCalendar().get(Calendar.YEAR), getCalendar().get(Calendar.MONTH),
674                                getCalendar().get(Calendar.DAY_OF_MONTH));
675                jewishCalendar.setInIsrael(inIsrael);
676                
677                if(jewishCalendar.hasCandleLighting() && currentTime.compareTo(getElevationAdjustedSunset()) >= 0) { //erev shabbos, YT or YT sheni and after shkiah
678                        return true;
679                }
680                
681                if(jewishCalendar.isAssurBemelacha()  && currentTime.compareTo(tzais) <= 0) { //is shabbos or YT and it is before tzais
682                        return true;
683                }
684                
685                return false;
686        }
687
688        /**
689         * A generic utility method for calculating any <em>shaah zmanis</em> (temporal hour) based <em>zman</em> with the
690         * day defined as the start and end of day (or night) and the number of <em>shaahos zmaniyos</em> passed to the
691         * method. This simplifies the code in other methods such as {@link #getPlagHamincha(Date, Date)} and cuts down on
692         * code replication. As an example, passing {@link #getSunrise() sunrise} and {@link #getSunset sunset} or {@link
693         * #getSeaLevelSunrise() sea level sunrise} and {@link #getSeaLevelSunset() sea level sunset} (depending on the
694         * {@link #isUseElevation()} elevation setting) and 10.75 hours to this method will return <em>plag mincha</em>
695         * according to the opinion of the <em><a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a></em>.
696         * 
697         * @param startOfDay
698         *            the start of day for calculating the <em>zman</em>. This can be sunrise or any <em>alos</em> passed
699         *            to this method.
700         * @param endOfDay
701         *            the end of day for calculating the <em>zman</em>. This can be sunrise or any <em>alos</em> passed to
702         *            this method.
703         * @param hours
704         *            the number of <em>shaahos zmaniyos</em> (temporal hours) to offset from the start of day
705         * @return the <code>Date</code> of the time of <em>zman</em> with the <em>shaahos zmaniyos</em> (temporal hours)
706         *         in the day offset from the start of day passed to this method. If the calculation can't be computed such
707         *         as in the Arctic Circle where there is at least one day a year where the sun does not rise, and one
708         *         where it does not set, a null will be  returned. See detailed explanation on top of the {@link
709         *         AstronomicalCalendar} documentation.
710         */
711        public Date getShaahZmanisBasedZman(Date startOfDay, Date endOfDay, double hours) {
712                long shaahZmanis = getTemporalHour(startOfDay, endOfDay);
713                return getTimeOffset(startOfDay, shaahZmanis * hours);
714        }
715}