PageSourceSearch

https://factjo.com/js/PrayTimes.js?v=20241129b

js factjo.com collected 2026-10-02 11:55:07 UTC 14,878 bytes, 569 lines download raw bytes

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

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.