fork download
  1. //--------------------- Copyright Block ----------------------
  2. /*
  3.  
  4. PrayTimes.js: Prayer Times Calculator (ver 2.3)
  5. Copyright (C) 2007-2011 PrayTimes.org
  6.  
  7. Developer: Hamid Zarrabi-Zadeh
  8. License: GNU LGPL v3.0
  9.  
  10. TERMS OF USE:
  11. Permission is granted to use this code, with or
  12. without modification, in any website or application
  13. provided that credit is given to the original work
  14. with a link back to PrayTimes.org.
  15.  
  16. This program is distributed in the hope that it will
  17. be useful, but WITHOUT ANY WARRANTY.
  18.  
  19. PLEASE DO NOT REMOVE THIS COPYRIGHT BLOCK.
  20.  
  21. */
  22.  
  23.  
  24. //--------------------- Help and Manual ----------------------
  25. /*
  26.  
  27. User's Manual:
  28. http://p...content-available-to-author-only...s.org/manual
  29.  
  30. Calculation Formulas:
  31. http://p...content-available-to-author-only...s.org/calculation
  32.  
  33.  
  34.  
  35. //------------------------ User Interface -------------------------
  36.  
  37.  
  38. getTimes (date, coordinates [, timeZone [, dst [, timeFormat]]])
  39.  
  40. setMethod (method) // set calculation method
  41. adjust (parameters) // adjust calculation parameters
  42. tune (offsets) // tune times by given offsets
  43.  
  44. getMethod () // get calculation method
  45. getSetting () // get current calculation parameters
  46. getOffsets () // get current time offsets
  47.  
  48.  
  49. //------------------------- Sample Usage --------------------------
  50.  
  51.  
  52. var PT = new PrayTimes('ISNA');
  53. var times = PT.getTimes(new Date(), [43, -80], -5);
  54. document.write('Sunrise = '+ times.sunrise)
  55.  
  56.  
  57. */
  58.  
  59.  
  60. //----------------------- PrayTimes Class ------------------------
  61.  
  62.  
  63. function PrayTimes(method) {
  64.  
  65.  
  66. //------------------------ Constants --------------------------
  67. var
  68.  
  69. // Time Names
  70. timeNames = {
  71. imsak : 'Imsak',
  72. fajr : 'Fajr',
  73. sunrise : 'Sunrise',
  74. dhuhr : 'Dhuhr',
  75. asr : 'Asr',
  76. sunset : 'Sunset',
  77. maghrib : 'Maghrib',
  78. isha : 'Isha',
  79. midnight : 'Midnight'
  80. },
  81.  
  82.  
  83. // Calculation Methods
  84. methods = {
  85. MWL: {
  86. name: 'Muslim World League',
  87. params: { fajr: 18, isha: 17 } },
  88. ISNA: {
  89. name: 'Islamic Society of North America (ISNA)',
  90. params: { fajr: 15, isha: 15 } },
  91. Egypt: {
  92. name: 'Egyptian General Authority of Survey',
  93. params: { fajr: 19.5, isha: 17.5 } },
  94. Makkah: {
  95. name: 'Umm Al-Qura University, Makkah',
  96. params: { fajr: 18.5, isha: '90 min' } }, // fajr was 19 degrees before 1430 hijri
  97. Karachi: {
  98. name: 'University of Islamic Sciences, Karachi',
  99. params: { fajr: 18, isha: 18 } },
  100. Tehran: {
  101. name: 'Institute of Geophysics, University of Tehran',
  102. params: { fajr: 17.7, isha: 14, maghrib: 4.5, midnight: 'Jafari' } }, // isha is not explicitly specified in this method
  103. Jafari: {
  104. name: 'Shia Ithna-Ashari, Leva Institute, Qum',
  105. params: { fajr: 16, isha: 14, maghrib: 4, midnight: 'Jafari' } }
  106. },
  107.  
  108.  
  109. // Default Parameters in Calculation Methods
  110. defaultParams = {
  111. maghrib: '0 min', midnight: 'Standard'
  112.  
  113. },
  114.  
  115.  
  116. //----------------------- Parameter Values ----------------------
  117. /*
  118.  
  119. // Asr Juristic Methods
  120. asrJuristics = [
  121. 'Standard', // Shafi`i, Maliki, Ja`fari, Hanbali
  122. 'Hanafi' // Hanafi
  123. ],
  124.  
  125.  
  126. // Midnight Mode
  127. midnightMethods = [
  128. 'Standard', // Mid Sunset to Sunrise
  129. 'Jafari' // Mid Sunset to Fajr
  130. ],
  131.  
  132.  
  133. // Adjust Methods for Higher Latitudes
  134. highLatMethods = [
  135. 'NightMiddle', // middle of night
  136. 'AngleBased', // angle/60th of night
  137. 'OneSeventh', // 1/7th of night
  138. 'None' // No adjustment
  139. ],
  140.  
  141.  
  142. // Time Formats
  143. timeFormats = [
  144. '24h', // 24-hour format
  145. '12h', // 12-hour format
  146. '12hNS', // 12-hour format with no suffix
  147. 'Float' // floating point number
  148. ],
  149. */
  150.  
  151.  
  152. //---------------------- Default Settings --------------------
  153.  
  154. calcMethod = 'MWL',
  155.  
  156. // do not change anything here; use adjust method instead
  157. setting = {
  158. imsak : '10 min',
  159. dhuhr : '0 min',
  160. asr : 'Standard',
  161. highLats : 'NightMiddle'
  162. },
  163.  
  164. timeFormat = '24h',
  165. timeSuffixes = ['am', 'pm'],
  166. invalidTime = '-----',
  167.  
  168. numIterations = 1,
  169. offset = {},
  170.  
  171.  
  172. //----------------------- Local Variables ---------------------
  173.  
  174. lat, lng, elv, // coordinates
  175. timeZone, jDate; // time variables
  176.  
  177.  
  178. //---------------------- Initialization -----------------------
  179.  
  180.  
  181. // set methods defaults
  182. var defParams = defaultParams;
  183. for (var i in methods) {
  184. var params = methods[i].params;
  185. for (var j in defParams)
  186. if ((typeof(params[j]) == 'undefined'))
  187. params[j] = defParams[j];
  188. };
  189.  
  190. // initialize settings
  191. calcMethod = methods[method] ? method : calcMethod;
  192. var params = methods[calcMethod].params;
  193. for (var id in params)
  194. setting[id] = params[id];
  195.  
  196. // init time offsets
  197. for (var i in timeNames)
  198. offset[i] = 0;
  199.  
  200.  
  201.  
  202. //----------------------- Public Functions ------------------------
  203. return {
  204.  
  205.  
  206. // set calculation method
  207. setMethod: function(method) {
  208. if (methods[method]) {
  209. this.adjust(methods[method].params);
  210. calcMethod = method;
  211. }
  212. },
  213.  
  214.  
  215. // set calculating parameters
  216. adjust: function(params) {
  217. for (var id in params)
  218. setting[id] = params[id];
  219. },
  220.  
  221.  
  222. // set time offsets
  223. tune: function(timeOffsets) {
  224. for (var i in timeOffsets)
  225. offset[i] = timeOffsets[i];
  226. },
  227.  
  228.  
  229. // get current calculation method
  230. getMethod: function() { return calcMethod; },
  231.  
  232. // get current setting
  233. getSetting: function() { return setting; },
  234.  
  235. // get current time offsets
  236. getOffsets: function() { return offset; },
  237.  
  238. // get default calc parametrs
  239. getDefaults: function() { return methods; },
  240.  
  241.  
  242. // return prayer times for a given date
  243. getTimes: function(date, coords, timezone, dst, format) {
  244. lat = 1* coords[0];
  245. lng = 1* coords[1];
  246. elv = coords[2] ? 1* coords[2] : 0;
  247. timeFormat = format || timeFormat;
  248. if (date.constructor === Date)
  249. date = [date.getFullYear(), date.getMonth()+ 1, date.getDate()];
  250. if (typeof(timezone) == 'undefined' || timezone == 'auto')
  251. timezone = this.getTimeZone(date);
  252. if (typeof(dst) == 'undefined' || dst == 'auto')
  253. dst = this.getDst(date);
  254. timeZone = 1* timezone+ (1* dst ? 1 : 0);
  255. jDate = this.julian(date[0], date[1], date[2])- lng/ (15* 24);
  256.  
  257. return this.computeTimes();
  258. },
  259.  
  260.  
  261. // convert float time to the given format (see timeFormats)
  262. getFormattedTime: function(time, format, suffixes) {
  263. if (isNaN(time))
  264. return invalidTime;
  265. if (format == 'Float') return time;
  266. suffixes = suffixes || timeSuffixes;
  267.  
  268. time = DMath.fixHour(time+ 0.5/ 60); // add 0.5 minutes to round
  269. var hours = Math.floor(time);
  270. var minutes = Math.floor((time- hours)* 60);
  271. var suffix = (format == '12h') ? suffixes[hours < 12 ? 0 : 1] : '';
  272. var hour = (format == '24h') ? this.twoDigitsFormat(hours) : ((hours+ 12 -1)% 12+ 1);
  273. return hour+ ':'+ this.twoDigitsFormat(minutes)+ (suffix ? ' '+ suffix : '');
  274. },
  275.  
  276.  
  277. //---------------------- Calculation Functions -----------------------
  278.  
  279.  
  280. // compute mid-day time
  281. midDay: function(time) {
  282. var eqt = this.sunPosition(jDate+ time).equation;
  283. var noon = DMath.fixHour(12- eqt);
  284. return noon;
  285. },
  286.  
  287.  
  288. // compute the time at which sun reaches a specific angle below horizon
  289. sunAngleTime: function(angle, time, direction) {
  290. var decl = this.sunPosition(jDate+ time).declination;
  291. var noon = this.midDay(time);
  292. var t = 1/15* DMath.arccos((-DMath.sin(angle)- DMath.sin(decl)* DMath.sin(lat))/
  293. (DMath.cos(decl)* DMath.cos(lat)));
  294. return noon+ (direction == 'ccw' ? -t : t);
  295. },
  296.  
  297.  
  298. // compute asr time
  299. asrTime: function(factor, time) {
  300. var decl = this.sunPosition(jDate+ time).declination;
  301. var angle = -DMath.arccot(factor+ DMath.tan(Math.abs(lat- decl)));
  302. return this.sunAngleTime(angle, time);
  303. },
  304.  
  305.  
  306. // compute declination angle of sun and equation of time
  307. // Ref: http://a...content-available-to-author-only...y.mil/faq/docs/SunApprox.php
  308. sunPosition: function(jd) {
  309. var D = jd - 2451545.0;
  310. var g = DMath.fixAngle(357.529 + 0.98560028* D);
  311. var q = DMath.fixAngle(280.459 + 0.98564736* D);
  312. var L = DMath.fixAngle(q + 1.915* DMath.sin(g) + 0.020* DMath.sin(2*g));
  313.  
  314. var R = 1.00014 - 0.01671* DMath.cos(g) - 0.00014* DMath.cos(2*g);
  315. var e = 23.439 - 0.00000036* D;
  316.  
  317. var RA = DMath.arctan2(DMath.cos(e)* DMath.sin(L), DMath.cos(L))/ 15;
  318. var eqt = q/15 - DMath.fixHour(RA);
  319. var decl = DMath.arcsin(DMath.sin(e)* DMath.sin(L));
  320.  
  321. return {declination: decl, equation: eqt};
  322. },
  323.  
  324.  
  325. // convert Gregorian date to Julian day
  326. // Ref: Astronomical Algorithms by Jean Meeus
  327. julian: function(year, month, day) {
  328. if (month <= 2) {
  329. year -= 1;
  330. month += 12;
  331. };
  332. var A = Math.floor(year/ 100);
  333. var B = 2- A+ Math.floor(A/ 4);
  334.  
  335. var JD = Math.floor(365.25* (year+ 4716))+ Math.floor(30.6001* (month+ 1))+ day+ B- 1524.5;
  336. return JD;
  337. },
  338.  
  339.  
  340. //---------------------- Compute Prayer Times -----------------------
  341.  
  342.  
  343. // compute prayer times at given julian date
  344. computePrayerTimes: function(times) {
  345. times = this.dayPortion(times);
  346. var params = setting;
  347.  
  348. var imsak = this.sunAngleTime(this.eval(params.imsak), times.imsak, 'ccw');
  349. var fajr = this.sunAngleTime(this.eval(params.fajr), times.fajr, 'ccw');
  350. var sunrise = this.sunAngleTime(this.riseSetAngle(), times.sunrise, 'ccw');
  351. var dhuhr = this.midDay(times.dhuhr);
  352. var asr = this.asrTime(this.asrFactor(params.asr), times.asr);
  353. var sunset = this.sunAngleTime(this.riseSetAngle(), times.sunset);;
  354. var maghrib = this.sunAngleTime(this.eval(params.maghrib), times.maghrib);
  355. var isha = this.sunAngleTime(this.eval(params.isha), times.isha);
  356.  
  357. return {
  358. imsak: imsak, fajr: fajr, sunrise: sunrise, dhuhr: dhuhr,
  359. asr: asr, sunset: sunset, maghrib: maghrib, isha: isha
  360. };
  361. },
  362.  
  363.  
  364. // compute prayer times
  365. computeTimes: function() {
  366. // default times
  367. var times = {
  368. imsak: 5, fajr: 5, sunrise: 6, dhuhr: 12,
  369. asr: 13, sunset: 18, maghrib: 18, isha: 18
  370. };
  371.  
  372. // main iterations
  373. for (var i=1 ; i<=numIterations ; i++)
  374. times = this.computePrayerTimes(times);
  375.  
  376. times = this.adjustTimes(times);
  377.  
  378. // add midnight time
  379. times.midnight = (setting.midnight == 'Jafari') ?
  380. times.sunset+ this.timeDiff(times.sunset, times.fajr)/ 2 :
  381. times.sunset+ this.timeDiff(times.sunset, times.sunrise)/ 2;
  382.  
  383. times = this.tuneTimes(times);
  384. return this.modifyFormats(times);
  385. },
  386.  
  387.  
  388. // adjust times
  389. adjustTimes: function(times) {
  390. var params = setting;
  391. for (var i in times)
  392. times[i] += timeZone- lng/ 15;
  393.  
  394. if (params.highLats != 'None')
  395. times = this.adjustHighLats(times);
  396.  
  397. if (this.isMin(params.imsak))
  398. times.imsak = times.fajr- this.eval(params.imsak)/ 60;
  399. if (this.isMin(params.maghrib))
  400. times.maghrib = times.sunset+ this.eval(params.maghrib)/ 60;
  401. if (this.isMin(params.isha))
  402. times.isha = times.maghrib+ this.eval(params.isha)/ 60;
  403. times.dhuhr += this.eval(params.dhuhr)/ 60;
  404.  
  405. return times;
  406. },
  407.  
  408.  
  409. // get asr shadow factor
  410. asrFactor: function(asrParam) {
  411. var factor = {Standard: 1, Hanafi: 2}[asrParam];
  412. return factor || this.eval(asrParam);
  413. },
  414.  
  415.  
  416. // return sun angle for sunset/sunrise
  417. riseSetAngle: function() {
  418. //var earthRad = 6371009; // in meters
  419. //var angle = DMath.arccos(earthRad/(earthRad+ elv));
  420. var angle = 0.0347* Math.sqrt(elv); // an approximation
  421. return 0.833+ angle;
  422. },
  423.  
  424.  
  425. // apply offsets to the times
  426. tuneTimes: function(times) {
  427. for (var i in times)
  428. times[i] += offset[i]/ 60;
  429. return times;
  430. },
  431.  
  432.  
  433. // convert times to given time format
  434. modifyFormats: function(times) {
  435. for (var i in times)
  436. times[i] = this.getFormattedTime(times[i], timeFormat);
  437. return times;
  438. },
  439.  
  440.  
  441. // adjust times for locations in higher latitudes
  442. adjustHighLats: function(times) {
  443. var params = setting;
  444. var nightTime = this.timeDiff(times.sunset, times.sunrise);
  445.  
  446. times.imsak = this.adjustHLTime(times.imsak, times.sunrise, this.eval(params.imsak), nightTime, 'ccw');
  447. times.fajr = this.adjustHLTime(times.fajr, times.sunrise, this.eval(params.fajr), nightTime, 'ccw');
  448. times.isha = this.adjustHLTime(times.isha, times.sunset, this.eval(params.isha), nightTime);
  449. times.maghrib = this.adjustHLTime(times.maghrib, times.sunset, this.eval(params.maghrib), nightTime);
  450.  
  451. return times;
  452. },
  453.  
  454.  
  455. // adjust a time for higher latitudes
  456. adjustHLTime: function(time, base, angle, night, direction) {
  457. var portion = this.nightPortion(angle, night);
  458. var timeDiff = (direction == 'ccw') ?
  459. this.timeDiff(time, base):
  460. this.timeDiff(base, time);
  461. if (isNaN(time) || timeDiff > portion)
  462. time = base+ (direction == 'ccw' ? -portion : portion);
  463. return time;
  464. },
  465.  
  466.  
  467. // the night portion used for adjusting times in higher latitudes
  468. nightPortion: function(angle, night) {
  469. var method = setting.highLats;
  470. var portion = 1/2 // MidNight
  471. if (method == 'AngleBased')
  472. portion = 1/60* angle;
  473. if (method == 'OneSeventh')
  474. portion = 1/7;
  475. return portion* night;
  476. },
  477.  
  478.  
  479. // convert hours to day portions
  480. dayPortion: function(times) {
  481. for (var i in times)
  482. times[i] /= 24;
  483. return times;
  484. },
  485.  
  486.  
  487. //---------------------- Time Zone Functions -----------------------
  488.  
  489.  
  490. // get local time zone
  491. getTimeZone: function(date) {
  492. var year = date[0];
  493. var t1 = this.gmtOffset([year, 0, 1]);
  494. var t2 = this.gmtOffset([year, 6, 1]);
  495. return Math.min(t1, t2);
  496. },
  497.  
  498.  
  499. // get daylight saving for a given date
  500. getDst: function(date) {
  501. return 1* (this.gmtOffset(date) != this.getTimeZone(date));
  502. },
  503.  
  504.  
  505. // GMT offset for a given date
  506. gmtOffset: function(date) {
  507. var localDate = new Date(date[0], date[1]- 1, date[2], 12, 0, 0, 0);
  508. var GMTString = localDate.toGMTString();
  509. var GMTDate = new Date(GMTString.substring(0, GMTString.lastIndexOf(' ')- 1));
  510. var hoursDiff = (localDate- GMTDate) / (1000* 60* 60);
  511. return hoursDiff;
  512. },
  513.  
  514.  
  515. //---------------------- Misc Functions -----------------------
  516.  
  517. // convert given string into a number
  518. eval: function(str) {
  519. return 1* (str+ '').split(/[^0-9.+-]/)[0];
  520. },
  521.  
  522.  
  523. // detect if input contains 'min'
  524. isMin: function(arg) {
  525. return (arg+ '').indexOf('min') != -1;
  526. },
  527.  
  528.  
  529. // compute the difference between two times
  530. timeDiff: function(time1, time2) {
  531. return DMath.fixHour(time2- time1);
  532. },
  533.  
  534.  
  535. // add a leading 0 if necessary
  536. twoDigitsFormat: function(num) {
  537. return (num <10) ? '0'+ num : num;
  538. }
  539.  
  540. }}
  541.  
  542.  
  543.  
  544. //---------------------- Degree-Based Math Class -----------------------
  545.  
  546.  
  547. var DMath = {
  548.  
  549. dtr: function(d) { return (d * Math.PI) / 180.0; },
  550. rtd: function(r) { return (r * 180.0) / Math.PI; },
  551.  
  552. sin: function(d) { return Math.sin(this.dtr(d)); },
  553. cos: function(d) { return Math.cos(this.dtr(d)); },
  554. tan: function(d) { return Math.tan(this.dtr(d)); },
  555.  
  556. arcsin: function(d) { return this.rtd(Math.asin(d)); },
  557. arccos: function(d) { return this.rtd(Math.acos(d)); },
  558. arctan: function(d) { return this.rtd(Math.atan(d)); },
  559.  
  560. arccot: function(x) { return this.rtd(Math.atan(1/x)); },
  561. arctan2: function(y, x) { return this.rtd(Math.atan2(y, x)); },
  562.  
  563. fixAngle: function(a) { return this.fix(a, 360); },
  564. fixHour: function(a) { return this.fix(a, 24 ); },
  565.  
  566. fix: function(a, b) {
  567. a = a- b* (Math.floor(a/ b));
  568. return (a < 0) ? a+ b : a;
  569. }
  570. }
  571.  
  572.  
  573. //---------------------- Init Object -----------------------
  574.  
  575.  
  576. var prayTimes = new PrayTimes();
  577.  
  578.  
  579.  
Success #stdin #stdout 1s 58428KB
stdin
Standard input is empty
stdout
Standard output is empty