From 511925f50a4cb5e720da36aa43f40bdacb9271b6 Mon Sep 17 00:00:00 2001 From: Ely Date: Wed, 27 May 2026 01:14:03 -0400 Subject: [PATCH 1/3] add tekufa methods --- .../hebrewcalendar/HebrewDateFormatter.java | 20 +++++++ .../zmanim/hebrewcalendar/JewishCalendar.java | 55 +++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/src/main/java/com/kosherjava/zmanim/hebrewcalendar/HebrewDateFormatter.java b/src/main/java/com/kosherjava/zmanim/hebrewcalendar/HebrewDateFormatter.java index a46e47c1..b67924d7 100644 --- a/src/main/java/com/kosherjava/zmanim/hebrewcalendar/HebrewDateFormatter.java +++ b/src/main/java/com/kosherjava/zmanim/hebrewcalendar/HebrewDateFormatter.java @@ -404,6 +404,8 @@ public void setTransliteratedHolidayList(String[] transliteratedHolidays) { "שושן פורים קטן", "אסרו חג"}; + private final String[] tekufaNames = new String[] {"Tishrei", "Teves", "Nissan", "Tammuz"}; + /** * Formats the Yom Tov (holiday) in Hebrew or transliterated Latin characters. * @@ -1008,4 +1010,22 @@ public String formatSpecialParsha(JewishCalendar jewishCalendar) { JewishCalendar.Parsha specialParsha = jewishCalendar.getSpecialShabbos(); return hebrewFormat ? hebrewParshaMap.get(specialParsha) : transliteratedParshaMap.get(specialParsha); } + + /** + * Returns the name of the upcoming tekufa/season. + * @return the name of the upcoming tekufa/season, which could be: "Tishrei", "Teves", "Nissan", "Tammuz" + */ + public String getTekufaName(JewishCalendar jewishCalendar) { + double INITIAL_TEKUFA_OFFSET = 12.625; // the number of days Tekufas Tishrei occurs before JEWISH_EPOCH + double days = JewishDate.getJewishCalendarElapsedDays(jewishCalendar.getJewishYear()) + jewishCalendar.getDaysSinceStartOfJewishYear() + INITIAL_TEKUFA_OFFSET - 1; // total days since first Tekufas Tishrei event + + double solarDaysElapsed = days % 365.25; // total days elapsed since start of solar year + int currentTekufaNumber = (int) (solarDaysElapsed / 91.3125); // the current quarter of the solar year + double tekufaDaysElapsed = solarDaysElapsed % 91.3125; // the number of days that have passed since a tekufa event + if (tekufaDaysElapsed > 0 && tekufaDaysElapsed <= 1) { // if the tekufa happens in the upcoming 24 hours + return tekufaNames[currentTekufaNumber];//0 for Tishrei, 1 for Tevet, 2, for Nissan, 3 for Tammuz + } else { + return ""; + } + } } diff --git a/src/main/java/com/kosherjava/zmanim/hebrewcalendar/JewishCalendar.java b/src/main/java/com/kosherjava/zmanim/hebrewcalendar/JewishCalendar.java index 2d0458bf..9740ece7 100644 --- a/src/main/java/com/kosherjava/zmanim/hebrewcalendar/JewishCalendar.java +++ b/src/main/java/com/kosherjava/zmanim/hebrewcalendar/JewishCalendar.java @@ -1379,6 +1379,61 @@ public int getTekufasTishreiElapsedDays() { double solar = (getJewishYear() - 1) * 365.25; return (int) Math.floor(days - solar); } + + /** + * Returns a Double that represents the hours for when the Tekufa (season) changes. There are 4 tekufas + * a year: Nissan/Spring, Tammuz/Summer, Tishri/Fall, and Tevet/Winter. This is calculation is according to Shmuel + * in Eruvin 56a, which is a more rounded up version of Rav Adda's calculation. The Rama writes in Yoreh De'ah 116:5 + * writes that one should not drink water during the tekufa change. + * + * @return the number of hours into the hebrew day that the tekufa (season) change takes place, or null if the + * tekufa does not occur on current day. For example: 19.5 would mean that the tekufa occurs 19 hours and a half into + * the hebrew date, or 13 and a half hours (-6 hours) into the Gregorian date. + */ + public Double getTekufa() { + double INITIAL_TEKUFA_OFFSET = 12.625; // the number of days Tekufas Tishrei occurs before JEWISH_EPOCH + + double days = getJewishCalendarElapsedDays(getJewishYear()) + getDaysSinceStartOfJewishYear() + INITIAL_TEKUFA_OFFSET - 1; // total days since first Tekufas Tishrei event + + double solarDaysElapsed = days % 365.25; // total days elapsed since start of solar year + double tekufaDaysElapsed = solarDaysElapsed % 91.3125; // the number of days that have passed since a tekufa event + if (tekufaDaysElapsed > 0 && tekufaDaysElapsed <= 1) { // if the tekufa happens in the upcoming 24 hours + return ((1.0 - tekufaDaysElapsed) * 24.0) % 24;// rationalize the tekufa event to number of hours since start of jewish day + } else { + return null; + } + } + + /** + * Returns a Instant if the current day has a tekufa (season) change. The Instant will contain the time that the tekufa (season) + * is arriving. If this method is called on a day without a tekufa change, it will return a null. + * The default implementation of this method will return the Tekufa change according to the calculations of Rabbi + * Tulchinsky in his calendar Luach Itim + * Lebinah. However, there is also the opinion of Rabbi Yonah Boron, who says to calculate + * the tekufa based on local midday in Israel which causes a 21-minute difference. There is a third opinion as well + * to use seasonal midday but that is not a generally followed opinion, so it has not been implemented. + * @param shouldMinus21Minutes if true, removes 21 minutes from the time of Rabbi Tulchinsky's tekufa which will + * result to the opinion of Rabbi Yonah Boron. + * @return an Instant with the time that the tekufa (season) changes or a null on a day with no tekufa change. + */ + public Instant getTekufaAsInstant(boolean shouldMinus21Minutes) { + Double hours = getTekufa(); + if (hours == null) { + return null; + } + // The tekufa Date (point in time) must be generated using standard time. Using "Asia/Jerusalem" timezone will result in the time + // being incorrectly off by an hour in the summer due to DST. Proper adjustment for the actual time in DST will be done by the date + // formatter class used to display the Date. + ZoneId yerushalayimStandardTZ = ZoneId.of("GMT+2"); + + hours = hours - 6; // minus 6 hours because the hebrew date starts at sunset which is at 6PM + int minutes = (int) ((hours - hours.intValue()) * 60); + + LocalTime time = LocalTime.of(hours.intValue(), minutes); + ZonedDateTime tekufaZDT = ZonedDateTime.of(getLocalDate(), time, yerushalayimStandardTZ); + + return tekufaZDT.minusMinutes(shouldMinus21Minutes ? 21 : 0).toInstant(); + } /** * Returns true if the current day is Isru Chag. The method returns true for the day following Pesach From 2ca9a9af54945da039c583e51fa3e8902c0c6f7c Mon Sep 17 00:00:00 2001 From: Ely Date: Wed, 27 May 2026 17:18:06 -0400 Subject: [PATCH 2/3] amend javadoc and getTekufaName to formatTekufaName --- .../zmanim/hebrewcalendar/HebrewDateFormatter.java | 8 +++++--- .../kosherjava/zmanim/hebrewcalendar/JewishCalendar.java | 5 +++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/kosherjava/zmanim/hebrewcalendar/HebrewDateFormatter.java b/src/main/java/com/kosherjava/zmanim/hebrewcalendar/HebrewDateFormatter.java index b67924d7..4ab2a30b 100644 --- a/src/main/java/com/kosherjava/zmanim/hebrewcalendar/HebrewDateFormatter.java +++ b/src/main/java/com/kosherjava/zmanim/hebrewcalendar/HebrewDateFormatter.java @@ -1012,10 +1012,12 @@ public String formatSpecialParsha(JewishCalendar jewishCalendar) { } /** - * Returns the name of the upcoming tekufa/season. - * @return the name of the upcoming tekufa/season, which could be: "Tishrei", "Teves", "Nissan", "Tammuz" + * Returns a string if the current day has a tekufa event. The string will contain the name of the tekufa/season that is arriving. + * If this method is called on a day without a tekufa event, it will return an empty string. + * @return a string with the name of the upcoming tekufa/season, which could be: "Tishrei", "Teves", "Nissan", "Tammuz", + * or an empty string on a day without a tekufa event. */ - public String getTekufaName(JewishCalendar jewishCalendar) { + public String formatTekufaName(JewishCalendar jewishCalendar) { double INITIAL_TEKUFA_OFFSET = 12.625; // the number of days Tekufas Tishrei occurs before JEWISH_EPOCH double days = JewishDate.getJewishCalendarElapsedDays(jewishCalendar.getJewishYear()) + jewishCalendar.getDaysSinceStartOfJewishYear() + INITIAL_TEKUFA_OFFSET - 1; // total days since first Tekufas Tishrei event diff --git a/src/main/java/com/kosherjava/zmanim/hebrewcalendar/JewishCalendar.java b/src/main/java/com/kosherjava/zmanim/hebrewcalendar/JewishCalendar.java index 9740ece7..a67fb95a 100644 --- a/src/main/java/com/kosherjava/zmanim/hebrewcalendar/JewishCalendar.java +++ b/src/main/java/com/kosherjava/zmanim/hebrewcalendar/JewishCalendar.java @@ -1382,9 +1382,10 @@ public int getTekufasTishreiElapsedDays() { /** * Returns a Double that represents the hours for when the Tekufa (season) changes. There are 4 tekufas - * a year: Nissan/Spring, Tammuz/Summer, Tishri/Fall, and Tevet/Winter. This is calculation is according to Shmuel + * a year: Nissan/Spring, Tammuz/Summer, Tishri/Fall, and Tevet/Winter. This calculation is according to Shmuel * in Eruvin 56a, which is a more rounded up version of Rav Adda's calculation. The Rama writes in Yoreh De'ah 116:5 - * writes that one should not drink water during the tekufa change. + * that one should not drink water during the tekufa change. Rabbi Ovadia Yosef (Halichot Olam, Chelek 7, Page 183) + * recommends to abstain from drinking water for a range of 1 hour. (30 minutes before and after the tekufa event) * * @return the number of hours into the hebrew day that the tekufa (season) change takes place, or null if the * tekufa does not occur on current day. For example: 19.5 would mean that the tekufa occurs 19 hours and a half into From 0bffabc335251f2f2e7cde8d0a2340994b6c812e Mon Sep 17 00:00:00 2001 From: Ely Date: Wed, 27 May 2026 17:30:20 -0400 Subject: [PATCH 3/3] support hebrew --- .../kosherjava/zmanim/hebrewcalendar/HebrewDateFormatter.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/kosherjava/zmanim/hebrewcalendar/HebrewDateFormatter.java b/src/main/java/com/kosherjava/zmanim/hebrewcalendar/HebrewDateFormatter.java index 4ab2a30b..e4715b2a 100644 --- a/src/main/java/com/kosherjava/zmanim/hebrewcalendar/HebrewDateFormatter.java +++ b/src/main/java/com/kosherjava/zmanim/hebrewcalendar/HebrewDateFormatter.java @@ -406,6 +406,7 @@ public void setTransliteratedHolidayList(String[] transliteratedHolidays) { private final String[] tekufaNames = new String[] {"Tishrei", "Teves", "Nissan", "Tammuz"}; + private final String[] hebrewTekufaNames = new String[] {"תשרי", "טבת", "ניסן", "תמוז"}; /** * Formats the Yom Tov (holiday) in Hebrew or transliterated Latin characters. * @@ -1025,7 +1026,7 @@ public String formatTekufaName(JewishCalendar jewishCalendar) { int currentTekufaNumber = (int) (solarDaysElapsed / 91.3125); // the current quarter of the solar year double tekufaDaysElapsed = solarDaysElapsed % 91.3125; // the number of days that have passed since a tekufa event if (tekufaDaysElapsed > 0 && tekufaDaysElapsed <= 1) { // if the tekufa happens in the upcoming 24 hours - return tekufaNames[currentTekufaNumber];//0 for Tishrei, 1 for Tevet, 2, for Nissan, 3 for Tammuz + return isHebrewFormat() ? "תקופת " + hebrewTekufaNames[currentTekufaNumber] : "Tekufas " + tekufaNames[currentTekufaNumber];//0 for Tishrei, 1 for Tevet, 2, for Nissan, 3 for Tammuz } else { return ""; }