001/* 002 * Zmanim Java API 003 * Copyright © 2004-2026 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. 007 * 008 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied 009 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 010 * details. 011 * You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to 012 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA, 013 * or connect to: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html 014 */ 015package com.kosherjava.zmanim; 016 017import java.time.Duration; 018import java.time.Instant; 019import java.time.LocalDate; 020import java.util.Objects; 021 022import com.kosherjava.zmanim.hebrewcalendar.JewishCalendar; 023import com.kosherjava.zmanim.util.AstronomicalCalculator; 024import com.kosherjava.zmanim.util.GeoLocation; 025 026/** 027 * The ZmanimCalendar is a specialized calendar that can calculate sunrise, sunset and Jewish <em>zmanim</em> (religious times) 028 * for prayers and other Jewish religious duties. This class contains the main functionality of the <em>Zmanim</em> library. For 029 * a much more extensive list of <em>zmanim</em>, use the {@link ComprehensiveZmanimCalendar} that extends this class. See 030 * documentation for the {@link ComprehensiveZmanimCalendar} and {@link AstronomicalCalendar} for simple examples on using the API. 031 * <strong>Elevation based <em>zmanim</em> (even sunrise and sunset) should not be used <em>lekula</em> without the guidance 032 * of a <em>posek</em></strong>. According to Rabbi Dovid Yehudah Bursztyn in his <a href="https://www.worldcat.org/oclc/1158574217" 033 * >Zmanim Kehilchasam, 7th edition</a> chapter 2, section 7 (pages 181-182) and section 9 (pages 186-187), no <em>zmanim</em> 034 * besides sunrise and sunset should use elevation. However, Rabbi Yechiel Avrahom Zilber in the <a href= 035 * "https://hebrewbooks.org/51654">Birur Halacha Vol. 6</a> Ch. 58 Pages <a href= 036 * "https://hebrewbooks.org/pdfpager.aspx?req=51654&pgnum=42">34</a> and <a href= 037 * "https://hebrewbooks.org/pdfpager.aspx?req=51654&pgnum=50">42</a> is of the opinion that elevation should be accounted for 038 * in <em>zmanim</em> calculations. Related to this, Rabbi Yaakov Karp in <a href="https://www.worldcat.org/oclc/919472094" 039 * >Shimush Zekeinim</a>, Ch. 1, page 17 states that obstructing horizons should be factored into <em>zmanim</em> calculations. The 040 * setting defaults to false (elevation will not be used for <em>zmanim</em> calculations besides sunrise and sunset), unless the 041 * setting is changed to true in {@link #setUseElevation(boolean)}. This will impact sunrise and sunset-based <em>zmanim</em> such as 042 * {@link #getSunrise()}, {@link #getSunset()}, {@link #getSofZmanShmaGRA()}, <em>alos</em>-based 043 * <em>zmanim</em> such as {@link #getSofZmanShmaMGA72Minutes()} that are based on a fixed offset of sunrise or sunset and 044 * <em>zmanim</em> based on a percentage of the day such as {@link ComprehensiveZmanimCalendar#getSofZmanShmaMGA90MinutesZmanis()} 045 * that are based on sunrise and sunset. Even when set to true it will not impact <em>zmanim</em> that are a degree-based offset of 046 * sunrise and sunset, such as {@link ComprehensiveZmanimCalendar#getSofZmanShmaMGA16Point1Degrees()} or {@link 047 * ComprehensiveZmanimCalendar#getSofZmanShmaBaalHatanya()} since these <em>zmanim</em> are not linked to sunrise or sunset times 048 * (the calculations are based on the astronomical definition of sunrise and sunset calculated in a vacuum with the solar radius 049 * above the horizon), and are therefore not impacted by the use of elevation. For additional information on the <em>halachic</em> 050 * impact of elevation on <em>zmanim</em> see: 051 * <ul> 052 * <li><a href="https://www.nli.org.il/en/books/NNL_ALEPH002542826/NLI">Zmanei Halacha Lema'aseh</a> 4th edition by <a href= 053 * "http://beinenu.com/rabbis/%D7%94%D7%A8%D7%91-%D7%99%D7%93%D7%99%D7%93%D7%99%D7%94-%D7%9E%D7%A0%D7%AA">Rabbi Yedidya Manat</a>. 054 * See section 1, pages 11-12 for a very concise write-up, with details in section 2, pages 37 - 63 and 133 - 151.</li> 055 * <li><a href="https://www.worldcat.org/oclc/1158574217">Zmanim Kehilchasam</a> 7th edition, by Rabbi Dovid Yehuda Burstein, vol 1, 056 * chapter 2, pages 95 - 188.</li> 057 * <li><a href="https://www.worldcat.org/oclc/36089452">Hazmanim Bahalacha</a> by Rabbi Chaim Benish , perek 7, pages 53 - 63.</li> 058 * </ul> 059 * 060 * <p><b>Note:</b> It is important to read the technical notes on top of the {@link AstronomicalCalculator} documentation 061 * before using this code. 062 * <p>I would like to thank <a href="https://www.worldcat.org/search?q=au%3AShakow%2C+Yaakov">Rabbi Yaakov Shakow</a>, the 063 * author of Luach Ikvei Hayom who spent a considerable amount of time reviewing, correcting and making suggestions on the 064 * documentation in this library. 065 * <h2>Disclaimer:</h2> I did my best to get accurate results, but please double-check before relying on these 066 * <em>zmanim</em> for <em>halacha lema'aseh</em>. 067 * 068 * @author © Eliyahu Hershfeld 2004 - 2026 069 */ 070public class ZmanimCalendar extends AstronomicalCalendar { 071 072 /** 073 * Is elevation factored in for some <em>zmanim</em> (see {@link #isUseElevation()} for additional information). 074 * @see #isUseElevation() 075 * @see #setUseElevation(boolean) 076 */ 077 private boolean useElevation; 078 079 /** 080 * Is elevation above sea level calculated for times besides sunrise and sunset. According to Rabbi Dovid Yehuda Bursztyn in 081 * his <a href="https://www.worldcat.org/oclc/659793988">Zmanim Kehilchasam (second edition published in 2007)</a> chapter 2 082 * (pages 186-187) no <em>zmanim</em> besides sunrise and sunset should use elevation. However, Rabbi Yechiel Avrahom Zilber 083 * in the <a href="https://hebrewbooks.org/51654">Birur Halacha Vol. 6</a> Ch. 58 Pages <a href= 084 * "https://hebrewbooks.org/pdfpager.aspx?req=51654&pgnum=42">34</a> and <a href= 085 * "https://hebrewbooks.org/pdfpager.aspx?req=51654&pgnum=50">42</a> is of the opinion that elevation should be accounted 086 * for in <em>zmanim</em> calculations. Related to this, Rabbi Yaakov Karp in <a href= 087 * "https://www.worldcat.org/oclc/919472094">Shimush Zekeinim</a>, Ch. 1, page 17 states that obstructing horizons should be 088 * factored into <em>zmanim</em> calculations.The setting defaults to false (elevation will not be used for <em>zmanim</em> 089 * calculations), unless the setting is changed to true in {@link #setUseElevation(boolean)}. This will impact sunrise and 090 * sunset based <em>zmanim</em> such as {@link #getSofZmanShmaGRA()}, alos based <em>zmanim</em> such as {@link 091 * getSofZmanShmaMGA72Minutes()} that are based on a fixed offset of sunrise or sunset and <em>zmanim</em> based on a 092 * percentage of the day such as {@link ComprehensiveZmanimCalendar#getSofZmanShmaMGA90MinutesZmanis()} that are based on 093 * sunrise and sunset. It will not impact <em>zmanim</em> that are a degree based offset of sunrise and sunset, such as {@link 094 * ComprehensiveZmanimCalendar#getSofZmanShmaMGA16Point1Degrees()} or {@link 095 * ComprehensiveZmanimCalendar#getSofZmanShmaBaalHatanya()}. 096 * 097 * @return if the use of elevation is active 098 * 099 * @see #setUseElevation(boolean) 100 */ 101 public boolean isUseElevation() { 102 return useElevation; 103 } 104 105 /** 106 * Sets whether elevation above sea level is factored into <em>zmanim</em> calculations for times besides sunrise and sunset. 107 * See {@link #isUseElevation()} for more details. 108 * @see #isUseElevation() 109 * 110 * @param useElevation set to true to use elevation in <em>zmanim</em> calculations 111 */ 112 public void setUseElevation(boolean useElevation) { 113 this.useElevation = useElevation; 114 } 115 116 /** 117 * Is astronomical <em>chatzos</em> used for <em>zmanim</em> calculations. The default value of <code>true</code> will 118 * keep the standard astronomical <em>chatzos</em> calculation, while setting it to <code>false</code> will use half of 119 * a solar day / night calculation for <em>chatzos</em>. 120 * @see #isUseAstronomicalChatzos() 121 * @see #isUseAstronomicalChatzosForOtherZmanim() 122 * @see #setUseAstronomicalChatzos(boolean) 123 * @see #getChatzosHayom() 124 * @see #getChatzosHalayla() 125 * @see #getSunTransit() 126 * @see #getChatzosHayomAsHalfDay() 127 */ 128 private boolean useAstronomicalChatzos = true; 129 130 /** 131 * Is {@link #getSunTransit() astronomical <em>chatzos</em>} used for {@link #getChatzosHayom()} and {@link #getChatzosHalayla()} 132 * for enhanced accuracy. For example as the day lengthens, the second half of the day is longer than the first and astronomical 133 * <em>chatzos</em> would be a drop earlier than half of the time between sunrise and sunset. 134 * 135 * @todo In the future, if this is set to true, the following may change to enhance accuracy. {@link #getSofZmanShmaGRA() 136 * <em>Sof zman Shma</em> GRA} would be calculated as 3 <em>shaos zmaniyos</em> after sunrise, but the <em>shaos 137 * zmaniyos</em> would be calculated a a 6th of the time between sunrise and <em>chatzos</em>, as opposed to a 12th of the 138 * time between sunrise and sunset. {@link #getMinchaGedolaGRA() <em>mincha gedola</em>} will be calculated as half a 139 * <em>shaah zmanis</em> of afternoon hours (a 6th of the time between <em>chatzos</em> and sunset after astronomical 140 * <em>chatzos</em> as opposed to 6.5 <em>shaos zmaniyos</em> after sunrise. {@link #getPlagHaminchaGRA() <em>Plag 141 * hamincha</em>} would be calculated as 4.75 <em>shaos zmaniyos</em> after astronomical <em>chatzos</em> as opposed to 10.75 142 * <em>shaos zmaniyos</em> after sunrise. Etc. 143 * 144 * @return if the use of astronomical <em>chatzos</em> is active. 145 * @see #isUseAstronomicalChatzos() 146 * @see #setUseAstronomicalChatzos(boolean) 147 * @see #getChatzosHayom() 148 * @see #getChatzosHalayla() 149 * @see #getSunTransit() 150 * @see #getChatzosHayomAsHalfDay() 151 * @see #isUseAstronomicalChatzosForOtherZmanim() 152 */ 153 public boolean isUseAstronomicalChatzos() { 154 return useAstronomicalChatzos; 155 } 156 157 /** 158 * Sets if astronomical <em>chatzos</em> should be used in calculations of other <em>zmanim</em> for enhanced accuracy. 159 * @param useAstronomicalChatzos set to true to use astronomical in <em>chatzos</em> in <em>zmanim</em> calculations. 160 * @see #isUseAstronomicalChatzos() 161 * @see #getChatzosHayom() 162 * @see #getChatzosHalayla() 163 * @see #getSunTransit() 164 * @see #getChatzosHayomAsHalfDay() 165 * @see #setUseAstronomicalChatzosForOtherZmanim(boolean) 166 */ 167 public void setUseAstronomicalChatzos(boolean useAstronomicalChatzos) { 168 this.useAstronomicalChatzos = useAstronomicalChatzos; 169 } 170 171 /** 172 * Is astronomical <em>chatzos</em> used for <em>zmanim</em> calculations besides <em>chatzos</em> itself for enhanced 173 * accuracy. The default value of <code>false</code> will keep the standard start to end of day calculations, while setting 174 * it to <code>true</code> will use half of a solar day calculation for <em>zmanim</em>. 175 * @see #isUseAstronomicalChatzosForOtherZmanim() 176 * @see #setUseAstronomicalChatzosForOtherZmanim(boolean) 177 * @see #isUseAstronomicalChatzos() 178 * @see #setUseAstronomicalChatzos(boolean) 179 * @see #getChatzosHayom() 180 * @see #getChatzosHalayla() 181 */ 182 private boolean useAstronomicalChatzosForOtherZmanim = false; 183 184 /** 185 * Is astronomical <em>chatzos</em> used for <em>zmanim</em> calculations besides <em>chatzos</em> itself for enhanced 186 * accuracy. For example as the day is lengthening (as we approach spring season), the second half of the day is longer than 187 * the first and astronomical <em>chatzos</em> would be a drop earlier than half of the time between sunrise and sunset. 188 * Conversely, the second half of the day would be shorter in the autumn as the days start getting shorter. 189 * 190 * @todo In the future, if this is set to true, the following may change to enhance accuracy. {@link #getSofZmanShmaGRA() 191 * <em>Sof zman Shma</em> GRA} would be calculated as 3 <em>shaos zmaniyos</em> after sunrise, but the <em>shaos 192 * zmaniyos</em> would be calculated a a 6th of the time between sunrise and <em>chatzos</em>, as opposed to a 12th of the 193 * time between sunrise and sunset. {@link #getMinchaGedolaGRA() <em>mincha gedola GRA</em>} will be calculated as half a 194 * <em>shaah zmanis</em> of afternoon hours (a 6th of the time between <em>chatzos</em> and sunset after astronomical 195 * <em>chatzos</em> as opposed to 6.5 <em>shaos zmaniyos</em> after sunrise. {@link #getPlagHaminchaGRA() <em>Plag 196 * hamincha</em>} would be calculated as 4.75 <em>shaos zmaniyos</em> after astronomical <em>chatzos</em> as opposed to 10.75 197 * <em>shaos zmaniyos</em> after sunrise. Etc. 198 * 199 * @return if the use of astronomical <em>chatzos</em> is active. 200 * @see #setUseAstronomicalChatzosForOtherZmanim(boolean) 201 * @see #isUseAstronomicalChatzos() 202 * @see #setUseAstronomicalChatzos(boolean) 203 */ 204 public boolean isUseAstronomicalChatzosForOtherZmanim() { 205 return useAstronomicalChatzosForOtherZmanim; 206 } 207 208 /** 209 * Sets if astronomical <em>chatzos</em> should be used in calculations of other <em>zmanim</em> for enhanced accuracy. 210 * @param useAstronomicalChatzosForOtherZmanim set to true to use astronomical in <em>chatzos</em> in <em>zmanim</em> calculations. 211 * @see #isUseAstronomicalChatzos() 212 */ 213 public void setUseAstronomicalChatzosForOtherZmanim(boolean useAstronomicalChatzosForOtherZmanim) { 214 this.useAstronomicalChatzosForOtherZmanim = useAstronomicalChatzosForOtherZmanim; 215 } 216 217 /** 218 * The zenith of 16.1° below geometric zenith (90°). 219 * @see #getAlos16Point1Degrees() 220 * @see ComprehensiveZmanimCalendar#getTzais16Point1Degrees() 221 * @see ComprehensiveZmanimCalendar#getSofZmanShmaMGA16Point1Degrees() 222 * @see ComprehensiveZmanimCalendar#getSofZmanTfilaMGA16Point1Degrees() 223 * @see ComprehensiveZmanimCalendar#getMinchaGedola16Point1Degrees() 224 * @see ComprehensiveZmanimCalendar#getMinchaKetana16Point1Degrees() 225 * @see ComprehensiveZmanimCalendar#getPlagHamincha16Point1Degrees() 226 * 227 * @see ComprehensiveZmanimCalendar#getSofZmanShmaAlos16Point1DegreesToTzaisGeonim7Point083Degrees() 228 * @see ComprehensiveZmanimCalendar#getPlagAlos16Point1DegreesToTzaisGeonim7Point083Degrees() 229 * @see ComprehensiveZmanimCalendar#getSofZmanShmaAlos16Point1ToSunset() 230 * @see ComprehensiveZmanimCalendar#getShaahZmanis16Point1Degrees() 231 * @see ComprehensiveZmanimCalendar#getShaahZmanisAlos16Point1DegreesToTzaisGeonim3Point7Degrees() 232 * @see ComprehensiveZmanimCalendar#getShaahZmanisAlos16Point1DegreesToTzaisGeonim3Point8Degrees() 233 * @see ComprehensiveZmanimCalendar#getShaahZmanisAlos16Point1DegreesToTzaisGeonim7Point083Degrees() 234 * 235 */ 236 protected static final double ZENITH_16_POINT_1 = GEOMETRIC_ZENITH + 16.1; 237 238 /** 239 * The zenith of 8.5° below geometric zenith (90°). 240 * @see #getTzaisGeonim8Point5Degrees() 241 */ 242 protected static final double ZENITH_8_POINT_5 = GEOMETRIC_ZENITH + 8.5; 243 244 /** 245 * The zenith of 1.583° below {@link AstronomicalCalendar#GEOMETRIC_ZENITH} (90°). 246 * @see #getSunriseBaalHatanya() 247 * @see #getSunsetBaalHatanya() 248 */ 249 protected static final double ZENITH_1_POINT_583 = GEOMETRIC_ZENITH + 1.583; 250 251 /** 252 * The default <em>Shabbos</em> candle lighting offset is 18 minutes. This can be changed via the 253 * {@link #setCandleLightingOffset(double)} and retrieved by the {@link #getCandleLightingOffset()}. 254 */ 255 private double candleLightingOffset = 18; 256 257 /** 258 * This method will return {@link #getSeaLevelSunrise() sea level sunrise} if {@link #isUseElevation()} is false (the default), 259 * or elevation adjusted {@link #getSunrise()} if it is true. This allows relevant <em>zmanim</em> in this and 260 * extending classes (such as the {@link ComprehensiveZmanimCalendar}) to automatically adjust to the elevation setting. 261 * 262 * @return {@link #getSeaLevelSunrise()} if {@link #isUseElevation()} is false (the default), or elevation adjusted 263 * {@link #getSunrise()} if it is true. 264 * @see #getSunrise() 265 */ 266 protected Instant getSunriseBasedOnElevationSetting() { 267 if (isUseElevation()) { 268 return super.getSunrise(); 269 } 270 return getSeaLevelSunrise(); 271 } 272 273 /** 274 * This method will return {@link #getSeaLevelSunset() sea level sunset} if {@link #isUseElevation()} is false (the default), or 275 * elevation adjusted {@link #getSunset()} if it is true. This allows relevant <em>zmanim</em>in this and extending classes (such 276 * as the {@link ComprehensiveZmanimCalendar}) to automatically adjust to the elevation setting. 277 * 278 * @return {@link #getSeaLevelSunset()} if {@link #isUseElevation()} is false (the default), or elevation adjusted 279 * {@link #getSunset()} if it is true. 280 * @see #getSunset() 281 */ 282 protected Instant getSunsetBasedOnElevationSetting() { 283 if (isUseElevation()) { 284 return super.getSunset(); 285 } 286 return getSeaLevelSunset(); 287 } 288 289 /** 290 * A method that returns <em>tzais</em> (nightfall) when the sun is {@link ZENITH_8_POINT_5 8.5°} below the {@link 291 * AstronomicalCalendar#GEOMETRIC_ZENITH} (90°) after {@link #getSunset() sunset}, a time that Rabbi Meir Posen in his the <em><a 292 * href="https://www.worldcat.org/oclc/29283612">Ohr Meir</a></em> calculated that 3 small stars are visible, which is later than 293 * the required 3 medium stars. This calculation is based on the sun's position below the horizon 36 minutes after {@link 294 * getSeaLevelSunrise() sunset} in Jerusalem <a href="https://kosherjava.com/2022/01/12/equinox-vs-equilux-zmanim-calculations/" 295 * >around the equinox / equilux</a>, which is 8.5° below {@link AstronomicalCalendar#GEOMETRIC_ZENITH}. 296 * 297 * @return The <code>Instant</code> of nightfall. If the calculation can't be computed such as northern and southern locations 298 * even south of the Arctic Circle and north of the Antarctic Circle where the sun may not reach low enough below the 299 * horizon for this calculation, a <code>null</code> will be returned. See detailed explanation on top of the {@link 300 * AstronomicalCalendar} documentation. 301 * ComprehensiveZmanimCalendar#getTzaisGeonim8Point5Degrees() that returns an identical time to this generic <em>tzais</em> 302 */ 303 public Instant getTzaisGeonim8Point5Degrees() { 304 return getSunsetOffsetByDegrees(ZENITH_8_POINT_5); 305 } 306 307 /** 308 * Returns <em>alos</em> (dawn) based on the time when the sun is {@link ZENITH_16_POINT_1 16.1°} below the eastern {@link 309 * AstronomicalCalendar#GEOMETRIC_ZENITH} before {@link #getSunrise() sunrise}. This is based on the calculation that the time 310 * between dawn and sunrise (and sunset to nightfall) is 72 minutes, the time that is takes to walk 4 <a href= 311 * "https://en.wikipedia.org/wiki/Biblical_mile">mil</a> at 18 minutes a mil (<a href="https://en.wikipedia.org/wiki/Maimonides" 312 * >Rambam</a> and others). The sun's position below the horizon 72 minutes before {@link #getSunrise() sunrise} in Jerusalem on 313 * the <a href="https://kosherjava.com/2022/01/12/equinox-vs-equilux-zmanim-calculations/">around the equinox / equilux</a> is 314 * 16.1° below {@link AstronomicalCalendar#GEOMETRIC_ZENITH}. 315 * 316 * @see ComprehensiveZmanimCalendar#getTzais16Point1Degrees() 317 * 318 * @return The <code>Instant</code> of dawn. If the calculation can't be computed such as northern and southern 319 * locations even south of the Arctic Circle and north of the Antarctic Circle where the sun may not reach 320 * low enough below the horizon for this calculation, a <code>null</code> will be returned. See detailed 321 * explanation on top of the {@link AstronomicalCalendar} documentation. 322 */ 323 public Instant getAlos16Point1Degrees() { 324 return getSunriseOffsetByDegrees(ZENITH_16_POINT_1); 325 } 326 327 /** 328 * Method to return <em>alos</em> (dawn) calculated as 72 minutes before {@link #getSunrise() sunrise} or {@link 329 * #getSeaLevelSunrise() sea level sunrise} (depending on the {@link #isUseElevation()} setting). This time 330 * is based on the time to walk the distance of 4 <a href="https://en.wikipedia.org/wiki/Biblical_mile">mil</a> at 18 minutes a mil. The 331 * 72-minute time (but not the concept of fixed minutes) is based on the opinion that the time of the <em>Neshef</em> 332 * (twilight between dawn and sunrise) does not vary by the time of year or location but depends on the time it takes 333 * to walk the distance of 4 mil. 334 * 335 * @return the <code>Instant</code> representing the time. If the calculation can't be computed such as in the Arctic 336 * Circle where there is at least one day a year where the sun does not rise, and one where it does not set, 337 * a <code>null</code> will be returned. See detailed explanation on top of the {@link AstronomicalCalendar} 338 * documentation. 339 */ 340 public Instant getAlos72Minutes() { 341 return getTimeOffset(getSunriseBasedOnElevationSetting(), Duration.ofMinutes(-72)); 342 } 343 344 /** 345 * This method returns {@link #getSunTransit() Astronomical <em>chatzos hayom</em>} if the 346 * {@link com.kosherjava.zmanim.util.AstronomicalCalculator calculator} class used supports it and 347 * {@link #isUseAstronomicalChatzos() isUseAstronomicalChatzos()} is set to <em>true</em> or the {@link #getChatzosHayomAsHalfDay() 348 * halfway point between sunrise and sunset} if it does not support it, or it is not configured to use it. There are currently 349 * two {@link com.kosherjava.zmanim.util.AstronomicalCalculator calculators} available in the API, the default {@link 350 * com.kosherjava.zmanim.util.NOAACalculator NOAA calculator} and the {@link com.kosherjava.zmanim.util.SunTimesCalculator USNO 351 * calculator}. The USNO calculator calculates <em>chatzos</em> as halfway between sunrise and sunset (identical to six <em>shaos 352 * zmaniyos</em> after sunrise), while the NOAACalculator calculates it more accurately as {@link #getSunTransit() astronomical 353 * <em>chatzos</em>}. See <a href="https://kosherjava.com/2020/07/02/definition-of-chatzos/">The Definition of <em>Chatzos</em></a> 354 * for a detailed explanation of the ways to calculate <em>Chatzos</em>. Since half-day <em>chatzos</em> can be <code>null</code> in 355 * the Arctic on a day when either sunrise or sunset did not happen and astronomical <em>chatzos</em> can be calculated even in the 356 * Arctic, if half-day <em>chatzos</em> calculates as <code>null</code> and astronomical <em>chatzos</em> is supported by the 357 * calculator, astronomical <em>chatzos</em> will be returned to avoid returning a <code>null</code>. 358 * 359 * @see #getSunTransit() 360 * @see #getChatzosHayomAsHalfDay() 361 * @see #isUseAstronomicalChatzos() 362 * @see #setUseAstronomicalChatzos(boolean) 363 * @return the <code>Instant</code> of <em>chatzos</em>. If the calculation can't be computed such as in the Arctic Circle 364 * where there is at least one day where the sun does not rise, and one where it does not set, and the calculator does not 365 * support astronomical calculations (that will never report a <code>null</code>) a <code>null</code> will be returned. 366 * See detailed explanation on top of the {@link AstronomicalCalendar} documentation. 367 */ 368 public Instant getChatzosHayom() { 369 if (isUseAstronomicalChatzos()) { 370 return getSunTransit(); // can be null if the calculator does not support astronomical chatzos 371 } else { 372 Instant halfDayChatzos = getChatzosHayomAsHalfDay(); 373 if (halfDayChatzos == null) { 374 return getSunTransit(); // can be null if the calculator does not support astronomical chatzos 375 } else { 376 return halfDayChatzos; 377 } 378 } 379 } 380 381 /** 382 * A method that returns <em>chatzos halayla</em> at the <b>end of the day</b> (the last <em>zman</em> of the day 383 * returned by the calendar, that may actually be after midnight of the day it is being calculated for). For example, if 384 * calculating it for the date of <em>Erev Pesach</em>, the calculation will be for <em>Lail Pesach</em> to allow you to use the 385 * <em>zman</em> as <em>sof zman achilas afikoman</em>. {@link #getSolarMidnight() Astronomical <em>chatzos halayla</em>} will be 386 * returned if the {@link com.kosherjava.zmanim.util.AstronomicalCalculator calculator} class used supports it and {@link 387 * isUseAstronomicalChatzos() isUseAstronomicalChatzos()} is set to <em>true</em>. Otherwise the {@link #getChatzos(Instant, 388 * Instant) halfway point} between sunset and the following day's sunrise, if it does not support it, or it is not configured to 389 * use it. There are currently two {@link com.kosherjava.zmanim.util.AstronomicalCalculator calculators} available in the API, 390 * the default {@link com.kosherjava.zmanim.util.NOAACalculator NOAA calculator} and the {@link 391 * com.kosherjava.zmanim.util.SunTimesCalculator USNO calculator}. The USNO calculator calculates <em>chatzos halayla</em> as 392 * halfway between sunset and the following day's sunrise (identical to six <em>shaos zmaniyos</em> after sunset), while the 393 * NOAACalculator calculates it more accurately as {@link #getSolarMidnight() astronomical <em>chatzos halayla</em>}. See <a href= 394 * "https://kosherjava.com/2020/07/02/definition-of-chatzos/">The Definition of <em>Chatzos</em></a> for a detailed explanation 395 * of the ways to calculate <em>Chatzos</em>. Since half-night <em>chatzos</em> can be <code>null</code> in the Arctic on a day 396 * when either sunset or the following day's sunrise did not happen and astronomical <em>chatzos halayla</em> can be calculated 397 * even in the Arctic, if half-day <em>chatzos</em> calculates as <code>null</code> and astronomical <em>chatzos</em> is 398 * supported by the calculator, astronomical <em>chatzos</em> will be returned to avoid returning a <code>null</code>. 399 * 400 * @see #getSolarMidnight() 401 * @see #getChatzos(Instant, Instant) 402 * @see #isUseAstronomicalChatzos() 403 * @see #setUseAstronomicalChatzos(boolean) 404 * @return the <code>Instant</code> of <em>chatzos halayla</em> at the <b>end of the current day</b>. If the calculation can't be 405 * computed such as in the Arctic Circle where there is at least one day where the sun does not rise, and one where it 406 * does not set, and the calculator does not support astronomical calculations (that will never report a 407 * <code>null</code>) a <code>null</code> will be returned. See detailed explanation on top of the 408 * {@link AstronomicalCalendar} documentation. 409 */ 410 public Instant getChatzosHalayla() { 411 if (isUseAstronomicalChatzos()) { 412 return getSolarMidnight(); // can be null if the calculator does not support astronomical chatzos 413 } else { 414 ZmanimCalendar clonedCalendar = (ZmanimCalendar)this.clone(); 415 clonedCalendar.setLocalDate(getLocalDate().plusDays(1)); 416 Instant halfNightChatzos = getChatzos(getSeaLevelSunset(), clonedCalendar.getSeaLevelSunrise()); 417 if (halfNightChatzos == null) { 418 return getSolarMidnight(); // can be null if the calculator does not support astronomical chatzos 419 } else { 420 return halfNightChatzos; 421 } 422 } 423 } 424 425 /** 426 * A method that returns <em>chatzos</em> (<em>hayom</em> or <em>layla</em>) calculated as halfway between the begin and end 427 * times passed in. If sunrise and sunset (or sunset and the following sunrise for <em>chatzos halayla</em>) are passed in, 428 * the <em>zman</em> returned will be close to, but not exactly, when the Sun is <a href= 429 * "https://en.wikipedia.org/wiki/Transit_%28astronomy%29">transiting</a> the <a href= 430 * "https://en.wikipedia.org/wiki/Meridian_%28astronomy%29">celestial meridian</a> due to changes in declination (the 431 * lengthening or shortening day). See <a href="https://kosherjava.com/2020/07/02/definition-of-chatzos/">The Definition of 432 * <em>Chatzos</em></a> for a detailed explanation of the ways to calculate <em>Chatzos</em>. This method is a convenience 433 * method that calls the parent class's {@link #getSunTransit(Instant, Instant)}. A practical example of using this would be 434 * calculating <em>chatzos halayla</em> for the end of <em>zman achilas afikoman</em> on <em>Pesach</em> night, where 435 * <a href="https://en.wikipedia.org/wiki/Shlomo_Zalman_Auerbach">Rav Shlomo Zalman Auerbach</a> in the Halichos Shlomo, 436 * Moadim Nisan - Av, ch. 9, no. 44, pages 289-292, questioned the common practice of considering <em>chatzos halayla</em> as 437 * astronomical <em>chatzos halayla</em>, and felt that for this it should be at <em>chatzi halayla</em>, halfway between sunset 438 * and <em>alos</em> or <em>bedieved</em> from an early <em>tzais</em> that is lower (degree-wise) than <em>alos</em> the next 439 * morning, thus making this <em>zman</em> significantly earlier. <a href="https://en.wikipedia.org/wiki/Moshe_Sternbuch">Rav 440 * Moshe Sternbuch</a> in <a href="https://hebrewbooks.org/pdfpager.aspx?req=69091&pgnum=15">Teshuvos Vehanhagos v. VII, ch 1, p. 441 * 3</a>, agreed to this calculation for <em>chatzos halayla</em> on <em>Pesach</em> night. 442 * 443 * @param begin the beginning of day or night for calculating <em>chatzos</em>. For <em>chatzos hayom</em>, this can be sea level 444 * sunrise, or any arbitrary sunrise or <em>alos</em> used as the beginning of the day, and for <em>chatzos halayla</em> 445 * this can be sea level sunset, or any arbitrary sunset or <em>tzais</em> used as the beginning of the night. 446 * @param end the end of day or night for calculating <em>chatzos</em>. For <em>chatzos hayom</em>, this can be sea level sunset, 447 * or any arbitrary sunset or <em>tzais</em> used as the end of day, and for <em>chatzos halayla</em> this can be sea 448 * level sunrise, or any arbitrary sunrise or <em>alos</em> used as the end of the night. 449 * @return the <code>Instant</code> representing <em>chatzos</em>. If the calculation can't be computed such as in the 450 * Arctic Circle where there is at least one day a year where the sun does not rise, and one where it does 451 * not set, <code>null</code> will be returned. See detailed explanation on top of the page. 452 * @see #getSunTransit(Instant, Instant) 453 * @see #getChatzosHayomAsHalfDay() 454 * @see #getChatzosHayom() 455 * @see #getChatzosHalayla() 456 */ 457 public Instant getChatzos(Instant begin, Instant end) { 458 return getSunTransit(begin, end); 459 } 460 461 /** 462 * Returns <em>chatzos</em> calculated as halfway between sunrise and sunset. Many are of the opinion that 463 * <em>chatzos</em> is calculated as the midpoint between {@link #getSeaLevelSunrise() sea level sunrise} and 464 * {@link #getSeaLevelSunset() sea level sunset}, despite it not being the most accurate way to calculate it. A day 465 * starting at <em>alos</em> and ending at <em>tzais</em> using the same time or degree offset will also return 466 * the same time. In reality due to lengthening or shortening of day, this is not necessarily the exact midpoint of 467 * the day, but it is very close. This method allows you to use the NOAACalculator and still calculate <em>chatzos 468 * </em> as six <em>shaos zmaniyos</em> after sunrise. There are currently two {@link 469 * com.kosherjava.zmanim.util.AstronomicalCalculator calculators} available in the API, the {@link 470 * com.kosherjava.zmanim.util.NOAACalculator} and the {@link com.kosherjava.zmanim.util.SunTimesCalculator}. 471 * The SunTimesCalculator calculates <em>chatzos</em> as halfway between sunrise and sunset (and of six <em>shaos 472 * zmaniyos</em>), while the NOAACalculator calculates it as astronomical <em>chatzos</em> that is slightly more 473 * accurate. This method allows you to use the NOAACalculator and still calculate <em>chatzos</em> as six <em>shaos 474 * zmaniyos</em> after sunrise. See <a href="https://kosherjava.com/2020/07/02/definition-of-chatzos/">The Definition 475 * of <em>Chatzos</em></a> for a detailed explanation of the ways to calculate <em>Chatzos</em>. 476 * 477 * @return the <code>Instant</code> of the latest <em>chatzos</em>. If the calculation can't be computed such 478 * as in the Arctic Circle where there is at least one day a year where the sun does not rise, and one where 479 * it does not set, a <code>null</code> will be returned. See detailed explanation on top of the 480 * {@link AstronomicalCalendar} documentation. 481 * @see com.kosherjava.zmanim.util.NOAACalculator#getUTCNoon(LocalDate, GeoLocation) 482 * @see com.kosherjava.zmanim.util.SunTimesCalculator#getUTCNoon(LocalDate, GeoLocation) 483 * @see com.kosherjava.zmanim.util.AstronomicalCalculator#getUTCNoon(LocalDate, GeoLocation) 484 * @see #getSunTransit(Instant, Instant) 485 * @see #getChatzosHayom() 486 * @see #getChatzosHalayla() 487 * @see #getChatzos(Instant, Instant) 488 * @see #getSunTransit() 489 * @see #isUseAstronomicalChatzos() 490 */ 491 public Instant getChatzosHayomAsHalfDay() { 492 return getChatzos(getSeaLevelSunrise(), getSeaLevelSunset()); 493 } 494 495 /** 496 * A generic method for calculating the latest <em>zman krias shema</em> (time to recite shema in the morning) that is 3 * 497 * <em>shaos zmaniyos</em> (temporal hours) after the start of the day, calculated using the start and end of the day passed 498 * to this method. The time from the start of day to the end of day are divided into 12 <em>shaos zmaniyos</em> (temporal 499 * hours), and the latest <em>zman krias shema</em> is calculated as 3 of those <em>shaos zmaniyos</em> after the beginning of 500 * the day. If {@link #isUseAstronomicalChatzosForOtherZmanim()} is <code>true</code>, the 3 <em>shaos zmaniyos</em> will be 501 * based on 1/6 of the time between sunrise and {@link #getSunTransit() astronomical <em>chatzos</em>}. As an example, passing 502 * {@link #getSunrise() sunrise} and {@link #getSunset() sunset} or {@link #getSeaLevelSunrise() sea level 503 * sunrise} and {@link #getSeaLevelSunset() sea level sunset} to this method (or {@link #getSunriseBasedOnElevationSetting()} and 504 * {@link #getSunsetBasedOnElevationSetting()} that is driven off the {@link #isUseElevation()} setting) will return <em>sof zman 505 * krias shema</em> according to the opinion of the <a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a>. In cases where 506 * the start and end dates are not synchronous such as in {@link ComprehensiveZmanimCalendar 507 * #getSofZmanShmaAlos16Point1ToTzaisGeonim7Point083Degrees()} <code>false</code> should be passed to the synchronous parameter 508 * to ensure that {@link #isUseAstronomicalChatzosForOtherZmanim()} will not be used. 509 * 510 * @param startOfDay the start of day for calculating <em>zman krias shema</em>. This can be sunrise or any <em>alos</em> passed 511 * to this method. 512 * @param endOfDay the end of day for calculating <em>zman krias shema</em>. This can be sunset or any <em>tzais</em> passed to 513 * this method. 514 * @param synchronous If the <em>zman</em> has a synchronous start and end of the day. If this is <code>false</code>, using a 515 * {@link #isUseAstronomicalChatzosForOtherZmanim()} makes no sense and will be ignored even if set to true, since by 516 * definition <em>chatzos</em> will not be the middle of the day for the <em>zman</em>. 517 * @see #isUseAstronomicalChatzosForOtherZmanim() 518 * @return the <code>Instant</code> of the latest <em>zman shema</em> based on the start and end of day times passed to this 519 * method. If the calculation can't be computed such as in the Arctic Circle where there is at least one day 520 * a year where the sun does not rise, and one where it does not set, a <code>null</code> will be returned. See 521 * detailed explanation on top of the {@link AstronomicalCalendar} documentation. 522 */ 523 public Instant getSofZmanShma(Instant startOfDay, Instant endOfDay, boolean synchronous) { 524 if (isUseAstronomicalChatzosForOtherZmanim() && synchronous) { 525 return getHalfDayBasedZman(startOfDay, getChatzosHayom(), 3); 526 } else { 527 return getShaahZmanisBasedZman(startOfDay, endOfDay, 3); 528 } 529 } 530 531 /** 532 * A generic method for calculating the latest <em>zman krias shema</em> that calls {@link #getSofZmanShma(Instant, Instant, boolean)} 533 * passing <code>false</code> to the synchronous parameter since there is no way to know if the start and end of the day are 534 * synchronous. Passing true when they are not synchronous is too much of a risk. See information on that method for more details. 535 * @param startOfDay the start of day for calculating <em>zman krias shema</em>. This can be sunrise or any <em>alos</em> passed 536 * to this method. 537 * @param endOfDay the end of day for calculating <em>zman krias shema</em>. This can be sunset or any <em>tzais</em> passed to 538 * this method. 539 * @return the <code>Instant</code> of the latest <em>zman shema</em> based on the start and end of day times passed to this 540 * method. If the calculation can't be computed such as in the Arctic Circle where there is at least one day 541 * a year where the sun does not rise, and one where it does not set, a <code>null</code> will be returned. See 542 * detailed explanation on top of the {@link AstronomicalCalendar} documentation. 543 * @see #getSofZmanShma(Instant, Instant, boolean) 544 */ 545 public Instant getSofZmanShma(Instant startOfDay, Instant endOfDay) { 546 return getSofZmanShma(startOfDay, endOfDay, false); 547 } 548 549 /** 550 * This method returns the latest <em>zman krias shema</em> (time to recite shema in the morning) that is 3 * 551 * {@link #getShaahZmanisGRA() <em>shaos zmaniyos</em>} (solar hours) after {@link #getSunrise() sunrise} or 552 * {@link #getSeaLevelSunrise() sea level sunrise} (depending on the {@link #isUseElevation()} setting), according 553 * to the <a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a>. 554 * The day is calculated from {@link #getSeaLevelSunrise() sea level sunrise} to {@link #getSeaLevelSunset() sea level 555 * sunset} or from {@link #getSunrise() sunrise} to {@link #getSunset() sunset} (depending on the 556 * {@link #isUseElevation()} setting). 557 * 558 * @see #getSofZmanShma(Instant, Instant) 559 * @see #getShaahZmanisGRA() 560 * @see #isUseElevation() 561 * @see ComprehensiveZmanimCalendar#getSofZmanShmaBaalHatanya() 562 * @return the <code>Instant</code> of the latest <em>zman shema</em> according to the GRA. If the calculation can't be 563 * computed such as in the Arctic Circle where there is at least one day a year where the sun does not rise, 564 * and one where it does not set, a <code>null</code> will be returned. See the detailed explanation on top 565 * of the {@link AstronomicalCalendar} documentation. 566 */ 567 public Instant getSofZmanShmaGRA() { 568 return getSofZmanShma(getSunriseBasedOnElevationSetting(), getSunsetBasedOnElevationSetting(), true); 569 } 570 571 /** 572 * This method returns the latest <em>zman krias shema</em> (time to recite Shema in the morning) according to the opinion of 573 * the <a href="https://en.wikipedia.org/wiki/Avraham_Gombiner">Magen Avraham (MGA)</a> based on <em>alos</em> being {@link 574 * getAlos72Minutes() 72} minutes before {@link #getSunrise() sunrise}. This time is 3 {@link 575 * getShaahZmanis72Minutes() <em>shaos zmaniyos</em>} (solar hours) after {@link #getAlos72Minutes() dawn} based on the opinion 576 * of the MGA that the day is calculated from a {@link #getAlos72Minutes() dawn} of 72 minutes before sunrise to 577 * {@link #getTzais72Minutes() nightfall} of 72 minutes after sunset. This returns the time of 3 * {@link 578 * getShaahZmanis72Minutes()} after {@link #getAlos72Minutes() dawn}. 579 * 580 * @return the <code>Instant</code> of the latest <em>zman krias shema</em>. If the calculation can't be computed such 581 * as in the Arctic Circle where there is at least one day a year where the sun does not rise, and one where 582 * it does not set, a <code>null</code> will be returned. See detailed explanation on top of the 583 * {@link AstronomicalCalendar} documentation. 584 * @see #isUseAstronomicalChatzosForOtherZmanim() 585 * @see #getShaahZmanis72Minutes() 586 * @see #getAlos72Minutes() 587 * @see #getSofZmanShmaMGA72Minutes() 588 * @see #getSofZmanShma(Instant, Instant, boolean) 589 */ 590 public Instant getSofZmanShmaMGA72Minutes() { 591 return getSofZmanShma(getAlos72Minutes(), getTzais72Minutes(), true); 592 } 593 594 /** 595 * This method returns the <em>tzais</em> (nightfall) based on the opinion of <em>Rabbeinu Tam</em> that <em>tzais hakochavim</em> 596 * is calculated as 72 minutes after sunset, the time it takes to walk 4 <a href= 597 * "https://en.wikipedia.org/wiki/Biblical_mile">mil</a> at 18 minutes a mil. According to the <a href= 598 * "https://en.wikipedia.org/wiki/Samuel_Loew">Machtzis Hashekel</a> in Orach Chaim 235:3, the <a href= 599 * "https://en.wikipedia.org/wiki/Joseph_ben_Meir_Teomim">Pri Megadim</a> in Orach Chaim 261:2 (see the Biur Halacha) and others 600 * (see Hazmanim Bahalacha 17:3 and 17:5) the 72 minutes are standard clock minutes any time of the year in any location. 601 * Depending on the {@link #isUseElevation()} setting, a 72-minute offset from either {@link #getSunset() sunset} or 602 * {@link #getSeaLevelSunset() sea level sunset} is used. 603 * 604 * @return the <code>Instant</code> representing 72 minutes after sunset. If the calculation can't be 605 * computed such as in the Arctic Circle where there is at least one day a year where the sun does not rise, 606 * and one where it does not set, a <code>null</code> will be returned See detailed explanation on top of the 607 * {@link AstronomicalCalendar} documentation. 608 * @see ComprehensiveZmanimCalendar#getTzais16Point1Degrees() 609 */ 610 public Instant getTzais72Minutes() { 611 return getTimeOffset(getSunsetBasedOnElevationSetting(), Duration.ofMinutes(72)); 612 } 613 614 /** 615 * A method to return candle lighting time, calculated as {@link #getCandleLightingOffset()} minutes before {@link 616 * #getSeaLevelSunset() sea level sunset}. This will return the time for any day of the week, since it can be used to calculate 617 * candle lighting time for <em>Yom Tov</em> (mid-week holidays) as well. Elevation adjustments are intentionally not performed 618 * by this method, but you can calculate it by passing the elevation adjusted sunset to {@link #getTimeOffset(Instant, Duration)}. 619 * 620 * @return candle lighting time. If the calculation can't be computed such as in the Arctic Circle where there is at 621 * least one day a year where the sun does not rise, and one where it does not set, a <code>null</code> will 622 * be returned. See detailed explanation on top of the {@link AstronomicalCalendar} documentation. 623 * @see #getSeaLevelSunset() 624 * @see #getCandleLightingOffset() 625 * @see #setCandleLightingOffset(double) 626 */ 627 public Instant getCandleLighting() { 628 long totalNanos = (long) (-getCandleLightingOffset() * MINUTE_NANOS); 629 return getTimeOffset(getSeaLevelSunset(), Duration.ofNanos(totalNanos)); 630 } 631 632 /** 633 * A generic method for calculating the latest <em>zman tfilah</em> (time to recite the morning prayers) that is 4 * <em>shaos 634 * zmaniyos</em> (temporal hours) after the start of the day, calculated using the start and end of the day passed to this method. 635 * The time from the start of day to the end of day are divided into 12 <em>shaos zmaniyos</em> (temporal hours), and <em>sof 636 * zman tfila</em> is calculated as 4 of those <em>shaos zmaniyos</em> after the beginning of the day. As an example, passing 637 * {@link #getSunriseBasedOnElevationSetting()} and {@link #getSunsetBasedOnElevationSetting()} (depends on the {@link 638 * #isUseElevation()} elevation setting) to this method will return <em>zman tfilah</em> according to the opinion of the <a href= 639 * "https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a>. This method's synchronous parameter indicates if the start and end of day 640 * for the calculation are synchronous, having the same offset. This is typically the case, but some <em>zmanim</em> calculations 641 * are based on a start and end at different offsets from the real start and end of the day, such as starting the day at 642 * <em>alos</em> and an ending it at <em>tzais Geonim</em> or some other variant. If the day is not synchronous a {@link 643 * #getHalfDayBasedZman(Instant, Instant, double) half-day based calculations} will be bypassed. It would be illogical to use a 644 * half-day based calculation that start/end at <em>chatzos</em> when the two "halves" of the day are not equal, and the halfway 645 * point between them is not at <em>chatzos</em>. 646 * 647 * @param startOfDay the start of day for calculating <em>zman tfilah</em>. This can be sunrise or any <em>alos</em> passed 648 * to this method. 649 * @param endOfDay the end of day for calculating <em>zman tfilah</em>. This can be sunset or any <em>tzais</em> passed 650 * to this method. 651 * @param synchronous If the <em>zman</em> has a synchronous start and end of the day. If this is <code>false</code>, using a 652 * {@link #isUseAstronomicalChatzosForOtherZmanim()} makes no sense and will be ignored even if set to true, since by 653 * definition <em>chatzos</em> will not be the middle of the day for the <em>zman</em>. 654 * @return the <code>Instant</code> of the latest <em>zman tfilah</em> based on the start and end of day times passed to this 655 * method. If the calculation can't be computed such as in the Arctic Circle where there is at least one day a year where 656 * the sun does not rise, and one where it does not set, a <code>null</code> will be returned. See detailed explanation 657 * on top of the {@link AstronomicalCalendar} documentation. 658 */ 659 public Instant getSofZmanTfila(Instant startOfDay, Instant endOfDay, boolean synchronous) { 660 if (isUseAstronomicalChatzosForOtherZmanim() && synchronous) { 661 return getHalfDayBasedZman(startOfDay, getChatzosHayom(), 4); 662 } else { 663 return getShaahZmanisBasedZman(startOfDay, endOfDay, 4); 664 } 665 } 666 667 /** 668 * A generic method for calculating <em>sof zman biur chametz</em> or the latest time one is allowed burning 669 * <em>chametz</em> on <em>Erev Pesach</em> that is 5 * <em>shaos zmaniyos</em> (temporal hours) after the start of the 670 * day, calculated using the start and end of the day passed to this method. If the date is not <em>erev Pesach</em>, a 671 * null will be returned. The time from the start of day to the end of day is divided into 12 <em>shaos zmaniyos</em> 672 * (temporal hours), and <em>sof zman biur chametz</em> is calculated as 5 of those <em>shaos zmaniyos</em> after the 673 * beginning of the day. As an example, passing {@link #getSunrise() sunrise} and {@link #getSunset() sunset} to this 674 * method will return <em>sof zman biur chametz</em> according to the opinion of the <a href= 675 * "https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a>. This method's synchronous parameter indicates if the start 676 * and end of day for the calculation are synchronous, having the same offset. This is typically the case, but some 677 * <em>zmanim</em> calculations are based on a start and end at different offsets from the real start and end of the day, 678 * such as starting the day at <em>alos</em> and an ending it at <em>tzais Geonim</em> or some other variant. If the day 679 * is not synchronous a {@link #getHalfDayBasedZman(Instant, Instant, double) half-day based calculations} will be bypassed. 680 * It would be illogical to use a half-day based calculation that start/end at <em>chatzos</em> when the two "halves" of 681 * the day are not equal, and the halfway point between them is not at <em>chatzos</em>. 682 * 683 * @param startOfDay the start of day for calculating <em>sof zman biur chametz</em>. This can be sunrise or any <em>alos</em> 684 * passed to this method. 685 * @param endOfDay the end of day for calculating <em>sof zman biur chametz</em>. This can be sunset or any <em>tzais</em> 686 * passed to this method. 687 * @param synchronous If the <em>zman</em> has a synchronous start and end of the day. If this is <code>false</code>, using a 688 * {@link #isUseAstronomicalChatzosForOtherZmanim()} makes no sense and will be ignored even if set to true, since by 689 * definition <em>chatzos</em> will not be the middle of the day for the <em>zman</em>. 690 * @return the <code>Instant</code> of the <em>sof zman biur chametz</em> based on the start and end of day times passed 691 * to this method. If the date is not <em>Erev Pesach</em> or if the calculation can't be computed such as in the 692 * Arctic Circle where there is at least one day a year where the sun does not rise, and one where it does not set, 693 * a <code>null</code> will be returned. See detailed explanation on top of the {@link AstronomicalCalendar} 694 * documentation. 695 */ 696 public Instant getSofZmanBiurChametz(Instant startOfDay, Instant endOfDay, boolean synchronous) { 697 JewishCalendar jewishCalendar = new JewishCalendar(getLocalDate()); 698 if (jewishCalendar.getJewishMonth() == JewishCalendar.NISSAN && jewishCalendar.getJewishDayOfMonth() == 14) { 699 if (isUseAstronomicalChatzosForOtherZmanim() && synchronous) { 700 return getHalfDayBasedZman(startOfDay, getChatzosHayom(), 5); 701 } else { 702 return getShaahZmanisBasedZman(startOfDay, endOfDay, 5); 703 } 704 } else { 705 return null; 706 } 707 } 708 709 /** 710 * A generic method for calculating <em>sof zman achilas chametz</em> or the latest time one is allowed eating 711 * <em>chametz</em> on <em>Erev Pesach</em> that is 4 * <em>shaos zmaniyos</em> (temporal hours) after the start of the 712 * day, calculated using the start and end of the day passed to this method. If the date is not <em>erev Pesach</em>, a 713 * null will be returned. The time from the start of day to the end of day is divided into 12 <em>shaos zmaniyos</em> 714 * (temporal hours), and <em>sof zman achilas chametz</em> is calculated as 4 of those <em>shaos zmaniyos</em> after the 715 * beginning of the day. As an example, passing {@link #getSunrise() sunrise} and {@link #getSunset() sunset} to this 716 * method will return <em>sof zman achilas chametz</em> according to the opinion of the <a href= 717 * "https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a>. This method's synchronous parameter indicates if the start 718 * and end of day for the calculation are synchronous, having the same offset. This is typically the case, but some 719 * <em>zmanim</em> calculations are based on a start and end at different offsets from the real start and end of the day, 720 * such as starting the day at <em>alos</em> and an ending it at <em>tzais Geonim</em> or some other variant. If the day 721 * is not synchronous a {@link #getHalfDayBasedZman(Instant, Instant, double) half-day based calculations} will be bypassed. 722 * It would be illogical to use a half-day based calculation that start/end at <em>chatzos</em> when the two "halves" of 723 * the day are not equal, and the halfway point between them is not at <em>chatzos</em>. 724 * 725 * @param startOfDay the start of day for calculating <em>sof zman achilas chametz</em>. This can be sunrise or any <em>alos</em> 726 * passed to this method. 727 * @param endOfDay the end of day for calculating <em>sof zman achilas chametz</em>. This can be sunset or any <em>tzais</em> 728 * passed to this method. 729 * @param synchronous If the <em>zman</em> has a synchronous start and end of the day. If this is <code>false</code>, using a {@link 730 * isUseAstronomicalChatzosForOtherZmanim()} makes no sense and will be ignored even if set to true, since by definition 731 * <em>chatzos</em> will not be the middle of the day for the <em>zman</em>. 732 * @return the <code>Instant</code> of the <em>sof zman achilas chametz</em> based on the start and end of day times passed 733 * to this method. If the date is not <em>Erev Pesach</em> or if the calculation can't be computed such as in the 734 * Arctic Circle where there is at least one day a year where the sun does not rise, and one where it does not set, 735 * a <code>null</code> will be returned. See detailed explanation on top of the {@link AstronomicalCalendar} 736 * documentation. 737 */ 738 public Instant getSofZmanAchilasChametz(Instant startOfDay, Instant endOfDay, boolean synchronous) { 739 JewishCalendar jewishCalendar = new JewishCalendar(getLocalDate()); 740 if (jewishCalendar.getJewishMonth() == JewishCalendar.NISSAN && jewishCalendar.getJewishDayOfMonth() == 14) { 741 return getSofZmanTfila(startOfDay, endOfDay, synchronous); 742 } else { 743 return null; 744 } 745 } 746 747 /** 748 * A generic method for calculating the latest <em>zman tfila</em> that calls {@link #getSofZmanTfila(Instant, Instant, boolean)} 749 * passing <code>false</code> to the synchronous parameter since there is no way to know if the start and end of the day are 750 * synchronous. Passing true when they are not synchronous is too much of a risk. See information on that method for more details. 751 * @param startOfDay the start of day for calculating <em>zman tfilah</em>. This can be sunrise or any <em>alos</em> passed 752 * to this method. 753 * @param endOfDay the end of day for calculating <em>zman tfilah</em>. This can be sunset or any <em>tzais</em> passed to 754 * this method. 755 * @return the <code>Instant</code> of the latest <em>zman tfilah</em> based on the start and end of day times passed to this 756 * method. If the calculation can't be computed such as in the Arctic Circle where there is at least one day 757 * a year where the sun does not rise, and one where it does not set, a <code>null</code> will be returned. See 758 * detailed explanation on top of the {@link AstronomicalCalendar} documentation. 759 * @see #getSofZmanShma(Instant, Instant, boolean) 760 */ 761 public Instant getSofZmanTfila(Instant startOfDay, Instant endOfDay) { 762 return getSofZmanTfila(startOfDay, endOfDay, false); 763 } 764 765 /** 766 * This method returns the latest <em>zman tfila</em> (time to recite shema in the morning) that is 4 * 767 * {@link #getShaahZmanisGRA() <em>shaos zmaniyos</em> }(solar hours) after {@link #getSunrise() sunrise} or 768 * {@link #getSeaLevelSunrise() sea level sunrise} (depending on the {@link #isUseElevation()} setting), according 769 * to the <a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a>. 770 * The day is calculated from {@link #getSeaLevelSunrise() sea level sunrise} to {@link #getSeaLevelSunset() sea level 771 * sunset} or from {@link #getSunrise() sunrise} to {@link #getSunset() sunset} (depending on the 772 * {@link #isUseElevation()} setting). 773 * 774 * @see #getSofZmanTfila(Instant, Instant) 775 * @see #getShaahZmanisGRA() 776 * @see ComprehensiveZmanimCalendar#getSofZmanTfilaBaalHatanya() 777 * @return the <code>Instant</code> of the latest <em>zman tfilah</em>. If the calculation can't be computed such as in 778 * the Arctic Circle where there is at least one day a year where the sun does not rise, and one where it 779 * does not set, a <code>null</code> will be returned. See detailed explanation on top of the 780 * {@link AstronomicalCalendar} documentation. 781 */ 782 public Instant getSofZmanTfilaGRA() { 783 return getSofZmanTfila(getSunriseBasedOnElevationSetting(), getSunsetBasedOnElevationSetting(), true); 784 } 785 786 /** 787 * This method returns the latest <em>zman tfila</em> (time to recite shema in the morning) that is 4 * {@link 788 * getShaahZmanis72Minutes() <em>shaos zmaniyos</em>} (solar hours) after {@link #getAlos72Minutes()}, according to the 789 * <em><a href="https://en.wikipedia.org/wiki/Avraham_Gombiner">Magen Avraham (MGA)</a></em>. The day is calculated 790 * from 72 minutes before {@link #getSunriseBasedOnElevationSetting()} to 72 minutes after {@link 791 * getSunsetBasedOnElevationSetting()}. The use of elevation depends on the {@link #isUseElevation()} setting). 792 * 793 * @return the <code>Instant</code> of the latest <em>zman tfila</em>. If the calculation can't be computed such as in 794 * the Arctic Circle where there is at least one day a year where the sun does not rise, and one where it 795 * does not set, a <code>null</code> will be returned. See detailed explanation on top of the 796 * {@link AstronomicalCalendar} documentation. 797 * @see #getSofZmanTfila(Instant, Instant, boolean) 798 * @see #getShaahZmanis72Minutes() 799 * @see #getAlos72Minutes() 800 */ 801 public Instant getSofZmanTfilaMGA72Minutes() { 802 return getSofZmanTfila(getAlos72Minutes(), getTzais72Minutes(), true); 803 } 804 805 /** 806 * A generic method for calculating <em>mincha gedola</em> (the earliest time to recite the <em>mincha</em> prayers) that 807 * is 6.5 * <em>shaos zmaniyos</em> (temporal hours) after the start of the day, calculated using the start and end of the 808 * day passed to this method. The time from the start of day to the end of day are divided into 12 <em>shaos zmaniyos</em> 809 * (temporal hours), and <em>mincha gedola</em> is calculated as 6.5 of those <em>shaos zmaniyos</em> after the beginning 810 * of the day. As an example, passing {@link #getSunrise() sunrise} and {@link #getSunset() sunset} or 811 * {@link #getSeaLevelSunrise() sea level sunrise} and {@link #getSeaLevelSunset() sea level sunset} (depending on the {@link 812 * isUseElevation()} elevation setting) to this method will return <em>mincha gedola</em> according to the opinion of the 813 * <a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a>. Alternatively, this method uses {@link 814 * isUseAstronomicalChatzosForOtherZmanim()} to control if the time is based on 6.5 <em>shaos zmaniyos</em> into the day 815 * mentioned above, or as half an hour <em>zmaniyos</em> based on the second half of the day after <em>chatzos</em> ({@link 816 * getSunTransit() astronomical <em>chatzos</em>} if supported by the {@link AstronomicalCalculator calculator} and {@link 817 * isUseAstronomicalChatzos() configured} or {@link #getChatzosHayomAsHalfDay() <em>chatzos</em> as half a day} if not. This 818 * method's synchronous parameter indicates if the start and end of day for the calculation are synchronous, having the same 819 * offset. This is typically the case, but some <em>zmanim</em> calculations are based on a start and end at different offsets 820 * from the real start and end of the day, such as starting the day at <em>alos</em> and an ending it at <em>tzais Geonim</em> 821 * or some other variant. If the day is not synchronous a {@link #getHalfDayBasedZman(Instant, Instant, double) half-day based 822 * calculations} will be bypassed. It would be illogical to use a half-day based calculation that start/end at <em>chatzos</em> 823 * when the two "halves" of the day are not equal, and the halfway point between them is not at <em>chatzos</em>. 824 * 825 * @param startOfDay the start of day for calculating <em>Mincha gedola</em>. This can be sunrise or any <em>alos</em> passed 826 * to this method. 827 * @param endOfDay the end of day for calculating <em>Mincha gedola</em>. This can be sunset or any <em>tzais</em> passed 828 * to this method. 829 * @param synchronous If the <em>zman</em> has a synchronous start and end of the day. If this is <code>false</code>, using a 830 * {@link #isUseAstronomicalChatzosForOtherZmanim()} makes no sense and will be ignored even if set to true, since by 831 * definition <em>chatzos</em> will not be the middle of the day for the <em>zman</em>. 832 * @return the <code>Instant</code> of the time of <em>Mincha gedola</em> based on the start and end of day times 833 * passed to this method. If the calculation can't be computed such as in the Arctic Circle where there is 834 * at least one day a year where the sun does not rise, and one where it does not set, a <code>null</code> will 835 * be returned. See detailed explanation on top of the {@link AstronomicalCalendar} documentation. 836 * @see #getSunTransit() 837 * @see #getChatzosHayomAsHalfDay() 838 * @see #getChatzosHayom() 839 * @see #getChatzosHalayla() 840 * @see #isUseAstronomicalChatzos() 841 * @see #isUseAstronomicalChatzosForOtherZmanim() 842 */ 843 public Instant getMinchaGedola(Instant startOfDay, Instant endOfDay, boolean synchronous) { 844 if (isUseAstronomicalChatzosForOtherZmanim() && synchronous) { 845 return getHalfDayBasedZman(getChatzosHayom(), endOfDay, 0.5); 846 } else { 847 return getShaahZmanisBasedZman(startOfDay, endOfDay, 6.5); 848 } 849 } 850 851 /** 852 * A generic method for calculating <em>mincha gedola</em> that calls {@link #getMinchaGedola(Instant, Instant, boolean)} passing 853 * <code>false</code> to the synchronous parameter since there is no way to know if the start and end of the day are 854 * synchronous. Passing true when they are not synchronous is too much of a risk. See information on that method for more 855 * details. 856 * @param startOfDay the start of day for calculating <em>Mincha gedola</em>. This can be sunrise or any <em>alos</em> passed 857 * to this method. 858 * @param endOfDay the end of day for calculating <em>Mincha gedola</em>. This can be sunset or any <em>tzais</em> passed to 859 * this method. 860 * @return the <code>Instant</code> of the latest <em>Mincha gedola</em> based on the start and end of day times passed to this 861 * method. If the calculation can't be computed such as in the Arctic Circle where there is at least one day 862 * a year where the sun does not rise, and one where it does not set, a <code>null</code> will be returned. See 863 * detailed explanation on top of the {@link AstronomicalCalendar} documentation. 864 * @see #getMinchaGedola(Instant, Instant, boolean) 865 */ 866 public Instant getMinchaGedola(Instant startOfDay, Instant endOfDay) { 867 return getMinchaGedola(startOfDay, endOfDay, false); 868 } 869 870 /** 871 * This method returns the latest <em>mincha gedola</em>,the earliest time one can pray <em>mincha</em> that is 6.5 * 872 * {@link #getShaahZmanisGRA() <em>shaos zmaniyos</em>} (solar hours) after {@link #getSunrise() sunrise} or 873 * {@link #getSeaLevelSunrise() sea level sunrise} (depending on the {@link #isUseElevation()} setting), according 874 * to the <a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a>. <em>Mincha gedola</em> is the earliest 875 * time one can pray <em>mincha</em>. The Ramba"m is of the opinion that it is better to delay <em>mincha</em> until 876 * {@link #getMinchaKetanaGRA() <em>mincha ketana GRA</em>} while the Ra"sh, Tur, GRA and others are of the 877 * opinion that <em>mincha</em> can be prayed <em>lechatchila</em> starting at <em>mincha gedola</em>. 878 * The day is calculated from {@link #getSeaLevelSunrise() sea level sunrise} to {@link #getSeaLevelSunset() sea level 879 * sunset} or {@link #getSunrise() sunrise} to {@link #getSunset() sunset} (depending on the {@link #isUseElevation()} 880 * setting). 881 * @todo Consider adjusting this to calculate the time as half an hour <em>zmaniyos</em> after {@link #getChatzosHayom()} 882 * that uses {@link #isUseAstronomicalChatzos()} to determine the type of <em>chatzos</em> to utilize (if the 883 * {@link com.kosherjava.zmanim.util.AstronomicalCalculator calculator} support astronomical <em>chatzos</em>), 884 * based on the {@link #isUseAstronomicalChatzos()} setting. 885 * @see #getMinchaGedola(Instant, Instant) 886 * @see #getShaahZmanisGRA() 887 * @see #getMinchaKetanaGRA() 888 * @see ComprehensiveZmanimCalendar#getMinchaGedolaBaalHatanya() 889 * @return the <code>Instant</code> of the time of mincha gedola. If the calculation can't be computed such as in the 890 * Arctic Circle where there is at least one day a year where the sun does not rise, and one where it does 891 * not set, a <code>null</code> will be returned. See detailed explanation on top of the 892 * {@link AstronomicalCalendar} documentation. 893 */ 894 public Instant getMinchaGedolaGRA() { 895 return getMinchaGedola(getSunriseBasedOnElevationSetting(), getSunsetBasedOnElevationSetting(), true); 896 } 897 898 /** 899 * A generic method for calculating <em>samuch lemincha ketana</em>, / near <em>mincha ketana</em> time that is half 900 * an hour before {@link #getMinchaKetana(Instant, Instant)} or 9 * <em>shaos zmaniyos</em> (temporal hours) after the 901 * start of the day, calculated using the start and end of the day passed to this method. 902 * The time from the start of day to the end of day are divided into 12 <em>shaos zmaniyos</em> (temporal hours), and 903 * <em>samuch lemincha ketana</em> is calculated as 9 of those <em>shaos zmaniyos</em> after the beginning of the day. 904 * For example, passing {@link #getSunrise() sunrise} and {@link #getSunset() sunset} or {@link #getSeaLevelSunrise() sea 905 * level sunrise} and {@link #getSeaLevelSunset() sea level sunset} (depending on the {@link #isUseElevation()} elevation 906 * setting) to this method will return <em>samuch lemincha ketana</em> according to the opinion of the 907 * <a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a>. See the <a href= 908 * "https://hebrewbooks.org/pdfpager.aspx?req=60387&st=&pgnum=294">Mechaber and Mishna Berurah 232</a> and <a href= 909 * "https://hebrewbooks.org/pdfpager.aspx?req=60388&pgnum=34">249:2</a>. 910 * 911 * @param startOfDay the start of day for calculating <em>samuch lemincha ketana</em>. This can be sunrise or any <em>alos</em> 912 * passed to this method. 913 * @param endOfDay the end of day for calculating <em>samuch lemincha ketana</em>. This can be sunset or any <em>tzais</em> 914 * passed to this method. 915 * @param synchronous If the <em>zman</em> has a synchronous start and end of the day. If this is <code>false</code>, using a 916 * {@link #isUseAstronomicalChatzosForOtherZmanim()} makes no sense and will be ignored even if set to true, since by 917 * definition <em>chatzos</em> will not be the middle of the day for the <em>zman</em>. 918 * @return the <code>Instant</code> of the time of <em>Mincha ketana</em> based on the start and end of day times 919 * passed to this method. If the calculation can't be computed such as in the Arctic Circle where there is 920 * at least one day a year where the sun does not rise, and one where it does not set, a <code>null</code> will 921 * be returned. See detailed explanation on top of the {@link AstronomicalCalendar} documentation. 922 * @see ComprehensiveZmanimCalendar#getSamuchLeMinchaKetanaGRA() 923 * @see ComprehensiveZmanimCalendar#getSamuchLeMinchaKetana16Point1Degrees() 924 * @see ComprehensiveZmanimCalendar#getSamuchLeMinchaKetana72Minutes() 925 */ 926 public Instant getSamuchLeMinchaKetana(Instant startOfDay, Instant endOfDay, boolean synchronous) { 927 if (isUseAstronomicalChatzosForOtherZmanim() && synchronous) { 928 return getHalfDayBasedZman(getChatzosHayom(), endOfDay, 3); 929 } else { 930 return getShaahZmanisBasedZman(startOfDay, endOfDay, 9); 931 } 932 } 933 934 /** 935 * A generic method for calculating <em>samuch lemincha ketana</em> that calls {@link #getSamuchLeMinchaKetana(Instant, Instant, boolean)} 936 * passing <code>false</code> to the synchronous parameter since there is no way to know if the start and end of the day are 937 * synchronous. Passing true when they are not synchronous is too much of a risk. See information on that method for more details. 938 * @param startOfDay the start of day for calculating <em>samuch lemincha ketana</em>. This can be sunrise or any <em>alos</em> 939 * passed to this method. 940 * @param endOfDay the end of day for calculating <em>samuch lemincha ketana</em>. This can be sunset or any <em>tzais</em> 941 * passed to this method. 942 * @return the <code>Instant</code> of the time of <em>samuch lemincha ketana</em> based on the start and end of day times 943 * passed to this method. If the calculation can't be computed such as in the Arctic Circle where there is 944 * at least one day a year where the sun does not rise, and one where it does not set, a <code>null</code> will 945 * be returned. See detailed explanation on top of the {@link AstronomicalCalendar} documentation. 946 * @see #getSamuchLeMinchaKetana(Instant, Instant, boolean) 947 */ 948 public Instant getSamuchLeMinchaKetana(Instant startOfDay, Instant endOfDay) { 949 return getSamuchLeMinchaKetana(startOfDay, endOfDay, false); 950 } 951 952 /** 953 * A generic method for calculating <em>mincha ketana</em>, (the preferred time to recite the mincha prayers in 954 * the opinion of the <em><a href="https://en.wikipedia.org/wiki/Maimonides">Rambam</a></em> and others) that is 955 * 9.5 * <em>shaos zmaniyos</em> (temporal hours) after the start of the day, calculated using the start and end 956 * of the day passed to this method. 957 * The time from the start of day to the end of day are divided into 12 <em>shaos zmaniyos</em> (temporal hours), and 958 * <em>mincha ketana</em> is calculated as 9.5 of those <em>shaos zmaniyos</em> after the beginning of the day. As an 959 * example, passing {@link #getSunrise() sunrise} and {@link #getSunset() sunset} or {@link #getSeaLevelSunrise() sea 960 * level sunrise} and {@link #getSeaLevelSunset() sea level sunset} (depending on the {@link #isUseElevation()} 961 * elevation setting) to this method will return <em>mincha ketana</em> according to the opinion of the 962 * <a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a>. This method's synchronous parameter indicates if the start 963 * and end of day for the calculation are synchronous, having the same offset. This is typically the case, but some 964 * <em>zmanim</em> calculations are based on a start and end at different offsets from the real start and end of the day, 965 * such as starting the day at <em>alos</em> and an ending it at <em>tzais Geonim</em> or some other variant. If the day 966 * is not synchronous a {@link #getHalfDayBasedZman(Instant, Instant, double) half-day based calculations} will be bypassed. 967 * It would be illogical to use a half-day based calculation that start/end at <em>chatzos</em> when the two "halves" of 968 * the day are not equal, and the halfway point between them is not at <em>chatzos</em>. 969 * 970 * @param startOfDay the start of day for calculating <em>Mincha ketana</em>. This can be sunrise or any <em>alos</em> passed 971 * to this method. 972 * @param endOfDay the end of day for calculating <em>Mincha ketana</em>. This can be sunset or any <em>tzais</em> passed to 973 * this method. 974 * @param synchronous If the <em>zman</em> has a synchronous start and end of the day. If this is <code>false</code>, using a 975 * {@link #isUseAstronomicalChatzosForOtherZmanim()} makes no sense and will be ignored even if set to true, since by 976 * definition <em>chatzos</em> will not be the middle of the day for the <em>zman</em>. 977 * @return the <code>Instant</code> of the time of <em>Mincha ketana</em> based on the start and end of day times 978 * passed to this method. If the calculation can't be computed such as in the Arctic Circle where there is 979 * at least one day a year where the sun does not rise, and one where it does not set, a <code>null</code> will 980 * be returned. See detailed explanation on top of the {@link AstronomicalCalendar} documentation. 981 */ 982 public Instant getMinchaKetana(Instant startOfDay, Instant endOfDay, boolean synchronous) { 983 if (isUseAstronomicalChatzosForOtherZmanim() && synchronous) { 984 return getHalfDayBasedZman(getChatzosHayom(), endOfDay, 3.5); 985 } else { 986 return getShaahZmanisBasedZman(startOfDay, endOfDay, 9.5); 987 } 988 } 989 990 /** 991 * A generic method for calculating <em>mincha ketana</em> that calls {@link #getMinchaKetana(Instant, Instant, boolean)} passing 992 * <code>false</code> to the synchronous parameter since there is no way to know if the start and end of the day are synchronous. 993 * Passing true when they are not synchronous is too much of a risk. See information on that method for more details. 994 * @param startOfDay the start of day for calculating <em>Mincha ketana</em>. This can be sunrise or any <em>alos</em> passed 995 * to this method. 996 * @param endOfDay the end of day for calculating <em>Mincha ketana</em>. This can be sunset or any <em>tzais</em> passed to 997 * this method. 998 * @return the <code>Instant</code> of the time of <em>Mincha ketana</em> based on the start and end of day times 999 * passed to this method. If the calculation can't be computed such as in the Arctic Circle where there is 1000 * at least one day a year where the sun does not rise, and one where it does not set, a <code>null</code> will 1001 * be returned. See detailed explanation on top of the {@link AstronomicalCalendar} documentation. 1002 * @see #getMinchaKetana(Instant, Instant, boolean) 1003 */ 1004 public Instant getMinchaKetana(Instant startOfDay, Instant endOfDay) { 1005 return getMinchaKetana(startOfDay, endOfDay, false); 1006 } 1007 1008 /** 1009 * This method returns <em>mincha ketana</em>,the preferred earliest time to pray <em>mincha</em> in the 1010 * opinion of the <em><a href="https://en.wikipedia.org/wiki/Maimonides">Rambam</a></em> and others, that is 9.5 1011 * * {@link #getShaahZmanisGRA() <em>shaos zmaniyos</em>} (solar hours) after {@link #getSunrise() sunrise} or 1012 * {@link #getSeaLevelSunrise() sea level sunrise} (depending on the {@link #isUseElevation()} setting), according 1013 * to the <a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a>. For more information on this see the 1014 * documentation on {@link #getMinchaGedolaGRA() <em>mincha gedola</em>}. 1015 * The day is calculated from {@link #getSeaLevelSunrise() sea level sunrise} to {@link #getSeaLevelSunset() sea level 1016 * sunset} or from {@link #getSunrise() sunrise} to {@link #getSunset() sunset} (depending on the {@link #isUseElevation()} 1017 * setting. 1018 * 1019 * @see #getMinchaKetana(Instant, Instant) 1020 * @see #getShaahZmanisGRA() 1021 * @see #getMinchaGedolaGRA() 1022 * @see ComprehensiveZmanimCalendar#getMinchaKetanaBaalHatanya() 1023 * @return the <code>Instant</code> of the time of mincha ketana. If the calculation can't be computed such as in the 1024 * Arctic Circle where there is at least one day a year where the sun does not rise, and one where it does 1025 * not set, a <code>null</code> will be returned. See detailed explanation on top of the 1026 * {@link AstronomicalCalendar} documentation. 1027 */ 1028 public Instant getMinchaKetanaGRA() { 1029 return getMinchaKetana(getSunriseBasedOnElevationSetting(), getSunsetBasedOnElevationSetting(), true); 1030 } 1031 1032 /** 1033 * A generic method for calculating <em>plag hamincha</em> (the earliest time that Shabbos can be started) that is 1034 * 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 1035 * the day passed to the method. 1036 * The time from the start of day to the end of day are divided into 12 <em>shaos zmaniyos</em> (temporal hours), and 1037 * <em>plag hamincha</em> is calculated as 10.75 of those <em>shaos zmaniyos</em> after the beginning of the day. As an 1038 * example, passing {@link #getSunrise() sunrise} and {@link #getSunset() sunset} or {@link #getSeaLevelSunrise() sea level 1039 * sunrise} and {@link #getSeaLevelSunset() sea level sunset} (depending on the {@link #isUseElevation()} elevation 1040 * setting) to this method will return <em>plag mincha</em> according to the opinion of the 1041 * <a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a>. This method's synchronous parameter indicates if the start 1042 * and end of day for the calculation are synchronous, having the same offset. This is typically the case, but some 1043 * <em>zmanim</em> calculations are based on a start and end at different offsets from the real start and end of the day, 1044 * such as starting the day at <em>alos</em> and an ending it at <em>tzais Geonim</em> or some other variant. If the day 1045 * is not synchronous a {@link #getHalfDayBasedZman(Instant, Instant, double) half-day based calculations} will be bypassed. It 1046 * would be illogical to use a half-day based calculation that start/end at <em>chatzos</em> when the two "halves" of the 1047 * day are not equal, and the halfway point between them is not at <em>chatzos</em>. 1048 * 1049 * @param startOfDay the start of day for calculating <em>plag hamincha</em>. This can be sunrise or any <em>alos</em> passed to 1050 * this method. 1051 * @param endOfDay the end of day for calculating <em>plag hamincha</em>. This can be sunset or any <em>tzais</em> passed to 1052 * this method. 1053 * @param synchronous If the <em>zman</em> has a synchronous start and end of the day. If this is <code>false</code>, using a 1054 * {@link #isUseAstronomicalChatzosForOtherZmanim()} makes no sense and will be ignored even if set to true, since by 1055 * definition <em>chatzos</em> will not be the middle of the day for the <em>zman</em>. 1056 * @return the <code>Instant</code> of the time of <em>plag hamincha</em> based on the start and end of day times 1057 * passed to this method. If the calculation can't be computed such as in the Arctic Circle where there is 1058 * at least one day a year where the sun does not rise, and one where it does not set, a <code>null</code> 1059 * will be returned. See detailed explanation on top of the {@link AstronomicalCalendar} documentation. 1060 */ 1061 public Instant getPlagHamincha(Instant startOfDay, Instant endOfDay, boolean synchronous) { 1062 if (isUseAstronomicalChatzosForOtherZmanim() && synchronous) { 1063 return getHalfDayBasedZman(getChatzosHayom(), endOfDay, 4.75); 1064 } else { 1065 return getShaahZmanisBasedZman(startOfDay, endOfDay, 10.75); 1066 } 1067 } 1068 1069 /** 1070 * A generic method for calculating <em>plag hamincha</em> that calls {@link #getPlagHamincha(Instant, Instant, boolean)} passing 1071 * <code>false</code> to the synchronous parameter since there is no way to know if the start and end of the day are synchronous. 1072 * Passing true when they are not synchronous is too much of a risk. See information on that method for more details. 1073 * @param startOfDay the start of day for calculating <em>plag hamincha</em>. This can be sunrise or any <em>alos</em> passed to 1074 * this method. 1075 * @param endOfDay the end of day for calculating <em>plag hamincha</em>. This can be sunset or any <em>tzais</em> passed to this 1076 * method. 1077 * @return the <code>Instant</code> of the time of <em>plag hamincha</em> based on the start and end of day times 1078 * passed to this method. If the calculation can't be computed such as in the Arctic Circle where there is 1079 * at least one day a year where the sun does not rise, and one where it does not set, a <code>null</code> 1080 * will be returned. See detailed explanation on top of the {@link AstronomicalCalendar} documentation. 1081 * @see #getPlagHamincha(Instant, Instant, boolean) 1082 */ 1083 public Instant getPlagHamincha(Instant startOfDay, Instant endOfDay) { 1084 return getPlagHamincha(startOfDay, endOfDay, false); 1085 } 1086 1087 /** 1088 * This method returns <em>plag hamincha</em>, that is 10.75 * {@link #getShaahZmanisGRA() <em>shaos zmaniyos</em>} 1089 * (solar hours) after {@link #getSunrise() sunrise} or {@link #getSeaLevelSunrise() sea level sunrise} (depending on 1090 * the {@link #isUseElevation()} setting), according to the <a href="https://en.wikipedia.org/wiki/Vilna_Gaon" 1091 * >GRA</a>. <em>Plag hamincha</em> is the earliest time that <em>Shabbos</em> can be started. 1092 * The day is calculated from {@link #getSeaLevelSunrise() sea level sunrise} to {@link #getSeaLevelSunset() sea level 1093 * sunset} or {@link #getSunrise() sunrise} to {@link #getSunset() sunset} (depending on the {@link #isUseElevation()} 1094 * 1095 * @see #getPlagHamincha(Instant, Instant, boolean) 1096 * @see #getPlagHamincha(Instant, Instant) 1097 * @see ComprehensiveZmanimCalendar#getPlagHaminchaBaalHatanya() 1098 * @return the <code>Instant</code> of the time of <em>plag hamincha</em>. If the calculation can't be computed such as 1099 * in the Arctic Circle where there is at least one day a year where the sun does not rise, and one where it 1100 * does not set, a <code>null</code> will be returned. See detailed explanation on top of the 1101 * {@link AstronomicalCalendar} documentation. 1102 */ 1103 public Instant getPlagHaminchaGRA() { 1104 return getPlagHamincha(getSunriseBasedOnElevationSetting(), getSunsetBasedOnElevationSetting(), true); 1105 } 1106 1107 /** 1108 * A method that returns a <em>shaah zmanis</em> ({@link #getTemporalHour(Instant, Instant) temporal hour}) according to 1109 * the opinion of the <a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a>. This calculation divides the day 1110 * based on the opinion of the <em>GRA</em> that the day runs from {@link #getSeaLevelSunrise() sea level sunrise} to 1111 * {@link #getSeaLevelSunset() sea level sunset} or {@link #getSunrise() sunrise} to {@link #getSunset() sunset} (depending 1112 * on the {@link #isUseElevation()} setting). The day is split into 12 equal parts with each one being a <em>shaah zmanis</em>. 1113 * This method is similar to {@link #getTemporalHour()}, but can account for elevation. 1114 * 1115 * @return the <code>Duration</code> of a <em>shaah zmanis</em> calculated from sunrise to sunset. If the calculation can't be 1116 * computed such as in the Arctic Circle where there is at least one day a year where the sun does not rise, and one 1117 * where it does not set, a <code>null</code> will be returned. See detailed explanation on top of the 1118 * {@link AstronomicalCalendar} documentation. 1119 * @see #getTemporalHour(Instant, Instant) 1120 * @see #getSeaLevelSunrise() 1121 * @see #getSeaLevelSunset() 1122 * @see ComprehensiveZmanimCalendar#getShaahZmanisBaalHatanya() 1123 */ 1124 public Duration getShaahZmanisGRA() { 1125 return getTemporalHour(getSunriseBasedOnElevationSetting(), getSunsetBasedOnElevationSetting()); 1126 } 1127 1128 /** 1129 * A utility method to return <em>alos</em> (dawn) or <em>tzais</em> (dusk) based on a fractional day offset. As an 1130 * example passing 1.5 to this method as done in the {@link ComprehensiveZmanimCalendar#getTzais90Zmanis()} will return 1131 * the time 90 minutes <em>zmaniyos</em> after {@link #getSunsetBasedOnElevationSetting()}, a <em>zman</em> known as 1132 * the <em>achtel zman</em> or 1/8th of the length of the day (12 * 60 = 720-minute day / 8 = 90 or 1.5 hours 1133 * <em>zmaniyos</em>) after sunset. 1134 * @param hours the number of <em>shaos zmaniyos</em> (temporal hours) before sunrise or after sunset that defines dawn 1135 * or dusk. If a negative number is passed in, it will return the time of <em>alos</em> (dawn) (subtracting the 1136 * time from sunrise) and if a positive number is passed in, it will return the time of <em>tzais</em> (dusk) 1137 * (adding the time to sunset). If 0 is passed in, a <code>null</code> will be returned (since we can't tell if it 1138 * is sunrise or sunset based). 1139 * @return the <code>Instant</code> representing the time. If the calculation can't be computed such as in the Arctic 1140 * Circle where there is at least one day a year where the sun does not rise, and one where it does not set, 1141 * a <code>null</code> will be returned. See detailed explanation on top of the {@link AstronomicalCalendar} 1142 * documentation. A <code>null</code> will also be returned if 0 is passed in, since we can't tell if it is a 1143 * sunrise or sunset based <em>zman</em>. 1144 * @see <a href="{@docRoot}/search.html?q=ComprehensiveZmanimCalendar%20Zmanis()">ComprehensiveZmanimCalendar...Zmanis()</a> 1145 * based <em>zmanim</em>. 1146 */ 1147 public Instant getZmanisBasedOffset(double hours) { 1148 Duration shaahZmanis = getShaahZmanisGRA(); 1149 if (shaahZmanis == null || hours == 0) { 1150 return null; 1151 } 1152 1153 long totalNanos = (long) (shaahZmanis.toNanos() * hours); 1154 Duration offsetDuration = Duration.ofNanos(totalNanos); 1155 1156 if (hours > 0) { 1157 return getTimeOffset(getSunsetBasedOnElevationSetting(), offsetDuration); 1158 } else { 1159 return getTimeOffset(getSunriseBasedOnElevationSetting(), offsetDuration); 1160 } 1161 } 1162 1163 /** 1164 * A method that returns a <em>shaah zmanis</em> (temporal hour) according to the opinion of the <em><a href= 1165 * "https://en.wikipedia.org/wiki/Avraham_Gombiner">Magen Avraham (MGA)</a></em> based on a 72-minute <em>alos</em> 1166 * and <em>tzais</em>. This calculation divides the day that runs from dawn to dusk (for <em>sof zman krias shema</em> and 1167 * <em>tfila</em>). Dawn for this calculation is 72 minutes before {@link #getSunrise() sunrise} or {@link #getSeaLevelSunrise() 1168 * sea level sunrise} (depending on the {@link #isUseElevation()} elevation setting) and dusk is 72 minutes after {@link 1169 * getSunset() sunset} or {@link #getSeaLevelSunset() sea level sunset} (depending on the {@link #isUseElevation()} elevation 1170 * setting). This day is split into 12 equal parts with each part being a <em>shaah zmanis</em>. Alternate methods of calculating 1171 * a <em>shaah zmanis</em> according to the Magen Avraham (MGA) are available in the subclass {@link ComprehensiveZmanimCalendar}. 1172 * 1173 * @return the <code>Duration</code> of a <em>shaah zmanis</em>. If the calculation can't be computed 1174 * such as in the Arctic Circle where there is at least one day a year where the sun does not rise, and one 1175 * where it does not set, a <code>null</code> will be returned. See detailed explanation on top of the 1176 * {@link AstronomicalCalendar} documentation. 1177 */ 1178 public Duration getShaahZmanis72Minutes() { 1179 return getTemporalHour(getAlos72Minutes(), getTzais72Minutes()); 1180 } 1181 1182 /** 1183 * Default constructor will set a default {@link GeoLocation#GeoLocation()}, a default 1184 * {@link AstronomicalCalculator#getDefault() AstronomicalCalculator} and default the calendar to the current date. 1185 * 1186 * @see AstronomicalCalendar#AstronomicalCalendar() 1187 */ 1188 public ZmanimCalendar() { 1189 super(); 1190 } 1191 1192 /** 1193 * A constructor that takes a {@link GeoLocation} as a parameter. 1194 * 1195 * @param location the location 1196 */ 1197 public ZmanimCalendar(GeoLocation location) { 1198 super(location); 1199 } 1200 1201 /** 1202 * A method to get the offset in minutes before {@link #getSeaLevelSunset() sea level sunset} which 1203 * is used in calculating candle lighting time. The default time used is 18 minutes before sea level sunset. Some 1204 * calendars use 15 minutes, while the custom in Jerusalem is to use a 40-minute offset. Please check the local custom 1205 * for candle lighting time. 1206 * 1207 * @return Returns the currently set candle lighting offset in minutes. 1208 * @see #getCandleLighting() 1209 * @see #setCandleLightingOffset(double) 1210 */ 1211 public double getCandleLightingOffset() { 1212 return candleLightingOffset; 1213 } 1214 1215 /** 1216 * A method to set the offset in minutes before {@link #getSeaLevelSunset() sea level sunset} that is 1217 * used in calculating candle lighting time. The default time used is 18 minutes before sunset. Some calendars use 15 1218 * minutes, while the custom in Jerusalem is to use a 40-minute offset. 1219 * 1220 * @param candleLightingOffset The candle lighting offset to set in minutes. 1221 * @see #getCandleLighting() 1222 * @see #getCandleLightingOffset() 1223 */ 1224 public void setCandleLightingOffset(double candleLightingOffset) { 1225 this.candleLightingOffset = candleLightingOffset; 1226 } 1227 1228 /** 1229 * This is a utility method to determine if the current Instant passed in has a <em>melacha</em> (work) prohibition. 1230 * 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 1231 * class. Sunset is the classes current day's {@link #getSunsetBasedOnElevationSetting() elevation adjusted sunset} that observes the 1232 * {@link #isUseElevation()} settings. The {@link JewishCalendar#getInIsrael()} will be set by the inIsrael parameter. 1233 * 1234 * @param currentTime the current time 1235 * @param tzais the time of tzais 1236 * @param inIsrael whether to use Israel holiday scheme or not 1237 * @return true if <em>melacha</em> is prohibited or false if it is not. 1238 * @see JewishCalendar#isAssurBemelacha() 1239 * @see JewishCalendar#hasCandleLighting() 1240 * @see JewishCalendar#setInIsrael(boolean) 1241 */ 1242 public boolean isAssurBemelacha(Instant currentTime, Instant tzais, boolean inIsrael) { 1243 JewishCalendar jewishCalendar = new JewishCalendar(); 1244 jewishCalendar.setGregorianDate(getLocalDate()); 1245 1246 jewishCalendar.setInIsrael(inIsrael); 1247 1248 if (jewishCalendar.hasCandleLighting() && currentTime.compareTo(getSunsetBasedOnElevationSetting()) >= 0) { //erev shabbos, YT or YT sheni and after shkiah 1249 return true; 1250 } 1251 1252 //is shabbos or YT and it is before tzais 1253 return jewishCalendar.isAssurBemelacha() && currentTime.compareTo(tzais) <= 0; 1254 } 1255 1256 /** 1257 * A method that returns the <a href="https://en.wikipedia.org/wiki/Shneur_Zalman_of_Liadi">Baal Hatanya</a>'s <em>netz amiti</em> 1258 * (sunrise) without {@link AstronomicalCalculator#getElevationAdjustment(double)}. This forms the base for the Baal Hatanya's 1259 * dawn-based calculations that are calculated as a dip below the horizon before sunrise. According to the Baal Hatanya, <em>netz 1260 * amiti</em>, or true (halachic) sunrise, is when the top of the sun's disk is visible at an elevation similar to the mountains 1261 * of Eretz Yisrael. The time is calculated as the point at which the center of the sun's disk is 1.583° below the horizon. This 1262 * degree-based calculation can be found in Rabbi Shalom DovBer Levine's commentary on The <a href= 1263 * "https://www.chabadlibrary.org/books/pdf/Seder-Hachnosas-Shabbos.pdf">Baal Hatanya's Seder Hachnasas Shabbos</a>. From an 1264 * elevation of 546 meters, the top of <a href="https://en.wikipedia.org/wiki/Mount_Carmel">Har Hacarmel</a>, the sun disappears 1265 * when it is 1° 35' or 1.583° below the sea level horizon. This in turn is based on the Gemara <a href= 1266 * "https://hebrewbooks.org/shas.aspx?mesechta=2&daf=35">Shabbos 35a</a>. There are other opinions brought down by Rabbi Levine, 1267 * including Rabbi Yosef Yitzchok Feigelstock who calculates it as the degrees below the horizon 4 minutes after sunset in 1268 * Yerushalayim (on the equinox). That is brought down as 1.583°. This is identical to the 1° 35' <em>zman</em> and is probably a 1269 * typo and should be 1.683°. These calculations are used by most <a href="https://en.wikipedia.org/wiki/Chabad">Chabad</a> 1270 * calendars that use the Baal Hatanya's <em>zmanim</em>. See 1271 * <a href="https://www.chabad.org/library/article_cdo/aid/3209349/jewish/About-Our-Zmanim-Calculations.htm">About Our 1272 * <em>Zmanim</em> Calculations @ Chabad.org</a>. 1273 * 1274 * Note: <em>netz amiti</em> is used only for calculating certain <em>zmanim</em>, and is intentionally unpublished. For 1275 * practical purposes, daytime <em>mitzvos</em> like <em>shofar</em> and <em>lulav</em> should not be done until after the 1276 * published time for <em>netz</em> / sunrise. 1277 * 1278 * @return the <code>Instant</code> representing the exact sea level <em>netz amiti</em> (sunrise) time. If the calculation can't 1279 * be computed such as in the Arctic Circle where there is at least one day a year where the sun does not rise, and one 1280 * where it does not set, a <code>null</code> will be returned. See detailed explanation on top of the page. 1281 * @see #getSunrise() 1282 * @see #getSeaLevelSunrise() 1283 * @see #getSunsetBaalHatanya() 1284 * @see #ZENITH_1_POINT_583 1285 */ 1286 protected Instant getSunriseBaalHatanya() { 1287 return getSunriseOffsetByDegrees(ZENITH_1_POINT_583); 1288 } 1289 1290 /** 1291 * A method that returns the <a href="https://en.wikipedia.org/wiki/Shneur_Zalman_of_Liadi">Baal Hatanya</a>'s <em>shkiah 1292 * amiti</em> (sunset) without {@link AstronomicalCalculator#getElevationAdjustment(double) elevation adjustment}. This forms 1293 * the base for the Baal Hatanya's dusk-based calculations that are calculated as a dip below the horizon after sunset. According 1294 * to the Baal Hatanya, <em>shkiah amiti</em>, true (<em>halachic</em>) sunset, is when the top of the sun's disk disappears from 1295 * view at an elevation similar to the mountains of <em>Eretz Yisrael</em>. This time is calculated as the point at which the 1296 * center of the sun's disk is 1.583° below the horizon. 1297 * 1298 * Note: <em>shkiah amiti</em> is used only for calculating certain <em>zmanim</em>, and is intentionally unpublished. For 1299 * practical purposes, all daytime mitzvos should be completed before the published time for <em>shkiah</em> / sunset. For further 1300 * explanation of the calculations used for the Baal Hatanya's <em>zmanim</em> in this library, see <a href= 1301 * "https://www.chabad.org/library/article_cdo/aid/3209349/jewish/About-Our-Zmanim-Calculations.htm">About Our <em>Zmanim</em> 1302 * Calculations @ Chabad.org</a>. 1303 * 1304 * @return the <code>Instant</code> representing the exact sea level <em>shkiah amiti</em> (sunset) time. If the calculation can't 1305 * be computed such as in the Arctic Circle where there is at least one day a year where the sun does not rise, and one 1306 * where it does not set, a <code>null</code> will be returned. See detailed explanation on top of the {@link 1307 * AstronomicalCalendar} documentation. 1308 * @see #getSunset() 1309 * @see #getSeaLevelSunset() 1310 * @see #getSunriseBaalHatanya() 1311 * @see #ZENITH_1_POINT_583 1312 */ 1313 protected Instant getSunsetBaalHatanya() { 1314 return getSunsetOffsetByDegrees(ZENITH_1_POINT_583); 1315 } 1316 1317 /** 1318 * A generic utility method for calculating any <em>shaah zmanis</em> (temporal hour) based <em>zman</em> with the day 1319 * defined as the start and end of day (or night) and the number of <em>shaos zmaniyos</em> passed to the method. This 1320 * simplifies the code in other methods such as {@link #getPlagHamincha(Instant, Instant)} and cuts down on code replication. 1321 * As an example, passing {@link #getSunrise() sunrise} and {@link #getSunset() sunset} or {@link 1322 * getSeaLevelSunrise() sea level sunrise} and {@link #getSeaLevelSunset() sea level sunset} (depending on the {@link 1323 * isUseElevation()} elevation setting) and 10.75 hours to this method will return <em>plag mincha</em> according to the 1324 * opinion of the <a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a>. 1325 * 1326 * @param startOfDay the start of day for calculating the <em>zman</em>. This can be sunrise or any <em>alos</em> passed to 1327 * this method. 1328 * @param endOfDay the end of day for calculating the <em>zman</em>. This can be sunset or any <em>tzais</em> passed to this 1329 * method. 1330 * @param hours the number of <em>shaos zmaniyos</em> (temporal hours) to offset from the start of day 1331 * @return the <code>Instant</code> of the time of <em>zman</em> with the <em>shaos zmaniyos</em> (temporal hours) 1332 * in the day offset from the start of day passed to this method. If the calculation can't be computed such 1333 * as in the Arctic Circle where there is at least one day a year where the sun does not rise, and one 1334 * where it does not set, a <code>null</code> will be returned. See detailed explanation on top of the 1335 * {@link AstronomicalCalendar} documentation. 1336 */ 1337 public Instant getShaahZmanisBasedZman(Instant startOfDay, Instant endOfDay, double hours) { 1338 Duration shaahZmanis = getTemporalHour(startOfDay, endOfDay); 1339 if (shaahZmanis == null) { //defensive, should not be needed 1340 return null; 1341 } 1342 1343 long totalNanos = (long) (shaahZmanis.toNanos() * hours); 1344 return getTimeOffset(startOfDay, Duration.ofNanos(totalNanos)); 1345 } 1346 1347 1348 /** 1349 * A utility method that returns the percentage of a <em>shaah zmanis</em> after sunset (or before sunrise) for a given degree 1350 * offset. For the <a href="https://kosherjava.com/2022/01/12/equinox-vs-equilux-zmanim-calculations/">equilux</a> where there 1351 * is a 720-minute day, passing 16.1° for the location of Jerusalem will return about 1.2. This will work for any location or 1352 * date, but will typically only be of interest at the equinox/equilux to calculate the percentage of a <em>shaah zmanis</em> for 1353 * those who want to use the <a href="https://en.wikipedia.org/wiki/Abraham_Cohen_Pimentel">Minchas Cohen</a> in Ma'amar 2:4 and 1354 * the <a href="https://en.wikipedia.org/wiki/Hezekiah_da_Silva">Pri Chadash</a> who calculate <em>tzais</em> as a percentage of 1355 * the day after sunset. While the Minchas Cohen only applies this to 72 minutes or a 1/10 of the day around the world (based on 1356 * the equinox / equilux in Israel), this method allows calculations for any degree level for any location. 1357 * 1358 * @param degrees the number of degrees below the horizon after sunset. 1359 * @param sunset if <code>true</code> the calculation is in degrees after sunset, otherwise it is degrees before sunrise. 1360 * @return the <code>double</code> percentage of a <em>sha'ah zmanis</em> for a given set of degrees below the astronomical horizon 1361 * for the current calendar. If the calculation can't be computed a {@link Double#MIN_VALUE} will be returned. See detailed 1362 * explanation on top of the page. 1363 */ 1364 public double getPercentOfShaahZmanisFromDegrees(double degrees, boolean sunset) { 1365 Instant seaLevelSunrise = getSeaLevelSunrise(); 1366 Instant seaLevelSunset = getSeaLevelSunset(); 1367 Instant twilight; 1368 if (sunset) { 1369 twilight = getSunsetOffsetByDegrees(GEOMETRIC_ZENITH + degrees); 1370 } else { 1371 twilight = getSunriseOffsetByDegrees(GEOMETRIC_ZENITH + degrees); 1372 } 1373 if (seaLevelSunrise == null || seaLevelSunset == null || twilight == null) { 1374 return Double.MIN_VALUE; 1375 } 1376 double shaahZmanis = (seaLevelSunset.toEpochMilli() - seaLevelSunrise.toEpochMilli()) / 12.0; 1377 long riseSetToTwilight; 1378 if (sunset) { 1379 riseSetToTwilight = twilight.toEpochMilli() - seaLevelSunset.toEpochMilli(); 1380 } else { 1381 riseSetToTwilight = seaLevelSunrise.toEpochMilli() - twilight.toEpochMilli(); 1382 } 1383 return riseSetToTwilight / shaahZmanis; 1384 } 1385 1386 /** 1387 * A utility method to calculate <em>zmanim</em> based on <a href="https://en.wikipedia.org/wiki/Moshe_Feinstein">Rav Moshe 1388 * Feinstein</a> and others as calculated in <a href="https://en.wikipedia.org/wiki/Mesivtha_Tifereth_Jerusalem">MTJ</a>, <a href= 1389 * "https://en.wikipedia.org/wiki/Mesivtha_Tifereth_Jerusalem">Yeshiva of Staten Island</a>, and Camp Yeshiva 1390 * of Staten Island and other calendars. The day is split in two, from <em>alos</em> / sunrise to <em>chatzos</em>, and the 1391 * second half of the day, from <em>chatzos</em> to sunset / <em>tzais</em>. Morning based times are calculated. based on the first 1392 * 6 hours of the day, and afternoon times based on the second half of the day. As an example, passing 0.5, a start of 1393 * <em>chatzos</em> and an end of day as sunset will return the time of <em>mincha gedola</em> GRA as half an hour <em>zmanis</em> 1394 * based on the second half of the day. Some <em>zmanim</em> calculations can be based on subtracting <em>shaos zmaniyos</em> 1395 * from the end of the day, and that is supported by passing a negative hour to this method. 1396 * 1397 * @param startOfHalfDay The start of the half day. This would be <em>alos</em> or sunrise for morning based times such as 1398 * <em>sof zman krias shema</em> and <em>chatzos</em> for afternoon based times such as <em>mincha gedola</em>. 1399 * @param endOfHalfDay The end of the half day. This would be <em>chatzos</em> for morning based times such as <em>sof zman 1400 * krias shema</em> and sunset or <em>tzais</em> for afternoon based times such as <em>mincha gedola</em>. 1401 * @param hours The number of <em>shaos zmaniyos</em> (hours) to offset the beginning of the first or second half of the day. For 1402 * example, 3 for <em>sof zman Shma</em>, 0.5 for <em>mincha gedola</em> (half an hour after <em>chatzos</em>) and 4.75 1403 * for <em>plag hamincha</em>. If the number of hours is negative, it will subtract the number of <em>shaos zmaniyos</em> 1404 * from the end of the day. 1405 * @return the <code>Instant</code> of <em>zman</em> based on calculation of the first or second half of the day. If the 1406 * calculation can't be computed such as in the Arctic Circle where there is at least one day a year where the 1407 * sun does not rise, and one where it does not set, a <code>null</code> will be returned. See detailed explanation 1408 * on top of the {@link AstronomicalCalendar} documentation. 1409 * @see ComprehensiveZmanimCalendar#getFixedLocalChatzosHayom() 1410 */ 1411 public Instant getHalfDayBasedZman(Instant startOfHalfDay, Instant endOfHalfDay, double hours) { 1412 if (startOfHalfDay == null || endOfHalfDay == null) { 1413 return null; 1414 } 1415 Duration shaahZmanis = getHalfDayBasedShaahZmanis(startOfHalfDay, endOfHalfDay); 1416 if (shaahZmanis == null) { //defensive, should not be needed 1417 return null; 1418 } 1419 1420 long totalNanos = (long)(shaahZmanis.toNanos() * hours); 1421 Duration offsetDuration = Duration.ofNanos(totalNanos); 1422 1423 if (hours >= 0) { // forward from start of day 1424 return getTimeOffset(startOfHalfDay, offsetDuration); 1425 } else { // subtract from end of day 1426 return getTimeOffset(endOfHalfDay, offsetDuration); 1427 } 1428 } 1429 1430 /** 1431 * A utility method to calculate the length of a <em>sha'ah zmanis</em> based on 1/6 of a 6-hour day. 1432 * @param startOfHalfDay The start of the half-day. This would be <em>alos</em> or sunrise for the first half of the day, or 1433 * <em>chatzos</em> for the second half of the day. 1434 * @param endOfHalfDay The end of the half-day. This would be <em>chatzos</em> for the first half of the day, or sunset or 1435 * <em>tzais</em> for the second half of the day. 1436 * @return The <code>Duration</code> of a <em>shaah zmanis</em> based on 1/6 of a half-day. If the calculation can't be computed 1437 * 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 does 1438 * not set, a <code>null</code> will be returned. See detailed explanation on top of the {@link AstronomicalCalendar} 1439 * documentation. 1440 * @see #getHalfDayBasedZman(Instant, Instant, double) 1441 * @see #isUseAstronomicalChatzosForOtherZmanim() 1442 * @todo Consider adjusting various shaah zmanis times to use this. 1443 */ 1444 public Duration getHalfDayBasedShaahZmanis(Instant startOfHalfDay, Instant endOfHalfDay) { 1445 if (startOfHalfDay == null || endOfHalfDay == null) { 1446 return null; 1447 } 1448 return Duration.between(startOfHalfDay, endOfHalfDay).dividedBy(6); 1449 } 1450 1451 /** 1452 * @see java.lang.Object#equals(Object) 1453 */ 1454 public boolean equals(Object object) { 1455 if (this == object) { 1456 return true; 1457 } 1458 if (object == null || getClass() != object.getClass()) { 1459 return false; 1460 } 1461 if (!super.equals(object)) { 1462 return false; 1463 } 1464 ZmanimCalendar that = (ZmanimCalendar) object; 1465 return useElevation == that.useElevation 1466 && useAstronomicalChatzos == that.useAstronomicalChatzos 1467 && useAstronomicalChatzosForOtherZmanim == that.useAstronomicalChatzosForOtherZmanim 1468 && candleLightingOffset == that.candleLightingOffset; 1469 } 1470 1471 /** 1472 * @see java.lang.Object#hashCode() 1473 */ 1474 public int hashCode() { 1475 return Objects.hash(super.hashCode(), useElevation, useAstronomicalChatzos, 1476 useAstronomicalChatzosForOtherZmanim, Double.hashCode(candleLightingOffset)); 1477 } 1478}