001/* 002 * Zmanim Java API 003 * Copyright (C) 2017 - 2025 Eliyahu Hershfeld 004 * 005 * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General 006 * Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) 007 * any later version. 008 * 009 * This library is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied 010 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 011 * details. 012 * You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to 013 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA, 014 * or connect to: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html 015 */ 016package com.kosherjava.zmanim.hebrewcalendar; 017 018import java.util.Calendar; 019import java.util.GregorianCalendar; 020 021 022/** 023 * This class calculates the <a href="https://en.wikipedia.org/wiki/Jerusalem_Talmud">Talmud Yerusalmi</a> <a href= 024 * "https://en.wikipedia.org/wiki/Daf_Yomi">Daf Yomi</a> page ({@link Daf}) for the a given date. 025 * 026 * @author © elihaidv 027 * @author © Eliyahu Hershfeld 2017 - 2025 028 */ 029public class YerushalmiYomiCalculator { 030 031 /** 032 * The start date of the first Daf Yomi Yerushalmi cycle of February 2, 1980 / 15 Shevat, 5740. 033 */ 034 private final static Calendar DAF_YOMI_START_DAY = new GregorianCalendar(1980, Calendar.FEBRUARY, 2); 035 /** The number of milliseconds in a day. */ 036 private final static int DAY_MILIS = 1000 * 60 * 60 * 24; 037 /** The number of pages in the Talmud Yerushalmi.*/ 038 private final static int WHOLE_SHAS_DAFS = 1554; 039 /** The number of pages per <em>masechta</em> (tractate).*/ 040 private final static int[] BLATT_PER_MASECHTA = { 041 68, 37, 34, 44, 31, 59, 26, 33, 28, 20, 13, 92, 65, 71, 22, 22, 42, 26, 26, 33, 34, 22, 042 19, 85, 72, 47, 40, 47, 54, 48, 44, 37, 34, 44, 9, 57, 37, 19, 13}; 043 044 /** 045 * Default constructor. 046 */ 047 public YerushalmiYomiCalculator() { 048 // nothing here 049 } 050 051 /** 052 * Returns the <a href="https://en.wikipedia.org/wiki/Daf_Yomi">Daf Yomi</a> 053 * <a href="https://en.wikipedia.org/wiki/Jerusalem_Talmud">Yerusalmi</a> page ({@link Daf}) for a given date. 054 * The first Daf Yomi cycle started on 15 Shevat (Tu Bishvat), 5740 (February, 2, 1980) and calculations 055 * prior to this date will result in an IllegalArgumentException thrown. A null will be returned on Tisha B'Av or 056 * Yom Kippur. 057 * 058 * @param calendar 059 * the calendar date for calculation 060 * @return the {@link Daf} or null if the date is on Tisha B'Av or Yom Kippur. 061 * 062 * @throws IllegalArgumentException 063 * if the date is prior to the February 2, 1980, the start of the first Daf Yomi Yerushalmi cycle 064 */ 065 public static Daf getDafYomiYerushalmi(JewishCalendar calendar) { 066 067 Calendar nextCycle = new GregorianCalendar(); 068 Calendar prevCycle = new GregorianCalendar(); 069 Calendar requested = calendar.getGregorianCalendar(); 070 int masechta = 0; 071 Daf dafYomi = null; 072 073 // There isn't Daf Yomi on Yom Kippur or Tisha B'Av. 074 if ( calendar.getYomTovIndex() == JewishCalendar.YOM_KIPPUR || 075 calendar.getYomTovIndex() == JewishCalendar.TISHA_BEAV ) { 076 return null; 077 } 078 079 080 if (requested.before(DAF_YOMI_START_DAY)) { 081 throw new IllegalArgumentException(requested + " is prior to organized Daf Yomi Yerushalmi cycles that started on " 082 + DAF_YOMI_START_DAY); 083 } 084 085 // Start to calculate current cycle. init the start day 086 nextCycle.setTime(DAF_YOMI_START_DAY.getTime()); 087 088 // Go cycle by cycle, until we get the next cycle 089 while (requested.after(nextCycle)) { 090 prevCycle.setTime(nextCycle.getTime()); 091 092 // Adds the number of whole shas dafs. and the number of days that not have daf. 093 nextCycle.add(Calendar.DAY_OF_MONTH, WHOLE_SHAS_DAFS); 094 nextCycle.add(Calendar.DAY_OF_MONTH, getNumOfSpecialDays(prevCycle, nextCycle)); 095 } 096 097 // Get the number of days from cycle start until request. 098 int dafNo = (int)(getDiffBetweenDays(prevCycle, requested)); 099 100 // Get the number of special day to subtract 101 int specialDays = getNumOfSpecialDays(prevCycle, requested); 102 int total = dafNo - specialDays; 103 104 // Finally find the daf. 105 for (int i : BLATT_PER_MASECHTA) { 106 if (total < i) { 107 dafYomi = new Daf(masechta, total + 1); 108 break; 109 } 110 total -= i; 111 masechta++; 112 } 113 114 return dafYomi; 115 } 116 117 /** 118 * Return the number of special days (Yom Kippur and Tisha Beav, where there are no dafim), between the start date 119 * (as a <code>Calendar</code>) and end date (also as a <code>Calendar</code>). 120 * 121 * @param start date to start calculating from 122 * @param end date to finish calculating at 123 * @return the number of special days between the start and end dates 124 */ 125 private static int getNumOfSpecialDays(Calendar start, Calendar end) { 126 127 // Find the start and end Jewish years 128 int startYear = new JewishCalendar(start).getJewishYear(); 129 int endYear = new JewishCalendar(end).getJewishYear(); 130 131 // Value to return 132 int specialDays = 0; 133 134 //Instant of special Dates 135 JewishCalendar yom_kippur = new JewishCalendar(5770, 7, 10); 136 JewishCalendar tisha_beav = new JewishCalendar(5770, 5, 9); 137 138 // Go over the years and find special dates 139 for (int i = startYear; i <= endYear; i++) { 140 yom_kippur.setJewishYear(i); 141 tisha_beav.setJewishYear(i); 142 143 if (isBetween(start, yom_kippur.getGregorianCalendar(), end)) { 144 specialDays++; 145 } 146 if (isBetween(start, tisha_beav.getGregorianCalendar(), end)) { 147 specialDays++; 148 } 149 } 150 151 return specialDays; 152 } 153 154 /** 155 * Return if the date is between two dates 156 * 157 * @param start the start date 158 * @param date the date being compared 159 * @param end the end date 160 * @return if the date is between the start and end dates 161 */ 162 private static boolean isBetween(Calendar start, Calendar date, Calendar end ) { 163 return start.before(date) && end.after(date); 164 } 165 166 /** 167 * Return the number of days between the dates passed in 168 * @param start the start date 169 * @param end the end date 170 * @return the number of days between the start and end dates 171 */ 172 private static long getDiffBetweenDays(Calendar start, Calendar end) { 173 return (end.getTimeInMillis() - start.getTimeInMillis()) / DAY_MILIS; 174 } 175}