diff --git a/src/main/java/com/kosherjava/zmanim/hebrewcalendar/HebrewDateFormatter.java b/src/main/java/com/kosherjava/zmanim/hebrewcalendar/HebrewDateFormatter.java index 4e1a7bdb..22016429 100644 --- a/src/main/java/com/kosherjava/zmanim/hebrewcalendar/HebrewDateFormatter.java +++ b/src/main/java/com/kosherjava/zmanim/hebrewcalendar/HebrewDateFormatter.java @@ -824,6 +824,303 @@ 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()) + + ": " + formatMishnaNumber(mishnaYomi.getStartMishna()) : mishnaYomi.getMasechtaTransliterated() + " " + + mishnaYomi.getStartChapter() + ":" + mishnaYomi.getStartMishna()); + if (mishnaYomi.getStartMasechtaNumber() == mishnaYomi.getEndMasechtaNumber() + && mishnaYomi.getStartChapter() == mishnaYomi.getEndChapter()) { + return start + "-" + (hebrewFormat ? formatMishnaNumber(mishnaYomi.getEndMishna()) : mishnaYomi.getEndMishna()); + } + return start + "-" + (hebrewFormat ? mishnaYomi.getEndMasechta() + " " + formatHebrewNumber(mishnaYomi.getEndChapter()) + + ": " + formatMishnaNumber(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) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < rambamYomi.getReadingCount(); i++) { + if (i > 0) { + sb.append(", "); + } + String start = rambamYomi.getStartChapter(i); + String end = rambamYomi.getEndChapter(i); + if (hebrewFormat) { + sb.append(formatRambamHebrewName(rambamYomi.getBookNumber(i))); + sb.append(start.equals(end) ? " פרק " : " פרקים "); + sb.append(formatRambamChapter(start)); + if (!start.equals(end)) { + sb.append("-").append(formatRambamChapter(end)); + } + } else { + sb.append(rambamYomi.getName(i)).append(" ").append(start); + if (!start.equals(end)) { + sb.append("-").append(end); + } + } + } + return sb.toString(); + } + + /** + * 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) { + String section = formatShemirasSection(shemirasYomi.getSection()); + return "שמירת הלשון, חלק " + formatHebrewNumber(shemirasYomi.getBook()) + + (section.length() == 0 ? ", " : ", " + section + ", ") + + formatShemirasSectionRef(shemirasYomi.getStart()) + + (shemirasYomi.getStart().equals(shemirasYomi.getEnd()) ? "" + : formatShemirasSectionRangeEnd(shemirasYomi.getStart(), shemirasYomi.getEnd())); + } + String section = formatShemirasEnglishSection(shemirasYomi.getSection()); + return "Shemirat HaLashon, Part " + shemirasYomi.getBook() + + (section.length() == 0 ? ", " : ", " + section + ", ") + + formatShemirasEnglishSectionRef(shemirasYomi.getStart()) + + (shemirasYomi.getStart().equals(shemirasYomi.getEnd()) ? "" + : formatShemirasEnglishSectionRangeEnd(shemirasYomi.getStart(), 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 formatRambamHebrewName(int bookNumber) { + String name = LimudYomiData.RAMBAM_NAMES_HEBREW[bookNumber]; + if (bookNumber < 4 || "סדר התפילה".equals(name)) { + return name; + } + return "הלכות " + name; + } + + private String formatRambamChapter(String chapter) { + String[] range = chapter.split("-"); + if (range.length == 2) { + return formatRambamChapterPart(range[0]) + "-" + formatRambamChapterPart(range[1]); + } + return formatRambamChapterPart(chapter); + } + + private String formatRambamChapterPart(String chapter) { + String[] parts = chapter.split(":"); + if (parts.length == 2) { + return formatPlainHebrewNumber(Integer.parseInt(parts[0])) + ":" + formatPlainHebrewNumber(Integer.parseInt(parts[1])); + } + return formatPlainHebrewNumber(Integer.parseInt(chapter)); + } + + private String formatShemirasKlalRef(String ref) { + String[] parts = ref.split("\\."); + return "פרק " + formatHebrewNumber(Integer.parseInt(parts[0])) + (parts.length > 1 ? " הלכה " + formatPlainHebrewToken(parts[1]) : ""); + } + + private String formatShemirasEnglishKlalRef(String ref) { + String[] parts = ref.split("\\."); + return "Perek " + parts[0] + (parts.length > 1 ? " Halacha " + parts[1] : ""); + } + + private String formatShemirasEnglishSection(String section) { + if ("Hakdamah".equals(section)) { + return "Hakdamah"; + } + if ("Shar Hazechira".equals(section)) { + return "Shaar HaZechirah"; + } + if ("Shar Hatvuna".equals(section)) { + return "Shaar HaTevunah"; + } + if ("Shar Hatorah".equals(section)) { + return "Shaar HaTorah"; + } + if ("Chasimas Hasefer".equals(section)) { + return "Chasima"; + } + if ("x".equals(section)) { + return ""; + } + return section; + } + + private String formatShemirasSection(String section) { + if ("Hakdamah".equals(section)) { + return "הקדמה"; + } + if ("Shar Hazechira".equals(section)) { + return "שער הזכירה"; + } + if ("Shar Hatvuna".equals(section)) { + return "שער התבונה"; + } + if ("Shar Hatorah".equals(section)) { + return "שער התורה"; + } + if ("Chasimas Hasefer".equals(section)) { + return "חתימה"; + } + if ("x".equals(section)) { + return ""; + } + return section; + } + + private String formatShemirasSectionRef(String ref) { + if (ref.indexOf('.') >= 0) { + return formatShemirasKlalRef(ref); + } + return formatPlainHebrewToken(ref); + } + + private String formatShemirasEnglishSectionRef(String ref) { + if (ref.indexOf('.') >= 0) { + return formatShemirasEnglishKlalRef(ref); + } + return ref; + } + + private String formatShemirasSectionRangeEnd(String start, String end) { + if (start.indexOf('.') >= 0 && end.indexOf('.') >= 0) { + return sameShemirasKlal(start, end) ? "-" + shemirasHalacha(end) : " - " + formatShemirasKlalRef(end); + } + return "-" + formatPlainHebrewToken(end); + } + + private String formatShemirasEnglishSectionRangeEnd(String start, String end) { + if (start.indexOf('.') >= 0 && end.indexOf('.') >= 0) { + return sameShemirasKlal(start, end) ? "-" + shemirasHalachaEnglish(end) : " - " + formatShemirasEnglishKlalRef(end); + } + return "-" + end; + } + + 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 shemirasHalachaEnglish(String ref) { + String[] parts = ref.split("\\."); + return parts.length > 1 ? parts[1] : ""; + } + + private String formatHebrewToken(String token) { + if ("E".equals(token)) { + return "סוף"; + } + if ("Shmita".equals(token)) { + return "שמיטה"; + } + if ("Klalim".equals(token)) { + return "כללים"; + } + try { + return formatHebrewNumber(Integer.parseInt(token)); + } catch (NumberFormatException e) { + return token; + } + } + + private String formatPlainHebrewToken(String token) { + if ("E".equals(token)) { + return "סוף"; + } + if ("Shmita".equals(token)) { + return "שמיטה"; + } + if ("Klalim".equals(token)) { + return "כללים"; + } + try { + return formatPlainHebrewNumber(Integer.parseInt(token)); + } catch (NumberFormatException e) { + return token; + } + } + + 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. * * @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 new file mode 100644 index 00000000..7c51ee51 --- /dev/null +++ b/src/test/java/com/kosherjava/zmanim/hebrewcalendar/LimudYomiCalculatorTest.java @@ -0,0 +1,142 @@ +package com.kosherjava.zmanim.hebrewcalendar; + +import java.time.LocalDate; +import org.junit.Assert; +import org.junit.Test; + +public class LimudYomiCalculatorTest { + private final HebrewDateFormatter formatter = new HebrewDateFormatter(); + private final HebrewDateFormatter hebrewFormatter = new HebrewDateFormatter(); + + public LimudYomiCalculatorTest() { + hebrewFormatter.setHebrewFormat(true); + } + + @Test + public void testMishnaYomi() { + JewishCalendar calendar = new JewishCalendar(LocalDate.of(2020, 9, 21)); + Assert.assertEquals("Kelim 11:7-8", formatter.formatMishnaYomi(calendar.getMishnaYomi())); + Assert.assertEquals( + "כלים י״א: ז-ח", hebrewFormatter.formatMishnaYomi(calendar.getMishnaYomi())); + } + + @Test + public void testMishnaYomiHebrewFifteen() { + JewishCalendar calendar = new JewishCalendar(LocalDate.of(2020, 10, 18)); + Assert.assertEquals("Kelim 17:14-15", formatter.formatMishnaYomi(calendar.getMishnaYomi())); + Assert.assertEquals( + "כלים י״ז: י״ד-ט״ו", hebrewFormatter.formatMishnaYomi(calendar.getMishnaYomi())); + } + + @Test + public void testRambamYomiOneChapter() { + JewishCalendar calendar = new JewishCalendar(LocalDate.of(2020, 11, 11)); + Assert.assertEquals("Sabbath 17", formatter.formatRambamYomi(calendar.getRambamYomi())); + Assert.assertEquals( + "הלכות שבת פרק יז", 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)); + Assert.assertEquals( + "Gifts to the Poor 8-10", formatter.formatRambamYomi(calendar.getRambamYomi3Chapters())); + Assert.assertEquals( + "הלכות מתנות עניים פרקים ח-י", + 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)); + Assert.assertEquals( + "Psalms 106-107", formatter.formatDailyTehillim(calendar.getDailyTehillim())); + Assert.assertEquals( + "תהילים ק״ו-ק״ז", hebrewFormatter.formatDailyTehillim(calendar.getDailyTehillim())); + } + + @Test + public void testTanachYomi() { + JewishCalendar calendar = new JewishCalendar(LocalDate.of(2024, 6, 9)); + Assert.assertEquals("Psalms Seder 3", formatter.formatTanachYomi(calendar.getTanachYomi())); + Assert.assertEquals("תהלים ס׳ ג׳", hebrewFormatter.formatTanachYomi(calendar.getTanachYomi())); + } + + @Test + public void testKitzurShulchanAruchYomi() { + JewishCalendar calendar = new JewishCalendar(LocalDate.of(2024, 7, 9)); + Assert.assertEquals( + "161:18-162:5", + formatter.formatKitzurShulchanAruchYomi(calendar.getKitzurShulchanAruchYomi())); + Assert.assertEquals( + "קס״א: יח - קס״ב: ה", + hebrewFormatter.formatKitzurShulchanAruchYomi(calendar.getKitzurShulchanAruchYomi())); + } + + @Test + public void testShemirasHaLashonYomi() { + JewishCalendar calendar = new JewishCalendar(LocalDate.of(2024, 6, 26)); + Assert.assertEquals( + "Shemirat HaLashon, Part 2, Perek 9 Halacha 8-10", + formatter.formatShemirasHaLashonYomi(calendar.getShemirasHaLashonYomi())); + Assert.assertEquals( + "שמירת הלשון, חלק ב׳, פרק ט׳ הלכה ח-י", + hebrewFormatter.formatShemirasHaLashonYomi(calendar.getShemirasHaLashonYomi())); + } + + @Test + public void testShemirasHaLashonSectionYomi() { + JewishCalendar calendar = new JewishCalendar(LocalDate.of(2024, 10, 3)); + Assert.assertEquals( + "Shemirat HaLashon, Part 1, Hakdamah, 1-2", + formatter.formatShemirasHaLashonYomi(calendar.getShemirasHaLashonYomi())); + Assert.assertEquals( + "שמירת הלשון, חלק א׳, הקדמה, א-ב", + hebrewFormatter.formatShemirasHaLashonYomi(calendar.getShemirasHaLashonYomi())); + } + + @Test + public void testShemirasHaLashonShaarYomi() { + JewishCalendar calendar = new JewishCalendar(LocalDate.of(2024, 10, 13)); + Assert.assertEquals( + "Shemirat HaLashon, Part 1, Shaar HaZechirah, Perek 1 Halacha 1-4", + formatter.formatShemirasHaLashonYomi(calendar.getShemirasHaLashonYomi())); + Assert.assertEquals( + "שמירת הלשון, חלק א׳, שער הזכירה, פרק א׳ הלכה א-ד", + hebrewFormatter.formatShemirasHaLashonYomi(calendar.getShemirasHaLashonYomi())); + } +}