From 45878e64e76b6d16b3edcd48e23cb2fb4e33499a Mon Sep 17 00:00:00 2001 From: noamtu123 Date: Wed, 1 Jul 2026 12:30:57 +0300 Subject: [PATCH 1/5] Add offline Limud Yomi calculators --- .../hebrewcalendar/HebrewDateFormatter.java | 168 +++++++ .../zmanim/hebrewcalendar/JewishCalendar.java | 56 +++ .../KitzurShulchanAruchYomi.java | 27 ++ .../KitzurShulchanAruchYomiCalculator.java | 61 +++ .../zmanim/hebrewcalendar/LimudYomiData.java | 102 ++++ .../zmanim/hebrewcalendar/MishnaYomi.java | 81 ++++ .../hebrewcalendar/MishnaYomiCalculator.java | 58 +++ .../zmanim/hebrewcalendar/RambamYomi.java | 59 +++ .../hebrewcalendar/RambamYomiCalculator.java | 62 +++ .../hebrewcalendar/ShemirasHaLashonYomi.java | 39 ++ .../ShemirasHaLashonYomiCalculator.java | 447 ++++++++++++++++++ .../zmanim/hebrewcalendar/TanachYomi.java | 33 ++ .../hebrewcalendar/TanachYomiCalculator.java | 198 ++++++++ .../zmanim/hebrewcalendar/TehillimYomi.java | 27 ++ .../TehillimYomiCalculator.java | 29 ++ .../LimudYomiCalculatorTest.java | 78 +++ 16 files changed, 1525 insertions(+) create mode 100644 src/main/java/com/kosherjava/zmanim/hebrewcalendar/KitzurShulchanAruchYomi.java create mode 100644 src/main/java/com/kosherjava/zmanim/hebrewcalendar/KitzurShulchanAruchYomiCalculator.java create mode 100644 src/main/java/com/kosherjava/zmanim/hebrewcalendar/LimudYomiData.java create mode 100644 src/main/java/com/kosherjava/zmanim/hebrewcalendar/MishnaYomi.java create mode 100644 src/main/java/com/kosherjava/zmanim/hebrewcalendar/MishnaYomiCalculator.java create mode 100644 src/main/java/com/kosherjava/zmanim/hebrewcalendar/RambamYomi.java create mode 100644 src/main/java/com/kosherjava/zmanim/hebrewcalendar/RambamYomiCalculator.java create mode 100644 src/main/java/com/kosherjava/zmanim/hebrewcalendar/ShemirasHaLashonYomi.java create mode 100644 src/main/java/com/kosherjava/zmanim/hebrewcalendar/ShemirasHaLashonYomiCalculator.java create mode 100644 src/main/java/com/kosherjava/zmanim/hebrewcalendar/TanachYomi.java create mode 100644 src/main/java/com/kosherjava/zmanim/hebrewcalendar/TanachYomiCalculator.java create mode 100644 src/main/java/com/kosherjava/zmanim/hebrewcalendar/TehillimYomi.java create mode 100644 src/main/java/com/kosherjava/zmanim/hebrewcalendar/TehillimYomiCalculator.java create mode 100644 src/test/java/com/kosherjava/zmanim/hebrewcalendar/LimudYomiCalculatorTest.java diff --git a/src/main/java/com/kosherjava/zmanim/hebrewcalendar/HebrewDateFormatter.java b/src/main/java/com/kosherjava/zmanim/hebrewcalendar/HebrewDateFormatter.java index 4e1a7bdb..c91f1815 100644 --- a/src/main/java/com/kosherjava/zmanim/hebrewcalendar/HebrewDateFormatter.java +++ b/src/main/java/com/kosherjava/zmanim/hebrewcalendar/HebrewDateFormatter.java @@ -824,6 +824,174 @@ public String formatDafYomiYerushalmi(Daf daf) { } } + /** + * Formats the Mishna Yomi reading. + * @param mishnaYomi the Mishna Yomi to be formatted. + * @return the formatted Mishna Yomi. + */ + public String formatMishnaYomi(MishnaYomi mishnaYomi) { + String start = (hebrewFormat ? mishnaYomi.getMasechta() + " " + formatHebrewNumber(mishnaYomi.getStartChapter()) + + ": " + formatPlainHebrewNumber(mishnaYomi.getStartMishna()) : mishnaYomi.getMasechtaTransliterated() + " " + + mishnaYomi.getStartChapter() + ":" + mishnaYomi.getStartMishna()); + if (mishnaYomi.getStartMasechtaNumber() == mishnaYomi.getEndMasechtaNumber() + && mishnaYomi.getStartChapter() == mishnaYomi.getEndChapter()) { + return start + "-" + (hebrewFormat ? formatPlainHebrewNumber(mishnaYomi.getEndMishna()) : mishnaYomi.getEndMishna()); + } + return start + "-" + (hebrewFormat ? mishnaYomi.getEndMasechta() + " " + formatHebrewNumber(mishnaYomi.getEndChapter()) + + ": " + formatPlainHebrewNumber(mishnaYomi.getEndMishna()) : mishnaYomi.getEndMasechtaTransliterated() + " " + + mishnaYomi.getEndChapter() + ":" + mishnaYomi.getEndMishna()); + } + + /** + * Formats the daily Rambam reading. + * @param rambamYomi the Rambam Yomi to be formatted. + * @return the formatted Rambam Yomi. + */ + public String formatRambamYomi(RambamYomi rambamYomi) { + if (hebrewFormat) { + if (rambamYomi.getBookNumber() != rambamYomi.getEndBookNumber()) { + return "הלכות " + rambamYomi.getHebrewName() + " פרק " + formatPlainHebrewNumber(rambamYomi.getStartChapter()) + + " - הלכות " + rambamYomi.getEndHebrewName() + " פרק " + formatPlainHebrewNumber(rambamYomi.getEndChapter()); + } + String chapterPrefix = rambamYomi.getStartChapter() == rambamYomi.getEndChapter() ? " פרק " : " פרקים "; + String chapters = formatPlainHebrewNumber(rambamYomi.getStartChapter()); + if (rambamYomi.getStartChapter() != rambamYomi.getEndChapter()) { + chapters += "-" + formatPlainHebrewNumber(rambamYomi.getEndChapter()); + } + return "הלכות " + rambamYomi.getHebrewName() + chapterPrefix + chapters; + } + if (rambamYomi.getBookNumber() != rambamYomi.getEndBookNumber()) { + return rambamYomi.getName() + " " + rambamYomi.getStartChapter() + "-" + rambamYomi.getEndName() + " " + + rambamYomi.getEndChapter(); + } + return rambamYomi.getName() + " " + rambamYomi.getStartChapter() + + (rambamYomi.getStartChapter() == rambamYomi.getEndChapter() ? "" : "-" + rambamYomi.getEndChapter()); + } + + /** + * Formats the daily Tehillim reading. + * @param tehillimYomi the daily Tehillim to be formatted. + * @return the formatted daily Tehillim. + */ + public String formatDailyTehillim(TehillimYomi tehillimYomi) { + if (hebrewFormat) { + return "תהילים " + formatHebrewNumber(tehillimYomi.getStartChapter()) + + (tehillimYomi.getStartChapter() == tehillimYomi.getEndChapter() ? "" : "-" + formatHebrewNumber(tehillimYomi.getEndChapter())); + } + return "Psalms " + tehillimYomi.getStartChapter() + + (tehillimYomi.getStartChapter() == tehillimYomi.getEndChapter() ? "" : "-" + tehillimYomi.getEndChapter()); + } + + /** + * Formats the Tanach Yomi reading. + * @param tanachYomi the Tanach Yomi to be formatted. + * @return the formatted Tanach Yomi. + */ + public String formatTanachYomi(TanachYomi tanachYomi) { + if (tanachYomi == null) { + return ""; + } + if (hebrewFormat) { + String[] parts = tanachYomi.getSeder().split("\\."); + String seder = " ס׳ " + formatHebrewNumber(Integer.parseInt(parts[0])); + if (parts.length> 1) { + seder += " " + formatHebrewNumber(Integer.parseInt(parts[1])); + } + return tanachYomi.getHebrewBook() + seder; + } + return tanachYomi.getBook() + " Seder " + tanachYomi.getSeder(); + } + + /** + * Formats the Kitzur Shulchan Aruch Yomi reading. + * @param kitzurYomi the Kitzur Shulchan Aruch Yomi to be formatted. + * @return the formatted Kitzur Shulchan Aruch Yomi. + */ + public String formatKitzurShulchanAruchYomi(KitzurShulchanAruchYomi kitzurYomi) { + if (kitzurYomi == null) { + return ""; + } + if (kitzurYomi.getStart().equals(kitzurYomi.getEnd())) { + return formatKitzurRef(kitzurYomi.getStart()); + } + String[] start = kitzurYomi.getStart().split(":"); + String[] end = kitzurYomi.getEnd().split(":"); + if (start.length> 1 && end.length> 1 && start[0].equals(end[0])) { + return formatKitzurRef(kitzurYomi.getStart()) + "-" + (hebrewFormat ? formatPlainHebrewToken(end[1]) : end[1]); + } + return formatKitzurRef(kitzurYomi.getStart()) + (hebrewFormat ? " - " : "-") + formatKitzurRef(kitzurYomi.getEnd()); + } + + /** + * Formats the Shemiras HaLashon Yomi reading. + * @param shemirasYomi the Shemiras HaLashon Yomi to be formatted. + * @return the formatted Shemiras HaLashon Yomi. + */ + public String formatShemirasHaLashonYomi(ShemirasHaLashonYomi shemirasYomi) { + if (shemirasYomi == null) { + return ""; + } + if (hebrewFormat) { + return formatShemirasRef(shemirasYomi.getStart()) + (shemirasYomi.getStart().equals(shemirasYomi.getEnd()) ? "" + : (sameShemirasKlal(shemirasYomi.getStart(), shemirasYomi.getEnd()) ? "-" + shemirasHalacha(shemirasYomi.getEnd()) + : " - " + formatShemirasRef(shemirasYomi.getEnd()))); + } + String prefix = "Book " + (shemirasYomi.getBook() == 1 ? "I" : "II") + " "; + return prefix + shemirasYomi.getStart() + (shemirasYomi.getStart().equals(shemirasYomi.getEnd()) ? "" : "-" + shemirasYomi.getEnd()); + } + + private String formatKitzurRef(String ref) { + String[] parts = ref.split(":"); + if (hebrewFormat) { + return formatHebrewToken(parts[0]) + (parts.length> 1 ? ": " + formatPlainHebrewToken(parts[1]) : ""); + } + return ref; + } + + private String formatShemirasRef(String ref) { + String[] parts = ref.split("\\."); + return "כלל " + formatHebrewNumber(Integer.parseInt(parts[0])) + " " + (parts.length> 1 ? formatPlainHebrewToken(parts[1]) : ""); + } + + private boolean sameShemirasKlal(String start, String end) { + return start.split("\\.")[0].equals(end.split("\\.")[0]); + } + + private String shemirasHalacha(String ref) { + String[] parts = ref.split("\\."); + return parts.length> 1 ? formatPlainHebrewToken(parts[1]) : ""; + } + + private String formatHebrewToken(String token) { + if ("E".equals(token)) { + return "סוף"; + } + if ("Shmita".equals(token)) { + return "שמיטה"; + } + if ("Klalim".equals(token)) { + return "כללים"; + } + return formatHebrewNumber(Integer.parseInt(token)); + } + + private String formatPlainHebrewToken(String token) { + if ("E".equals(token)) { + return "סוף"; + } + if ("Shmita".equals(token)) { + return "שמיטה"; + } + if ("Klalim".equals(token)) { + return "כללים"; + } + return formatPlainHebrewNumber(Integer.parseInt(token)); + } + + private String formatPlainHebrewNumber(int number) { + return formatHebrewNumber(number).replace(GERESH, "").replace(GERSHAYIM, ""); + } + /** * Returns a Hebrew formatted string of a number. The method can calculate from 0 to 9999. * * @author © Eliyahu Hershfeld 2011 - 2026 */ diff --git a/src/test/java/com/kosherjava/zmanim/hebrewcalendar/LimudYomiCalculatorTest.java b/src/test/java/com/kosherjava/zmanim/hebrewcalendar/LimudYomiCalculatorTest.java index 59c17dcb..f98bdc82 100644 --- a/src/test/java/com/kosherjava/zmanim/hebrewcalendar/LimudYomiCalculatorTest.java +++ b/src/test/java/com/kosherjava/zmanim/hebrewcalendar/LimudYomiCalculatorTest.java @@ -28,6 +28,21 @@ public void testRambamYomiOneChapter() { "הלכות שבת פרק יז", hebrewFormatter.formatRambamYomi(calendar.getRambamYomi())); } + @Test + public void testRambamYomiIntroAndSpecialChapters() { + JewishCalendar calendar = new JewishCalendar(LocalDate.of(1984, 4, 29)); + Assert.assertEquals( + "Transmission of the Oral Law 1-21", formatter.formatRambamYomi(calendar.getRambamYomi())); + Assert.assertEquals( + "מסירת תורה שבעל פה פרק א-כא", hebrewFormatter.formatRambamYomi(calendar.getRambamYomi())); + + calendar = new JewishCalendar(LocalDate.of(2023, 8, 8)); + Assert.assertEquals( + "The Order of Prayer 4-5", formatter.formatRambamYomi(calendar.getRambamYomi())); + Assert.assertEquals( + "סדר התפילה פרקים ד-ה", hebrewFormatter.formatRambamYomi(calendar.getRambamYomi())); + } + @Test public void testRambamYomiThreeChapters() { JewishCalendar calendar = new JewishCalendar(LocalDate.of(2024, 7, 29)); @@ -38,6 +53,25 @@ public void testRambamYomiThreeChapters() { hebrewFormatter.formatRambamYomi(calendar.getRambamYomi3Chapters())); } + @Test + public void testRambamYomiThreeChapterSpecialCases() { + JewishCalendar calendar = new JewishCalendar(LocalDate.of(1984, 4, 29)); + Assert.assertEquals( + "Transmission of the Oral Law 1-45", + formatter.formatRambamYomi(calendar.getRambamYomi3Chapters())); + Assert.assertEquals( + "מסירת תורה שבעל פה פרקים א-מה", + hebrewFormatter.formatRambamYomi(calendar.getRambamYomi3Chapters())); + + calendar = new JewishCalendar(LocalDate.of(2020, 9, 3)); + Assert.assertEquals( + "Leavened and Unleavened Bread 8-9, Shofar, Sukkah and Lulav 1-2", + formatter.formatRambamYomi(calendar.getRambamYomi3Chapters())); + Assert.assertEquals( + "הלכות חמץ ומצה פרקים ח-ט, הלכות שופר וסוכה ולולב פרקים א-ב", + hebrewFormatter.formatRambamYomi(calendar.getRambamYomi3Chapters())); + } + @Test public void testDailyTehillim() { JewishCalendar calendar = new JewishCalendar(LocalDate.of(2024, 1, 3)); @@ -75,4 +109,15 @@ public void testShemirasHaLashonYomi() { "כלל ט׳ ח-י", hebrewFormatter.formatShemirasHaLashonYomi(calendar.getShemirasHaLashonYomi())); } + + @Test + public void testShemirasHaLashonSectionYomi() { + JewishCalendar calendar = new JewishCalendar(LocalDate.of(2024, 10, 3)); + Assert.assertEquals( + "Book I, Hakdamah 1-2", + formatter.formatShemirasHaLashonYomi(calendar.getShemirasHaLashonYomi())); + Assert.assertEquals( + "הקדמה א-ב", + hebrewFormatter.formatShemirasHaLashonYomi(calendar.getShemirasHaLashonYomi())); + } } From 651583dcb513f7a4349a3980916a936e7a0fc388 Mon Sep 17 00:00:00 2001 From: noamtu123 Date: Wed, 1 Jul 2026 16:16:07 +0300 Subject: [PATCH 3/5] Adjust Shemirat HaLashon formatting --- .../hebrewcalendar/HebrewDateFormatter.java | 19 +++++++++++++++++-- .../LimudYomiCalculatorTest.java | 4 ++-- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/kosherjava/zmanim/hebrewcalendar/HebrewDateFormatter.java b/src/main/java/com/kosherjava/zmanim/hebrewcalendar/HebrewDateFormatter.java index 72f5699d..42c13054 100644 --- a/src/main/java/com/kosherjava/zmanim/hebrewcalendar/HebrewDateFormatter.java +++ b/src/main/java/com/kosherjava/zmanim/hebrewcalendar/HebrewDateFormatter.java @@ -944,8 +944,13 @@ public String formatShemirasHaLashonYomi(ShemirasHaLashonYomi shemirasYomi) { return formatShemirasSection(shemirasYomi.getSection()) + " " + formatShemirasSectionRef(shemirasYomi.getStart()) + (shemirasYomi.getStart().equals(shemirasYomi.getEnd()) ? "" : formatShemirasSectionRangeEnd(shemirasYomi.getStart(), shemirasYomi.getEnd())); } - String prefix = "Book " + (shemirasYomi.getBook() == 1 ? "I" : "II") + ("x".equals(shemirasYomi.getSection()) ? " " : ", " + shemirasYomi.getSection() + " "); - return prefix + shemirasYomi.getStart() + (shemirasYomi.getStart().equals(shemirasYomi.getEnd()) ? "" : "-" + shemirasYomi.getEnd()); + if ("x".equals(shemirasYomi.getSection())) { + return formatShemirasEnglishKlalRef(shemirasYomi.getStart()) + (shemirasYomi.getStart().equals(shemirasYomi.getEnd()) ? "" + : (sameShemirasKlal(shemirasYomi.getStart(), shemirasYomi.getEnd()) ? "-" + shemirasHalachaEnglish(shemirasYomi.getEnd()) + : " - " + formatShemirasEnglishKlalRef(shemirasYomi.getEnd()))); + } + return "Shemirat HaLashon, " + shemirasYomi.getSection() + " " + shemirasYomi.getStart() + + (shemirasYomi.getStart().equals(shemirasYomi.getEnd()) ? "" : "-" + shemirasYomi.getEnd()); } private String formatKitzurRef(String ref) { @@ -985,6 +990,11 @@ private String formatShemirasKlalRef(String ref) { return "כלל " + formatHebrewNumber(Integer.parseInt(parts[0])) + " " + (parts.length> 1 ? formatPlainHebrewToken(parts[1]) : ""); } + private String formatShemirasEnglishKlalRef(String ref) { + String[] parts = ref.split("\\."); + return "Klal " + parts[0] + " Halacha " + (parts.length> 1 ? parts[1] : ""); + } + private String formatShemirasSection(String section) { if ("Hakdamah".equals(section)) { return "הקדמה"; @@ -1027,6 +1037,11 @@ private String shemirasHalacha(String ref) { return parts.length> 1 ? formatPlainHebrewToken(parts[1]) : ""; } + private String shemirasHalachaEnglish(String ref) { + String[] parts = ref.split("\\."); + return parts.length> 1 ? parts[1] : ""; + } + private String formatHebrewToken(String token) { if ("E".equals(token)) { return "סוף"; diff --git a/src/test/java/com/kosherjava/zmanim/hebrewcalendar/LimudYomiCalculatorTest.java b/src/test/java/com/kosherjava/zmanim/hebrewcalendar/LimudYomiCalculatorTest.java index f98bdc82..9222e322 100644 --- a/src/test/java/com/kosherjava/zmanim/hebrewcalendar/LimudYomiCalculatorTest.java +++ b/src/test/java/com/kosherjava/zmanim/hebrewcalendar/LimudYomiCalculatorTest.java @@ -103,7 +103,7 @@ public void testKitzurShulchanAruchYomi() { public void testShemirasHaLashonYomi() { JewishCalendar calendar = new JewishCalendar(LocalDate.of(2024, 6, 26)); Assert.assertEquals( - "Book II 9.8-9.10", + "Klal 9 Halacha 8-10", formatter.formatShemirasHaLashonYomi(calendar.getShemirasHaLashonYomi())); Assert.assertEquals( "כלל ט׳ ח-י", @@ -114,7 +114,7 @@ public void testShemirasHaLashonYomi() { public void testShemirasHaLashonSectionYomi() { JewishCalendar calendar = new JewishCalendar(LocalDate.of(2024, 10, 3)); Assert.assertEquals( - "Book I, Hakdamah 1-2", + "Shemirat HaLashon, Hakdamah 1-2", formatter.formatShemirasHaLashonYomi(calendar.getShemirasHaLashonYomi())); Assert.assertEquals( "הקדמה א-ב", From 50616ec53ca9919f2ef2d1d213aa19d82d7e3186 Mon Sep 17 00:00:00 2001 From: noamtu123 Date: Wed, 1 Jul 2026 16:38:32 +0300 Subject: [PATCH 4/5] Polish Limud Yomi calculators --- .../hebrewcalendar/HebrewDateFormatter.java | 10 +++- .../KitzurShulchanAruchYomi.java | 7 +++ .../KitzurShulchanAruchYomiCalculator.java | 19 ++++++- .../zmanim/hebrewcalendar/LimudYomiData.java | 7 +++ .../zmanim/hebrewcalendar/MishnaYomi.java | 7 +++ .../hebrewcalendar/MishnaYomiCalculator.java | 18 +++++- .../zmanim/hebrewcalendar/RambamYomi.java | 18 +++++- .../hebrewcalendar/RambamYomiCalculator.java | 32 ++++++++++- .../hebrewcalendar/ShemirasHaLashonYomi.java | 7 +++ .../ShemirasHaLashonYomiCalculator.java | 22 +++++++- .../zmanim/hebrewcalendar/TanachYomi.java | 7 +++ .../hebrewcalendar/TanachYomiCalculator.java | 17 +++++- .../zmanim/hebrewcalendar/TehillimYomi.java | 7 +++ .../TehillimYomiCalculator.java | 55 +++++++++++++++++-- .../LimudYomiCalculatorTest.java | 8 +++ 15 files changed, 224 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/kosherjava/zmanim/hebrewcalendar/HebrewDateFormatter.java b/src/main/java/com/kosherjava/zmanim/hebrewcalendar/HebrewDateFormatter.java index 42c13054..d8bec5ed 100644 --- a/src/main/java/com/kosherjava/zmanim/hebrewcalendar/HebrewDateFormatter.java +++ b/src/main/java/com/kosherjava/zmanim/hebrewcalendar/HebrewDateFormatter.java @@ -831,14 +831,14 @@ public String formatDafYomiYerushalmi(Daf daf) { */ public String formatMishnaYomi(MishnaYomi mishnaYomi) { String start = (hebrewFormat ? mishnaYomi.getMasechta() + " " + formatHebrewNumber(mishnaYomi.getStartChapter()) - + ": " + formatPlainHebrewNumber(mishnaYomi.getStartMishna()) : mishnaYomi.getMasechtaTransliterated() + " " + + ": " + formatMishnaNumber(mishnaYomi.getStartMishna()) : mishnaYomi.getMasechtaTransliterated() + " " + mishnaYomi.getStartChapter() + ":" + mishnaYomi.getStartMishna()); if (mishnaYomi.getStartMasechtaNumber() == mishnaYomi.getEndMasechtaNumber() && mishnaYomi.getStartChapter() == mishnaYomi.getEndChapter()) { - return start + "-" + (hebrewFormat ? formatPlainHebrewNumber(mishnaYomi.getEndMishna()) : mishnaYomi.getEndMishna()); + return start + "-" + (hebrewFormat ? formatMishnaNumber(mishnaYomi.getEndMishna()) : mishnaYomi.getEndMishna()); } return start + "-" + (hebrewFormat ? mishnaYomi.getEndMasechta() + " " + formatHebrewNumber(mishnaYomi.getEndChapter()) - + ": " + formatPlainHebrewNumber(mishnaYomi.getEndMishna()) : mishnaYomi.getEndMasechtaTransliterated() + " " + + ": " + formatMishnaNumber(mishnaYomi.getEndMishna()) : mishnaYomi.getEndMasechtaTransliterated() + " " + mishnaYomi.getEndChapter() + ":" + mishnaYomi.getEndMishna()); } @@ -1080,6 +1080,10 @@ private String formatPlainHebrewNumber(int number) { return formatHebrewNumber(number).replace(GERESH, "").replace(GERSHAYIM, ""); } + private String formatMishnaNumber(int number) { + return formatHebrewNumber(number).replace(GERESH, ""); + } + /** * Returns a Hebrew formatted string of a number. The method can calculate from 0 to 9999. *