Created
November 18, 2020 21:44
-
-
Save rali14/9607926a3a795ec6b49bf763e0bffe35 to your computer and use it in GitHub Desktop.
PrayTimes
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//--------------------- Copyright Block ---------------------- | |
/* | |
PrayTimes.js: Prayer Times Calculator (ver 2.3) | |
Copyright (C) 2007-2011 PrayTimes.org | |
Developer: Hamid Zarrabi-Zadeh | |
License: GNU LGPL v3.0 | |
TERMS OF USE: | |
Permission is granted to use this code, with or | |
without modification, in any website or application | |
provided that credit is given to the original work | |
with a link back to PrayTimes.org. | |
This program is distributed in the hope that it will | |
be useful, but WITHOUT ANY WARRANTY. | |
PLEASE DO NOT REMOVE THIS COPYRIGHT BLOCK. | |
*/ | |
//--------------------- Help and Manual ---------------------- | |
/* | |
User's Manual: | |
http://praytimes.org/manual | |
Calculation Formulas: | |
http://praytimes.org/calculation | |
//------------------------ User Interface ------------------------- | |
getTimes (date, coordinates [, timeZone [, dst [, timeFormat]]]) | |
setMethod (method) // set calculation method | |
adjust (parameters) // adjust calculation parameters | |
tune (offsets) // tune times by given offsets | |
getMethod () // get calculation method | |
getSetting () // get current calculation parameters | |
getOffsets () // get current time offsets | |
//------------------------- Sample Usage -------------------------- | |
var PT = new PrayTimes('ISNA'); | |
var times = PT.getTimes(new Date(), [43, -80], -5); | |
document.write('Sunrise = '+ times.sunrise) | |
*/ | |
//----------------------- PrayTimes Class ------------------------ | |
function PrayTimes(method) { | |
//------------------------ Constants -------------------------- | |
var | |
// Time Names | |
timeNames = { | |
imsak : 'Imsak', | |
fajr : 'Fajr', | |
sunrise : 'Sunrise', | |
dhuhr : 'Dhuhr', | |
asr : 'Asr', | |
sunset : 'Sunset', | |
maghrib : 'Maghrib', | |
isha : 'Isha', | |
midnight : 'Midnight' | |
}, | |
// Calculation Methods | |
methods = { | |
MWL: { | |
name: 'Muslim World League', | |
params: { fajr: 18, isha: 17 } }, | |
ISNA: { | |
name: 'Islamic Society of North America (ISNA)', | |
params: { fajr: 15, isha: 15 } }, | |
Egypt: { | |
name: 'Egyptian General Authority of Survey', | |
params: { fajr: 19.5, isha: 17.5 } }, | |
Makkah: { | |
name: 'Umm Al-Qura University, Makkah', | |
params: { fajr: 18.5, isha: '90 min' } }, // fajr was 19 degrees before 1430 hijri | |
Karachi: { | |
name: 'University of Islamic Sciences, Karachi', | |
params: { fajr: 18, isha: 18 } }, | |
Tehran: { | |
name: 'Institute of Geophysics, University of Tehran', | |
params: { fajr: 17.7, isha: 14, maghrib: 4.5, midnight: 'Jafari' } }, // isha is not explicitly specified in this method | |
Jafari: { | |
name: 'Shia Ithna-Ashari, Leva Institute, Qum', | |
params: { fajr: 16, isha: 14, maghrib: 4, midnight: 'Jafari' } } | |
}, | |
// Default Parameters in Calculation Methods | |
defaultParams = { | |
maghrib: '0 min', midnight: 'Standard' | |
}, | |
//----------------------- Parameter Values ---------------------- | |
/* | |
// Asr Juristic Methods | |
asrJuristics = [ | |
'Standard', // Shafi`i, Maliki, Ja`fari, Hanbali | |
'Hanafi' // Hanafi | |
], | |
// Midnight Mode | |
midnightMethods = [ | |
'Standard', // Mid Sunset to Sunrise | |
'Jafari' // Mid Sunset to Fajr | |
], | |
// Adjust Methods for Higher Latitudes | |
highLatMethods = [ | |
'NightMiddle', // middle of night | |
'AngleBased', // angle/60th of night | |
'OneSeventh', // 1/7th of night | |
'None' // No adjustment | |
], | |
// Time Formats | |
timeFormats = [ | |
'24h', // 24-hour format | |
'12h', // 12-hour format | |
'12hNS', // 12-hour format with no suffix | |
'Float' // floating point number | |
], | |
*/ | |
//---------------------- Default Settings -------------------- | |
calcMethod = 'MWL', | |
// do not change anything here; use adjust method instead | |
setting = { | |
imsak : '10 min', | |
dhuhr : '0 min', | |
asr : 'Standard', | |
highLats : 'NightMiddle' | |
}, | |
timeFormat = '24h', | |
timeSuffixes = ['am', 'pm'], | |
invalidTime = '-----', | |
numIterations = 1, | |
offset = {}, | |
//----------------------- Local Variables --------------------- | |
lat, lng, elv, // coordinates | |
timeZone, jDate; // time variables | |
//---------------------- Initialization ----------------------- | |
// set methods defaults | |
var defParams = defaultParams; | |
for (var i in methods) { | |
var params = methods[i].params; | |
for (var j in defParams) | |
if ((typeof(params[j]) == 'undefined')) | |
params[j] = defParams[j]; | |
}; | |
// initialize settings | |
calcMethod = methods[method] ? method : calcMethod; | |
var params = methods[calcMethod].params; | |
for (var id in params) | |
setting[id] = params[id]; | |
// init time offsets | |
for (var i in timeNames) | |
offset[i] = 0; | |
//----------------------- Public Functions ------------------------ | |
return { | |
// set calculation method | |
setMethod: function(method) { | |
if (methods[method]) { | |
this.adjust(methods[method].params); | |
calcMethod = method; | |
} | |
}, | |
// set calculating parameters | |
adjust: function(params) { | |
for (var id in params) | |
setting[id] = params[id]; | |
}, | |
// set time offsets | |
tune: function(timeOffsets) { | |
for (var i in timeOffsets) | |
offset[i] = timeOffsets[i]; | |
}, | |
// get current calculation method | |
getMethod: function() { return calcMethod; }, | |
// get current setting | |
getSetting: function() { return setting; }, | |
// get current time offsets | |
getOffsets: function() { return offset; }, | |
// get default calc parametrs | |
getDefaults: function() { return methods; }, | |
// return prayer times for a given date | |
getTimes: function(date, coords, timezone, dst, format) { | |
lat = 1* coords[0]; | |
lng = 1* coords[1]; | |
elv = coords[2] ? 1* coords[2] : 0; | |
timeFormat = format || timeFormat; | |
if (date.constructor === Date) | |
date = [date.getFullYear(), date.getMonth()+ 1, date.getDate()]; | |
if (typeof(timezone) == 'undefined' || timezone == 'auto') | |
timezone = this.getTimeZone(date); | |
if (typeof(dst) == 'undefined' || dst == 'auto') | |
dst = this.getDst(date); | |
timeZone = 1* timezone+ (1* dst ? 1 : 0); | |
jDate = this.julian(date[0], date[1], date[2])- lng/ (15* 24); | |
return this.computeTimes(); | |
}, | |
// convert float time to the given format (see timeFormats) | |
getFormattedTime: function(time, format, suffixes) { | |
if (isNaN(time)) | |
return invalidTime; | |
if (format == 'Float') return time; | |
suffixes = suffixes || timeSuffixes; | |
time = DMath.fixHour(time+ 0.5/ 60); // add 0.5 minutes to round | |
var hours = Math.floor(time); | |
var minutes = Math.floor((time- hours)* 60); | |
var suffix = (format == '12h') ? suffixes[hours < 12 ? 0 : 1] : ''; | |
var hour = (format == '24h') ? this.twoDigitsFormat(hours) : ((hours+ 12 -1)% 12+ 1); | |
return hour+ ':'+ this.twoDigitsFormat(minutes)+ (suffix ? ' '+ suffix : ''); | |
}, | |
//---------------------- Calculation Functions ----------------------- | |
// compute mid-day time | |
midDay: function(time) { | |
var eqt = this.sunPosition(jDate+ time).equation; | |
var noon = DMath.fixHour(12- eqt); | |
return noon; | |
}, | |
// compute the time at which sun reaches a specific angle below horizon | |
sunAngleTime: function(angle, time, direction) { | |
var decl = this.sunPosition(jDate+ time).declination; | |
var noon = this.midDay(time); | |
var t = 1/15* DMath.arccos((-DMath.sin(angle)- DMath.sin(decl)* DMath.sin(lat))/ | |
(DMath.cos(decl)* DMath.cos(lat))); | |
return noon+ (direction == 'ccw' ? -t : t); | |
}, | |
// compute asr time | |
asrTime: function(factor, time) { | |
var decl = this.sunPosition(jDate+ time).declination; | |
var angle = -DMath.arccot(factor+ DMath.tan(Math.abs(lat- decl))); | |
return this.sunAngleTime(angle, time); | |
}, | |
// compute declination angle of sun and equation of time | |
// Ref: http://aa.usno.navy.mil/faq/docs/SunApprox.php | |
sunPosition: function(jd) { | |
var D = jd - 2451545.0; | |
var g = DMath.fixAngle(357.529 + 0.98560028* D); | |
var q = DMath.fixAngle(280.459 + 0.98564736* D); | |
var L = DMath.fixAngle(q + 1.915* DMath.sin(g) + 0.020* DMath.sin(2*g)); | |
var R = 1.00014 - 0.01671* DMath.cos(g) - 0.00014* DMath.cos(2*g); | |
var e = 23.439 - 0.00000036* D; | |
var RA = DMath.arctan2(DMath.cos(e)* DMath.sin(L), DMath.cos(L))/ 15; | |
var eqt = q/15 - DMath.fixHour(RA); | |
var decl = DMath.arcsin(DMath.sin(e)* DMath.sin(L)); | |
return {declination: decl, equation: eqt}; | |
}, | |
// convert Gregorian date to Julian day | |
// Ref: Astronomical Algorithms by Jean Meeus | |
julian: function(year, month, day) { | |
if (month <= 2) { | |
year -= 1; | |
month += 12; | |
}; | |
var A = Math.floor(year/ 100); | |
var B = 2- A+ Math.floor(A/ 4); | |
var JD = Math.floor(365.25* (year+ 4716))+ Math.floor(30.6001* (month+ 1))+ day+ B- 1524.5; | |
return JD; | |
}, | |
//---------------------- Compute Prayer Times ----------------------- | |
// compute prayer times at given julian date | |
computePrayerTimes: function(times) { | |
times = this.dayPortion(times); | |
var params = setting; | |
var imsak = this.sunAngleTime(this.eval(params.imsak), times.imsak, 'ccw'); | |
var fajr = this.sunAngleTime(this.eval(params.fajr), times.fajr, 'ccw'); | |
var sunrise = this.sunAngleTime(this.riseSetAngle(), times.sunrise, 'ccw'); | |
var dhuhr = this.midDay(times.dhuhr); | |
var asr = this.asrTime(this.asrFactor(params.asr), times.asr); | |
var sunset = this.sunAngleTime(this.riseSetAngle(), times.sunset);; | |
var maghrib = this.sunAngleTime(this.eval(params.maghrib), times.maghrib); | |
var isha = this.sunAngleTime(this.eval(params.isha), times.isha); | |
return { | |
imsak: imsak, fajr: fajr, sunrise: sunrise, dhuhr: dhuhr, | |
asr: asr, sunset: sunset, maghrib: maghrib, isha: isha | |
}; | |
}, | |
// compute prayer times | |
computeTimes: function() { | |
// default times | |
var times = { | |
imsak: 5, fajr: 5, sunrise: 6, dhuhr: 12, | |
asr: 13, sunset: 18, maghrib: 18, isha: 18 | |
}; | |
// main iterations | |
for (var i=1 ; i<=numIterations ; i++) | |
times = this.computePrayerTimes(times); | |
times = this.adjustTimes(times); | |
// add midnight time | |
times.midnight = (setting.midnight == 'Jafari') ? | |
times.sunset+ this.timeDiff(times.sunset, times.fajr)/ 2 : | |
times.sunset+ this.timeDiff(times.sunset, times.sunrise)/ 2; | |
times = this.tuneTimes(times); | |
return this.modifyFormats(times); | |
}, | |
// adjust times | |
adjustTimes: function(times) { | |
var params = setting; | |
for (var i in times) | |
times[i] += timeZone- lng/ 15; | |
if (params.highLats != 'None') | |
times = this.adjustHighLats(times); | |
if (this.isMin(params.imsak)) | |
times.imsak = times.fajr- this.eval(params.imsak)/ 60; | |
if (this.isMin(params.maghrib)) | |
times.maghrib = times.sunset+ this.eval(params.maghrib)/ 60; | |
if (this.isMin(params.isha)) | |
times.isha = times.maghrib+ this.eval(params.isha)/ 60; | |
times.dhuhr += this.eval(params.dhuhr)/ 60; | |
return times; | |
}, | |
// get asr shadow factor | |
asrFactor: function(asrParam) { | |
var factor = {Standard: 1, Hanafi: 2}[asrParam]; | |
return factor || this.eval(asrParam); | |
}, | |
// return sun angle for sunset/sunrise | |
riseSetAngle: function() { | |
//var earthRad = 6371009; // in meters | |
//var angle = DMath.arccos(earthRad/(earthRad+ elv)); | |
var angle = 0.0347* Math.sqrt(elv); // an approximation | |
return 0.833+ angle; | |
}, | |
// apply offsets to the times | |
tuneTimes: function(times) { | |
for (var i in times) | |
times[i] += offset[i]/ 60; | |
return times; | |
}, | |
// convert times to given time format | |
modifyFormats: function(times) { | |
for (var i in times) | |
times[i] = this.getFormattedTime(times[i], timeFormat); | |
return times; | |
}, | |
// adjust times for locations in higher latitudes | |
adjustHighLats: function(times) { | |
var params = setting; | |
var nightTime = this.timeDiff(times.sunset, times.sunrise); | |
times.imsak = this.adjustHLTime(times.imsak, times.sunrise, this.eval(params.imsak), nightTime, 'ccw'); | |
times.fajr = this.adjustHLTime(times.fajr, times.sunrise, this.eval(params.fajr), nightTime, 'ccw'); | |
times.isha = this.adjustHLTime(times.isha, times.sunset, this.eval(params.isha), nightTime); | |
times.maghrib = this.adjustHLTime(times.maghrib, times.sunset, this.eval(params.maghrib), nightTime); | |
return times; | |
}, | |
// adjust a time for higher latitudes | |
adjustHLTime: function(time, base, angle, night, direction) { | |
var portion = this.nightPortion(angle, night); | |
var timeDiff = (direction == 'ccw') ? | |
this.timeDiff(time, base): | |
this.timeDiff(base, time); | |
if (isNaN(time) || timeDiff > portion) | |
time = base+ (direction == 'ccw' ? -portion : portion); | |
return time; | |
}, | |
// the night portion used for adjusting times in higher latitudes | |
nightPortion: function(angle, night) { | |
var method = setting.highLats; | |
var portion = 1/2 // MidNight | |
if (method == 'AngleBased') | |
portion = 1/60* angle; | |
if (method == 'OneSeventh') | |
portion = 1/7; | |
return portion* night; | |
}, | |
// convert hours to day portions | |
dayPortion: function(times) { | |
for (var i in times) | |
times[i] /= 24; | |
return times; | |
}, | |
//---------------------- Time Zone Functions ----------------------- | |
// get local time zone | |
getTimeZone: function(date) { | |
var year = date[0]; | |
var t1 = this.gmtOffset([year, 0, 1]); | |
var t2 = this.gmtOffset([year, 6, 1]); | |
return Math.min(t1, t2); | |
}, | |
// get daylight saving for a given date | |
getDst: function(date) { | |
return 1* (this.gmtOffset(date) != this.getTimeZone(date)); | |
}, | |
// GMT offset for a given date | |
gmtOffset: function(date) { | |
var localDate = new Date(date[0], date[1]- 1, date[2], 12, 0, 0, 0); | |
var GMTString = localDate.toGMTString(); | |
var GMTDate = new Date(GMTString.substring(0, GMTString.lastIndexOf(' ')- 1)); | |
var hoursDiff = (localDate- GMTDate) / (1000* 60* 60); | |
return hoursDiff; | |
}, | |
//---------------------- Misc Functions ----------------------- | |
// convert given string into a number | |
eval: function(str) { | |
return 1* (str+ '').split(/[^0-9.+-]/)[0]; | |
}, | |
// detect if input contains 'min' | |
isMin: function(arg) { | |
return (arg+ '').indexOf('min') != -1; | |
}, | |
// compute the difference between two times | |
timeDiff: function(time1, time2) { | |
return DMath.fixHour(time2- time1); | |
}, | |
// add a leading 0 if necessary | |
twoDigitsFormat: function(num) { | |
return (num <10) ? '0'+ num : num; | |
} | |
}} | |
//---------------------- Degree-Based Math Class ----------------------- | |
var DMath = { | |
dtr: function(d) { return (d * Math.PI) / 180.0; }, | |
rtd: function(r) { return (r * 180.0) / Math.PI; }, | |
sin: function(d) { return Math.sin(this.dtr(d)); }, | |
cos: function(d) { return Math.cos(this.dtr(d)); }, | |
tan: function(d) { return Math.tan(this.dtr(d)); }, | |
arcsin: function(d) { return this.rtd(Math.asin(d)); }, | |
arccos: function(d) { return this.rtd(Math.acos(d)); }, | |
arctan: function(d) { return this.rtd(Math.atan(d)); }, | |
arccot: function(x) { return this.rtd(Math.atan(1/x)); }, | |
arctan2: function(y, x) { return this.rtd(Math.atan2(y, x)); }, | |
fixAngle: function(a) { return this.fix(a, 360); }, | |
fixHour: function(a) { return this.fix(a, 24 ); }, | |
fix: function(a, b) { | |
a = a- b* (Math.floor(a/ b)); | |
return (a < 0) ? a+ b : a; | |
} | |
} | |
//---------------------- Init Object ----------------------- | |
var prayTimes = new PrayTimes(); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment