001/*
002 * Zmanim Java API
003 * Copyright (C) 2004-2018 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 net.sourceforge.zmanim;
017
018import java.util.Calendar;
019import java.util.Date;
020
021import net.sourceforge.zmanim.hebrewcalendar.JewishCalendar;
022import net.sourceforge.zmanim.util.AstronomicalCalculator;
023import net.sourceforge.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 - 2018
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 is 16.1&deg; below
106         * {@link #GEOMETRIC_ZENITH geometric zenith}.
107         * 
108         * @see #getAlosHashachar()
109         * @see ComplexZmanimCalendar#getAlos16Point1Degrees()
110         * @see ComplexZmanimCalendar#getTzais16Point1Degrees()
111         * @see ComplexZmanimCalendar#getSofZmanShmaMGA16Point1Degrees()
112         * @see ComplexZmanimCalendar#getSofZmanTfilaMGA16Point1Degrees()
113         * @see ComplexZmanimCalendar#getMinchaGedola16Point1Degrees()
114         * @see ComplexZmanimCalendar#getMinchaKetana16Point1Degrees()
115         * @see ComplexZmanimCalendar#getPlagHamincha16Point1Degrees()
116         * @see ComplexZmanimCalendar#getPlagAlos16Point1ToTzaisGeonim7Point083Degrees()
117         * @see ComplexZmanimCalendar#getSofZmanShmaAlos16Point1ToSunset()
118         */
119        protected static final double ZENITH_16_POINT_1 = GEOMETRIC_ZENITH + 16.1;
120
121        /**
122         * The zenith of 8.5&deg; below geometric zenith (90&deg;). This calculation is used for calculating <em>alos</em>
123         * (dawn) and <em>tzais</em> (nightfall) in some opinions. This calculation is based on the position of the sun 36
124         * minutes after {@link #getSunset sunset} in Jerusalem on March 16, about 4 days before the equinox, the day that a
125         * solar hour is 60 minutes, which is 8.5&deg; below {@link #GEOMETRIC_ZENITH geometric zenith}. The <em><a href=
126         * "http://www.worldcat.org/oclc/29283612">Ohr Meir</a></em> considers this the time that 3 small stars are visible,
127         * which is later than the required 3 medium stars.
128         * 
129         * @see #getTzais()
130         * @see ComplexZmanimCalendar#getTzaisGeonim8Point5Degrees()
131         */
132        protected static final double ZENITH_8_POINT_5 = GEOMETRIC_ZENITH + 8.5;
133
134        /**
135         * The default <em>Shabbos</em> candle lighting offset is 18 minutes. This can be changed via the
136         * {@link #setCandleLightingOffset(double)} and retrieved by the {@link #getCandleLightingOffset()}.
137         */
138        private double candleLightingOffset = 18;
139        
140        /**
141         * This method will return {@link #getSeaLevelSunrise() sea level sunrise} if {@link #isUseElevation()} is false
142         * (the default), or elevation adjusted {@link AstronomicalCalendar#getSunrise()} if it is true. This allows relevant zmanim
143         * in this and extending classes (such as the {@link ComplexZmanimCalendar}) to automatically adjust to the elevation setting.
144         * 
145         * @return {@link #getSeaLevelSunrise()} if {@link #isUseElevation()} is false (the default), or elevation adjusted
146         *          {@link AstronomicalCalendar#getSunrise()} if it is true.
147         * @see net.sourceforge.zmanim.AstronomicalCalendar#getSunrise()
148         */
149        protected Date getElevationAdjustedSunrise() {
150                if(isUseElevation()) {
151                        return super.getSunrise();
152                }
153                return getSeaLevelSunrise();
154        }
155        
156        /**
157         * This method will return {@link #getSeaLevelSunrise() sea level sunrise} if {@link #isUseElevation()} is false
158         * (the default), or elevation adjusted {@link AstronomicalCalendar#getSunrise()} if it is true. This allows relevant zmanim
159         * in this and extending classes (such as the {@link ComplexZmanimCalendar}) to automatically adjust to the elevation setting.
160         * 
161         * @return {@link #getSeaLevelSunset()} if {@link #isUseElevation()} is false (the default), or elevation adjusted
162         *          {@link AstronomicalCalendar#getSunset()} if it is true.
163         * @see net.sourceforge.zmanim.AstronomicalCalendar#getSunset()
164         */
165        protected Date getElevationAdjustedSunset() {
166                if(isUseElevation()) {
167                        return super.getSunset();
168                }
169                return getSeaLevelSunset();
170        }
171
172        /**
173         * A method that returns <em>tzais</em> (nightfall) when the sun is {@link ZENITH_8_POINT_5 8.5&deg;} below the
174         * {@link #GEOMETRIC_ZENITH geometric horizon} (90&deg;) after {@link #getSunset sunset}, a time that Rabbi Meir
175         * Posen in his the <em><a href="http://www.worldcat.org/oclc/29283612">Ohr Meir</a></em> calculated that 3 small
176         * stars are visible, which is later than the required 3 medium stars. See the {@link #ZENITH_8_POINT_5} constant.
177         * 
178         * @see #ZENITH_8_POINT_5
179         * 
180         * @return The <code>Date</code> of nightfall. If the calculation can't be computed such as northern and southern
181         *         locations even south of the Arctic Circle and north of the Antarctic Circle where the sun may not reach
182         *         low enough below the horizon for this calculation, a null will be returned. See detailed explanation on
183         *         top of the {@link AstronomicalCalendar} documentation.
184         * @see #ZENITH_8_POINT_5
185         * ComplexZmanimCalendar#getTzaisGeonim8Point5Degrees() that returns an identical time to this generic <em>tzais</em>
186         */
187        public Date getTzais() {
188                return getSunsetOffsetByDegrees(ZENITH_8_POINT_5);
189        }
190
191        /**
192         * Returns <em>alos</em> (dawn) based on the time when the sun is {@link #ZENITH_16_POINT_1 16.1&deg;} below the
193         * eastern {@link #GEOMETRIC_ZENITH geometric horizon} before {@link #getSunrise sunrise}. This is based on the
194         * calculation that the time between dawn and sunrise (and sunset to nightfall) is 72 minutes, the time that is
195         * takes to walk 4 <em>mil</em> at 18 minutes a mil (<em><a href="https://en.wikipedia.org/wiki/Maimonides"
196         * >Rambam</a></em> and others). The sun's position at 72 minutes before {@link #getSunrise sunrise} in Jerusalem
197         * on the equinox is 16.1&deg; below. See the {@link #GEOMETRIC_ZENITH} constant.
198         * 
199         * @see #ZENITH_16_POINT_1
200         * @see ComplexZmanimCalendar#getAlos16Point1Degrees()
201         * 
202         * @return The <code>Date</code> of dawn. If the calculation can't be computed such as northern and southern
203         *         locations even south of the Arctic Circle and north of the Antarctic Circle where the sun may not reach
204         *         low enough below the horizon for this calculation, a null will be returned. See detailed explanation on
205         *         top of the {@link AstronomicalCalendar} documentation.
206         */
207        public Date getAlosHashachar() {
208                return getSunriseOffsetByDegrees(ZENITH_16_POINT_1);
209        }
210
211        /**
212         * Method to return <em>alos</em> (dawn) calculated using 72 minutes before {@link #getSunrise() sunrise} or
213         * {@link #getSeaLevelSunrise() sea level sunrise} (depending on the {@link #isUseElevation()} setting). This time
214         * 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
215         * not the concept of fixed minutes) is based on the opinion that the time of the <em>Neshef</em> (twilight between
216         * dawn and sunrise) does not vary by the time of year or location but depends on the time it takes to walk the
217         * distance of 4 <em>Mil</em>.
218         * 
219         * @return the <code>Date</code> representing the time. If the calculation can't be computed such as in the Arctic
220         *         Circle where there is at least one day a year where the sun does not rise, and one where it does not set,
221         *         a null will be returned. See detailed explanation on top of the {@link AstronomicalCalendar}
222         *         documentation.
223         */
224        public Date getAlos72() {
225                return getTimeOffset(getElevationAdjustedSunrise(), -72 * MINUTE_MILLIS);
226        }
227
228        /**
229         * This method returns <em>chatzos</em> (midday) following most opinions that <em>chatzos</em> is the midpoint
230         * between {@link #getSeaLevelSunrise sea level sunrise} and {@link #getSeaLevelSunset sea level sunset}. A day
231         * starting at <em>alos</em> and ending at <em>tzais</em> using the same time or degree offset will also return
232         * the same time. The returned value is identical to {@link #getSunTransit()}. In reality due to lengthening or
233         * shortening of day, this is not necessarily the exact midpoint of the day, but it is very close.
234         * 
235         * @see AstronomicalCalendar#getSunTransit()
236         * @return the <code>Date</code> of chatzos. If the calculation can't be computed such as in the Arctic Circle
237         *         where there is at least one day where the sun does not rise, and one where it does not set, a null will
238         *         be returned. See detailed explanation on top of the {@link AstronomicalCalendar} documentation.
239         */
240        public Date getChatzos() {
241                return getSunTransit();
242        }
243
244        /**
245         * A generic method for calculating the latest <em>zman krias shema</em> (time to recite shema in the morning)
246         * that is 3 * <em>shaos zmaniyos</em> (temporal hours) after the start of the day, calculated using the start and
247         * end of the day passed to this method.
248         * The time from the start of day to the end of day are divided into 12 <em>shaos zmaniyos</em> (temporal hours),
249         * and the latest <em>zman krias shema</em> is calculated as 3 of those <em>shaos zmaniyos</em> after the beginning of
250         * the day. As an example, passing {@link #getSunrise() sunrise} and {@link #getSunset sunset} or {@link #getSeaLevelSunrise()
251         * sea level sunrise} and {@link #getSeaLevelSunset() sea level sunset} (depending on the {@link #isUseElevation()}
252         * elevation setting) to this method will return <em>sof zman krias shema</em> according to the opinion of the
253         * <em><a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a></em>.
254         * 
255         * @param startOfDay
256         *            the start of day for calculating <em>zman krias shema</em>. This can be sunrise or any alos passed to
257         *            this method.
258         * @param endOfDay
259         *            the start of day for calculating <em>zman krias shema</em>. This can be sunset or any tzais passed to
260         *            this method.
261         * @return the <code>Date</code> of the latest <em>zman shema</em> based on the start and end of day times passed to this
262         *         method. If the calculation can't be computed such as in the Arctic Circle where there is at least one day
263         *         a year where the sun does not rise, and one where it does not set, a null will be returned. See detailed
264         *         explanation on top of the {@link AstronomicalCalendar} documentation.
265         */
266        public Date getSofZmanShma(Date startOfDay, Date endOfDay) {
267                long shaahZmanis = getTemporalHour(startOfDay, endOfDay);
268                return getTimeOffset(startOfDay, shaahZmanis * 3);
269        }
270
271        /**
272         * This method returns the latest <em>zman krias shema</em> (time to recite shema in the morning) that is 3 *
273         * <em>{@link #getShaahZmanisGra() shaos zmaniyos}</em> (solar hours) after {@link #getSunrise() sunrise} or
274         * {@link #getSeaLevelSunrise() sea level sunrise} (depending on the {@link #isUseElevation()} setting), according
275         * to the <em><a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a></em>. 
276         *  The day is calculated from {@link #getSeaLevelSunrise() sea level sunrise} to {@link #getSeaLevelSunrise sea level
277         *  sunset} or {@link #getSunrise() sunrise} to {@link #getSunset() sunset} (depending on the {@link #isUseElevation()}
278         *  setting).
279         * 
280         * @see #getSofZmanShma(Date, Date)
281         * @see #getShaahZmanisGra()
282         * @see #isUseElevation()
283         * @see ComplexZmanimCalendar#getSofZmanShmaBaalHatanya()
284         * @return the <code>Date</code> of the latest zman shema according to the GRA. If the calculation can't be computed
285         * 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
286         * does not set, a null will be returned. See the detailed explanation on top of the {@link AstronomicalCalendar}
287         * documentation.
288         */
289        public Date getSofZmanShmaGRA() {
290                return getSofZmanShma(getElevationAdjustedSunrise(), getElevationAdjustedSunset());
291        }
292
293        /**
294         * This method returns the latest <em>zman krias shema</em> (time to recite shema in the morning) that is 3 *
295         * <em>{@link #getShaahZmanisMGA() shaos zmaniyos}</em> (solar hours) after {@link #getAlos72()}, according to the
296         * <em><a href="https://en.wikipedia.org/wiki/Avraham_Gombinern">Magen Avraham (MGA)</a></em>. The day is calculated
297         * from 72 minutes before {@link #getSeaLevelSunrise() sea level sunrise} to 72 minutes after {@link
298         * #getSeaLevelSunrise sea level sunset} or from 72 minutes before {@link #getSunrise() sunrise} to {@link #getSunset()
299         * sunset} (depending on the {@link #isUseElevation()} setting).
300         * 
301         * @return the <code>Date</code> of the latest <em>zman shema</em>. If the calculation can't be computed such as in
302         *         the Arctic Circle where there is at least one day a year where the sun does not rise, and one where it
303         *         does not set, a null will be returned. See detailed explanation on top of the
304         *         {@link AstronomicalCalendar} documentation.
305         * @see #getSofZmanShma(Date, Date)
306         * @see ComplexZmanimCalendar#getShaahZmanis72Minutes()
307         * @see ComplexZmanimCalendar#getAlos72()
308         * @see ComplexZmanimCalendar#getSofZmanShmaMGA72Minutes() that 
309         */
310        public Date getSofZmanShmaMGA() {
311                return getSofZmanShma(getAlos72(), getTzais72());
312        }
313
314        /**
315         * This method returns the <em>tzais</em> (nightfall) based on the opinion of the <em><a href=
316         * "https://en.wikipedia.org/wiki/Maimonides">Rambam</a></em> and <em>Rabbeinu Tam</em> that <em>tzais</em> is
317         * calculated as 72 minutes, the time it takes to walk 4 <em>Mil</em> at 18 minutes a <em>Mil</em>. Based on
318         * the on the {@link #isUseElevation()} setting) a 72 minute offset from either {@link #getSunset() sunset} or
319         * {@link #getSeaLevelSunset() sea level sunset} is used.
320         * 
321         * @see ComplexZmanimCalendar#getTzais16Point1Degrees()
322         * @return the <code>Date</code> representing 72 minutes after sunset. If the calculation can't be
323         *         computed such as in the Arctic Circle where there is at least one day a year where the sun does not rise,
324         *         and one where it does not set, a null will be returned See detailed explanation on top of the
325         *         {@link AstronomicalCalendar} documentation.
326         */
327        public Date getTzais72() {
328                return getTimeOffset(getElevationAdjustedSunset(), 72 * MINUTE_MILLIS);
329        }
330
331        /**
332         * A method to return candle lighting time, calculated as {@link #getCandleLightingOffset()} minutes before
333         * {@link #getSeaLevelSunset() sea level sunset}. This will return the time for any day of the week, since it can be
334         * used to calculate candle lighting time for <em>Yom Tov</em> (mid-week holidays) as well. Elevation adjustments
335         * are intentionally not performed by this method, but you can calculate it by passing the elevation adjusted sunset
336         * to {@link #getTimeOffset(Date, long)}.
337         * 
338         * @return candle lighting time. If the calculation can't be computed such as in the Arctic Circle where there is at
339         *         least one day a year where the sun does not rise, and one where it does not set, a null will be returned.
340         *         See detailed explanation on top of the {@link AstronomicalCalendar} documentation.
341         * 
342         * @see #getSeaLevelSunset()
343         * @see #getCandleLightingOffset()
344         * @see #setCandleLightingOffset(double)
345         */
346        public Date getCandleLighting() {
347                return getTimeOffset(getSeaLevelSunset(), -getCandleLightingOffset() * MINUTE_MILLIS);
348        }
349
350        /**
351         * A generic method for calculating the latest <em>zman tfilah</em> (time to recite the morning prayers)
352         * that is 4 * <em>shaos zmaniyos</em> (temporal hours) after the start of the day, calculated using the start and
353         * end of the day passed to this method.
354         * The time from the start of day to the end of day are divided into 12 <em>shaos zmaniyos</em> (temporal hours),
355         * and <em>sof zman tfila</em> is calculated as 4 of those <em>shaos zmaniyos</em> after the beginning of the day.
356         * As an example, passing {@link #getSunrise() sunrise} and {@link #getSunset sunset} or {@link #getSeaLevelSunrise()
357         * sea level sunrise} and {@link #getSeaLevelSunset() sea level sunset} (depending on the {@link #isUseElevation()}
358         * elevation setting) to this method will return <em>zman tfilah</em> according to the opinion of the <em><a href=
359         * "https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a></em>.
360         * 
361         * @param startOfDay
362         *            the start of day for calculating <em>zman tfilah</em>. This can be sunrise or any alos passed to
363         *            this method.
364         * @param endOfDay
365         *            the start of day for calculating <em>zman tfilah</em>. This can be sunset or any tzais passed to this
366         *            method.
367         * @return the <code>Date</code> of the latest <em>zman tfilah</em> based on the start and end of day times passed
368         *         to this method. If the calculation can't be computed such as in the Arctic Circle where there is at least
369         *         one day a year where the sun does not rise, and one where it does not set, a null will be returned. See
370         *         detailed explanation on top of the {@link AstronomicalCalendar} documentation.
371         */
372        public Date getSofZmanTfila(Date startOfDay, Date endOfDay) {
373                long shaahZmanis = getTemporalHour(startOfDay, endOfDay);
374                return getTimeOffset(startOfDay, shaahZmanis * 4);
375        }
376
377        /**
378         * This method returns the latest <em>zman tfila</em> (time to recite shema in the morning) that is 4 *
379         * <em>{@link #getShaahZmanisGra() shaos zmaniyos}</em> (solar hours) after {@link #getSunrise() sunrise} or
380         * {@link #getSeaLevelSunrise() sea level sunrise} (depending on the {@link #isUseElevation()} setting), according
381         * to the <em><a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a></em>. 
382         * The day is calculated from {@link #getSeaLevelSunrise() sea level sunrise} to {@link #getSeaLevelSunrise sea level
383         * sunset} or {@link #getSunrise() sunrise} to {@link #getSunset() sunset} (depending on the {@link #isUseElevation()}
384         * setting).
385         * 
386         * @see #getSofZmanTfila(Date, Date)
387         * @see #getShaahZmanisGra()
388         * @see ComplexZmanimCalendar#getSofZmanTfilaBaalHatanya()
389         * @return the <code>Date</code> of the latest zman tfilah. If the calculation can't be computed such as in the
390         *         Arctic Circle where there is at least one day a year where the sun does not rise, and one where it does
391         *         not set, a null will be returned. See detailed explanation on top of the {@link AstronomicalCalendar}
392         *         documentation.
393         */
394        public Date getSofZmanTfilaGRA() {
395                return getSofZmanTfila(getElevationAdjustedSunrise(), getElevationAdjustedSunset());
396        }
397
398        /**
399         * This method returns the latest <em>zman tfila</em> (time to recite shema in the morning) that is 4 *
400         * <em>{@link #getShaahZmanisMGA() shaos zmaniyos}</em> (solar hours) after {@link #getAlos72()}, according to the
401         * <em><a href="https://en.wikipedia.org/wiki/Avraham_Gombinern">Magen Avraham (MGA)</a></em>. The day is calculated
402         * from 72 minutes before {@link #getSeaLevelSunrise() sea level sunrise} to 72 minutes after {@link
403         * #getSeaLevelSunrise sea level sunset} or from 72 minutes before {@link #getSunrise() sunrise} to {@link #getSunset()
404         * sunset} (depending on the {@link #isUseElevation()} setting).
405         * 
406         * @return the <code>Date</code> of the latest zman tfila. If the calculation can't be computed such as in the
407         *         Arctic Circle where there is at least one day a year where the sun does not rise, and one where it does
408         *         not set), a null will be returned. See detailed explanation on top of the {@link AstronomicalCalendar}
409         *         documentation.
410         * @see #getSofZmanTfila(Date, Date)
411         * @see #getShaahZmanisMGA()
412         * @see #getAlos72()
413         */
414        public Date getSofZmanTfilaMGA() {
415                return getSofZmanTfila(getAlos72(), getTzais72());
416        }
417
418        /**
419         * A generic method for calculating the latest <em>mincha gedola</em> (the earliest time to recite the mincha  prayers)
420         * that is 6.5 * <em>shaos zmaniyos</em> (temporal hours) after the start of the day, calculated using the start and end
421         * of the day passed to this method.
422         * The time from the start of day to the end of day are divided into 12 <em>shaos zmaniyos</em> (temporal hours), and
423         * <em>mincha gedola</em> is calculated as 6.5 of those <em>shaos zmaniyos</em> after the beginning of the day. As an
424         * example, passing {@link #getSunrise() sunrise} and {@link #getSunset sunset} or {@link #getSeaLevelSunrise() sea level
425         * sunrise} and {@link #getSeaLevelSunset() sea level sunset} (depending on the {@link #isUseElevation()} elevation
426         * setting) to this method will return <em>mincha gedola</em> according to the opinion of the
427         * <em><a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a></em>.
428         * 
429         * @param startOfDay
430         *            the start of day for calculating <em>Mincha gedola</em>. This can be sunrise or any alos passed to
431         *            this method.
432         * @param endOfDay
433         *            the start of day for calculating <em>Mincha gedola</em>. This can be sunrise or any alos passed to
434         *            this method.
435         * @return the <code>Date</code> of the time of <em>Mincha gedola</em> based on the start and end of day times
436         *         passed to this method. If the calculation can't be computed such as in the Arctic Circle where there is
437         *         at least one day a year where the sun does not rise, and one where it does not set, a null will be
438         *         returned. See detailed explanation on top of the {@link AstronomicalCalendar} documentation.
439         */
440        public Date getMinchaGedola(Date startOfDay, Date endOfDay) {
441                long shaahZmanis = getTemporalHour(startOfDay, endOfDay);
442                return getTimeOffset(startOfDay, shaahZmanis * 6.5);
443        }
444
445        /**
446         * This method returns the latest <em>mincha gedola</em>,the earliest time one can pray <em>mincha</em> that is 6.5 *
447         * <em>{@link #getShaahZmanisGra() shaos zmaniyos}</em> (solar hours) after {@link #getSunrise() sunrise} or
448         * {@link #getSeaLevelSunrise() sea level sunrise} (depending on the {@link #isUseElevation()} setting), according
449         * to the <em><a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a></em>. <em>Mincha gedola</em> is the earliest
450         * time one can pray <em>mincha</em>. The Ramba"m is of the opinion that it is better to delay <em>mincha</em> until
451         * <em>{@link #getMinchaKetana() mincha ketana}</em> while the <em>Ra"sh, Tur, GRA</em> and others are of the
452         * opinion that <em>mincha</em> can be prayed <em>lechatchila</em> starting at <em>mincha gedola</em>.
453         * The day is calculated from {@link #getSeaLevelSunrise() sea level sunrise} to {@link #getSeaLevelSunrise sea level
454         * sunset} or {@link #getSunrise() sunrise} to {@link #getSunset() sunset} (depending on the {@link #isUseElevation()}
455         * setting).
456         * 
457         * @see #getMinchaGedola(Date, Date)
458         * @see #getShaahZmanisGra()
459         * @see #getMinchaKetana()
460         * @see ComplexZmanimCalendar#getMinchaGedolaBaalHatanya()
461         * @return the <code>Date</code> of the time of mincha gedola. If the calculation can't be computed such as in the
462         *         Arctic Circle where there is at least one day a year where the sun does not rise, and one where it does
463         *         not set, a null will be returned. See detailed explanation on top of the {@link AstronomicalCalendar}
464         *         documentation.
465         */
466        public Date getMinchaGedola() {
467                return getMinchaGedola(getElevationAdjustedSunrise(), getElevationAdjustedSunset());
468        }
469
470        /**
471         * A generic method for calculating <em>mincha ketana</em>, (the preferred time to recite the mincha prayers in
472         * the opinion of the <em><a href="https://en.wikipedia.org/wiki/Maimonides">Rambam</a></em> and others) that is
473         * 9.5 * <em>shaos zmaniyos</em> (temporal hours) after the start of the day, calculated using the start and end
474         * of the day passed to this method.
475         * The time from the start of day to the end of day are divided into 12 <em>shaos zmaniyos</em> (temporal hours), and
476         * <em>mincha ketana</em> is calculated as 9.5 of those <em>shaos zmaniyos</em> after the beginning of the day. As an
477         * example, passing {@link #getSunrise() sunrise} and {@link #getSunset sunset} or {@link #getSeaLevelSunrise() sea level
478         * sunrise} and {@link #getSeaLevelSunset() sea level sunset} (depending on the {@link #isUseElevation()} elevation
479         * setting) to this method will return <em>mincha ketana</em> according to the opinion of the
480         * <em><a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a></em>.
481         * 
482         * @param startOfDay
483         *            the start of day for calculating <em>Mincha ketana</em>. This can be sunrise or any alos passed to
484         *            this method.
485         * @param endOfDay
486         *            the start of day for calculating <em>Mincha ketana</em>. This can be sunrise or any alos passed to
487         *            this method.
488         * @return the <code>Date</code> of the time of <em>Mincha ketana</em> based on the start and end of day times
489         *         passed to this method. If the calculation can't be computed such as in the Arctic Circle where there is
490         *         at least one day a year where the sun does not rise, and one where it does not set, a null will be
491         *         returned. See detailed explanation on top of the {@link AstronomicalCalendar} documentation.
492         *
493         */
494        public Date getMinchaKetana(Date startOfDay, Date endOfDay) {
495                long shaahZmanis = getTemporalHour(startOfDay, endOfDay);
496                return getTimeOffset(startOfDay, shaahZmanis * 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 start 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                long shaahZmanis = getTemporalHour(startOfDay, endOfDay);
545                return getTimeOffset(startOfDay, shaahZmanis * 10.75);
546        }
547
548        /**
549         * This method returns <em>plag hamincha</em>, that is 10.75 * <em>{@link #getShaahZmanisGra() shaos zmaniyos}</em>
550         * (solar hours) after {@link #getSunrise() sunrise} or {@link #getSeaLevelSunrise() sea level sunrise} (depending on
551         * the {@link #isUseElevation()} setting), according to the <em><a href="https://en.wikipedia.org/wiki/Vilna_Gaon"
552         * >GRA</a></em>. Plag hamincha is the earliest time that <em>Shabbos</em> can be started.
553         * The day is calculated from {@link #getSeaLevelSunrise() sea level sunrise} to {@link #getSeaLevelSunrise sea level
554         * sunset} or {@link #getSunrise() sunrise} to {@link #getSunset() sunset} (depending on the {@link #isUseElevation()}
555         * 
556         * @see #getPlagHamincha(Date, Date)
557         * @see ComplexZmanimCalendar#getPlagHaminchaBaalHatanya()
558         * @return the <code>Date</code> of the time of <em>plag hamincha</em>. If the calculation can't be computed such as
559         *         in the Arctic Circle where there is at least one day a year where the sun does not rise, and one where it
560         *         does not set, a null will be returned. See detailed explanation on top of the
561         *         {@link AstronomicalCalendar} documentation.
562         */
563        public Date getPlagHamincha() {
564                return getPlagHamincha(getElevationAdjustedSunrise(), getElevationAdjustedSunset());
565        }
566
567        /**
568         * A method that returns a <em>shaah zmanis</em> ({@link #getTemporalHour(Date, Date) temporal hour}) according to
569         * the opinion of the <em><a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a></em>. This calculation divides
570         * the day based on the opinion of the <em>GRA</em> that the day runs from from {@link #getSeaLevelSunrise() sea
571         * level sunrise} to {@link #getSeaLevelSunrise sea level sunset} or {@link #getSunrise() sunrise} to
572         * {@link #getSunset() sunset} (depending on the {@link #isUseElevation()} setting). The day is split into 12 equal
573         * parts with each one being a <em>shaah zmanis</em>. This method is similar to {@link #getTemporalHour}, but can
574         * account for elevation.
575         * 
576         * @return the <code>long</code> millisecond length of a <em>shaah zmanis</em> calculated from sunrise to sunset.
577         *         If the calculation can't be computed such as in the Arctic Circle where there is at least one day a year
578         *         where the sun does not rise, and one where it does not set, {@link Long#MIN_VALUE} will be returned. See
579         *         detailed explanation on top of the {@link AstronomicalCalendar} documentation.
580         * @see #getTemporalHour(Date, Date)
581         * @see #getSeaLevelSunrise()
582         * @see #getSeaLevelSunset()
583         * @see ComplexZmanimCalendar#getShaahZmanisBaalHatanya()
584         */
585        public long getShaahZmanisGra() {
586                return getTemporalHour(getElevationAdjustedSunrise(), getElevationAdjustedSunset());
587        }
588
589        /**
590         * A method that returns a <em>shaah zmanis</em> (temporal hour) according to the opinion of the <em><a href=
591         * "https://en.wikipedia.org/wiki/Avraham_Gombinern">Magen Avraham (MGA)</a></em> based on a 72 minutes <em>alos</em>
592         * and <em>tzais</em>. This calculation divides the day that runs from dawn to dusk (for sof zman krias shema and tfila).
593         * Dawn for this calculation is 72 minutes before {@link #getSunrise() sunrise} or {@link #getSeaLevelSunrise() sea level
594         * sunrise} (depending on the {@link #isUseElevation()} elevation setting) and dusk is 72 minutes after {@link #getSunset
595         * sunset} or {@link #getSeaLevelSunset() sea level sunset} (depending on the {@link #isUseElevation()} elevation setting).
596         * This day is split into 12 equal parts with each part being a <em>shaah zmanis</em>. Alternate methods of calculating a
597         * <em>shaah zmanis</em> according to the Magen Avraham (MGA) are available in the subclass {@link ComplexZmanimCalendar}.
598         * 
599         * @return the <code>long</code> millisecond length of a <em>shaah zmanis</em>. If the calculation can't be computed
600         *         such as in the Arctic Circle where there is at least one day a year where the sun does not rise, and one
601         *         where it does not set, {@link Long#MIN_VALUE} will be returned. See detailed explanation on top of the
602         *         {@link AstronomicalCalendar} documentation.
603         */
604        public long getShaahZmanisMGA() {
605                return getTemporalHour(getAlos72(), getTzais72());
606        }
607
608        /**
609         * Default constructor will set a default {@link GeoLocation#GeoLocation()}, a default
610         * {@link AstronomicalCalculator#getDefault() AstronomicalCalculator} and default the calendar to the current date.
611         * 
612         * @see AstronomicalCalendar#AstronomicalCalendar()
613         */
614        public ZmanimCalendar() {
615                super();
616        }
617
618        /**
619         * A constructor that takes a {@link GeoLocation} as a parameter.
620         * 
621         * @param location
622         *            the location
623         */
624        public ZmanimCalendar(GeoLocation location) {
625                super(location);
626        }
627
628        /**
629         * A method to get the offset in minutes before {@link AstronomicalCalendar#getSeaLevelSunset() sea level sunset} which
630         * is used in calculating candle lighting time. The default time used is 18 minutes before sea level sunset. Some
631         * calendars use 15 minutes, while the custom in Jerusalem is to use a 40 minute offset. Please check the local custom
632         * for candle lighting time.
633         * 
634         * @return Returns the currently set candle lighting offset in minutes.
635         * @see #getCandleLighting()
636         * @see #setCandleLightingOffset(double)
637         */
638        public double getCandleLightingOffset() {
639                return candleLightingOffset;
640        }
641
642        /**
643         * A method to set the offset in minutes before {@link AstronomicalCalendar#getSeaLevelSunset() sea level sunset} that is
644         * used in calculating candle lighting time. The default time used is 18 minutes before sunset. Some calendars use 15
645         * minutes, while the custom in Jerusalem is to use a 40 minute offset.
646         * 
647         * @param candleLightingOffset
648         *            The candle lighting offset to set in minutes.
649         * @see #getCandleLighting()
650         * @see #getCandleLightingOffset()
651         */
652        public void setCandleLightingOffset(double candleLightingOffset) {
653                this.candleLightingOffset = candleLightingOffset;
654        }
655        
656        /**
657         * This is a utility method to determine if the current Date (date-time) passed in has a <em>melacha</em> (work) prohibition.
658         * 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
659         * class. Sunset is the classes current day's {@link #getElevationAdjustedSunset() elevation adjusted sunset} that observes the
660         * {@link isUseElevation()} settings. The {@link JewishCalendar#getInIsrael()} will be set by the inIsrael parameter.
661         * 
662         * @param currentTime the current time
663         * @param tzais the time of tzais
664         * @param inIsrael whether to use Israel holiday scheme or not
665         * 
666         * @return true if <em>melacha</em> is prohibited or false if it is not.
667         * 
668         * @see JewishCalendar#isAssurBemelacha()
669         * @see JewishCalendar#hasCandleLighting()
670         * @see JewishCalendar#setInIsrael(boolean)
671         */
672        public boolean isAssurBemlacha(Date currentTime, Date tzais, boolean inIsrael) {
673                JewishCalendar jewishCalendar = new JewishCalendar();
674                jewishCalendar.setGregorianDate(getCalendar().get(Calendar.YEAR), getCalendar().get(Calendar.MONTH),
675                                getCalendar().get(Calendar.DAY_OF_MONTH));
676                jewishCalendar.setInIsrael(inIsrael);
677                
678                if(jewishCalendar.hasCandleLighting() && currentTime.compareTo(getElevationAdjustedSunset()) >= 0) { //erev shabbos, YT or YT sheni and after shkiah
679                        return true;
680                }
681                
682                if(jewishCalendar.isAssurBemelacha()  && currentTime.compareTo(tzais) <= 0) { //is shabbos or YT and it is before tzais
683                        return true;
684                }
685                
686                return false;
687        }
688}