khalidative commited on
Commit
7d87c26
·
verified ·
1 Parent(s): 5d4b172

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +402 -0
app.py ADDED
@@ -0,0 +1,402 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from datetime import date
3
+ import math
4
+ import re
5
+
6
+ # Assuming PrayTimes class is defined here or imported from praytimes.py
7
+
8
+ class PrayTimes():
9
+
10
+
11
+ #------------------------ Constants --------------------------
12
+
13
+ # Time Names
14
+ timeNames = {
15
+ 'imsak' : 'Imsak',
16
+ 'fajr' : 'Fajr',
17
+ 'sunrise' : 'Sunrise',
18
+ 'dhuhr' : 'Dhuhr',
19
+ 'asr' : 'Asr',
20
+ 'sunset' : 'Sunset',
21
+ 'maghrib' : 'Maghrib',
22
+ 'isha' : 'Isha',
23
+ 'midnight' : 'Midnight'
24
+ }
25
+
26
+ # Calculation Methods
27
+ methods = {
28
+ 'MWL': {
29
+ 'name': 'Muslim World League',
30
+ 'params': { 'fajr': 18, 'isha': 17 } },
31
+ 'ISNA': {
32
+ 'name': 'Islamic Society of North America (ISNA)',
33
+ 'params': { 'fajr': 15, 'isha': 15 } },
34
+ 'Egypt': {
35
+ 'name': 'Egyptian General Authority of Survey',
36
+ 'params': { 'fajr': 19.5, 'isha': 17.5 } },
37
+ 'Makkah': {
38
+ 'name': 'Umm Al-Qura University, Makkah',
39
+ 'params': { 'fajr': 18.5, 'isha': '90 min' } }, # fajr was 19 degrees before 1430 hijri
40
+ 'Karachi': {
41
+ 'name': 'University of Islamic Sciences, Karachi',
42
+ 'params': { 'fajr': 18, 'isha': 18 } },
43
+ 'Tehran': {
44
+ 'name': 'Institute of Geophysics, University of Tehran',
45
+ 'params': { 'fajr': 17.7, 'isha': 14, 'maghrib': 4.5, 'midnight': 'Jafari' } }, # isha is not explicitly specified in this method
46
+ 'Jafari': {
47
+ 'name': 'Shia Ithna-Ashari, Leva Institute, Qum',
48
+ 'params': { 'fajr': 16, 'isha': 14, 'maghrib': 4, 'midnight': 'Jafari' } }
49
+ }
50
+
51
+ # Default Parameters in Calculation Methods
52
+ defaultParams = {
53
+ 'maghrib': '0 min', 'midnight': 'Standard'
54
+ }
55
+
56
+
57
+ #---------------------- Default Settings --------------------
58
+
59
+ calcMethod = 'MWL'
60
+
61
+ # do not change anything here; use adjust method instead
62
+ settings = {
63
+ "imsak" : '10 min',
64
+ "dhuhr" : '0 min',
65
+ "asr" : 'Standard',
66
+ "highLats" : 'NightMiddle'
67
+ }
68
+
69
+ timeFormat = '24h'
70
+ timeSuffixes = ['am', 'pm']
71
+ invalidTime = '-----'
72
+
73
+ numIterations = 1
74
+ offset = {}
75
+
76
+
77
+ #---------------------- Initialization -----------------------
78
+
79
+ def __init__(self, method = "MWL") :
80
+
81
+ # set methods defaults
82
+ for method, config in self.methods.items():
83
+ for name, value in self.defaultParams.items():
84
+ if not name in config['params'] or config['params'][name] is None:
85
+ config['params'][name] = value
86
+
87
+ # initialize settings
88
+ self.calcMethod = method if method in self.methods else 'MWL'
89
+ params = self.methods[self.calcMethod]['params']
90
+ for name, value in params.items():
91
+ self.settings[name] = value
92
+
93
+ # init time offsets
94
+ for name in self.timeNames:
95
+ self.offset[name] = 0
96
+
97
+
98
+ #-------------------- Interface Functions --------------------
99
+
100
+ def setMethod(self, method):
101
+ if method in self.methods:
102
+ self.adjust(self.methods[method]['params'])
103
+ self.calcMethod = method
104
+
105
+ def adjust(self, params):
106
+ self.settings.update(params)
107
+
108
+ def tune(self, timeOffsets):
109
+ self.offsets.update(timeOffsets)
110
+
111
+ def getMethod(self):
112
+ return self.calcMethod
113
+
114
+ def getSettings(self):
115
+ return self.settings
116
+
117
+ def getOffsets(self):
118
+ return self.offset
119
+
120
+ def getDefaults(self):
121
+ return self.methods
122
+
123
+ # return prayer times for a given date
124
+ def getTimes(self, date, coords, timezone, dst = 0, format = None):
125
+ self.lat = coords[0]
126
+ self.lng = coords[1]
127
+ self.elv = coords[2] if len(coords)>2 else 0
128
+ if format != None:
129
+ self.timeFormat = format
130
+ if type(date).__name__ == 'date':
131
+ date = (date.year, date.month, date.day)
132
+ self.timeZone = timezone + (1 if dst else 0)
133
+ self.jDate = self.julian(date[0], date[1], date[2]) - self.lng / (15 * 24.0)
134
+ return self.computeTimes()
135
+
136
+ # convert float time to the given format (see timeFormats)
137
+ def getFormattedTime(self, time, format, suffixes = None):
138
+ if math.isnan(time):
139
+ return self.invalidTime
140
+ if format == 'Float':
141
+ return time
142
+ if suffixes == None:
143
+ suffixes = self.timeSuffixes
144
+
145
+ time = self.fixhour(time+ 0.5/ 60) # add 0.5 minutes to round
146
+ hours = math.floor(time)
147
+
148
+ minutes = math.floor((time- hours)* 60)
149
+ suffix = suffixes[ 0 if hours < 12 else 1 ] if format == '12h' else ''
150
+ formattedTime = "%02d:%02d" % (hours, minutes) if format == "24h" else "%d:%02d" % ((hours+11)%12+1, minutes)
151
+ return formattedTime + suffix
152
+
153
+
154
+ #---------------------- Calculation Functions -----------------------
155
+
156
+ # compute mid-day time
157
+ def midDay(self, time):
158
+ eqt = self.sunPosition(self.jDate + time)[1]
159
+ return self.fixhour(12 - eqt)
160
+
161
+ # compute the time at which sun reaches a specific angle below horizon
162
+ def sunAngleTime(self, angle, time, direction = None):
163
+ try:
164
+ decl = self.sunPosition(self.jDate + time)[0]
165
+ noon = self.midDay(time)
166
+ t = 1/15.0* self.arccos((-self.sin(angle)- self.sin(decl)* self.sin(self.lat))/
167
+ (self.cos(decl)* self.cos(self.lat)))
168
+ return noon+ (-t if direction == 'ccw' else t)
169
+ except ValueError:
170
+ return float('nan')
171
+
172
+ # compute asr time
173
+ def asrTime(self, factor, time):
174
+ decl = self.sunPosition(self.jDate + time)[0]
175
+ angle = -self.arccot(factor + self.tan(abs(self.lat - decl)))
176
+ return self.sunAngleTime(angle, time)
177
+
178
+ # compute declination angle of sun and equation of time
179
+ # Ref: http://aa.usno.navy.mil/faq/docs/SunApprox.php
180
+ def sunPosition(self, jd):
181
+ D = jd - 2451545.0
182
+ g = self.fixangle(357.529 + 0.98560028* D)
183
+ q = self.fixangle(280.459 + 0.98564736* D)
184
+ L = self.fixangle(q + 1.915* self.sin(g) + 0.020* self.sin(2*g))
185
+
186
+ R = 1.00014 - 0.01671*self.cos(g) - 0.00014*self.cos(2*g)
187
+ e = 23.439 - 0.00000036* D
188
+
189
+ RA = self.arctan2(self.cos(e)* self.sin(L), self.cos(L))/ 15.0
190
+ eqt = q/15.0 - self.fixhour(RA)
191
+ decl = self.arcsin(self.sin(e)* self.sin(L))
192
+
193
+ return (decl, eqt)
194
+
195
+ # convert Gregorian date to Julian day
196
+ # Ref: Astronomical Algorithms by Jean Meeus
197
+ def julian(self, year, month, day):
198
+ if month <= 2:
199
+ year -= 1
200
+ month += 12
201
+ A = math.floor(year / 100)
202
+ B = 2 - A + math.floor(A / 4)
203
+ return math.floor(365.25 * (year + 4716)) + math.floor(30.6001 * (month + 1)) + day + B - 1524.5
204
+
205
+
206
+
207
+ #---------------------- Compute Prayer Times -----------------------
208
+
209
+ # compute prayer times at given julian date
210
+ def computePrayerTimes(self, times):
211
+ times = self.dayPortion(times)
212
+ params = self.settings
213
+
214
+ imsak = self.sunAngleTime(self.eval(params['imsak']), times['imsak'], 'ccw')
215
+ fajr = self.sunAngleTime(self.eval(params['fajr']), times['fajr'], 'ccw')
216
+ sunrise = self.sunAngleTime(self.riseSetAngle(self.elv), times['sunrise'], 'ccw')
217
+ dhuhr = self.midDay(times['dhuhr'])
218
+ asr = self.asrTime(self.asrFactor(params['asr']), times['asr'])
219
+ sunset = self.sunAngleTime(self.riseSetAngle(self.elv), times['sunset'])
220
+ maghrib = self.sunAngleTime(self.eval(params['maghrib']), times['maghrib'])
221
+ isha = self.sunAngleTime(self.eval(params['isha']), times['isha'])
222
+ return {
223
+ 'imsak': imsak, 'fajr': fajr, 'sunrise': sunrise, 'dhuhr': dhuhr,
224
+ 'asr': asr, 'sunset': sunset, 'maghrib': maghrib, 'isha': isha
225
+ }
226
+
227
+ # compute prayer times
228
+ def computeTimes(self):
229
+ times = {
230
+ 'imsak': 5, 'fajr': 5, 'sunrise': 6, 'dhuhr': 12,
231
+ 'asr': 13, 'sunset': 18, 'maghrib': 18, 'isha': 18
232
+ }
233
+ # main iterations
234
+ for i in range(self.numIterations):
235
+ times = self.computePrayerTimes(times)
236
+ times = self.adjustTimes(times)
237
+ # add midnight time
238
+ if self.settings['midnight'] == 'Jafari':
239
+ times['midnight'] = times['sunset'] + self.timeDiff(times['sunset'], times['fajr']) / 2
240
+ else:
241
+ times['midnight'] = times['sunset'] + self.timeDiff(times['sunset'], times['sunrise']) / 2
242
+
243
+ times = self.tuneTimes(times)
244
+ return self.modifyFormats(times)
245
+
246
+ # adjust times in a prayer time array
247
+ def adjustTimes(self, times):
248
+ params = self.settings
249
+ tzAdjust = self.timeZone - self.lng / 15.0
250
+ for t,v in times.items():
251
+ times[t] += tzAdjust
252
+
253
+ if params['highLats'] != 'None':
254
+ times = self.adjustHighLats(times)
255
+
256
+ if self.isMin(params['imsak']):
257
+ times['imsak'] = times['fajr'] - self.eval(params['imsak']) / 60.0
258
+ # need to ask about 'min' settings
259
+ if self.isMin(params['maghrib']):
260
+ times['maghrib'] = times['sunset'] - self.eval(params['maghrib']) / 60.0
261
+
262
+ if self.isMin(params['isha']):
263
+ times['isha'] = times['maghrib'] - self.eval(params['isha']) / 60.0
264
+ times['dhuhr'] += self.eval(params['dhuhr']) / 60.0
265
+
266
+ return times
267
+
268
+ # get asr shadow factor
269
+ def asrFactor(self, asrParam):
270
+ methods = {'Standard': 1, 'Hanafi': 2}
271
+ return methods[asrParam] if asrParam in methods else self.eval(asrParam)
272
+
273
+ # return sun angle for sunset/sunrise
274
+ def riseSetAngle(self, elevation = 0):
275
+ elevation = 0 if elevation == None else elevation
276
+ return 0.833 + 0.0347 * math.sqrt(elevation) # an approximation
277
+
278
+ # apply offsets to the times
279
+ def tuneTimes(self, times):
280
+ for name, value in times.items():
281
+ times[name] += self.offset[name] / 60.0
282
+ return times
283
+
284
+ # convert times to given time format
285
+ def modifyFormats(self, times):
286
+ for name, value in times.items():
287
+ times[name] = self.getFormattedTime(times[name], self.timeFormat)
288
+ return times
289
+
290
+ # adjust times for locations in higher latitudes
291
+ def adjustHighLats(self, times):
292
+ params = self.settings
293
+ nightTime = self.timeDiff(times['sunset'], times['sunrise']) # sunset to sunrise
294
+ times['imsak'] = self.adjustHLTime(times['imsak'], times['sunrise'], self.eval(params['imsak']), nightTime, 'ccw')
295
+ times['fajr'] = self.adjustHLTime(times['fajr'], times['sunrise'], self.eval(params['fajr']), nightTime, 'ccw')
296
+ times['isha'] = self.adjustHLTime(times['isha'], times['sunset'], self.eval(params['isha']), nightTime)
297
+ times['maghrib'] = self.adjustHLTime(times['maghrib'], times['sunset'], self.eval(params['maghrib']), nightTime)
298
+ return times
299
+
300
+ # adjust a time for higher latitudes
301
+ def adjustHLTime(self, time, base, angle, night, direction = None):
302
+ portion = self.nightPortion(angle, night)
303
+ diff = self.timeDiff(time, base) if direction == 'ccw' else self.timeDiff(base, time)
304
+ if math.isnan(time) or diff > portion:
305
+ time = base + (-portion if direction == 'ccw' else portion)
306
+ return time
307
+
308
+ # the night portion used for adjusting times in higher latitudes
309
+ def nightPortion(self, angle, night):
310
+ method = self.settings['highLats']
311
+ portion = 1/2.0 # midnight
312
+ if method == 'AngleBased':
313
+ portion = 1/60.0 * angle
314
+ if method == 'OneSeventh':
315
+ portion = 1/7.0
316
+ return portion * night
317
+
318
+ # convert hours to day portions
319
+ def dayPortion(self, times):
320
+ for i in times:
321
+ times[i] /= 24.0
322
+ return times
323
+
324
+
325
+ #---------------------- Misc Functions -----------------------
326
+
327
+ # compute the difference between two times
328
+ def timeDiff(self, time1, time2):
329
+ return self.fixhour(time2- time1)
330
+
331
+ # convert given string into a number
332
+ def eval(self, st):
333
+ val = re.split('[^0-9.+-]', str(st), 1)[0]
334
+ return float(val) if val else 0
335
+
336
+ # detect if input contains 'min'
337
+ def isMin(self, arg):
338
+ return isinstance(arg, str) and arg.find('min') > -1
339
+
340
+
341
+ #----------------- Degree-Based Math Functions -------------------
342
+
343
+ def sin(self, d): return math.sin(math.radians(d))
344
+ def cos(self, d): return math.cos(math.radians(d))
345
+ def tan(self, d): return math.tan(math.radians(d))
346
+
347
+ def arcsin(self, x): return math.degrees(math.asin(x))
348
+ def arccos(self, x): return math.degrees(math.acos(x))
349
+ def arctan(self, x): return math.degrees(math.atan(x))
350
+
351
+ def arccot(self, x): return math.degrees(math.atan(1.0/x))
352
+ def arctan2(self, y, x): return math.degrees(math.atan2(y, x))
353
+
354
+ def fixangle(self, angle): return self.fix(angle, 360.0)
355
+ def fixhour(self, hour): return self.fix(hour, 24.0)
356
+
357
+ def fix(self, a, mode):
358
+ if math.isnan(a):
359
+ return a
360
+ a = a - mode * (math.floor(a / mode))
361
+ return a + mode if a < 0 else a
362
+
363
+ # Initialize the PrayTimes object
364
+ PT = PrayTimes()
365
+
366
+ import streamlit as st
367
+ from datetime import date
368
+
369
+ # Assuming PrayTimes class is defined here or imported
370
+
371
+ # Initialize the PrayTimes object
372
+ PT = PrayTimes()
373
+
374
+ st.title('Muslim Daily Prayer Timings Calculator')
375
+
376
+ # Input fields for latitude and longitude
377
+ latitude = st.number_input('Enter your latitude:', format='%f')
378
+ longitude = st.number_input('Enter your longitude:', format='%f')
379
+
380
+ # Dropdown for calculation method selection
381
+ calc_method = st.selectbox('Select Calculation Method:', options=list(PT.methods.keys()))
382
+
383
+ # Assuming timezone offset and DST (Daylight Saving Time); you may want to let the user input these
384
+ timezone = st.number_input('Enter your timezone offset from UTC (e.g., -5 for EST):', format='%f')
385
+ dst = st.checkbox('Check if currently observing Daylight Saving Time')
386
+
387
+ # Button to show prayer times
388
+ if st.button('Show Prayer Times'):
389
+ # Set the calculation method based on user selection
390
+ PT.setMethod(calc_method)
391
+
392
+ # Get today's date
393
+ today = date.today()
394
+
395
+ # Get prayer times using the provided latitude, longitude, timezone, and today's date
396
+ times = PT.getTimes(today, (latitude, longitude), timezone, dst)
397
+
398
+ # Displaying the prayer times
399
+ st.subheader('Prayer Times:')
400
+ for time_name in ['Fajr', 'Sunrise', 'Dhuhr', 'Asr', 'Maghrib', 'Isha', 'Midnight']:
401
+ st.write(f"{time_name}: {times[time_name.lower()]}")
402
+