Skip to content

Commit 95199fb

Browse files
authored
Add generic sof zman achilas and biur chametz
These zmanim support half-day based calculations and significantly reduces code duplication in the ComprehensiveZmanimCalendar. This change required moving the previously private Baal Hatanya sunrise and sunset methods, to protected methods in this parent class.
1 parent 8283310 commit 95199fb

1 file changed

Lines changed: 180 additions & 0 deletions

File tree

src/main/java/com/kosherjava/zmanim/ZmanimCalendar.java

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,16 @@ public void setUseAstronomicalChatzosForOtherZmanim(boolean useAstronomicalChatz
251251
* @see ComprehensiveZmanimCalendar#getTzaisGeonim8Point5Degrees()
252252
*/
253253
protected static final double ZENITH_8_POINT_5 = GEOMETRIC_ZENITH + 8.5;
254+
255+
/**
256+
* The zenith of 1.583° below {@link #GEOMETRIC_ZENITH geometric zenith} (90°). This calculation is used for
257+
* calculating <em>netz amiti</em> (sunrise) and <em>shkiah amiti</em> (sunset) based on the opinion of the
258+
* <a href="https://en.wikipedia.org/wiki/Shneur_Zalman_of_Liadi">Baal Hatanya</a>.
259+
*
260+
* @see #getSunriseBaalHatanya()
261+
* @see #getSunsetBaalHatanya()
262+
*/
263+
protected static final double ZENITH_1_POINT_583 = GEOMETRIC_ZENITH + 1.583;
254264

255265
/**
256266
* The default <em>Shabbos</em> candle lighting offset is 18 minutes. This can be changed via the
@@ -600,6 +610,107 @@ public Instant getSofZmanTfila(Instant startOfDay, Instant endOfDay, boolean syn
600610
}
601611
}
602612

613+
614+
/**
615+
* This method returns the latest time for burning <em>chametz</em> on <em>Erev Pesach</em> according to the opinion
616+
* of the <a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a>. This time is 5 hours into the day based on the
617+
* opinion of the <a href="https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a> that the day is calculated from
618+
* sunrise to sunset. This returns the time 5 * {@link #getShaahZmanisGra()} after {@link #getSeaLevelSunrise() sea
619+
* level sunrise}. If it is not <em>erev Pesach</em>, a null will be returned.
620+
* @return the <code>Instant</code> of the latest time for burning <em>chametz</em> on <em>Erev Pesach</em>. If it is not
621+
* <em>erev Pesach</em> or the calculation can't be computed such as in the Arctic Circle where there is at least
622+
* one day a year where the sun does not rise, and one where it does not set, a <code>null</code> will be
623+
* returned. See detailed explanation on top of the {@link AstronomicalCalendar} documentation.
624+
* @see ZmanimCalendar#getShaahZmanisGra()
625+
* @see #getSofZmanBiurChametz(Instant, Instant, boolean)
626+
*/
627+
628+
/**
629+
* A generic method for calculating <em>sof zman biur chametz</em> or the latest time one is allowed burning
630+
* <em>chametz</em> on <em>Erev Pesach</em> that is 5 * <em>shaos zmaniyos</em> (temporal hours) after the start of the
631+
* day, calculated using the start and end of the day passed to this method. If the date is not <em>erev Pesach</em>, a
632+
* null will be returned. The time from the start of day to the end of day is divided into 12 <em>shaos zmaniyos</em>
633+
* (temporal hours), and <em>sof zman biur chametz</em> is calculated as 5 of those <em>shaos zmaniyos</em> after the
634+
* beginning of the day. As an example, passing {@link #getSunrise() sunrise} and {@link #getSunset() sunset} to this
635+
* method will return <em>sof zman biur chametz</em> according to the opinion of the <a href=
636+
* "https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a>. This method's synchronous parameter indicates if the start
637+
* and end of day for the calculation are synchronous, having the same offset. This is typically the case, but some
638+
* <em>zmanim</em> calculations are based on a start and end at different offsets from the real start and end of the day,
639+
* 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
640+
* is not synchronous a {@link #getHalfDayBasedZman(Instant, Instant, double) half-day based calculations} will be bypassed.
641+
* It would be illogical to use a half-day based calculation that start/end at <em>chatzos</em> when the two "halves" of
642+
* the day are not equal, and the halfway point between them is not at <em>chatzos</em>.
643+
*
644+
* @param startOfDay
645+
* the start of day for calculating <em>sof zman biur chametz</em>. This can be sunrise or any <em>alos</em>
646+
* passed to this method.
647+
* @param endOfDay
648+
* the end of day for calculating <em>sof zman biur chametz</em>. This can be sunset or any <em>tzais</em>
649+
* passed to this method.
650+
* @param synchronous
651+
* If the <em>zman</em> has a synchronous start and end of the day. If this is <code>false</code>, using a {@link
652+
* #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 <em>sof zman biur chametz</em> based on the start and end of day times passed
655+
* to this method. If the date is not <em>Erev Pesach</em> or if the calculation can't be computed such as in the
656+
* Arctic Circle where there is at least one day a year where the sun does not rise, and one where it does not set,
657+
* a <code>null</code> will be returned. See detailed explanation on top of the {@link AstronomicalCalendar}
658+
* documentation.
659+
*/
660+
public Instant getSofZmanBiurChametz(Instant startOfDay, Instant endOfDay, boolean synchronous) {
661+
JewishCalendar jewishCalendar = new JewishCalendar(getLocalDate());
662+
if (jewishCalendar.getJewishMonth() == JewishCalendar.NISSAN && jewishCalendar.getJewishDayOfMonth() == 14) {
663+
if (isUseAstronomicalChatzosForOtherZmanim() && synchronous) {
664+
return getHalfDayBasedZman(startOfDay, getChatzos(), 5);
665+
} else {
666+
return getShaahZmanisBasedZman(startOfDay, endOfDay, 5);
667+
}
668+
} else {
669+
return null;
670+
}
671+
}
672+
673+
/**
674+
* A generic method for calculating <em>sof zman achilas chametz</em> or the latest time one is allowed eating
675+
* <em>chametz</em> on <em>Erev Pesach</em> that is 4 * <em>shaos zmaniyos</em> (temporal hours) after the start of the
676+
* day, calculated using the start and end of the day passed to this method. If the date is not <em>erev Pesach</em>, a
677+
* null will be returned. The time from the start of day to the end of day is divided into 12 <em>shaos zmaniyos</em>
678+
* (temporal hours), and <em>sof zman achilas chametz</em> is calculated as 4 of those <em>shaos zmaniyos</em> after the
679+
* beginning of the day. As an example, passing {@link #getSunrise() sunrise} and {@link #getSunset() sunset} to this
680+
* method will return <em>sof zman achilas chametz</em> according to the opinion of the <a href=
681+
* "https://en.wikipedia.org/wiki/Vilna_Gaon">GRA</a>. This method's synchronous parameter indicates if the start
682+
* and end of day for the calculation are synchronous, having the same offset. This is typically the case, but some
683+
* <em>zmanim</em> calculations are based on a start and end at different offsets from the real start and end of the day,
684+
* 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
685+
* is not synchronous a {@link #getHalfDayBasedZman(Instant, Instant, double) half-day based calculations} will be bypassed.
686+
* It would be illogical to use a half-day based calculation that start/end at <em>chatzos</em> when the two "halves" of
687+
* the day are not equal, and the halfway point between them is not at <em>chatzos</em>.
688+
*
689+
* @param startOfDay
690+
* the start of day for calculating <em>sof zman achilas chametz</em>. This can be sunrise or any <em>alos</em>
691+
* passed to this method.
692+
* @param endOfDay
693+
* the end of day for calculating <em>sof zman achilas chametz</em>. This can be sunset or any <em>tzais</em>
694+
* passed to this method.
695+
* @param synchronous
696+
* If the <em>zman</em> has a synchronous start and end of the day. If this is <code>false</code>, using a {@link
697+
* #isUseAstronomicalChatzosForOtherZmanim()} makes no sense and will be ignored even if set to true, since by
698+
* definition <em>chatzos</em> will not be the middle of the day for the <em>zman</em>.
699+
* @return the <code>Instant</code> of the <em>sof zman achilas chametz</em> based on the start and end of day times passed
700+
* to this method. If the date is not <em>Erev Pesach</em> or if the calculation can't be computed such as in the
701+
* Arctic Circle where there is at least one day a year where the sun does not rise, and one where it does not set,
702+
* a <code>null</code> will be returned. See detailed explanation on top of the {@link AstronomicalCalendar}
703+
* documentation.
704+
*/
705+
public Instant getSofZmanAchilasChametz(Instant startOfDay, Instant endOfDay, boolean synchronous) {
706+
JewishCalendar jewishCalendar = new JewishCalendar(getLocalDate());
707+
if (jewishCalendar.getJewishMonth() == JewishCalendar.NISSAN && jewishCalendar.getJewishDayOfMonth() == 14) {
708+
return getSofZmanTfila(startOfDay, endOfDay, synchronous);
709+
} else {
710+
return null;
711+
}
712+
}
713+
603714
/**
604715
* A generic method for calculating the latest <em>zman tfila</em> that calls {@link #getSofZmanTfila(Instant, Instant, boolean)}
605716
* passing <code>false</code> to the synchronous parameter since there is no way to know if the start and end of the day are
@@ -1098,6 +1209,75 @@ public boolean isAssurBemlacha(Instant currentTime, Instant tzais, boolean inIsr
10981209
//is shabbos or YT and it is before tzais
10991210
return jewishCalendar.isAssurBemelacha() && currentTime.compareTo(tzais) <= 0;
11001211
}
1212+
1213+
/**
1214+
* A method that returns the <a href="https://en.wikipedia.org/wiki/Shneur_Zalman_of_Liadi">Baal Hatanya</a>'s
1215+
* <em>netz amiti</em> (sunrise) without {@link AstronomicalCalculator#getElevationAdjustment(double)
1216+
* elevation adjustment}. This forms the base for the Baal Hatanya's dawn-based calculations that are
1217+
* calculated as a dip below the horizon before sunrise.
1218+
*
1219+
* According to the Baal Hatanya, <em>netz amiti</em>, or true (halachic) sunrise, is when the top of the sun's
1220+
* disk is visible at an elevation similar to the mountains of Eretz Yisrael. The time is calculated as the point at which
1221+
* the center of the sun's disk is 1.583&deg; below the horizon. This degree-based calculation can be found in Rabbi Shalom
1222+
* DovBer Levine's commentary on The <a href="https://www.chabadlibrary.org/books/pdf/Seder-Hachnosas-Shabbos.pdf">Baal
1223+
* Hatanya's Seder Hachnasas Shabbos</a>. From an elevation of 546 meters, the top of <a href=
1224+
* "https://en.wikipedia.org/wiki/Mount_Carmel">Har Hacarmel</a>, the sun disappears when it is 1&deg; 35' or 1.583&deg;
1225+
* below the sea level horizon. This in turn is based on the Gemara <a href=
1226+
* "https://hebrewbooks.org/shas.aspx?mesechta=2&daf=35">Shabbos 35a</a>. There are other opinions brought down by
1227+
* Rabbi Levine, including Rabbi Yosef Yitzchok Feigelstock who calculates it as the degrees below the horizon 4 minutes after
1228+
* sunset in Yerushalayim (on the equinox). That is brought down as 1.583&deg;. This is identical to the 1&deg; 35' <em>zman</em>
1229+
* and is probably a typo and should be 1.683&deg;. These calculations are used by most <a href=
1230+
* "https://en.wikipedia.org/wiki/Chabad">Chabad</a> calendars that use the Baal Hatanya's <em>zmanim</em>. See
1231+
* <a href="https://www.chabad.org/library/article_cdo/aid/3209349/jewish/About-Our-Zmanim-Calculations.htm">About Our
1232+
* <em>Zmanim</em> Calculations @ Chabad.org</a>.
1233+
*
1234+
* Note: <em>netz amiti</em> is used only for calculating certain <em>zmanim</em>, and is intentionally unpublished. For
1235+
* practical purposes, daytime <em>mitzvos</em> like <em>shofar</em> and <em>lulav</em> should not be done until after the
1236+
* published time for <em>netz</em> / sunrise.
1237+
*
1238+
* @return the <code>Instant</code> representing the exact sea level <em>netz amiti</em> (sunrise) time. If the calculation can't be
1239+
* computed such as in the Arctic Circle where there is at least one day a year where the sun does not rise, and one
1240+
* where it does not set, a <code>null</code> will be returned. See detailed explanation on top of the page.
1241+
*
1242+
* @see #getSunriseWithElevation()
1243+
* @see #getSeaLevelSunrise()
1244+
* @see #getSunsetBaalHatanya()
1245+
* @see #ZENITH_1_POINT_583
1246+
*/
1247+
protected Instant getSunriseBaalHatanya() {
1248+
return getSunriseOffsetByDegrees(ZENITH_1_POINT_583);
1249+
}
1250+
1251+
/**
1252+
* A method that returns the <a href="https://en.wikipedia.org/wiki/Shneur_Zalman_of_Liadi">Baal Hatanya</a>'s
1253+
* <em>shkiah amiti</em> (sunset) without {@link AstronomicalCalculator#getElevationAdjustment(double)
1254+
* elevation adjustment}. This forms the base for the Baal Hatanya's dusk-based calculations that are calculated
1255+
* as a dip below the horizon after sunset.
1256+
*
1257+
* According to the Baal Hatanya, <em>shkiah amiti</em>, true (<em>halachic</em>) sunset, is when the top of the
1258+
* sun's disk disappears from view at an elevation similar to the mountains of <em>Eretz Yisrael</em>.
1259+
* This time is calculated as the point at which the center of the sun's disk is 1.583 degrees below the horizon.
1260+
*
1261+
* Note: <em>shkiah amiti</em> is used only for calculating certain <em>zmanim</em>, and is intentionally unpublished. For
1262+
* practical purposes, all daytime mitzvos should be completed before the published time for <em>shkiah</em> / sunset.
1263+
*
1264+
* For further explanation of the calculations used for the Baal Hatanya's <em>zmanim</em> in this library, see
1265+
* <a href="https://www.chabad.org/library/article_cdo/aid/3209349/jewish/About-Our-Zmanim-Calculations.htm">About Our
1266+
* <em>Zmanim</em> Calculations @ Chabad.org</a>.
1267+
*
1268+
* @return the <code>Instant</code> representing the exact sea level <em>shkiah amiti</em> (sunset) time. If the calculation
1269+
* can't be computed such as in the Arctic Circle where there is at least one day a year where the sun does not
1270+
* rise, and one where it does not set, a <code>null</code> will be returned. See detailed explanation on top of
1271+
* the {@link AstronomicalCalendar} documentation.
1272+
*
1273+
* @see #getSunsetWithElevation()
1274+
* @see #getSeaLevelSunset()
1275+
* @see #getSunriseBaalHatanya()
1276+
* @see #ZENITH_1_POINT_583
1277+
*/
1278+
protected Instant getSunsetBaalHatanya() {
1279+
return getSunsetOffsetByDegrees(ZENITH_1_POINT_583);
1280+
}
11011281

11021282
/**
11031283
* A generic utility method for calculating any <em>shaah zmanis</em> (temporal hour) based <em>zman</em> with the

0 commit comments

Comments
 (0)