diff --git a/pom.xml b/pom.xml index 5cbb98de..56dacce6 100644 --- a/pom.xml +++ b/pom.xml @@ -39,6 +39,11 @@ 4.13.1 test + + com.ibm.icu + icu4j + 78.1 + @@ -111,6 +116,24 @@ 8 + + org.apache.maven.plugins + maven-dependency-plugin + 3.7.0 + + + copy-dependencies + package + + copy-dependencies + + + ${project.build.directory}/dependency + compile + + + + 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.*;