Skip to content

Commit

Permalink
added support for safek mukaf choma, updated code with KosherJava cha…
Browse files Browse the repository at this point in the history
…nges
  • Loading branch information
Elyahu41 committed Sep 6, 2024
1 parent bfe64d8 commit ba52cc1
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 94 deletions.
2 changes: 1 addition & 1 deletion KosherSwiftNew.podspec
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Pod::Spec.new do |spec|

spec.name = "KosherSwiftNew"
spec.version = "1.0.7"
spec.version = "1.0.9"
spec.summary = "KosherJava Zmanim API / Library ported to Swift."

spec.description = "This 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.
Expand Down
8 changes: 4 additions & 4 deletions Sources/KosherSwift/ComplexZmanimCalendar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4033,7 +4033,7 @@ public class ComplexZmanimCalendar : ZmanimCalendar {
* @see getHalfDayBasedZman(Date, Date, double)
*/
public func getSofZmanShmaGRASunriseToFixedLocalChatzos() -> Date? {
return getHalfDayBasedZman(startOfHalfDay: getSunrise(), endOfHalfDay: getFixedLocalChatzos(), hours: 3);
return getHalfDayBasedZman(startOfHalfDay: getElevationAdjustedSunrise(), endOfHalfDay: getFixedLocalChatzos(), hours: 3);
}

/**
Expand All @@ -4053,7 +4053,7 @@ public class ComplexZmanimCalendar : ZmanimCalendar {
* @see getHalfDayBasedZman(Date, Date, double)
*/
public func getSofZmanTfilaGRASunriseToFixedLocalChatzos() -> Date? {
return getHalfDayBasedZman(startOfHalfDay: getSunrise(), endOfHalfDay: getFixedLocalChatzos(), hours: 4);
return getHalfDayBasedZman(startOfHalfDay: getElevationAdjustedSunrise(), endOfHalfDay: getFixedLocalChatzos(), hours: 4);
}

/**
Expand Down Expand Up @@ -4093,7 +4093,7 @@ public class ComplexZmanimCalendar : ZmanimCalendar {
* @see ZmanimCalendar#getHalfDayBasedZman(Date, Date, double)
*/
public func getMinchaKetanaGRAFixedLocalChatzosToSunset() -> Date? {
return getHalfDayBasedZman(startOfHalfDay: getFixedLocalChatzos(), endOfHalfDay: getSunset(), hours: 3.5);
return getHalfDayBasedZman(startOfHalfDay: getFixedLocalChatzos(), endOfHalfDay: getElevationAdjustedSunset(), hours: 3.5);
}

/**
Expand All @@ -4114,7 +4114,7 @@ public class ComplexZmanimCalendar : ZmanimCalendar {
* @see ZmanimCalendar#getHalfDayBasedZman(Date, Date, double)
*/
public func getPlagHaminchaGRAFixedLocalChatzosToSunset() -> Date? {
return getHalfDayBasedZman(startOfHalfDay: getFixedLocalChatzos(), endOfHalfDay: getSunset(), hours: 4.75);
return getHalfDayBasedZman(startOfHalfDay: getFixedLocalChatzos(), endOfHalfDay: getElevationAdjustedSunset(), hours: 4.75);
}

/**
Expand Down
47 changes: 41 additions & 6 deletions Sources/KosherSwift/hebrewcalendar/JewishCalendar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,13 @@ public class JewishCalendar {
*/
public var isMukafChoma: Bool = false

/**
* Is the calendar set to have a safek (doubtful) Purim <em>demukafim</em>, where Purim is celebrated (mainly) on the 14th and the 15th of Adar.
* @see #getIsSafekMukafChoma()
* @see #setIsSafekMukafChoma(boolean)
*/
public var isSafekMukafChoma = false

/**
* List of <em>parshiyos</em> or special <em>Shabasos</em>. ``NONE`` indicates a week without a <em>parsha</em>, while the enum for
* the <em>parsha</em> of ``VZOS_HABERACHA`` exists for consistency, but is not currently used. The special <em>Shabasos</em> of
Expand Down Expand Up @@ -678,6 +685,29 @@ public class JewishCalendar {
self.isMukafChoma = isMukafChoma;
}

/**
* Returns if the city is set as a city that may have been surrounded by a wall from the time of Yehoshua, and
* Shushan Purim should be celebrated as well as regular Purim.
* @return if the city is set as a city that may have been surrounded by a wall from the time of Yehoshua, and
* Shushan Purim should be celebrated as well as regular Purim.
* @see #setIsSafekMukafChoma(boolean)
*/
public func getIsSafekMukafChoma() -> Bool {
return isSafekMukafChoma
}

/**
* Sets if the location may have been surrounded by a wall from the time of Yehoshua, and Shushan Purim should be
* celebrated as well as regular Purim. This can be set for Baghdad Iraq, or other cities around the world that
* have the status of a "Safek Mukaf Choma". There are multiple cities in Israel that have this status.
* The exception being Yerushalayim.
* @param isSafekMukafChoma if the city may have been surrounded by a wall from the time of Yehoshua.
* @see #getIsSafekMukafChoma()
*/
public func setIsSafekMukafChoma(isSafekMukafChoma: Bool) {
self.isSafekMukafChoma = isSafekMukafChoma
}

/**
* The internal date object that all the calculations are dependant on. Change this date to effect all the other methods of the class. By default the date is set to the system's current time with the system's current timezone.
*/
Expand Down Expand Up @@ -1544,7 +1574,7 @@ public class JewishCalendar {
if (day == 15 || (day == 16 && !inIsrael)) {
return JewishCalendar.SUCCOS;
}
if (day >= 17 && day <= 20 || (day == 16 && inIsrael)) {
if (day >= 16 && day <= 20) {
return JewishCalendar.CHOL_HAMOED_SUCCOS;
}
if (day == 21) {
Expand Down Expand Up @@ -1641,7 +1671,7 @@ public class JewishCalendar {
*/
public func isYomTov() -> Bool {
let holidayIndex = getYomTovIndex();
if ((isErevYomTov() && (holidayIndex != JewishCalendar.HOSHANA_RABBA || (holidayIndex == JewishCalendar.CHOL_HAMOED_PESACH && getJewishDayOfMonth() != 20)))
if ((isErevYomTov() && !( holidayIndex == JewishCalendar.HOSHANA_RABBA || holidayIndex == JewishCalendar.CHOL_HAMOED_PESACH))
|| (isTaanis() && holidayIndex != JewishCalendar.YOM_KIPPUR) || holidayIndex == JewishCalendar.ISRU_CHAG) {
return false;
}
Expand Down Expand Up @@ -2018,17 +2048,22 @@ public class JewishCalendar {

/**
* Returns if the day is Purim (<a href="https://en.wikipedia.org/wiki/Purim#Shushan_Purim">Shushan Purim</a>
* in a mukaf choma and regular Purim in a non-mukaf choma).
* @return if the day is Purim (Shushan Purim in a mukaf choma and regular Purim in a non-mukaf choma)
* in a mukaf choma and regular Purim in a non-mukaf choma. On both days if {@link #setIsSafekMukafChoma(boolean)} is true).
* @return if the day is Purim (Shushan Purim in a mukaf choma and regular Purim in a non-mukaf choma or on both days
* if {@link #setIsSafekMukafChoma(boolean)} is true)
*
* @see #getIsMukafChoma()
* @see #setIsMukafChoma(boolean)
* @see #getIsSafekMukafChoma()
* @see #setIsSafekMukafChoma(boolean)
*/
public func isPurim() -> Bool {
if (isMukafChoma) {
return getYomTovIndex() == JewishCalendar.SHUSHAN_PURIM;
return getYomTovIndex() == JewishCalendar.SHUSHAN_PURIM
} else if (isSafekMukafChoma) {
return getYomTovIndex() == JewishCalendar.PURIM || getYomTovIndex() == JewishCalendar.SHUSHAN_PURIM
} else {
return getYomTovIndex() == JewishCalendar.PURIM;
return getYomTovIndex() == JewishCalendar.PURIM
}
}

Expand Down
117 changes: 34 additions & 83 deletions Sources/KosherSwift/util/NOAACalculator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,23 @@ public class NOAACalculator : AstronomicalCalculator {
public init(geoLocation: GeoLocation) {
NOAACalculator.geoLocation = geoLocation
}

/**
* An enum to indicate what type of solar event is being calculated.
*/
enum SolarEvent {
/**SUNRISE A solar event related to sunrise*/case SUNRISE
/**SUNSET A solar event related to sunset*/case SUNSET
// possibly add the following in the future, if added, an IllegalArgumentException should be thrown in getSunHourAngle
// /**NOON A solar event related to noon*/NOON, /**MIDNIGHT A solar event related to midnight*/MIDNIGHT
}

/**
* Returns the name of the algorithm.
* @return the descriptive name of the algorithm.
*/
public func getCalculatorName() -> String {
return "US National Oceanic and Atmospheric Administration Algorithm";
return "US National Oceanic and Atmospheric Administration Algorithm"; // Implementation of the Jean Meeus algorithm
}

/**
Expand All @@ -72,8 +82,7 @@ public class NOAACalculator : AstronomicalCalculator {
public override func getUTCSunrise(date: Date, geoLocation: GeoLocation, zenith: Double, adjustForElevation: Bool) -> Double {
let elevation = adjustForElevation ? geoLocation.getElevation() : 0;
let adjustedZenith = adjustZenith(zenith: zenith, elevation: elevation);

var sunrise = NOAACalculator.getSunriseUTC(julianDay: NOAACalculator.getJulianDay(date: date), latitude: geoLocation.getLatitude(), longitude: -geoLocation.getLongitude(), zenith: adjustedZenith);
var sunrise = NOAACalculator.getSunRiseSetUTC(julianDay: NOAACalculator.getJulianDay(date: date), latitude: geoLocation.getLatitude(), longitude: -geoLocation.getLongitude(), zenith: adjustedZenith, solarEvent: SolarEvent.SUNRISE);
sunrise = sunrise / 60;

// ensure that the time is >= 0 and < 24
Expand Down Expand Up @@ -111,7 +120,7 @@ public class NOAACalculator : AstronomicalCalculator {
let elevation = adjustForElevation ? geoLocation.getElevation() : 0;
let adjustedZenith = adjustZenith(zenith: zenith, elevation: elevation);

var sunset = NOAACalculator.getSunsetUTC(julianDay: NOAACalculator.getJulianDay(date: date), latitude: geoLocation.getLatitude(), longitude: -geoLocation.getLongitude(),zenith: adjustedZenith);
var sunset = NOAACalculator.getSunRiseSetUTC(julianDay: NOAACalculator.getJulianDay(date: date), latitude: geoLocation.getLatitude(), longitude: -geoLocation.getLongitude(),zenith: adjustedZenith, solarEvent: SolarEvent.SUNSET);
sunset = sunset / 60;

// ensure that the time is >= 0 and < 24
Expand Down Expand Up @@ -360,28 +369,9 @@ public class NOAACalculator : AstronomicalCalculator {
return toDegrees(radians: equationOfTime) * 4.0; // in minutes of time
}

/**
* Return the <a href="https://en.wikipedia.org/wiki/Hour_angle">hour angle</a> of the sun in
* <a href="https://en.wikipedia.org/wiki/Radian">radians</a> at sunrise for the latitude.
*
* @param lat
* the latitude of observer in degrees
* @param solarDec
* the declination angle of sun in degrees
* @param zenith
* the zenith
* @return hour angle of sunrise in <a href="https://en.wikipedia.org/wiki/Radian">radians</a>
*/
private static func getSunHourAngleAtSunrise(lat: Double, solarDec: Double, zenith: Double) -> Double {
let latRad = toRadians(degrees: lat);
let sdRad = toRadians(degrees: solarDec);

return acos(cos(toRadians(degrees: zenith)) / (cos(latRad) * cos(sdRad)) - tan(latRad) * tan(sdRad)); // in radians
}

/**
* Returns the <a href="https://en.wikipedia.org/wiki/Hour_angle">hour angle</a> of the sun in <a href=
* "https://en.wikipedia.org/wiki/Radian">radians</a>at sunset for the latitude.
* "https://en.wikipedia.org/wiki/Radian">radians</a>at for the latitude.
* @todo use - {@link #getSunHourAngleAtSunrise(double, double, double)} implementation to avoid duplication of code.
*
* @param lat
Expand All @@ -390,14 +380,19 @@ public class NOAACalculator : AstronomicalCalculator {
* the declination angle of sun in degrees
* @param zenith
* the zenith
* @param solarEvent
* If the hour angle is for sunrise or sunset
* @return the hour angle of sunset in <a href="https://en.wikipedia.org/wiki/Radian">radians</a>
*/
private static func getSunHourAngleAtSunset(lat: Double, solarDec: Double, zenith: Double) -> Double {
let latRad = toRadians(degrees: lat);
let sdRad = toRadians(degrees: solarDec);

let hourAngle = (acos(cos(toRadians(degrees: zenith)) / (cos(latRad) * cos(sdRad)) - tan(latRad) * tan(sdRad)));
return -hourAngle; // in radians
private static func getSunHourAngle(latitude: Double, solarDeclination: Double, zenith: Double, solarEvent: SolarEvent) -> Double {
let latRad = toRadians(degrees: latitude);
let sdRad = toRadians(degrees: solarDeclination);

var hourAngle = (acos(cos(toRadians(degrees: zenith)) / (cos(latRad) * cos(sdRad)) - tan(latRad) * tan(sdRad)));
if (solarEvent == SolarEvent.SUNSET) {
hourAngle = -hourAngle;
}
return hourAngle;
}

/**
Expand Down Expand Up @@ -474,52 +469,6 @@ public class NOAACalculator : AstronomicalCalculator {
return toDegrees(radians: atan(sin(hourAngle_rad) / ((cos(hourAngle_rad) * sin(lat_rad)) - (tan(dec_rad) * cos(lat_rad)))))+180.0;

}

/**
* Return the <a href="https://en.wikipedia.org/wiki/Universal_Coordinated_Time">Universal Coordinated Time</a> (UTC)
* of sunrise for the given day at the given location on earth.
*
* @param julianDay
* the Julian day
* @param latitude
* the latitude of observer in degrees
* @param longitude
* the longitude of observer in degrees
* @param zenith
* the zenith
* @return the time in minutes from zero UTC
*/
private static func getSunriseUTC(julianDay:Double, latitude:Double, longitude:Double, zenith:Double) -> Double {
let julianCenturies = getJulianCenturiesFromJulianDay(julianDay: julianDay);

// Find the time of solar noon at the location, and use that declination. This is better than start of the
// Julian day

let noonmin = getSolarNoonUTC(julianCenturies: julianCenturies, longitude: longitude);
let tnoon = getJulianCenturiesFromJulianDay(julianDay: julianDay + noonmin / 1440.0);

// First pass to approximate sunrise (using solar noon)

var eqTime = getEquationOfTime(julianCenturies: tnoon);
var solarDec = getSunDeclination(julianCenturies: tnoon);
var hourAngle = getSunHourAngleAtSunrise(lat: latitude, solarDec: solarDec, zenith: zenith);

var delta = longitude - toDegrees(radians: hourAngle);
var timeDiff = 4 * delta; // in minutes of time
var timeUTC = 720 + timeDiff - eqTime; // in minutes

// Second pass includes fractional Julian Day in gamma calc

let newt = getJulianCenturiesFromJulianDay(julianDay: getJulianDayFromJulianCenturies(julianCenturies: julianCenturies) + timeUTC
/ 1440.0);
eqTime = getEquationOfTime(julianCenturies: newt);
solarDec = getSunDeclination(julianCenturies: newt);
hourAngle = getSunHourAngleAtSunrise(lat: latitude, solarDec: solarDec, zenith: zenith);
delta = longitude - toDegrees(radians: hourAngle);
timeDiff = 4 * delta;
timeUTC = 720 + timeDiff - eqTime; // in minutes
return timeUTC;
}

/**
* Return the <a href="https://en.wikipedia.org/wiki/Universal_Coordinated_Time">Universal Coordinated Time</a> (UTC)
Expand Down Expand Up @@ -572,7 +521,7 @@ public class NOAACalculator : AstronomicalCalculator {
* @see #getUTCNoon(Calendar, GeoLocation)
*/
private static func getSolarNoonUTC(julianCenturies: Double, longitude: Double) -> Double {
// First pass uses approximate solar noon to calculate equation of time
// Only 1 pass for approximate solar noon to calculate equation of time
let tnoon = getJulianCenturiesFromJulianDay(julianDay: getJulianDayFromJulianCenturies(julianCenturies: julianCenturies) + longitude / 360.0);
var eqTime = getEquationOfTime(julianCenturies: tnoon);
let solNoonUTC = 720 + (longitude * 4) - eqTime; // min
Expand All @@ -586,7 +535,7 @@ public class NOAACalculator : AstronomicalCalculator {

/**
* Return the <a href="https://en.wikipedia.org/wiki/Universal_Coordinated_Time">Universal Coordinated Time</a> (UTC)
* of sunset for the given day at the given location on earth.
* of sunrise or sunset for the given day at the given location on earth.
*
* @param julianDay
* the Julian day
Expand All @@ -596,13 +545,15 @@ public class NOAACalculator : AstronomicalCalculator {
* longitude of observer in degrees
* @param zenith
* zenith
* @param solarEvent
* Is the calculation for sunrise or sunset
* @return the time in minutes from zero Universal Coordinated Time (UTC)
*/
private static func getSunsetUTC(julianDay:Double, latitude:Double, longitude: Double, zenith:Double) -> Double {
private static func getSunRiseSetUTC(julianDay: Double, latitude: Double, longitude: Double, zenith: Double, solarEvent: SolarEvent) -> Double {
let julianCenturies = getJulianCenturiesFromJulianDay(julianDay: julianDay);

// Find the time of solar noon at the location, and use that declination. This is better than start of the
// Julian day
// Find the time of solar noon at the location, and use that declination.
// This is better than start of the Julian day

let noonmin = getSolarNoonUTC(julianCenturies: julianCenturies, longitude: longitude);
let tnoon = getJulianCenturiesFromJulianDay(julianDay: julianDay + noonmin / 1440.0);
Expand All @@ -611,7 +562,7 @@ public class NOAACalculator : AstronomicalCalculator {

var eqTime = getEquationOfTime(julianCenturies: tnoon);
var solarDec = getSunDeclination(julianCenturies: tnoon);
var hourAngle = getSunHourAngleAtSunset(lat: latitude, solarDec: solarDec, zenith: zenith);
var hourAngle = getSunHourAngle(latitude: latitude, solarDeclination: solarDec, zenith: zenith, solarEvent: solarEvent);

var delta = longitude - toDegrees(radians: hourAngle);
var timeDiff = 4 * delta;
Expand All @@ -623,7 +574,7 @@ public class NOAACalculator : AstronomicalCalculator {
/ 1440.0);
eqTime = getEquationOfTime(julianCenturies: newt);
solarDec = getSunDeclination(julianCenturies: newt);
hourAngle = getSunHourAngleAtSunset(lat: latitude, solarDec: solarDec, zenith: zenith);
hourAngle = getSunHourAngle(latitude: latitude, solarDeclination: solarDec, zenith: zenith, solarEvent: solarEvent);

delta = longitude - toDegrees(radians: hourAngle);
timeDiff = 4 * delta;
Expand Down

0 comments on commit ba52cc1

Please sign in to comment.