diff --git a/src/main/java/com/kosherjava/zmanim/hebrewcalendar/JewishDate.java b/src/main/java/com/kosherjava/zmanim/hebrewcalendar/JewishDate.java
index dd38b1b5..dece8c48 100644
--- a/src/main/java/com/kosherjava/zmanim/hebrewcalendar/JewishDate.java
+++ b/src/main/java/com/kosherjava/zmanim/hebrewcalendar/JewishDate.java
@@ -309,7 +309,7 @@ private static int getLastDayOfGregorianMonth(int year, int month) {
* @return the {@code LocalDate}.
*/
private static LocalDate absDateToDate(int absDate) {
- int year = absDate / 366; // Search forward year by year from approximate year
+ int year = Math.floorDiv(absDate, 366); // Search forward year by year from approximate year
while (absDate >= gregorianDateToAbsDate(year + 1, 1, 1)) {
year++;
}
@@ -347,11 +347,12 @@ private static int gregorianDateToAbsDate(int year, int month, int dayOfMonth) {
}
int y = year - 1;
+ // Floor division, so that year 0, a leap year, gets its leap day
return (absDate // days this year
+ 365 * y // days in previous years ignoring leap days
- + y / 4 // Julian leap days before this year
- - y / 100 // minus prior century years
- + y / 400); // plus prior years divisible by 400
+ + Math.floorDiv(y, 4) // Julian leap days before this year
+ - Math.floorDiv(y, 100) // minus prior century years
+ + Math.floorDiv(y, 400)); // plus prior years divisible by 400
}
/**
@@ -670,13 +671,11 @@ public int getDaysInJewishMonth() {
}
/**
- * Computes and sets the Jewish date fields based on the provided absolute (Gregorian) date.
+ * Computes and sets the Jewish date fields based on the provided absolute (Gregorian) date. The date may be before
+ * January 1, 0001, as the molad of Teves 3761 is, on December 12, 0000.
* @param gregorianAbsDate the Gregorian absolute date.
*/
private synchronized void setAbsDate(int gregorianAbsDate) {
- if (gregorianAbsDate <= 0) {
- throw new IllegalArgumentException("Dates in the BC era are not supported");
- }
this.gregorianAbsDate = gregorianAbsDate;
// Approximation from below
jewishYear = (gregorianAbsDate - JEWISH_EPOCH) / 366;
@@ -696,8 +695,8 @@ private synchronized void setAbsDate(int gregorianAbsDate) {
// Calculate the day by subtraction
jewishDay = gregorianAbsDate - jewishDateToAbsDate(jewishYear, jewishMonth, 1) + 1;
- // day of week (same calculation as original)
- dayOfWeek = Math.abs(gregorianAbsDate % 7) + 1;
+ // day of week, with floorMod so that a date before January 1, 0001 gets the right day
+ dayOfWeek = Math.floorMod(gregorianAbsDate, 7) + 1;
}
/**
@@ -855,6 +854,9 @@ public void setGregorianDate(ZonedDateTime zonedDateTime) {
*/
public void setGregorianDate(LocalDate localDate) {
int absDate = gregorianDateToAbsDate(localDate.getYear(), localDate.getMonth().getValue(), localDate.getDayOfMonth());
+ if (absDate <= 0) {
+ throw new IllegalArgumentException("Dates in the BC era are not supported");
+ }
setAbsDate(absDate); // convert to Jewish date
}
@@ -975,7 +977,11 @@ public void minusDays(int days){
if (days < 1) {
throw new IllegalArgumentException("The number of days to subtract must be greater than zero.");
}
- setAbsDate(getAbsDate() - days);
+ int absDate = getAbsDate() - days;
+ if (absDate <= 0) {
+ throw new IllegalArgumentException("Dates in the BC era are not supported");
+ }
+ setAbsDate(absDate);
}
diff --git a/src/main/java/com/kosherjava/zmanim/hebrewcalendar/YerushalmiYomiCalculator.java b/src/main/java/com/kosherjava/zmanim/hebrewcalendar/YerushalmiYomiCalculator.java
index f816ef2e..ac3c06a2 100644
--- a/src/main/java/com/kosherjava/zmanim/hebrewcalendar/YerushalmiYomiCalculator.java
+++ b/src/main/java/com/kosherjava/zmanim/hebrewcalendar/YerushalmiYomiCalculator.java
@@ -149,14 +149,15 @@ private static int getNumOfSpecialDays(LocalDate start, LocalDate end) {
/**
- * Checks if a date is after start and on or before end.
+ * Checks if a date is on or after start and on or before end. A cycle can start on, or be extended to start
+ * on, Yom Kippur or Tisha B'Av, so the start day is counted.
* @param start the start ZonedDateTime
* @param date the ZonedDateTime to check
* @param end the end ZonedDateTime
* @return if the date is between the two dates
*/
private static boolean isBetween(LocalDate start, LocalDate date, LocalDate end) {
- return start.isBefore(date) && !end.isBefore(date);
+ return !date.isBefore(start) && !end.isBefore(date);
}
/**
diff --git a/src/test/java/com/kosherjava/zmanim/hebrewcalendar/UT_JewishDateNavigation.java b/src/test/java/com/kosherjava/zmanim/hebrewcalendar/UT_JewishDateNavigation.java
index aad45602..7141ec80 100644
--- a/src/test/java/com/kosherjava/zmanim/hebrewcalendar/UT_JewishDateNavigation.java
+++ b/src/test/java/com/kosherjava/zmanim/hebrewcalendar/UT_JewishDateNavigation.java
@@ -60,5 +60,18 @@ public void addYearsUsesConfiguredAdarMonthWhenMovingToLeapYear() {
Assert.assertEquals(10, adarBeisDate.getJewishDayOfMonth());
}
+ /**
+ * The molad of Teves 3761 is Tuesday 12 December of Gregorian year 0, which is a leap year.
+ */
+ @Test
+ public void moladInGregorianYear0() {
+ JewishDate molad = new JewishDate(3761, JewishDate.TEVES, 20).getMolad();
+ Assert.assertEquals(LocalDate.of(0, 12, 12), molad.getLocalDate());
+ Assert.assertEquals(Calendar.TUESDAY, molad.getDayOfWeek());
+ Assert.assertEquals(20, molad.getMoladHours());
+ Assert.assertEquals(7, molad.getMoladMinutes());
+ Assert.assertEquals(2, molad.getMoladChalakim());
+ }
+
} // End of UT_JewishDateNavigation class
diff --git a/src/test/java/com/kosherjava/zmanim/hebrewcalendar/UT_YerushalmiTest.java b/src/test/java/com/kosherjava/zmanim/hebrewcalendar/UT_YerushalmiTest.java
index 60b9d8b7..d605f7c4 100644
--- a/src/test/java/com/kosherjava/zmanim/hebrewcalendar/UT_YerushalmiTest.java
+++ b/src/test/java/com/kosherjava/zmanim/hebrewcalendar/UT_YerushalmiTest.java
@@ -1,5 +1,6 @@
package com.kosherjava.zmanim.hebrewcalendar;
+import java.time.LocalDate;
import java.util.Calendar;
import org.junit.*;
@@ -50,4 +51,33 @@ public void testCorrectSpecialDate() {
System.out.println(hdf.formatDafYomiYerushalmi(jewishCalendar.getDafYomiYerushalmi()));
}
+ /**
+ * The cycle ending in 2172 is extended for Tisha B'Av 5932. It still has every daf, ending with Niddah 13 on
+ * 7 August 2172.
+ */
+ @Test
+ public void testCycleExtendedForTishaBav() {
+ assertDaf(LocalDate.of(2172, 8, 6), 38, 12);
+ assertDaf(LocalDate.of(2172, 8, 7), 38, 13);
+ assertDaf(LocalDate.of(2172, 8, 8), 0, 1);
+ }
+
+ /**
+ * Tisha B'Av 6240 falls the day before the last daf of a cycle. The cycle still has every daf, ending with
+ * Niddah 13 on 16 August 2480, and the next one starts with Berachos 1.
+ */
+ @Test
+ public void testCycleWithTishaBavBeforeItsLastDaf() {
+ assertDaf(LocalDate.of(2480, 8, 14), 38, 12);
+ Assert.assertNull(new JewishCalendar(LocalDate.of(2480, 8, 15)).getDafYomiYerushalmi());
+ assertDaf(LocalDate.of(2480, 8, 16), 38, 13);
+ assertDaf(LocalDate.of(2480, 8, 17), 0, 1);
+ }
+
+ private static void assertDaf(LocalDate date, int masechtaNumber, int daf) {
+ Daf dafYomi = new JewishCalendar(date).getDafYomiYerushalmi();
+ Assert.assertEquals(date.toString(), masechtaNumber, dafYomi.getMasechtaNumber());
+ Assert.assertEquals(date.toString(), daf, dafYomi.getDaf());
+ }
+
}