diff --git a/src/main/java/com/kosherjava/zmanim/AstronomicalCalendar.java b/src/main/java/com/kosherjava/zmanim/AstronomicalCalendar.java
index 04f829d6..2ba67378 100644
--- a/src/main/java/com/kosherjava/zmanim/AstronomicalCalendar.java
+++ b/src/main/java/com/kosherjava/zmanim/AstronomicalCalendar.java
@@ -16,9 +16,9 @@
package com.kosherjava.zmanim;
import java.math.BigDecimal;
-import java.util.Calendar;
+import com.ibm.icu.util.Calendar;
import java.util.Date;
-import java.util.TimeZone;
+import com.ibm.icu.util.TimeZone;
import com.kosherjava.zmanim.util.AstronomicalCalculator;
import com.kosherjava.zmanim.util.GeoLocation;
@@ -49,7 +49,7 @@
* double longitude = -74.2094; // Lakewood, NJ
* double elevation = 20; // optional elevation correction in Meters
* // the String parameter in getTimeZone() has to be a valid timezone listed in
- * // {@link java.util.TimeZone#getAvailableIDs()}
+ * // {@link com.ibm.icu.util.TimeZone#getAvailableIDs()}
* TimeZone timeZone = TimeZone.getTimeZone("America/New_York");
* GeoLocation location = new GeoLocation(locationName, latitude, longitude, elevation, timeZone);
* AstronomicalCalendar ac = new AstronomicalCalendar(location);
@@ -350,6 +350,7 @@ public Date getSunriseOffsetByDegrees(double offsetZenith) {
*/
public Date getSunsetOffsetByDegrees(double offsetZenith) {
double sunset = getUTCSunset(offsetZenith);
+ // System.out.println("Jsunset: " + sunset);
if (Double.isNaN(sunset)) {
return null;
} else {
@@ -626,8 +627,9 @@ protected Date getDateFromTime(double time, SolarEvent solarEvent) {
return null;
}
double calculatedTime = time;
-
+
Calendar adjustedCalendar = getAdjustedCalendar();
+
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
cal.clear();// clear all fields
cal.set(Calendar.YEAR, adjustedCalendar.get(Calendar.YEAR));
@@ -637,10 +639,10 @@ protected Date getDateFromTime(double time, SolarEvent solarEvent) {
int hours = (int) calculatedTime; // retain only the hours
calculatedTime -= hours;
int minutes = (int) (calculatedTime *= 60); // retain only the minutes
- calculatedTime -= minutes;
+ calculatedTime -= minutes;
int seconds = (int) (calculatedTime *= 60); // retain only the seconds
calculatedTime -= seconds; // remaining milliseconds
-
+
// Check if a date transition has occurred, or is about to occur - this indicates the date of the event is
// actually not the target date, but the day prior or after
int localTimeHours = (int)getGeoLocation().getLongitude() / 15;
@@ -758,8 +760,9 @@ public Date getLocalMeanTime(double hours) {
if (hours < 0 || hours >= 24) {
throw new IllegalArgumentException("Hours must between 0 and 23.9999...");
}
- return getTimeOffset(getDateFromTime(hours - getGeoLocation().getTimeZone().getRawOffset()
- / (double) HOUR_MILLIS, SolarEvent.SUNRISE), -getGeoLocation().getLocalMeanTimeOffset());
+ long timezoneOffsetMillis = getCalendar().getTimeZone().getOffset(getCalendar().getTimeInMillis());
+ return getTimeOffset(getDateFromTime(hours - timezoneOffsetMillis
+ / (double) HOUR_MILLIS, SolarEvent.SUNRISE), -getGeoLocation().getLocalMeanTimeOffset(calendar));
}
/**
@@ -769,11 +772,11 @@ public Date getLocalMeanTime(double hours) {
* @return the adjusted Calendar
*/
private Calendar getAdjustedCalendar(){
- int offset = getGeoLocation().getAntimeridianAdjustment();
+ int offset = getGeoLocation().getAntimeridianAdjustment(getCalendar());
if (offset == 0) {
return getCalendar();
}
- Calendar adjustedCalendar = (Calendar) getCalendar().clone();
+ Calendar adjustedCalendar = getCalendar().clone();
adjustedCalendar.add(Calendar.DAY_OF_MONTH, offset);
return adjustedCalendar;
}
@@ -900,10 +903,10 @@ public void setCalendar(Calendar calendar) {
/**
* A method that creates a deep copy of the object.
- * Note: If the {@link java.util.TimeZone} in the cloned {@link com.kosherjava.zmanim.util.GeoLocation} will
+ * Note: If the {@link com.ibm.icu.util.TimeZone} in the cloned {@link com.kosherjava.zmanim.util.GeoLocation} will
* be changed from the original, it is critical that
* {@link com.kosherjava.zmanim.AstronomicalCalendar#getCalendar()}.
- * {@link java.util.Calendar#setTimeZone(TimeZone) setTimeZone(TimeZone)} be called in order for the
+ * {@link com.ibm.icu.util.Calendar#setTimeZone(TimeZone) setTimeZone(TimeZone)} be called in order for the
* AstronomicalCalendar to output times in the expected offset after being cloned.
*
* @see java.lang.Object#clone()
diff --git a/src/main/java/com/kosherjava/zmanim/ComplexZmanimCalendar.java b/src/main/java/com/kosherjava/zmanim/ComplexZmanimCalendar.java
index 4a0e2961..a42f7362 100644
--- a/src/main/java/com/kosherjava/zmanim/ComplexZmanimCalendar.java
+++ b/src/main/java/com/kosherjava/zmanim/ComplexZmanimCalendar.java
@@ -15,7 +15,7 @@
*/
package com.kosherjava.zmanim;
-import java.util.Calendar;
+import com.ibm.icu.util.Calendar;
import java.util.Date;
import com.kosherjava.zmanim.util.AstronomicalCalculator;
import com.kosherjava.zmanim.util.GeoLocation;
@@ -40,7 +40,7 @@
* double longitude = -74.222; // Lakewood, NJ
* double elevation = 20; // optional elevation correction in Meters
* // the String parameter in getTimeZone() has to be a valid time zone listed in
- * // {@link java.util.TimeZone#getAvailableIDs()}
+ * // {@link com.ibm.icu.util.TimeZone#getAvailableIDs()}
* TimeZone timeZone = TimeZone.getTimeZone("America/New_York");
* GeoLocation location = new GeoLocation(locationName, latitude, longitude, elevation, timeZone);
* ComplexZmanimCalendar czc = new ComplexZmanimCalendar(location);
@@ -3486,18 +3486,22 @@ public Date getSofZmanKidushLevanaBetweenMoldos(Date alos, Date tzais) {
*/
private Date getMoladBasedTime(Date moladBasedTime, Date alos, Date tzais, boolean techila) {
Date lastMidnight = getMidnightLastNight();
- Date midnightTonight = getMidnightTonight();
- if (!(moladBasedTime.before(lastMidnight) || moladBasedTime.after(midnightTonight))){
- if (alos != null || tzais != null) {
- if (techila && !(moladBasedTime.before(tzais) || moladBasedTime.after(alos))){
+ Date midnightTonight = getMidnightTonight();
+ if(moladBasedTime.before(lastMidnight) || moladBasedTime.after(midnightTonight)){ // Invalid time, bailout
+ return null;
+ } else if (alos == null || tzais == null){ // Not enough info to adjust
+ return moladBasedTime;
+ } else { // It's the daytime, get the next/prev night
+ if (moladBasedTime.after(alos) && moladBasedTime.before(tzais)) {
+ if (techila) {
return tzais;
} else {
return alos;
}
- }
- return moladBasedTime;
- }
- return null;
+ } else { // It's the night, the provided time is valid
+ return moladBasedTime;
+ }
+ }
}
/**
diff --git a/src/main/java/com/kosherjava/zmanim/ZmanimCalendar.java b/src/main/java/com/kosherjava/zmanim/ZmanimCalendar.java
index 74b79495..209d2dbd 100644
--- a/src/main/java/com/kosherjava/zmanim/ZmanimCalendar.java
+++ b/src/main/java/com/kosherjava/zmanim/ZmanimCalendar.java
@@ -15,7 +15,7 @@
*/
package com.kosherjava.zmanim;
-import java.util.Calendar;
+import com.ibm.icu.util.Calendar;
import java.util.Date;
import com.kosherjava.zmanim.hebrewcalendar.JewishCalendar;
diff --git a/src/main/java/com/kosherjava/zmanim/hebrewcalendar/JewishCalendar.java b/src/main/java/com/kosherjava/zmanim/hebrewcalendar/JewishCalendar.java
index acc987f2..044c1ac6 100644
--- a/src/main/java/com/kosherjava/zmanim/hebrewcalendar/JewishCalendar.java
+++ b/src/main/java/com/kosherjava/zmanim/hebrewcalendar/JewishCalendar.java
@@ -20,9 +20,9 @@
import com.kosherjava.zmanim.util.GeoLocation;
import java.time.LocalDate;
-import java.util.Calendar;
+import com.ibm.icu.util.Calendar;
import java.util.Date;
-import java.util.TimeZone;
+import com.ibm.icu.util.TimeZone;
/**
* The JewishCalendar extends the JewishDate class and adds calendar methods.
@@ -39,7 +39,7 @@
*
*
* @see java.util.Date
- * @see java.util.Calendar
+ * @see com.ibm.icu.util.Calendar
* @author © Y. Paritcher 2019 - 2022
* @author © Avrom Finkelstien 2002
* @author © Eliyahu Hershfeld 2011 - 2024
@@ -264,7 +264,7 @@ public JewishCalendar(Date date) {
}
/**
- * A constructor that initializes the date to the {@link java.util.Calendar Calendar} parameter.
+ * A constructor that initializes the date to the {@link com.ibm.icu.util.Calendar Calendar} parameter.
*
* @param calendar
* the Calendar to set the calendar to
@@ -1249,7 +1249,7 @@ public Date getMoladAsDate() {
molad.getMoladHours(), molad.getMoladMinutes(), (int) moladSeconds);
cal.set(Calendar.MILLISECOND, (int) (1000 * (moladSeconds - (int) moladSeconds)));
// subtract local time difference of 20.94 minutes (20 minutes and 56.496 seconds) to get to Standard time
- cal.add(Calendar.MILLISECOND, -1 * (int) geo.getLocalMeanTimeOffset());
+ cal.add(Calendar.MILLISECOND, -1 * (int) geo.getLocalMeanTimeOffset(cal));
return cal.getTime();
}
diff --git a/src/main/java/com/kosherjava/zmanim/hebrewcalendar/JewishDate.java b/src/main/java/com/kosherjava/zmanim/hebrewcalendar/JewishDate.java
index eb47d309..80e1f7d5 100644
--- a/src/main/java/com/kosherjava/zmanim/hebrewcalendar/JewishDate.java
+++ b/src/main/java/com/kosherjava/zmanim/hebrewcalendar/JewishDate.java
@@ -18,11 +18,12 @@
import java.time.LocalDate;
import java.util.Date;
-import java.util.Calendar;
-import java.util.GregorianCalendar;
+import com.ibm.icu.util.Calendar;
+import com.ibm.icu.util.GregorianCalendar;
+import com.ibm.icu.util.TimeZone;
/**
- * The JewishDate is the base calendar class, that supports maintenance of a {@link java.util.GregorianCalendar}
+ * The JewishDate is the base calendar class, that supports maintenance of a {@link com.ibm.icu.util.GregorianCalendar}
* instance along with the corresponding Jewish date. This class can use the standard Java Date and Calendar
* classes for setting and maintaining the dates, but it does not subclass these classes or use them internally
* in any calculations. This class also does not have a concept of a time (which the Date class does). Please
@@ -50,7 +51,7 @@
* @see JewishCalendar
* @see HebrewDateFormatter
* @see java.util.Date
- * @see java.util.Calendar
+ * @see com.ibm.icu.util.Calendar
* @author © Avrom Finkelstien 2002
* @author © Eliyahu Hershfeld 2011 - 2024
*/
@@ -567,8 +568,8 @@ private static int getJewishMonthOfYear(int year, int month) {
* @param month
* the Jewish month to validate. It will reject a month < 1 or > 12 (or 13 on a leap year) .
* @param dayOfMonth
- * the day of the Jewish month to validate. It will reject any value < 1 or > 30 TODO: check calling
- * methods to see if there is any reason that the class can validate that 30 is invalid for some months.
+ * the day of the Jewish month to validate. It will reject any value < 1 or > the number of days in the month
+ * for that year.
* @param hours
* the hours (for molad calculations). It will reject an hour < 0 or > 23
* @param minutes
@@ -590,9 +591,12 @@ private static void validateJewishDate(int year, int month, int dayOfMonth, int
throw new IllegalArgumentException("The Jewish month has to be between 1 and 12 (or 13 on a leap year). "
+ month + " is invalid for the year " + year + ".");
}
- if (dayOfMonth < 1 || dayOfMonth > 30) {
- throw new IllegalArgumentException("The Jewish day of month can't be < 1 or > 30. " + dayOfMonth
- + " is invalid.");
+
+ int maxDaysInMonth = getDaysInJewishMonth(month, year);
+
+ if (dayOfMonth < 1 || dayOfMonth > maxDaysInMonth) {
+ throw new IllegalArgumentException("The Jewish day of month can't be < 1 or > " + maxDaysInMonth + ". " + dayOfMonth
+ + " is invalid for the month " + month + " of the year " + year + ".");
}
// reject dates prior to 18 Teves, 3761 (1/1/1 AD). This restriction can be relaxed if the date coding is
// changed/corrected
@@ -986,7 +990,7 @@ public JewishDate(Date date) {
}
/**
- * A constructor that initializes the date to the {@link java.util.Calendar Calendar} parameter.
+ * A constructor that initializes the date to the {@link com.ibm.icu.util.Calendar Calendar} parameter.
*
* @param calendar
* the Calendar to set the calendar to
@@ -1010,7 +1014,7 @@ public JewishDate(LocalDate localDate) {
}
/**
- * Sets the date based on a {@link java.util.Calendar Calendar} object. Modifies the Jewish date as well.
+ * Sets the date based on a {@link com.ibm.icu.util.Calendar Calendar} object. Modifies the Jewish date as well.
*
* @param calendar
* the Calendar to set the calendar to
@@ -1174,13 +1178,18 @@ public void setJewishDate(int year, int month, int dayOfMonth, int hours, int mi
}
/**
- * Returns this object's date as a {@link java.util.Calendar} object.
+ * Returns this object's date as a {@link com.ibm.icu.util.Calendar} object.
*
- * @return The {@link java.util.Calendar}
+ * @return The {@link com.ibm.icu.util.Calendar}
*/
public Calendar getGregorianCalendar() {
Calendar calendar = Calendar.getInstance();
+ calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
calendar.set(getGregorianYear(), getGregorianMonth(), getGregorianDayOfMonth());
+ calendar.set(Calendar.HOUR_OF_DAY, 0);
+ calendar.set(Calendar.MINUTE, 0);
+ calendar.set(Calendar.SECOND, 0);
+ calendar.set(Calendar.MILLISECOND, 0);
return calendar;
}
@@ -1219,7 +1228,7 @@ public String toString() {
*
*
*
- * Calendar cal = jewishDate.getTime(); // get a java.util.Calendar representation of the JewishDate
+ * Calendar cal = jewishDate.getTime(); // get a com.ibm.icu.util.Calendar representation of the JewishDate
* cal.add(Calendar.MONTH, 3); // add 3 Gregorian months
* jewishDate.setDate(cal); // set the updated calendar back to this class
*
@@ -1292,28 +1301,36 @@ public void forward(int field, int amount) {
}
/**
- * Forward the Jewish date by the number of months passed in.
- * FIXME: Deal with forwarding a date such as 30 Nissan by a month. 30 Iyar does not exist. This should be dealt with similar to
- * the way that the Java Calendar behaves (not that simple since there is a difference between add() or roll().
+ * Advances the Jewish date forward by the specified number of months.
+ * If the day doesn't exist in the target month (e.g., 30 Iyar), it adjusts to the last day of that month (29 Iyar).
*
* @throws IllegalArgumentException if the amount is less than 1
- * @param amount the number of months to roll the month forward
+ * @param amount the number of months to advance (must be at least 1)
*/
private void forwardJewishMonth(int amount) {
if (amount < 1) {
throw new IllegalArgumentException("the amount of months to forward has to be greater than zero.");
}
+ int currentMonth = getJewishMonth();
+ int currentYear = getJewishYear();
+ int currentDay = getJewishDayOfMonth();
for (int i = 0; i < amount; i++) {
- if (getJewishMonth() == ELUL) {
- setJewishMonth(TISHREI);
- setJewishYear(getJewishYear() + 1);
- } else if ((! isJewishLeapYear() && getJewishMonth() == ADAR)
- || (isJewishLeapYear() && getJewishMonth() == ADAR_II)){
- setJewishMonth(NISSAN);
+ boolean isLeapYear = JewishDate.isJewishLeapYear(currentYear);
+ if (currentMonth == ELUL) {
+ currentMonth = TISHREI;
+ currentYear = currentYear + 1;
+ } else if ((!isLeapYear && currentMonth == ADAR)
+ || (isLeapYear && currentMonth == ADAR_II)){
+ currentMonth = NISSAN;
} else {
- setJewishMonth(getJewishMonth() + 1);
+ currentMonth = currentMonth + 1;
}
}
+ int maxDaysInMonth = JewishDate.getDaysInJewishMonth(currentMonth, currentYear);
+ if (currentDay > maxDaysInMonth) {
+ currentDay = maxDaysInMonth;
+ }
+ setJewishDate(currentYear, currentMonth, currentDay);
}
/**
@@ -1324,7 +1341,7 @@ private void forwardJewishMonth(int amount) {
*
*
*
- * Calendar cal = jewishDate.getTime(); // get a java.util.Calendar representation of the JewishDate
+ * Calendar cal = jewishDate.getTime(); // get a com.ibm.icu.util.Calendar representation of the JewishDate
* cal.add(Calendar.MONTH, -3); // subtract 3 Gregorian months
* jewishDate.setDate(cal); // set the updated calendar back to this class
*
@@ -1398,7 +1415,7 @@ public int compareTo(JewishDate jewishDate) {
/**
* Returns the Gregorian month (between 0-11).
*
- * @return the Gregorian month (between 0-11). Like the java.util.Calendar, months are 0 based.
+ * @return the Gregorian month (between 0-11). Like the com.ibm.icu.util.Calendar, months are 0 based.
*/
public int getGregorianMonth() {
return gregorianMonth - 1;
diff --git a/src/main/java/com/kosherjava/zmanim/hebrewcalendar/TefilaRules.java b/src/main/java/com/kosherjava/zmanim/hebrewcalendar/TefilaRules.java
index 7e1c3b2b..8a1a7fd7 100644
--- a/src/main/java/com/kosherjava/zmanim/hebrewcalendar/TefilaRules.java
+++ b/src/main/java/com/kosherjava/zmanim/hebrewcalendar/TefilaRules.java
@@ -16,7 +16,7 @@
*/
package com.kosherjava.zmanim.hebrewcalendar;
-import java.util.Calendar;
+import com.ibm.icu.util.Calendar;
/**
* Tefila Rules is a utility class that covers the various halachos and minhagim regarding
diff --git a/src/main/java/com/kosherjava/zmanim/hebrewcalendar/YerushalmiYomiCalculator.java b/src/main/java/com/kosherjava/zmanim/hebrewcalendar/YerushalmiYomiCalculator.java
index a5603e9b..00682520 100644
--- a/src/main/java/com/kosherjava/zmanim/hebrewcalendar/YerushalmiYomiCalculator.java
+++ b/src/main/java/com/kosherjava/zmanim/hebrewcalendar/YerushalmiYomiCalculator.java
@@ -15,8 +15,9 @@
*/
package com.kosherjava.zmanim.hebrewcalendar;
-import java.util.Calendar;
-import java.util.GregorianCalendar;
+import com.ibm.icu.util.Calendar;
+import com.ibm.icu.util.GregorianCalendar;
+import com.ibm.icu.util.TimeZone;
/**
@@ -31,7 +32,11 @@ public class YerushalmiYomiCalculator {
/**
* The start date of the first Daf Yomi Yerushalmi cycle of February 2, 1980 / 15 Shevat, 5740.
*/
- private final static Calendar DAF_YOMI_START_DAY = new GregorianCalendar(1980, Calendar.FEBRUARY, 2);
+ private final static Calendar DAF_YOMI_START_DAY;
+ static {
+ DAF_YOMI_START_DAY = new GregorianCalendar(1980, Calendar.FEBRUARY, 2);
+ DAF_YOMI_START_DAY.setTimeZone(TimeZone.getTimeZone("UTC"));
+ }
/** The number of milliseconds in a day. */
private final static int DAY_MILIS = 1000 * 60 * 60 * 24;
/** The number of pages in the Talmud Yerushalmi.*/
@@ -64,8 +69,8 @@ public YerushalmiYomiCalculator() {
*/
public static Daf getDafYomiYerushalmi(JewishCalendar calendar) {
- Calendar nextCycle = new GregorianCalendar();
- Calendar prevCycle = new GregorianCalendar();
+ Calendar nextCycle = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
+ Calendar prevCycle = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
Calendar requested = calendar.getGregorianCalendar();
int masechta = 0;
Daf dafYomi = null;
@@ -83,17 +88,23 @@ public static Daf getDafYomiYerushalmi(JewishCalendar calendar) {
}
// Start to calculate current cycle. init the start day
+ prevCycle.setTime(DAF_YOMI_START_DAY.getTime());
nextCycle.setTime(DAF_YOMI_START_DAY.getTime());
-
+ // Move the nextCycle to the last day of the current cycle
+ nextCycle.add(Calendar.DAY_OF_MONTH, WHOLE_SHAS_DAFS - 1);
+ nextCycle.add(Calendar.DAY_OF_MONTH, getNumOfSpecialDays(prevCycle, nextCycle));
+
// Go cycle by cycle, until we get the next cycle
while (requested.after(nextCycle)) {
+ // Move the prevCycle from the 1st day of the current cycle to the 1st day of the next cycle
prevCycle.setTime(nextCycle.getTime());
-
- // Adds the number of whole shas dafs. and the number of days that not have daf.
+ prevCycle.add(Calendar.DAY_OF_MONTH, 1);
+
+ // Move the nextCycle from the last day of the current cycle to the last day of the next cycle
nextCycle.add(Calendar.DAY_OF_MONTH, WHOLE_SHAS_DAFS);
- nextCycle.add(Calendar.DAY_OF_MONTH, getNumOfSpecialDays(prevCycle, nextCycle));
+ nextCycle.add(Calendar.DAY_OF_MONTH, getNumOfSpecialDays(prevCycle, nextCycle));
}
-
+
// Get the number of days from cycle start until request.
int dafNo = (int)(getDiffBetweenDays(prevCycle, requested));
@@ -110,6 +121,7 @@ public static Daf getDafYomiYerushalmi(JewishCalendar calendar) {
total -= i;
masechta++;
}
+
return dafYomi;
}
diff --git a/src/main/java/com/kosherjava/zmanim/hebrewcalendar/YomiCalculator.java b/src/main/java/com/kosherjava/zmanim/hebrewcalendar/YomiCalculator.java
index 90ba0b8c..64ce331b 100644
--- a/src/main/java/com/kosherjava/zmanim/hebrewcalendar/YomiCalculator.java
+++ b/src/main/java/com/kosherjava/zmanim/hebrewcalendar/YomiCalculator.java
@@ -15,8 +15,9 @@
*/
package com.kosherjava.zmanim.hebrewcalendar;
-import java.util.Calendar;
-import java.util.GregorianCalendar;
+import com.ibm.icu.util.Calendar;
+import com.ibm.icu.util.GregorianCalendar;
+import com.ibm.icu.util.TimeZone;
/**
* This class calculates the Daf Yomi Bavli page (daf) for a given date. To calculate Daf Yomi Yerushalmi
@@ -30,19 +31,27 @@ public class YomiCalculator {
/**
* The start date of the first Daf Yomi Bavli cycle of September 11, 1923 / Rosh Hashana 5684.
*/
- private static final Calendar dafYomiStartDay = new GregorianCalendar(1923, Calendar.SEPTEMBER, 11);
+ private static final Calendar DAF_YOMI_START_DAY;
+ static {
+ DAF_YOMI_START_DAY = new GregorianCalendar(1923, Calendar.SEPTEMBER, 11,0,0,0);
+ DAF_YOMI_START_DAY.setTimeZone(TimeZone.getTimeZone("UTC"));
+ }
/** The start date of the first Daf Yomi Bavli cycle in the Julian calendar. Used internally for calculations.*/
- private static final int dafYomiJulianStartDay = getJulianDay(dafYomiStartDay);
+ private static final int DAF_YOMI_JULIAN_START_DAY = getJulianDay(DAF_YOMI_START_DAY);
/**
* The date that the pagination for the Daf Yomi Maseches Shekalim changed to use the commonly used Vilna
* Shas pagination from the no longer commonly available Zhitomir / Slavuta Shas used by Rabbi Meir Shapiro.
*/
- private static final Calendar shekalimChangeDay = new GregorianCalendar(1975, Calendar.JUNE, 24);
+ private static final Calendar SHEKALIM_CHANGE_DAY;
+ static {
+ SHEKALIM_CHANGE_DAY = new GregorianCalendar(1975, Calendar.JUNE, 24,0,0,0);
+ SHEKALIM_CHANGE_DAY.setTimeZone(TimeZone.getTimeZone("UTC"));
+ }
/** The Julian date that the cycle for Shekalim changed.
* @see #getDafYomiBavli(JewishCalendar) for details.
*/
- private static final int shekalimJulianChangeDay = getJulianDay(shekalimChangeDay);
+ private static final int SHEKALIM_JULIAN_CHANGE_DAY = getJulianDay(SHEKALIM_CHANGE_DAY);
/**
* Default constructor.
@@ -89,17 +98,17 @@ public static Daf getDafYomiBavli(JewishCalendar jewishCalendar) {
int julianDay = getJulianDay(calendar);
int cycleNo;
int dafNo;
- if (calendar.before(dafYomiStartDay)) {
+ if (calendar.before(DAF_YOMI_START_DAY)) {
// TODO: should we return a null or throw an IllegalArgumentException?
throw new IllegalArgumentException(calendar + " is prior to organized Daf Yomi Bavli cycles that started on "
- + dafYomiStartDay);
+ + DAF_YOMI_START_DAY);
}
- if (calendar.equals(shekalimChangeDay) || calendar.after(shekalimChangeDay)) {
- cycleNo = 8 + ((julianDay - shekalimJulianChangeDay) / 2711);
- dafNo = ((julianDay - shekalimJulianChangeDay) % 2711);
+ if (calendar.equals(SHEKALIM_CHANGE_DAY) || calendar.after(SHEKALIM_CHANGE_DAY)) {
+ cycleNo = 8 + ((julianDay - SHEKALIM_JULIAN_CHANGE_DAY) / 2711);
+ dafNo = ((julianDay - SHEKALIM_JULIAN_CHANGE_DAY) % 2711);
} else {
- cycleNo = 1 + ((julianDay - dafYomiJulianStartDay) / 2702);
- dafNo = ((julianDay - dafYomiJulianStartDay) % 2702);
+ cycleNo = 1 + ((julianDay - DAF_YOMI_JULIAN_START_DAY) / 2702);
+ dafNo = ((julianDay - DAF_YOMI_JULIAN_START_DAY) % 2702);
}
int total = 0;
diff --git a/src/main/java/com/kosherjava/zmanim/hebrewcalendar/package-info.java b/src/main/java/com/kosherjava/zmanim/hebrewcalendar/package-info.java
index 8ed6ecad..fcf7cc80 100644
--- a/src/main/java/com/kosherjava/zmanim/hebrewcalendar/package-info.java
+++ b/src/main/java/com/kosherjava/zmanim/hebrewcalendar/package-info.java
@@ -1,6 +1,6 @@
/**
* This package contain classes that represent a Jewish Date/Calendar,
- * and allows conversion between {@link com.kosherjava.zmanim.hebrewcalendar.JewishDate Jewish} and {@link java.util.GregorianCalendar Gregorian dates}. The main calendar
+ * and allows conversion between {@link com.kosherjava.zmanim.hebrewcalendar.JewishDate Jewish} and {@link com.ibm.icu.util.GregorianCalendar Gregorian dates}. The main calendar
* classes {@link com.kosherjava.zmanim.hebrewcalendar.JewishCalendar} and {@link com.kosherjava.zmanim.hebrewcalendar.JewishDate}
* are based on Avrom Finkelstien's code,
* refactored to fit the Zmanim API. The parsha and season-based tefila change code was ported by Y. Paritcher from his
diff --git a/src/main/java/com/kosherjava/zmanim/package-info.java b/src/main/java/com/kosherjava/zmanim/package-info.java
index a559e64f..82294242 100644
--- a/src/main/java/com/kosherjava/zmanim/package-info.java
+++ b/src/main/java/com/kosherjava/zmanim/package-info.java
@@ -1,7 +1,7 @@
/**
* The KosherJava Zmanim library is an API for a specialized calendar that can calculate different
* astronomical times including sunrise and sunset and Jewish zmanim or religious
- * times for prayers and other Jewish religious duties. These classes extend the {@link java.util.GregorianCalendar} and can therefore use the
+ * times for prayers and other Jewish religious duties. These classes extend the {@link com.ibm.icu.util.GregorianCalendar} and can therefore use the
* standard Calendar functionality to change dates etc. For non-religious astronomical / solar calculations such as sunrise, sunset and twilight, use the {@link com.kosherjava.zmanim.AstronomicalCalendar}. The {@link com.kosherjava.zmanim.ZmanimCalendar} contains the most
diff --git a/src/main/java/com/kosherjava/zmanim/util/AstronomicalCalculator.java b/src/main/java/com/kosherjava/zmanim/util/AstronomicalCalculator.java
index b4d5fdf4..5603f1c8 100644
--- a/src/main/java/com/kosherjava/zmanim/util/AstronomicalCalculator.java
+++ b/src/main/java/com/kosherjava/zmanim/util/AstronomicalCalculator.java
@@ -15,7 +15,7 @@
*/
package com.kosherjava.zmanim.util;
-import java.util.Calendar;
+import com.ibm.icu.util.Calendar;
/**
* An abstract class that all sun time calculating classes extend. This allows the algorithm used to be changed at
diff --git a/src/main/java/com/kosherjava/zmanim/util/GeoLocation.java b/src/main/java/com/kosherjava/zmanim/util/GeoLocation.java
index b2888a33..aae07586 100644
--- a/src/main/java/com/kosherjava/zmanim/util/GeoLocation.java
+++ b/src/main/java/com/kosherjava/zmanim/util/GeoLocation.java
@@ -15,8 +15,9 @@
*/
package com.kosherjava.zmanim.util;
+import com.ibm.icu.util.Calendar;
import java.util.Objects;
-import java.util.TimeZone;
+import com.ibm.icu.util.TimeZone;
/**
* A class that contains location information such as latitude and longitude required for astronomical calculations. The
@@ -309,7 +310,7 @@ public TimeZone getTimeZone() {
* Method to set the TimeZone. If this is ever set after the GeoLocation is set in the
* {@link com.kosherjava.zmanim.AstronomicalCalendar}, it is critical that
* {@link com.kosherjava.zmanim.AstronomicalCalendar#getCalendar()}.
- * {@link java.util.Calendar#setTimeZone(TimeZone) setTimeZone(TimeZone)} be called in order for the
+ * {@link com.ibm.icu.util.Calendar#setTimeZone(TimeZone) setTimeZone(TimeZone)} be called in order for the
* AstronomicalCalendar to output times in the expected offset. This situation will arise if the
* AstronomicalCalendar is ever {@link com.kosherjava.zmanim.AstronomicalCalendar#clone() cloned}.
*
@@ -329,15 +330,17 @@ public void setTimeZone(TimeZone timeZone) {
* so a user who is 1° west of this will have noon at 4 minutes after standard time noon, and conversely, a user
* who is 1° east of the 15° longitude will have noon at 11:56 AM. Lakewood, N.J., whose longitude is
* -74.222, is 0.778 away from the closest multiple of 15 at -75°. This is multiplied by 4 to yield 3 minutes
- * and 10 seconds earlier than standard time. The offset returned does not account for the Daylight saving time offset since this class is
- * unaware of dates.
+ * and 10 seconds earlier than standard time. The offset returned uses the actual timezone offset at the specific
+ * date/time from the Calendar, accounting for Daylight
+ * saving time.
*
- * @return the offset in milliseconds not accounting for Daylight saving time. A positive value will be returned
- * East of the 15° timezone line, and a negative value West of it.
+ * @param calendar the Calendar containing the date/time to calculate the offset for
+ * @return the offset in milliseconds. A positive value will be returned East of the 15° timezone line, and a
+ * negative value West of it.
*/
- public long getLocalMeanTimeOffset() {
- return (long) (getLongitude() * 4 * MINUTE_MILLIS - getTimeZone().getRawOffset());
+ public long getLocalMeanTimeOffset(Calendar calendar) {
+ long timezoneOffsetMillis = calendar.getTimeZone().getOffset(calendar.getTimeInMillis());
+ return (long) (getLongitude() * 4 * MINUTE_MILLIS - timezoneOffsetMillis);
}
/**
@@ -355,10 +358,11 @@ public long getLocalMeanTimeOffset() {
* UTC time, the local DST offset of UTC+14:00 should be applied
* to bring the date back to 2018-02-03.
*
+ * @param calendar the Calendar containing the date/time to calculate the adjustment for
* @return the number of days to adjust the date This will typically be 0 unless the date crosses the antimeridian
*/
- public int getAntimeridianAdjustment() {
- double localHoursOffset = getLocalMeanTimeOffset() / (double)HOUR_MILLIS;
+ public int getAntimeridianAdjustment(Calendar calendar) {
+ double localHoursOffset = getLocalMeanTimeOffset(calendar) / (double)HOUR_MILLIS;
if (localHoursOffset >= 20){// if the offset is 20 hours or more in the future (never expected anywhere other
// than a location using a timezone across the antimeridian to the east such as Samoa)
@@ -565,6 +569,10 @@ public double getRhumbLineDistance(GeoLocation location) {
* @return The XML formatted String.
*/
public String toXML() {
+ Calendar cal = Calendar.getInstance(getTimeZone());
+ long gmtOffsetMillis = cal.getTimeZone().getOffset(cal.getTimeInMillis());
+ long dstOffsetMillis = getTimeZone().getDSTSavings();
+
return "\n" +
"\t" + getLocationName() + "\n" +
"\t" + getLatitude() + "\n" +
@@ -572,9 +580,9 @@ public String toXML() {
"\t" + getElevation() + " Meters" + "\n" +
"\t" + getTimeZone().getID() + "\n" +
"\t" + getTimeZone().getDisplayName() + "\n" +
- "\t" + getTimeZone().getRawOffset() / HOUR_MILLIS +
+ "\t" + gmtOffsetMillis / HOUR_MILLIS +
"\n" +
- "\t" + getTimeZone().getDSTSavings() / HOUR_MILLIS +
+ "\t" + dstOffsetMillis / HOUR_MILLIS +
"\n" +
"";
}
@@ -620,6 +628,10 @@ public int hashCode() {
* @see java.lang.Object#toString()
*/
public String toString() {
+ Calendar cal = Calendar.getInstance(getTimeZone());
+ long gmtOffsetMillis = cal.getTimeZone().getOffset(cal.getTimeInMillis());
+ long dstOffsetMillis = getTimeZone().getDSTSavings();
+
return "\nLocation Name:\t\t\t" + getLocationName() +
"\nLatitude:\t\t\t" + getLatitude() + "\u00B0" +
"\nLongitude:\t\t\t" + getLongitude() + "\u00B0" +
@@ -627,16 +639,16 @@ public String toString() {
"\nTimezone ID:\t\t\t" + getTimeZone().getID() +
"\nTimezone Display Name:\t\t" + getTimeZone().getDisplayName() +
" (" + getTimeZone().getDisplayName(false, TimeZone.SHORT) + ")" +
- "\nTimezone GMT Offset:\t\t" + getTimeZone().getRawOffset() / HOUR_MILLIS +
- "\nTimezone DST Offset:\t\t" + getTimeZone().getDSTSavings() / HOUR_MILLIS;
+ "\nTimezone GMT Offset:\t\t" + gmtOffsetMillis / HOUR_MILLIS +
+ "\nTimezone DST Offset:\t\t" + dstOffsetMillis / HOUR_MILLIS;
}
/**
* An implementation of the {@link java.lang.Object#clone()} method that creates a deep copy of the object.
- * Note: If the {@link java.util.TimeZone} in the clone will be changed from the original, it is critical
+ * Note: If the {@link com.ibm.icu.util.TimeZone} in the clone will be changed from the original, it is critical
* that {@link com.kosherjava.zmanim.AstronomicalCalendar#getCalendar()}.
- * {@link java.util.Calendar#setTimeZone(TimeZone) setTimeZone(TimeZone)} is called after cloning in order for the
+ * {@link com.ibm.icu.util.Calendar#setTimeZone(TimeZone) setTimeZone(TimeZone)} is called after cloning in order for the
* AstronomicalCalendar to output times in the expected offset.
*
* @see java.lang.Object#clone()
diff --git a/src/main/java/com/kosherjava/zmanim/util/NOAACalculator.java b/src/main/java/com/kosherjava/zmanim/util/NOAACalculator.java
index ec9a0453..964d749f 100644
--- a/src/main/java/com/kosherjava/zmanim/util/NOAACalculator.java
+++ b/src/main/java/com/kosherjava/zmanim/util/NOAACalculator.java
@@ -15,7 +15,8 @@
*/
package com.kosherjava.zmanim.util;
-import java.util.Calendar;
+import com.ibm.icu.util.Calendar;
+import com.ibm.icu.util.TimeZone;
/**
* Implementation of sunrise and sunset methods to calculate astronomical times based on the Universal Coordinated Time (UTC)
diff --git a/src/main/java/com/kosherjava/zmanim/util/SunTimesCalculator.java b/src/main/java/com/kosherjava/zmanim/util/SunTimesCalculator.java
index 9e3fee26..2e52a771 100644
--- a/src/main/java/com/kosherjava/zmanim/util/SunTimesCalculator.java
+++ b/src/main/java/com/kosherjava/zmanim/util/SunTimesCalculator.java
@@ -15,7 +15,7 @@
*/
package com.kosherjava.zmanim.util;
-import java.util.Calendar;
+import com.ibm.icu.util.Calendar;
/**
* Implementation of sunrise and sunset methods to calculate astronomical times. This calculator uses the Java algorithm
diff --git a/src/main/java/com/kosherjava/zmanim/util/Time.java b/src/main/java/com/kosherjava/zmanim/util/Time.java
index 1b190893..b361b75a 100644
--- a/src/main/java/com/kosherjava/zmanim/util/Time.java
+++ b/src/main/java/com/kosherjava/zmanim/util/Time.java
@@ -15,7 +15,7 @@
*/
package com.kosherjava.zmanim.util;
-import java.util.TimeZone;
+import com.ibm.icu.util.TimeZone;
/**
* A class that represents a numeric time. Times that represent a time of day are stored as {@link java.util.Date}s in
diff --git a/src/main/java/com/kosherjava/zmanim/util/Zman.java b/src/main/java/com/kosherjava/zmanim/util/Zman.java
index db6d26ff..8ff71450 100644
--- a/src/main/java/com/kosherjava/zmanim/util/Zman.java
+++ b/src/main/java/com/kosherjava/zmanim/util/Zman.java
@@ -32,7 +32,7 @@
* double latitude = 40.0828; // Lakewood, NJ
* double longitude = -74.2094; // Lakewood, NJ
* double elevation = 20; // optional elevation correction in Meters
- * // the String parameter in getTimeZone() has to be a valid timezone listed in {@link java.util.TimeZone#getAvailableIDs()}
+ * // the String parameter in getTimeZone() has to be a valid timezone listed in {@link com.ibm.icu.util.TimeZone#getAvailableIDs()}
* TimeZone timeZone = TimeZone.getTimeZone("America/New_York");
* GeoLocation location = new GeoLocation(locationName, latitude, longitude, elevation, timeZone);
* ComplexZmanimCalendar czc = new ComplexZmanimCalendar(location);
diff --git a/src/main/java/com/kosherjava/zmanim/util/ZmanimFormatter.java b/src/main/java/com/kosherjava/zmanim/util/ZmanimFormatter.java
index b0b4c2d5..a94bac57 100644
--- a/src/main/java/com/kosherjava/zmanim/util/ZmanimFormatter.java
+++ b/src/main/java/com/kosherjava/zmanim/util/ZmanimFormatter.java
@@ -16,15 +16,15 @@
package com.kosherjava.zmanim.util;
import java.lang.reflect.Method;
-import java.text.DateFormat;
+import com.ibm.icu.text.DateFormat;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
-import java.util.Calendar;
+import com.ibm.icu.util.Calendar;
import java.util.List;
-import java.util.TimeZone;
-import java.text.SimpleDateFormat;
+import com.ibm.icu.util.TimeZone;
+import com.ibm.icu.text.SimpleDateFormat;
import com.kosherjava.zmanim.AstronomicalCalendar;
/**
@@ -273,7 +273,7 @@ public String format(Time time) {
* @param dateTime
* the date to format
* @param calendar
- * the {@link java.util.Calendar Calendar} used to help format based on the Calendar's DST and other
+ * the {@link com.ibm.icu.util.Calendar Calendar} used to help format based on the Calendar's DST and other
* settings.
* @return the formatted String
*/
diff --git a/src/test/java/com/kosherjava/zmanim/hebrewcalendar/RegressionTestFileWriter.java b/src/test/java/com/kosherjava/zmanim/hebrewcalendar/RegressionTestFileWriter.java
index 4c3b0162..4326f6c3 100644
--- a/src/test/java/com/kosherjava/zmanim/hebrewcalendar/RegressionTestFileWriter.java
+++ b/src/test/java/com/kosherjava/zmanim/hebrewcalendar/RegressionTestFileWriter.java
@@ -6,7 +6,13 @@
import java.io.*;
import java.time.LocalDate;
-import java.util.*;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.StringJoiner;
+import com.ibm.icu.util.Calendar;
+import com.ibm.icu.util.GregorianCalendar;
+import com.ibm.icu.util.TimeZone;
public class RegressionTestFileWriter {
public static void main(String[] args) throws IOException {
diff --git a/src/test/java/com/kosherjava/zmanim/hebrewcalendar/UT_DaysInGregorianMonth.java b/src/test/java/com/kosherjava/zmanim/hebrewcalendar/UT_DaysInGregorianMonth.java
index 4dd5ac87..5e403981 100644
--- a/src/test/java/com/kosherjava/zmanim/hebrewcalendar/UT_DaysInGregorianMonth.java
+++ b/src/test/java/com/kosherjava/zmanim/hebrewcalendar/UT_DaysInGregorianMonth.java
@@ -6,7 +6,7 @@
import org.junit.*;
-import java.util.Calendar;
+import com.ibm.icu.util.Calendar;
/**
* Verify the calculation of the number of days in a month. Not too hard...just the rules about when February
diff --git a/src/test/java/com/kosherjava/zmanim/hebrewcalendar/UT_GregorianDateNavigation.java b/src/test/java/com/kosherjava/zmanim/hebrewcalendar/UT_GregorianDateNavigation.java
index 6feb7e38..70e331b7 100644
--- a/src/test/java/com/kosherjava/zmanim/hebrewcalendar/UT_GregorianDateNavigation.java
+++ b/src/test/java/com/kosherjava/zmanim/hebrewcalendar/UT_GregorianDateNavigation.java
@@ -6,7 +6,7 @@
import org.junit.*;
-import java.util.Calendar;
+import com.ibm.icu.util.Calendar;
/**
* Checks that we can roll forward & backward the gregorian dates...
diff --git a/src/test/java/com/kosherjava/zmanim/hebrewcalendar/UT_JewishDateNavigation.java b/src/test/java/com/kosherjava/zmanim/hebrewcalendar/UT_JewishDateNavigation.java
index 2a0d6e66..e2588e21 100644
--- a/src/test/java/com/kosherjava/zmanim/hebrewcalendar/UT_JewishDateNavigation.java
+++ b/src/test/java/com/kosherjava/zmanim/hebrewcalendar/UT_JewishDateNavigation.java
@@ -6,7 +6,7 @@
import org.junit.*;
-import java.util.Calendar;
+import com.ibm.icu.util.Calendar;
/**
*
diff --git a/src/test/java/com/kosherjava/zmanim/hebrewcalendar/UT_YerushalmiTest.java b/src/test/java/com/kosherjava/zmanim/hebrewcalendar/UT_YerushalmiTest.java
index 60b9d8b7..e9b3c3b3 100644
--- a/src/test/java/com/kosherjava/zmanim/hebrewcalendar/UT_YerushalmiTest.java
+++ b/src/test/java/com/kosherjava/zmanim/hebrewcalendar/UT_YerushalmiTest.java
@@ -1,6 +1,6 @@
package com.kosherjava.zmanim.hebrewcalendar;
-import java.util.Calendar;
+import com.ibm.icu.util.Calendar;
import org.junit.*;