diff --git a/AdhanTests/AdhanTests.swift b/AdhanTests/AdhanTests.swift index c01ad05..82865bc 100644 --- a/AdhanTests/AdhanTests.swift +++ b/AdhanTests/AdhanTests.swift @@ -238,6 +238,36 @@ class AdhanTests: XCTestCase { XCTAssertEqual(dateFormatter.string(from: p.isha), "5:02 PM") } + func testJafariMethod() { + // Values from http://praytimes.org/code/ + var comps = DateComponents() + comps.year = 2017 + comps.month = 6 + comps.day = 16 + let p = PrayerTimes(coordinates: Coordinates(latitude: 43, longitude: -80), date: comps, calculationParameters: CalculationMethod.shia.params)! + + let dateFormatter = DateFormatter() + dateFormatter.timeZone = TimeZone(identifier: "America/New_York")! + dateFormatter.dateStyle = .none + dateFormatter.timeStyle = .short + + XCTAssertEqual(dateFormatter.string(from: p.fajr), "3:43 AM") + XCTAssertEqual(dateFormatter.string(from: p.sunrise), "5:40 AM") + XCTAssertEqual(dateFormatter.string(from: p.dhuhr), "1:21 PM") + XCTAssertEqual(dateFormatter.string(from: p.asr), "5:26 PM") + XCTAssertEqual(dateFormatter.string(from: p.maghrib), "9:23 PM") + XCTAssertEqual(dateFormatter.string(from: p.isha), "10:40 PM") + + let p2 = PrayerTimes(coordinates: Coordinates(latitude: 43, longitude: -80), date: comps, calculationParameters: CalculationMethod.tehran.params)! + + XCTAssertEqual(dateFormatter.string(from: p2.fajr), "3:25 AM") + XCTAssertEqual(dateFormatter.string(from: p2.sunrise), "5:40 AM") + XCTAssertEqual(dateFormatter.string(from: p2.dhuhr), "1:21 PM") + XCTAssertEqual(dateFormatter.string(from: p2.asr), "5:26 PM") + XCTAssertEqual(dateFormatter.string(from: p2.maghrib), "9:26 PM") + XCTAssertEqual(dateFormatter.string(from: p2.isha), "10:40 PM") + } + func testTimeForPrayer() { var comps = DateComponents() comps.year = 2016 diff --git a/Sources/Models/CalculationMethod.swift b/Sources/Models/CalculationMethod.swift index c94d02b..f7b25f3 100644 --- a/Sources/Models/CalculationMethod.swift +++ b/Sources/Models/CalculationMethod.swift @@ -57,6 +57,12 @@ public enum CalculationMethod: CaseIterable { // Singapore case singapore + + // Institute of Geophysics, University of Tehran + case tehran + + // Shia Ithna-Ashari, Leva Institute, Qum + case shia // Other case other @@ -97,6 +103,10 @@ public enum CalculationMethod: CaseIterable { var params = CalculationParameters(fajrAngle: 20, ishaAngle: 18, method: self) params.methodAdjustments = PrayerAdjustments(dhuhr: 1) return params + case .tehran: + return CalculationParameters(fajrAngle: 17.7, maghribAngle: 4.5, ishaAngle: 14, method: self) + case .shia: + return CalculationParameters(fajrAngle: 16, maghribAngle: 4, ishaAngle: 14, method: self) case .other: return CalculationParameters(fajrAngle: 0, ishaAngle: 0, method: self) } diff --git a/Sources/Models/CalculationParameters.swift b/Sources/Models/CalculationParameters.swift index b7cd158..6ea170a 100644 --- a/Sources/Models/CalculationParameters.swift +++ b/Sources/Models/CalculationParameters.swift @@ -29,6 +29,7 @@ import Foundation public struct CalculationParameters { public var method: CalculationMethod = .other public var fajrAngle: Double + public var maghribAngle: Double = 0 public var ishaAngle: Double public var ishaInterval: Minute = 0 public var madhab: Madhab = .shafi @@ -55,6 +56,11 @@ public struct CalculationParameters { self.init(fajrAngle: fajrAngle, ishaInterval: ishaInterval) self.method = method } + + init(fajrAngle: Double, maghribAngle: Double, ishaAngle: Double, method: CalculationMethod) { + self.init(fajrAngle: fajrAngle, ishaAngle: ishaAngle, method: method) + self.maghribAngle = maghribAngle + } func nightPortions() -> (fajr: Double, isha: Double) { switch self.highLatitudeRule { diff --git a/Sources/Models/Madhab.swift b/Sources/Models/Madhab.swift index 56e6814..0ea22ca 100644 --- a/Sources/Models/Madhab.swift +++ b/Sources/Models/Madhab.swift @@ -29,6 +29,7 @@ import Foundation public enum Madhab { case shafi case hanafi + case jafari var shadowLength: Double { switch(self) { @@ -36,6 +37,8 @@ public enum Madhab { return 1 case .hanafi: return 2 + case .jafari: + return 1 } } } diff --git a/Sources/PrayerTimes.swift b/Sources/PrayerTimes.swift index 2cc5b56..df87e96 100644 --- a/Sources/PrayerTimes.swift +++ b/Sources/PrayerTimes.swift @@ -46,6 +46,7 @@ public struct PrayerTimes { var tempSunrise: Date? = nil var tempDhuhr: Date? = nil var tempAsr: Date? = nil + var tempSunset: Date? = nil var tempMaghrib: Date? = nil var tempIsha: Date? = nil let cal: Calendar = .gregorianUTC @@ -73,7 +74,7 @@ public struct PrayerTimes { } tempSunrise = cal.date(from: solarTime.sunrise) - tempMaghrib = cal.date(from: solarTime.sunset) + tempSunset = cal.date(from: solarTime.sunset) tempDhuhr = cal.date(from: solarTime.transit) if let asrComponents = solarTime.afternoon(shadowLength: calculationParameters.madhab.shadowLength) { @@ -110,7 +111,7 @@ public struct PrayerTimes { // Isha calculation with check against safe value if calculationParameters.ishaInterval > 0 { - tempIsha = tempMaghrib?.addingTimeInterval(calculationParameters.ishaInterval.timeInterval) + tempIsha = tempSunset?.addingTimeInterval(calculationParameters.ishaInterval.timeInterval) } else { if let ishaComponents = solarTime.timeForSolarAngle(Angle(-calculationParameters.ishaAngle), afterTransit: true) { tempIsha = cal.date(from: ishaComponents) @@ -137,6 +138,25 @@ public struct PrayerTimes { tempIsha = safeIsha } } + + // Maghrib calculation with check against safe value + if calculationParameters.maghribAngle > 0 { + if let maghribComponents = solarTime.timeForSolarAngle(Angle(-calculationParameters.maghribAngle), afterTransit: true) { + tempMaghrib = cal.date(from: maghribComponents) + } + + if let tempAsr = tempAsr, let tempIsha = tempIsha { + // maghrib safe if falls between asr and maghrib + if tempMaghrib == nil || tempMaghrib?.compare(tempAsr) == .orderedAscending || tempMaghrib?.compare(tempIsha) == .orderedDescending { + tempMaghrib = tempSunset + } + } else { + // fallback to regular sunset + tempMaghrib = tempSunset + } + } else { + tempMaghrib = tempSunset + } // if we don't have all prayer times then initialization failed guard let fajr = tempFajr,