Skip to content

Commit d103d3d

Browse files
authored
Start using java.time classes, remove deprecated methods
Breaking changes
1 parent 84fa545 commit d103d3d

1 file changed

Lines changed: 68 additions & 244 deletions

File tree

src/main/java/com/kosherjava/zmanim/hebrewcalendar/JewishCalendar.java

Lines changed: 68 additions & 244 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,13 @@
1717
*/
1818
package com.kosherjava.zmanim.hebrewcalendar;
1919

20-
import com.kosherjava.zmanim.util.GeoLocation;
21-
20+
import java.time.Duration;
21+
import java.time.Instant;
2222
import java.time.LocalDate;
23+
import java.time.ZoneOffset;
24+
import java.time.ZonedDateTime;
25+
import java.time.temporal.ChronoUnit;
2326
import java.util.Calendar;
24-
import java.util.Date;
25-
import java.util.TimeZone;
2627

2728
/**
2829
* The JewishCalendar extends the JewishDate class and adds calendar methods.
@@ -42,7 +43,7 @@
4243
* @see java.util.Calendar
4344
* @author © Y. Paritcher 2019 - 2022
4445
* @author © Avrom Finkelstien 2002
45-
* @author © Eliyahu Hershfeld 2011 - 2024
46+
* @author © Eliyahu Hershfeld 2011 - 2026
4647
*/
4748
public class JewishCalendar extends JewishDate {
4849
/** The 14th day of Nissan, the day before Pesach (Passover).*/
@@ -256,21 +257,21 @@ public JewishCalendar() {
256257
/**
257258
* A constructor that initializes the date to the {@link java.util.Date Date} parameter.
258259
*
259-
* @param date
260-
* the <code>Date</code> to set the calendar to
260+
* @param instant
261+
* the <code>Instant</code> to set the calendar to
261262
*/
262-
public JewishCalendar(Date date) {
263-
super(date);
263+
public JewishCalendar(Instant instant) {
264+
super(instant);
264265
}
265266

266267
/**
267268
* A constructor that initializes the date to the {@link java.util.Calendar Calendar} parameter.
268269
*
269-
* @param calendar
270-
* the <code>Calendar</code> to set the calendar to
270+
* @param zonedDateTime
271+
* the <code>ZonedDateTime</code> to set the calendar to
271272
*/
272-
public JewishCalendar(Calendar calendar) {
273-
super(calendar);
273+
public JewishCalendar(ZonedDateTime zonedDateTime) {
274+
super(zonedDateTime);
274275
}
275276

276277
/**
@@ -1230,27 +1231,41 @@ public boolean isTishaBav() {
12301231
*
12311232
* @return the Date representing the moment of the <em>molad</em> in Yerushalayim standard time (GMT + 2)
12321233
*/
1233-
public Date getMoladAsDate() {
1234-
JewishDate molad = getMolad();
1235-
String locationName = "Jerusalem, Israel";
1234+
public Instant getMoladAsInstant() {
1235+
JewishDate molad = getMolad();
1236+
1237+
// Har Habayis coordinates
1238+
//double latitude = 31.778;
1239+
double longitude = 35.2354;
1240+
1241+
// Standard time offset for Jerusalem: GMT+2
1242+
ZoneOffset jerusalemStandardOffset = ZoneOffset.ofHours(2);
1243+
1244+
// Compute molad seconds from chalakim
1245+
double moladSeconds = molad.getMoladChalakim() * 10.0 / 3.0;
1246+
int seconds = (int) moladSeconds;
1247+
int millis = (int) ((moladSeconds - seconds) * 1000);
1248+
1249+
// Construct ZonedDateTime in standard time (GMT+2)
1250+
ZonedDateTime moladZdt = ZonedDateTime.of(
1251+
molad.getGregorianYear(),
1252+
molad.getGregorianMonth() +1, // 1-based FIXME
1253+
molad.getGregorianDayOfMonth(),
1254+
molad.getMoladHours(),
1255+
molad.getMoladMinutes(),
1256+
seconds,
1257+
millis * 1_000_000, // nanos
1258+
jerusalemStandardOffset
1259+
);
12361260

1237-
double latitude = 31.778; // Har Habayis latitude
1238-
double longitude = 35.2354; // Har Habayis longitude
1261+
// Compute local mean time offset in milliseconds (example: 20.94 minutes = 1256400 ms)
1262+
long localMeanOffsetMillis = (long) ((longitude - 35.0) * 4 * 60 * 1000);
12391263

1240-
// The raw molad Date (point in time) must be generated using standard time. Using "Asia/Jerusalem" timezone will result in the time
1241-
// 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
1242-
// formatter class used to display the Date.
1243-
TimeZone yerushalayimStandardTZ = TimeZone.getTimeZone("GMT+2");
1244-
GeoLocation geo = new GeoLocation(locationName, latitude, longitude, yerushalayimStandardTZ);
1245-
Calendar cal = Calendar.getInstance(geo.getTimeZone());
1246-
cal.clear();
1247-
double moladSeconds = molad.getMoladChalakim() * 10 / (double) 3;
1248-
cal.set(molad.getGregorianYear(), molad.getGregorianMonth(), molad.getGregorianDayOfMonth(),
1249-
molad.getMoladHours(), molad.getMoladMinutes(), (int) moladSeconds);
1250-
cal.set(Calendar.MILLISECOND, (int) (1000 * (moladSeconds - (int) moladSeconds)));
1251-
// subtract local time difference of 20.94 minutes (20 minutes and 56.496 seconds) to get to Standard time
1252-
cal.add(Calendar.MILLISECOND, -1 * (int) geo.getLocalMeanTimeOffset());
1253-
return cal.getTime();
1264+
// Apply offset using ChronoUnit.MILLIS
1265+
moladZdt = moladZdt.minus(localMeanOffsetMillis, ChronoUnit.MILLIS);
1266+
1267+
// Return precise Instant
1268+
return moladZdt.toInstant();
12541269
}
12551270

12561271
/**
@@ -1263,12 +1278,8 @@ public Date getMoladAsDate() {
12631278
* @see com.kosherjava.zmanim.ComprehensiveZmanimCalendar#getTchilasZmanKidushLevana3Days()
12641279
* @see com.kosherjava.zmanim.ComprehensiveZmanimCalendar#getTchilasZmanKidushLevana3Days(Date, Date)
12651280
*/
1266-
public Date getTchilasZmanKidushLevana3Days() {
1267-
Date molad = getMoladAsDate();
1268-
Calendar cal = Calendar.getInstance();
1269-
cal.setTime(molad);
1270-
cal.add(Calendar.HOUR, 72); // 3 days after the molad
1271-
return cal.getTime();
1281+
public Instant getTchilasZmanKidushLevana3Days() {
1282+
return getMoladAsInstant().plus(Duration.ofHours(72)); // 3 days after the molad
12721283
}
12731284

12741285
/**
@@ -1283,12 +1294,8 @@ public Date getTchilasZmanKidushLevana3Days() {
12831294
* @see com.kosherjava.zmanim.ComprehensiveZmanimCalendar#getTchilasZmanKidushLevana7Days()
12841295
* @see com.kosherjava.zmanim.ComprehensiveZmanimCalendar#getTchilasZmanKidushLevana7Days(Date, Date)
12851296
*/
1286-
public Date getTchilasZmanKidushLevana7Days() {
1287-
Date molad = getMoladAsDate();
1288-
Calendar cal = Calendar.getInstance();
1289-
cal.setTime(molad);
1290-
cal.add(Calendar.HOUR, 168); // 7 days after the molad
1291-
return cal.getTime();
1297+
public Instant getTchilasZmanKidushLevana7Days() {
1298+
return getMoladAsInstant().plus(Duration.ofHours(168)); // 7 days after the molad
12921299
}
12931300

12941301
/**
@@ -1306,18 +1313,18 @@ public Date getTchilasZmanKidushLevana7Days() {
13061313
* @see com.kosherjava.zmanim.ComprehensiveZmanimCalendar#getSofZmanKidushLevanaBetweenMoldos()
13071314
* @see com.kosherjava.zmanim.ComprehensiveZmanimCalendar#getSofZmanKidushLevanaBetweenMoldos(Date, Date)
13081315
*/
1309-
public Date getSofZmanKidushLevanaBetweenMoldos() {
1310-
Date molad = getMoladAsDate();
1311-
Calendar cal = Calendar.getInstance();
1312-
cal.setTime(molad);
1313-
// add half the time between molad and molad (half of 29 days, 12 hours and 793 chalakim (44 minutes, 3.3
1314-
// seconds), or 14 days, 18 hours, 22 minutes and 666 milliseconds). Add it as hours, not days, to avoid
1315-
// DST/ST crossover issues.
1316-
cal.add(Calendar.HOUR, (24 * 14) + 18);
1317-
cal.add(Calendar.MINUTE, 22);
1318-
cal.add(Calendar.SECOND, 1);
1319-
cal.add(Calendar.MILLISECOND, 666);
1320-
return cal.getTime();
1316+
public Instant getSofZmanKidushLevanaBetweenMoldos() {
1317+
Instant molad = getMoladAsInstant();
1318+
1319+
// Duration for half of the lunar month:
1320+
// 14 days, 18 hours, 22 minutes, 1 second, 666 milliseconds
1321+
Duration halfLunarMonth = Duration.ofDays(14)
1322+
.plusHours(18)
1323+
.plusMinutes(22)
1324+
.plusSeconds(1)
1325+
.plusMillis(666);
1326+
1327+
return molad.plus(halfLunarMonth);
13211328
}
13221329

13231330
/**
@@ -1337,12 +1344,8 @@ public Date getSofZmanKidushLevanaBetweenMoldos() {
13371344
* @see com.kosherjava.zmanim.ComprehensiveZmanimCalendar#getSofZmanKidushLevana15Days()
13381345
* @see com.kosherjava.zmanim.ComprehensiveZmanimCalendar#getSofZmanKidushLevana15Days(Date, Date)
13391346
*/
1340-
public Date getSofZmanKidushLevana15Days() {
1341-
Date molad = getMoladAsDate();
1342-
Calendar cal = Calendar.getInstance();
1343-
cal.setTime(molad);
1344-
cal.add(Calendar.HOUR, 24 * 15); //15 days after the molad. Add it as hours, not days, to avoid DST/ST crossover issues.
1345-
return cal.getTime();
1347+
public Instant getSofZmanKidushLevana15Days() {
1348+
return getMoladAsInstant().plus(Duration.ofHours(24 * 15));
13461349
}
13471350

13481351
/**
@@ -1381,9 +1384,9 @@ public Daf getDafYomiYerushalmi() {
13811384
*
13821385
* @return the number of elapsed days since <em>tekufas Tishrei</em>.
13831386
*
1384-
* @see #isVeseinTalUmatarStartDate()
1385-
* @see #isVeseinTalUmatarStartingTonight()
1386-
* @see #isVeseinTalUmatarRecited()
1387+
* @see com.kosherjava.zmanim.hebrewcalendar.TefilaRules#isVeseinTalUmatarStartDate(JewishCalendar)
1388+
* @see com.kosherjava.zmanim.hebrewcalendar.TefilaRules#isVeseinTalUmatarStartingTonight(JewishCalendar)
1389+
* @see com.kosherjava.zmanim.hebrewcalendar.TefilaRules#isYaalehVeyavoRecited(JewishCalendar)
13871390
*/
13881391
public int getTekufasTishreiElapsedDays() {
13891392
// Days since Rosh Hashana year 1. Add 1/2 day as the first tekufas tishrei was 9 hours into the day. This allows all
@@ -1393,185 +1396,6 @@ public int getTekufasTishreiElapsedDays() {
13931396
double solar = (getJewishYear() - 1) * 365.25;
13941397
return (int) Math.floor(days - solar);
13951398
}
1396-
1397-
/**
1398-
* Returns if it is the Jewish day (starting the evening before) to start reciting <em>Vesein Tal Umatar
1399-
* Livracha</em> (<em>Sheailas Geshamim</em>). In Israel this is the 7th day of <em>Marcheshvan</em>. Outside
1400-
* Israel recitation starts on the evening of December 4th (or 5th if it is the year before a civil leap year)
1401-
* in the 21st century and shifts a day forward every century not evenly divisible by 400. This method will
1402-
* return true if <em>vesein tal umatar</em> on the current Jewish date that starts on the previous night, so
1403-
* Dec 5/6 will be returned by this method in the 21st century. <em>vesein tal umatar</em> is not recited on
1404-
* <em>Shabbos</em> and the start date will be delayed a day when the start day is on a <em>Shabbos</em> (this
1405-
* can only occur out of Israel).
1406-
*
1407-
* @deprecated Use {@link TefilaRules#isVeseinTalUmatarStartDate(JewishCalendar)} instead. This method will be
1408-
* removed in the v3.0 release.
1409-
*
1410-
* @return true if it is the first Jewish day (starting the prior evening of reciting <em>Vesein Tal Umatar
1411-
* Livracha</em> (<em>Sheailas Geshamim</em>)).
1412-
*
1413-
* @see #isVeseinTalUmatarStartingTonight()
1414-
* @see #isVeseinTalUmatarRecited()
1415-
*/
1416-
@Deprecated // (forRemoval=true) // add back once Java 9 is the minimum supported version
1417-
public boolean isVeseinTalUmatarStartDate() {
1418-
if (inIsrael) {
1419-
// The 7th Cheshvan can't occur on Shabbos, so always return true for 7 Cheshvan
1420-
return getJewishMonth() == CHESHVAN && getJewishDayOfMonth() == 7;
1421-
} else {
1422-
if (getDayOfWeek() == Calendar.SATURDAY) { //Not recited on Friday night
1423-
return false;
1424-
}
1425-
if (getDayOfWeek() == Calendar.SUNDAY) { // When starting on Sunday, it can be the start date or delayed from Shabbos
1426-
return getTekufasTishreiElapsedDays() == 48 || getTekufasTishreiElapsedDays() == 47;
1427-
} else {
1428-
return getTekufasTishreiElapsedDays() == 47;
1429-
}
1430-
}
1431-
}
1432-
1433-
/**
1434-
* Returns true if tonight is the first night to start reciting <em>Vesein Tal Umatar Livracha</em> (
1435-
* <em>Sheailas Geshamim</em>). In Israel this is the 7th day of <em>Marcheshvan</em> (so the 6th will return
1436-
* true). Outside Israel recitation starts on the evening of December 4th (or 5th if it is the year before a
1437-
* civil leap year) in the 21st century and shifts a day forward every century not evenly divisible by 400.
1438-
* <em>Vesein tal umatar</em> is not recited on <em>Shabbos</em> and the start date will be delayed a day when
1439-
* the start day is on a <em>Shabbos</em> (this can only occur out of Israel).
1440-
*
1441-
* @deprecated Use {@link TefilaRules#isVeseinTalUmatarStartingTonight(JewishCalendar)} instead. This method
1442-
* will be removed in the v3.0 release.
1443-
*
1444-
* @return true if it is the first Jewish day (starting the prior evening of reciting <em>Vesein Tal Umatar
1445-
* Livracha</em> (<em>Sheailas Geshamim</em>)).
1446-
*
1447-
* @see #isVeseinTalUmatarStartDate()
1448-
* @see #isVeseinTalUmatarRecited()
1449-
*/
1450-
@Deprecated // (forRemoval=true) // add back once Java 9 is the minimum supported version
1451-
public boolean isVeseinTalUmatarStartingTonight() {
1452-
if (inIsrael) {
1453-
// The 7th Cheshvan can't occur on Shabbos, so always return true for 6 Cheshvan
1454-
return getJewishMonth() == CHESHVAN && getJewishDayOfMonth() == 6;
1455-
} else {
1456-
if (getDayOfWeek() == Calendar.FRIDAY) { //Not recited on Friday night
1457-
return false;
1458-
}
1459-
if (getDayOfWeek() == Calendar.SATURDAY) { // When starting on motzai Shabbos, it can be the start date or delayed from Friday night
1460-
return getTekufasTishreiElapsedDays() == 47 || getTekufasTishreiElapsedDays() == 46;
1461-
} else {
1462-
return getTekufasTishreiElapsedDays() == 46;
1463-
}
1464-
}
1465-
}
1466-
1467-
/**
1468-
* Returns if <em>Vesein Tal Umatar Livracha</em> (<em>Sheailas Geshamim</em>) is recited. This will return
1469-
* true for the entire season, even on <em>Shabbos</em> when it is not recited.
1470-
*
1471-
* @deprecated Use {@link TefilaRules#isVeseinTalUmatarRecited(JewishCalendar)} instead. This method will
1472-
* be removed in the v3.0 release.
1473-
*
1474-
* @return true if <em>Vesein Tal Umatar Livracha</em> (<em>Sheailas Geshamim</em>) is recited.
1475-
*
1476-
* @see #isVeseinTalUmatarStartDate()
1477-
* @see #isVeseinTalUmatarStartingTonight()
1478-
*/
1479-
@Deprecated // (forRemoval=true) // add back once Java 9 is the minimum supported version
1480-
public boolean isVeseinTalUmatarRecited() {
1481-
if (getJewishMonth() == NISSAN && getJewishDayOfMonth() < 15) {
1482-
return true;
1483-
}
1484-
if (getJewishMonth() < CHESHVAN) {
1485-
return false;
1486-
}
1487-
if (inIsrael) {
1488-
return getJewishMonth() != CHESHVAN || getJewishDayOfMonth() >= 7;
1489-
} else {
1490-
return getTekufasTishreiElapsedDays() >= 47;
1491-
}
1492-
}
1493-
1494-
/**
1495-
* Returns if <em>Vesein Beracha</em> is recited. It is recited from 15 <em>Nissan</em> to the point that {@link
1496-
* #isVeseinTalUmatarRecited() <em>vesein tal umatar</em> is recited}.
1497-
*
1498-
* @deprecated Use {@link TefilaRules#isVeseinBerachaRecited(JewishCalendar)} instead. This method will be
1499-
* removed in the v3.0 release.
1500-
*
1501-
* @return true if <em>Vesein Beracha</em> is recited.
1502-
*
1503-
* @see #isVeseinTalUmatarRecited()
1504-
*/
1505-
@Deprecated // (forRemoval=true) // add back once Java 9 is the minimum supported version
1506-
public boolean isVeseinBerachaRecited() {
1507-
return !isVeseinTalUmatarRecited();
1508-
}
1509-
1510-
/**
1511-
* Returns if the date is the start date for reciting <em>Mashiv Haruach Umorid Hageshem</em>. The date is 22 <em>Tishrei</em>.
1512-
*
1513-
* @deprecated Use {@link TefilaRules#isMashivHaruachStartDate(JewishCalendar)} instead. This method will be
1514-
* removed in the v3.0 release.
1515-
*
1516-
* @return true if the date is the start date for reciting <em>Mashiv Haruach Umorid Hageshem</em>.
1517-
*
1518-
* @see #isMashivHaruachEndDate()
1519-
* @see #isMashivHaruachRecited()
1520-
*/
1521-
@Deprecated // (forRemoval=true) // add back once Java 9 is the minimum supported version
1522-
public boolean isMashivHaruachStartDate() {
1523-
return getJewishMonth() == TISHREI && getJewishDayOfMonth() == 22;
1524-
}
1525-
1526-
/**
1527-
* Returns if the date is the end date for reciting <em>Mashiv Haruach Umorid Hageshem</em>. The date is 15 <em>Nissan</em>.
1528-
*
1529-
* @deprecated Use {@link TefilaRules#isMashivHaruachEndDate(JewishCalendar)} instead. This method will be
1530-
* removed in the v3.0 release.
1531-
*
1532-
* @return true if the date is the end date for reciting <em>Mashiv Haruach Umorid Hageshem</em>.
1533-
*
1534-
* @see #isMashivHaruachStartDate()
1535-
* @see #isMashivHaruachRecited()
1536-
*/
1537-
@Deprecated // (forRemoval=true) // add back once Java 9 is the minimum supported version
1538-
public boolean isMashivHaruachEndDate() {
1539-
return getJewishMonth() == NISSAN && getJewishDayOfMonth() == 15;
1540-
}
1541-
1542-
/**
1543-
* Returns if <em>Mashiv Haruach Umorid Hageshem</em> is recited. This period starts on 22 <em>Tishrei</em> and ends
1544-
* on the 15th day of <em>Nissan</em>.
1545-
*
1546-
* @deprecated Use {@link TefilaRules#isMashivHaruachRecited(JewishCalendar)} instead. This method will be
1547-
* removed in the v3.0 release.
1548-
*
1549-
* @return true if <em>Mashiv Haruach Umorid Hageshem</em> is recited.
1550-
*
1551-
* @see #isMashivHaruachStartDate()
1552-
* @see #isMashivHaruachEndDate()
1553-
*/
1554-
@Deprecated // (forRemoval=true) // add back once Java 9 is the minimum supported version
1555-
public boolean isMashivHaruachRecited() {
1556-
JewishDate startDate = new JewishDate(getJewishYear(), TISHREI, 22);
1557-
JewishDate endDate = new JewishDate(getJewishYear(), NISSAN, 15);
1558-
return compareTo(startDate) > 0 && compareTo(endDate) < 0;
1559-
}
1560-
1561-
/**
1562-
* Returns if <em>Morid Hatal</em> (or the lack of reciting <em>Mashiv Haruach</em> following <em>nussach Ashkenaz</em>) is recited.
1563-
* This period starts on 22 <em>Tishrei</em> and ends on the 15th day of
1564-
* <em>Nissan</em>.
1565-
*
1566-
* @deprecated Use {@link TefilaRules#isMoridHatalRecited(JewishCalendar)} instead. This method will be
1567-
* removed in the v3.0 release.
1568-
*
1569-
* @return true if <em>Morid Hatal</em> (or the lack of reciting <em>Mashiv Haruach</em> following <em>nussach Ashkenaz</em>) is recited.
1570-
*/
1571-
@Deprecated // (forRemoval=true) // add back once Java 9 is the minimum supported version
1572-
public boolean isMoridHatalRecited() {
1573-
return !isMashivHaruachRecited() || isMashivHaruachStartDate() || isMashivHaruachEndDate();
1574-
}
15751399

15761400
/**
15771401
* Returns true if the current day is <em>Isru Chag</em>. The method returns true for the day following <em>Pesach</em>

0 commit comments

Comments
 (0)