Skip to content

Instantly share code, notes, and snippets.

@rali14
Created November 18, 2020 21:44
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rali14/9607926a3a795ec6b49bf763e0bffe35 to your computer and use it in GitHub Desktop.
Save rali14/9607926a3a795ec6b49bf763e0bffe35 to your computer and use it in GitHub Desktop.
PrayTimes
//--------------------- 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