ashikahmad / PrayerTimes-Swift

Islamic Prayer (salah) Time calculation written in swift.
61 stars 21 forks source link

Add 20 prayer times calculations methods #9

Open aagouda opened 4 years ago

aagouda commented 4 years ago

Here is info for 20 ready calculations methods if you add them it would be much better. These info can be tested and verified from this website:

https://www.muslimpro.com/prayer-times `

  static var methodParams: [CalculationMethod: MethodParams] = [
  .mwl: MethodParams(
    fajrAngle: 18,
    maghrib: .minutes(0),
    isha: .angles(17),
    midnight: .standard),

  .isna: MethodParams(
    fajrAngle: 15,
    maghrib: .minutes(0),
    isha: .angles(15),
    midnight: .standard),

  .egypt: MethodParams(
    fajrAngle: 19.5,
    maghrib: .minutes(0),
    isha: .angles(17.5),
    midnight: .standard),

  // fajrAngle was 19 degrees before 1430 hijri
  .makkah: MethodParams(
    fajrAngle: 18.5,
    maghrib: .minutes(0),
    isha: .minutes(90),
    midnight: .standard),

  .karachi: MethodParams(
    fajrAngle: 18,
    maghrib: .minutes(0),
    isha: .angles(18),
    midnight: .standard),

  .tehran: MethodParams(
    fajrAngle: 17.7,
    maghrib: .angles(4.5),
    isha: .angles(14),
    midnight: .jafari),

  .jafari: MethodParams(
    fajrAngle: 16,
    maghrib: .angles(4),
    isha: .angles(14),
    midnight: .jafari),

  .algeria: MethodParams(
    fajrAngle: 18,
    maghrib: .minutes(0),
    isha: .angles(17),
    midnight: .standard),

  .diyanet: MethodParams(
    fajrAngle: 18,
    maghrib: .minutes(0),
    isha: .angles(17),
    midnight: .standard),

  .egyptBis: MethodParams(
    fajrAngle: 20,
    maghrib: .minutes(0),
    isha: .angles(18),
    midnight: .standard),

  .fixedIsha: MethodParams(
    fajrAngle: 19.5,
    maghrib: .minutes(0),
    isha: .minutes(90),
    midnight: .standard),

  .uoif: MethodParams(
    fajrAngle: 12,
    maghrib: .minutes(0),
    isha: .angles(12),
    midnight: .standard),

  .fr15: MethodParams(
    fajrAngle: 15,
    maghrib: .minutes(0),
    isha: .angles(15),
    midnight: .standard),

  .fr18: MethodParams(
    fajrAngle: 18,
    maghrib: .minutes(0),
    isha: .angles(18),
    midnight: .standard),

  .jakim: MethodParams(
    fajrAngle: 20,
    maghrib: .minutes(0),
    isha: .angles(18),
    midnight: .standard),

  .muis: MethodParams(
    fajrAngle: 20,
    maghrib: .minutes(0),
    isha: .angles(18),
    midnight: .standard),

  .kemenag: MethodParams(
    fajrAngle: 20,
    maghrib: .minutes(0),
    isha: .angles(18),
    midnight: .standard),

  .tunisia: MethodParams(
    fajrAngle: 18,
    maghrib: .minutes(0),
    isha: .angles(18),
    midnight: .standard),

  .awqafuae: MethodParams(
    fajrAngle: 19.5,
    maghrib: .minutes(0),
    isha: .minutes(90),
    midnight: .standard),

// .uiptl: MethodParams( // fajrAngle: 18, // maghrib: .minutes(0), // isha: .angles(18), // midnight: .standard), // .custom: MethodParams( fajrAngle: 18, maghrib: .minutes(0), isha: .angles(17), midnight: .standard) ] } `

and here is the methods string names

"MWL" = "Muslim World League"; "ISNA" = "Islamic Society of North America"; "Egypt" = "Egyptian General Authority of Survey"; "Makkah" = "Umm al-Qura University, Makkah"; "Karachi" = "University of Islamic Science, Karachi"; "Tehran" = "Institute of Geophysics, University of Tehran"; "Jafari" = "Shia Ithna Ashari, Leva Research Institute, Qum"; "algeria" = "Algerian Minister of Religious Affairs and Wakfs"; "diyanet" = "Diyanet İşleri Başkanlığı"; "egyptBis" = "Egyptian General Authority (Bis)"; "fixedIsha" = "Fixed Isha Angle Interval"; "uoif" = "France UOIF - Angle 12°"; "fr15" = "France - Angle 15°"; "fr18" = "France - Angle 18°"; "jakim" = "JAKIM (Jabatan Kemajuan Islam Malaysia)"; "muis" = "MUIS (Majlis Ugama Islam Singapura)"; "kemenag" = "SIHAT/KEMENAG (Kementerian Agama RI)"; "tunisia" = "Tunisian Ministry of Religious Affairs"; "awqafuae" = "UAE General Authority of Islamic Affairs And Endowments"; "uiptl" = "London Unified Islamic Prayer Timetable";

"MWL" = "رابطة العالم الإسلامي"; "ISNA" = "الجمعية الإسلامية لأمريكا الشمالية"; "Egypt" = "الهيئة المصرية العامة للمساحة"; "Makkah" = "جامعة أم القرى"; "Karachi" = "جامعة العلوم الإسلامية بكراتشي"; "Tehran" = "معهد الجيوفيزياء ، جامعة طهران"; "Jafari" = "معهد ليفا للبحوث ، قم ، إيران"; "algeria" = "وزارة الشؤون الدينية الجزائرية والأوقاف"; "diyanet" = "مديرية الشؤون الدينية"; "egyptBis" = "الهيئة العامة المصرية (Bis)"; "fixedIsha" = "تثبيت زاوية العشاء"; "uoif" = "فرنسا UOIF ١٢°"; "fr15" = "°فرنسا ١٥"; "fr18" = "°فرنسا ١٨"; "jakim" = "إدارة التنمية الإسلامية في ماليزيا"; "muis" = "المجلس الديني الإسلامي في سنغافورة"; "kemenag" = "وزارة الشؤون الدينية"; "tunisia" = "وزارة الشؤون الدينية التونسية"; "awqafuae" = "الهيئة العامة الإماراتية للشؤون الإسلامية والأوقاف"; "uiptl" = "الجدول الزمني الموحد للصلاة الإسلامية في لندن";

ashikahmad commented 4 years ago

Jazakallah. InshaAllah I will check and try to add these methods.

aagouda commented 4 years ago

// // AKPrayerTime.swift // PrayerKit // // Created by Ashik Ahmad on 4/15/15. // Copyright (c) 2015 WNeeds. All rights reserved. //

import UIKit

public final class AKPrayerTime {

/* Time wraps double time into a formal namespace along with basic functionalities / public struct Time { public let duration: Double

public init(hours: Int, minutes: Int) {
  let fixedHours = Time.fixedHours(Double(hours))
  self.duration = fixedHours + Double(minutes) / 60.0
}

public init(duration: Double) {
  var ttime = duration + 0.5 / 60.0 // add 0.5 minutes to round
  ttime = Time.fixedHours(ttime)
  self.duration = ttime
}

private static func fixedHours(_ hours: Double) -> Double {
  return DMath.wrap(hours, min: 0, max: 24)
}

public var hours: Int {
  guard !duration.isNaN else {return 20}
  return Int(floor(duration))
}

public var minutes: Int {
  guard !duration.isNaN else {return 20}
  return Int(floor((duration - Double(hours)) * 60.0))
}

}

public struct Coordinate {
    public var latitude: Double
    public var longitude: Double
    public var elevation: Double

    public init(lat: Double, lng: Double, elv: Double = 0) {
        latitude = lat
        longitude = lng
        elevation = elv
    }
}

public enum TimeNames : String, CaseIterable {
    case imsak
    case fajr
    case sunrise
    case dhuhr
    case asr
    case sunset
    case maghrib
    case isha
    case midnight
    case qiyam

    public func toString()->String {
        return self.rawValue.capitalized
    }
}

///////////////////////////////////////// END Types.swift//////////////////

public enum CalculationMethod {

/// Muslim World League
case mwl

/// Islamic Society of North America
case isna

/// Egyptian General Authority of Survey
case egypt

/// Umm al-Qura University, Makkah
case makkah

/// University of Islamic Science, Karachi
case karachi

/// Institute of Geophysics, University of Tehran
case tehran

/// Shia Ithna Ashari, Leva Research Institute, Qum
case jafari

/// Algerian Minister of Religious Affairs and Wakfs
case algeria

/// Diyanet İşleri Başkanlığı
case diyanet

/// Egyptian General Authority (Bis)
case egyptBis

/// Fixed Isha Angle Interval
case fixedIsha

/// France UOIF - Angle 12°
case uoif

/// France - Angle 15°
case fr15

/// Fr18=France - Angle 18°
case fr18

/// JAKIM (Jabatan Kemajuan Islam Malaysia)
case jakim

/// MUIS (Majlis Ugama Islam Singapura)
case muis

/// SIHAT/KEMENAG (Kementerian Agama RI)
case kemenag

/// Tunisian Ministry of Religious Affairs
case tunisia

/// UAE General Authority of Islamic Affairs And Endowments
case awqafuae

/// London Unified Islamic Prayer Timetable // case uiptl

/// Custom, these can be changed as user sets.
case custom

}

public enum JuristicMethod: Int {

/// Shafi'i, Maliki, Ja'fari, and Hanbali
case shafii = 1

/// Hanafi
case hanafi = 2

func toInt()->Int { return self.rawValue }
var shadowCoefficient: Int { return self.rawValue }

}

public enum MidnightMethod: Int { case standard case jafari }

public enum HigherLatutudeAdjustment: String { case none case midNight case oneSeventh case angleBased

func toIndex() -> Int {
  switch self {
  case .none: return 0
  case .midNight: return 1
  case .oneSeventh: return 2
  case .angleBased: return 3
  }
}

}

///////////////////////////////////////////AKPrayerTimes.swift/////////////////////

public enum AnglesOrMinutes { case angles(Double) case minutes(Double) }

struct MethodParams { var fajrAngle: Double var maghrib: AnglesOrMinutes var isha: AnglesOrMinutes var midnight: MidnightMethod }

fileprivate enum Defaults { static let calendar = Calendar(identifier: .gregorian) static let componentsDMY = Set([Calendar.Component.year, Calendar.Component.month, Calendar.Component.day])

static let dayTimes: [TimeNames: Double] = [
  .imsak   : 5.0,
  .fajr    : 5.0,
  .sunrise : 6.0,
  .dhuhr   : 12.0,
  .asr     : 13.0,
  .sunset  : 18.0,
  .maghrib : 18.0,
  .isha    : 18.0
]

/**
 Required parameters for calculation methods.
 None but the `.Custom` parameters should be changed where appropriate.
 Mostly, you should not be touching is directly. Use set** methods instead
 as appropriate.
 */
static var methodParams: [CalculationMethod: MethodParams] = [
  .mwl: MethodParams(
    fajrAngle: 18,
    maghrib: .minutes(0),
    isha: .angles(17),
    midnight: .standard),

  .isna: MethodParams(
    fajrAngle: 15,
    maghrib: .minutes(0),
    isha: .angles(15),
    midnight: .standard),

  .egypt: MethodParams(
    fajrAngle: 19.5,
    maghrib: .minutes(0),
    isha: .angles(17.5),
    midnight: .standard),

  // fajrAngle was 19 degrees before 1430 hijri
  .makkah: MethodParams(
    fajrAngle: 18.5,
    maghrib: .minutes(0),
    isha: .minutes(90),
    midnight: .standard),

  .karachi: MethodParams(
    fajrAngle: 18,
    maghrib: .minutes(0),
    isha: .angles(18),
    midnight: .standard),

  .tehran: MethodParams(
    fajrAngle: 17.7,
    maghrib: .angles(4.5),
    isha: .angles(14),
    midnight: .jafari),

  .jafari: MethodParams(
    fajrAngle: 16,
    maghrib: .angles(4),
    isha: .angles(14),
    midnight: .jafari),

  .algeria: MethodParams(
    fajrAngle: 18,
    maghrib: .minutes(0),
    isha: .angles(17),
    midnight: .standard),

  .diyanet: MethodParams(
    fajrAngle: 18,
    maghrib: .minutes(0),
    isha: .angles(17),
    midnight: .standard),

  .egyptBis: MethodParams(
    fajrAngle: 20,
    maghrib: .minutes(0),
    isha: .angles(18),
    midnight: .standard),

  .fixedIsha: MethodParams(
    fajrAngle: 19.5,
    maghrib: .minutes(0),
    isha: .minutes(90),
    midnight: .standard),

  .uoif: MethodParams(
    fajrAngle: 12,
    maghrib: .minutes(0),
    isha: .angles(12),
    midnight: .standard),

  .fr15: MethodParams(
    fajrAngle: 15,
    maghrib: .minutes(0),
    isha: .angles(15),
    midnight: .standard),

  .fr18: MethodParams(
    fajrAngle: 18,
    maghrib: .minutes(0),
    isha: .angles(18),
    midnight: .standard),

  .jakim: MethodParams(
    fajrAngle: 20,
    maghrib: .minutes(0),
    isha: .angles(18),
    midnight: .standard),

  .muis: MethodParams(
    fajrAngle: 20,
    maghrib: .minutes(0),
    isha: .angles(18),
    midnight: .standard),

  .kemenag: MethodParams(
    fajrAngle: 20,
    maghrib: .minutes(0),
    isha: .angles(18),
    midnight: .standard),

  .tunisia: MethodParams(
    fajrAngle: 18,
    maghrib: .minutes(0),
    isha: .angles(18),
    midnight: .standard),

  .awqafuae: MethodParams(
    fajrAngle: 19.5,
    maghrib: .minutes(0),
    isha: .minutes(90),
    midnight: .standard),

// .uiptl: MethodParams( // fajrAngle: 18, // maghrib: .minutes(0), // isha: .angles(18), // midnight: .standard), // .custom: MethodParams( fajrAngle: 18, maghrib: .minutes(0), isha: .angles(17), midnight: .standard) ] }

//------------------------------------------------------ // MARK: - Technical Settings //------------------------------------------------------

/// number of iterations needed to compute times var numIterations:Int = 2

//------------------------------------------------------ // MARK: - Properties //------------------------------------------------------

public var offsets:[TimeNames: Double] = [ .imsak : 0, .fajr : 0, .sunrise : 0, .dhuhr : 0, .asr : 0, .sunset : 0, .maghrib : 0, .isha : 0, .midnight: 0, .qiyam : 0 ];

func setAllOffsets(_ offset: Double) { let offset = offset * 60 offsets = [.imsak: offset, .fajr: offset + SettingsManager.shared.singleOffset("Fajr"), .sunrise: offset + SettingsManager.shared.singleOffset("Sunrise"), .dhuhr: offset + SettingsManager.shared.singleOffset("Dhuhr"), .asr: offset + SettingsManager.shared.singleOffset("Asr"), .sunset: offset, .maghrib: offset + SettingsManager.shared.singleOffset("Maghrib"), .isha: offset + SettingsManager.shared.singleOffset("Isha"), .midnight: offset, .qiyam: offset] }

/// Once 'computePrayerTimes' is called, /// computed values are stored here for reuse public var currentPrayerTimes:[TimeNames: Time]?

/// Prayer calculation methods. /// See CalculationMethod enums for more details public var calculationMethod = CalculationMethod.mwl /// Asr method, Shafii or Hanafii public var asrJuristic = JuristicMethod.shafii /// Adjustment options for Higher Latitude public var highLatitudeAdjustment = HigherLatutudeAdjustment.midNight /// Prayer time output format. // public var outputFormat = OutputTimeFormat.time24 public var imsakSettings: AnglesOrMinutes = .minutes(10)

// Not sure if it should be replaced by offsets[.Dhuhr] public var dhuhrMinutes: Float = 0

/// Coordinate of the place, times will be calculated for. public var coordinate: Coordinate! { didSet { calculateJulianDate() } }

/// Timezone of the place, times will be calculated for. public var timeZone:Float = AKPrayerTime.systemTimeZone()

/// Date for which prayer times will be calculated. /// Defaults to today, when not set. public var calcDate:Date! { didSet { calculateJulianDate() } }

private lazy var jDate:Double = AKPrayerTime.julianDate(from: Date())

//------------------------------------------------------ // MARK: - Constructor //------------------------------------------------------

public init(lat:Double, lng:Double){ coordinate = Coordinate(lat: lat, lng: lng) calcDate = Date() }

//------------------------------------------------------ // MARK: - Utility Methods (Type Methods) //------------------------------------------------------

class func systemTimeZone()->Float { // print(TimeZone(secondsFromGMT: SettingsManager.shared.timeZoneSeconds)?.abbreviation()) // let timeZone = TimeZone(secondsFromGMT: SettingsManager.shared.timeZoneSeconds) ?? TimeZone.current // return Float(timeZone.secondsFromGMT())/3600.0 return Float(SettingsManager.shared.timeZoneSeconds)/3600.0 }

class func dayLightSavingOffset()->Double { let timeZone = TimeZone(secondsFromGMT: SettingsManager.shared.timeZoneSeconds) ?? TimeZone.current return Double(timeZone.daylightSavingTimeOffset(for: Date())) }

/// Sunrise/sunset angle with elevation adjustment private func riseSetAngle() -> Double { // let earthRad: Double = 6371009; // in meters // let angle = DMath.dArcCos(earthRad/(earthRad + coordinate.elevation)); let angle = 0.0347 * sqrt(coordinate.elevation); // an approximation return 0.833 + angle; }

//------------------------------------------------------ // MARK: - Public Methods: Get prayer times //------------------------------------------------------

/// Return prayer times for a given date, latitude, longitude and timeZone public func getDatePrayerTimes(year: Int, month: Int, day: Int, latitude: Double, longitude: Double, tZone: Float)-> [TimeNames: Time] {

coordinate = Coordinate(lat: latitude, lng: longitude)

var comp = DateComponents()
comp.year = year
comp.month = month
comp.day = day
calcDate = Defaults.calendar.date(from: comp)

timeZone = tZone

// This may not be necessary
jDate = AKPrayerTime.julianDate(year: year, month: month, day: day)
let lonDiff = longitude / (15.0 * 24.0)
jDate = jDate - lonDiff;

return computeDayTimes()

}

/// Returns prayer times for a date(or today) when everything is set public func getPrayerTimes()->[TimeNames: Time]? { // If coordinate is not set, cannot obtain prayer times if coordinate == nil { return nil }

// If date is not set, set today as calcDate
if calcDate == nil {
  calcDate = Date()
}

// jDate should be autometically set already
return computeDayTimes()

}

public func sorted(_ t: [TimeNames: Time]) -> [(TimeNames, Time)] { let seq: [AKPrayerTime.TimeNames] = [.imsak, .fajr, .sunrise, .dhuhr, .asr, .sunset, .maghrib, .isha, .midnight, .qiyam] return t.sorted {a,b in (seq.firstIndex(of: a.key) ?? 0) < (seq.firstIndex(of: b.key) ?? 0) } }

//------------------------------------------------------ // MARK: - Public Methods: Configurations //------------------------------------------------------

/// Set custom values for calculation parameters private func setCustomParams(_ changes: (inout MethodParams)->Void) { guard let mp = Defaults.methodParams[calculationMethod] else { return } var params = mp changes(&params) //Defaults.methodParams[.custom] = params calculationMethod = .custom }

/// Set the angle for calculating Fajr public func setFajrAngle(angle: Double) { setCustomParams { $0.fajrAngle = angle } }

/// Set the angle for calculating Maghrib public func setMaghribAngle(angle: Double) { setCustomParams { $0.maghrib = .angles(angle) } }

/// Set the angle for calculating Isha public func setIshaAngle(angle: Double) { setCustomParams { $0.isha = .angles(angle) } }

/// Set the minutes after Sunset for calculating Maghrib public func setMaghribMinutes(minutes: Double) { setCustomParams { $0.maghrib = .minutes(minutes) } }

/// Set the minutes after Maghrib for calculating Isha public func setIshaMinutes(minutes: Double) { setCustomParams { $0.isha = .minutes(minutes) } }

public func setMidnightMethod(_ method: MidnightMethod) { setCustomParams { $0.midnight = method } }

//------------------------------------------------------
// MARK: - Julian Date Calculation
//------------------------------------------------------

private func calculateJulianDate() {
    if let date = calcDate, let latlng = coordinate {
        let jdt = AKPrayerTime.julianDate(from: date)
        jDate = jdt - (latlng.longitude / (15.0 * 24.0))
    }
}

private class func julianDate(from date:Date)->Double {
    let components = Defaults.calendar.dateComponents(Defaults.componentsDMY, from: Date())
    return julianDate(year: components.year ?? 0,
                      month: components.month ?? 0,
                      day: components.day ?? 0)
}

private class func julianDate(year:Int, month:Int, day:Int)->Double {
    var yyear = year, mmonth = month, dday = day
    if mmonth < 2 {
        yyear -= 1
        mmonth += 12
    }

    let A = floor(Double(yyear)/100.0)
    let B = 2.0 - A + floor(A/4.0)

    return floor(365.25 * (Double(yyear) + 4716.0))
        + floor(30.6001 * (Double(mmonth) + 1.0))
        + Double(dday) + B - 1524.5
}

//------------------------------------------------------ // MARK: - Calculation Functions //------------------------------------------------------

// References: // http://praytimes.org/calculation/

/** Compute declination angle of sun and equation of time

///////////////////////////////////////////// ///////////////////////////////////////////// Types.swift /////////////////////////////

public extension AKPrayerTime.Time {

func toDate(base date: Date = Date(), calendar: Calendar = Calendar(identifier: .gregorian)) -> Date { var components = calendar.dateComponents([.year, .month, .day, .weekday, .hour, .minute], from: date) components.hour = hours components.minute = minutes return calendar.date(from: components) ?? date }

func toTime12(showSuffix: Bool = true) -> String { var h = hours % 12 let m = minutes let a = (showSuffix ? ((hours > 12) ? " pm" : " am") : "") if h == 0 { h = 12 } return String(format: "%02d:%02d%@", h, m, a) }

func toTime24() -> String { return String(format: "%02d:%02d", hours, minutes) }

}

extension AKPrayerTime.Time: Comparable {

public static func < (lhs: AKPrayerTime.Time, rhs: AKPrayerTime.Time) -> Bool { return lhs.duration < rhs.duration }

public static func == (lhs: AKPrayerTime.Time, rhs: AKPrayerTime.Time) -> Bool { return lhs.duration == rhs.duration } }

extension AKPrayerTime.Time { func prevDayDuration() -> Double { return duration - 24 }

func nextDayDuration() -> Double { return duration + 24 } }

//////////////////////// ////////////////////////////////DMATH.swift//////////////////////

class DMath {

class func wrap(_ a: Double, min: Double, max: Double)-> Double {
    var aa = a
    let range = max - min
    aa.formTruncatingRemainder(dividingBy: range)
    if aa < min { aa += range }
    if aa > max { aa -= range }
    return aa
}

// range reduce angle in degrees.
class func fixAngle(_ a: Double)-> Double {
    return a.reduce(max: 360) //wrap(a, min: 0, max: 360)
}

// radian to degree
class func radiansToDegrees(_ alpha: Double) -> Double{
    return ((alpha*180.0) / Double.pi);
}

// deree to radian
class func degreesToRadians(_ alpha: Double)-> Double {
    return ((alpha*Double.pi)/180.0);
}

// degree sin
class func dSin(_ d: Double)-> Double {
    return sin(degreesToRadians(d))
}

// degree cos
class func dCos(_ d: Double)-> Double {
    return cos(degreesToRadians(d))
}

// degree tan
class func dTan(_ d: Double)-> Double {
    return tan(degreesToRadians(d))
}

// degree arcsin
class func dArcSin(_ x: Double)-> Double {
    let val = asin(x)
    return radiansToDegrees(val)
}

// degree arccos
class func dArcCos(_ x: Double)-> Double {
    let val = acos(x);
    return radiansToDegrees(val)
}

// degree arctan
class func dArcTan(_ x: Double)-> Double {
    let val = atan(x);
    return radiansToDegrees(val)
}

// degree arctan2
class func dArcTan2(_ y: Double, x: Double)-> Double {
    let val = atan2(y, x);
    return radiansToDegrees(val)
}

// degree arccot
class func dArcCot(_ x: Double)-> Double {
    let val = atan2(1.0, x);
    return radiansToDegrees(val)
}

} /////////////////////////// /////////////////////////// Foundation + Extension.swift ///////////////////////// extension Double { func reduce(max: Double, min: Double = 0) -> Double { let range = max - min return self - range * floor((self - min)/range) } }

/* STEPS FOR PRAYER TIME CALCULATION

  1. Calculate julian date
  2. Calculate sun declination and equation of time for julian date & lat-lng
  3. Iterate computeTimes starting with default day times
  4. Adjust times
  5. Tune offsets
  6. Format

    BASE TIMES (Must be Angle-based calculation)

  7. Mid-day (Dhuhr)
  8. Sunrise
  9. Sunset
  10. Asr

    SECONDARY TIMES (May depend on Base times)

  11. Fajr (Based on Sunrise or angle-based)
  12. Maghrib(Based on Sunset or angle-based)
  13. Isha (Based on Maghrib or angle-based)
  14. Imsak (Based on Fajr or angle-based)

    CALCULATED TIMES (Relative to base times)

  15. Midnight (Based on Sunset-Fajr or Sunset-Sunrise)
  16. Qiyam Al-lyle (Based on Sunset-Fajr or Sunset-Sunrise)

    TIMES: Description

    • Fajr: When the sky begin to lighten. Dawn.
    • Sunrise: The time at which the first part of the sun appears above the horizon.
    • Dhuhr: When the sun begin to decline after reaching it's highest point in the sky.
    • Asr: The time when length of any objects shadow reaches a factor of the length of the object itself plus the length of that object's shadow at noon. The factor is either 1 or 2 accroding to different school of thoughts.
    • Sunset: The time at which the last part of the sun disappears below the horizon.
    • Maghrib: Soon after sunset.
    • Isha: The time at which the darkness falls and there is no scattered light in the sky.
    • Midnight: The mean time from sunset to sunrise (or from sunset to Fajr in some school of thoughts)

    Declination is calculated with the following formula: d = 23.45 sin [360 / 365 (284 + N)]

    Where: d = declination N = day number, January 1 = day 1

    =========================================== FEATURES TODO

    -[x] Separate time format from calculation flow -[ ] Get prayer times for array/range of dates (i.e. for week or month) -[ ] Get current prayer time: time name, start time, remaining time

    =========================================== CALCULATIONS

    // Date passed after noon of 1st January, 2000 (when jd = 2451545.0) jd2k = 2451545.0; d = jd - jd2k; // jd is the given Julian date

    // Mean anomaly of the Sun, in degrees. Need to reduce to 0-360 range. g = 357.529 + 0.98560028 d; // Mean longitude of the Sun, in degrees. Need to reduce to 0-360 range. q = 280.459 + 0.98564736 d; // Geocentric apparent ecliptic longitude of the Sun (adjusted for aberration), in degrees. Need to reduce to 0-360 range. L = q + 1.915 sin(g) + 0.020 sin(2*g);

    // The distance of the Sun from the Earth aproximated, in astronomical units (AU) R = 1.00014 - 0.01671 cos(g) - 0.00014 cos(2g); // Mean obliquity of the ecliptic, in degrees e = 23.439 - 0.00000036 d; // Sun's right ascension RA = arctan2(cos(e) sin(L), cos(L))/ 15; // declination of the Sun D = arcsin(sin(e) sin(L)); // Equation of time EqT = q/15 - RA;

    // Dhuhr

    Dhuhr = 12 + TimeZone - Lng/15 - EqT

    // Sun at Angle

    The time difference between the mid-day and the time at which sun reaches an angle α below the horizon can be computed using the following formula:

    T(α) = 1/15 arccos( (-sin(α) - sin(L)sin(D)) / (cos(L)*cos(D)) )

    // Sunrise/Sunset

    Astronomical sunrise and sunset occur at α=0. However, due to the refraction of light by terrestrial atmosphere, actual sunrise appears slightly before astronomical sunrise and actual sunset occurs after astronomical sunset. Actual sunrise and sunset can be computed using the following formulas:

    Sunrise = Dhuhr - T(0.833) Sunset = Dhuhr + T(0.833)

    // Asr

    The following formula computes the time difference between the mid-day and the time at which the object's shadow equals t times the length of the object itself plus the length of that object's shadow at noon:

    A(t) = 1/15 arccos( (sin( arccot(t + tan(L-D)))) - sin(L)sin(D)) / (cos(L)*cos(D)) )

    So, Asr is, Asr = Dhuhr + A(1); // For Shafi'i, Maliki, Ja'fari, and Hanbali school of thoughts Asr = Dhuhr + A(2); // For Hanafi school of thoughts */

basememara commented 2 years ago

We received reports that the UAE - General Authority of Islamic Affairs And Endowments (AWQAF) prayer times is incorrect based on 19.5 fair / 90 minute Isha. Have you found the correct formula for this?

https://www.awqaf.gov.ae/en/Pages/PrayerTimes.aspx