diff --git a/aladhan_com_fetcher.py b/aladhan_com_fetcher.py new file mode 100644 index 0000000..1be42e7 --- /dev/null +++ b/aladhan_com_fetcher.py @@ -0,0 +1,115 @@ +"""Fetches prayer times from 'www.aladhan.com'.""" + +import json +import requests +import util +from common import CalculationMethod +from datetime import datetime, timedelta +import time +from gmaps_client import GetTimezone, ReverseGeocodeCountry + +_ALADHAN_API_URL = 'http://api.aladhan.com/v1/timings/' + + +def GetCalcMethod(lat, lng): + """Returns the Calculation method based on given region + + MWL: Europe and Far East + ISNA: North America + Egypt: Africa, Syria, Lebanon, Malaysia + Umm Al Qura: Arabian Peninsula + U. of Islamic Sciences: Pakistan, Afganistan, India, Bangladesh + Institute of Geophysics, University of Tehran: Iran + Kuwait: Kuwait + Qatar: Qatar + Majlis Ugama Islam Singapura, Singapore: Singapore + Union Organization islamic de France: France + Diyanet Isleri Baskanligi, Turkey: Turkey + + Args: + lat: a double representing the latitude + lng: a double representing the longitude + + Returns: calculation method""" + + country = ReverseGeocodeCountry(lat, lng) + + if country: + country_calc_method = util.CountryToCalculationMethod(country) + if country_calc_method > 0: + return country_calc_method + + if lng >= -180 and lng < -30: + #ISNA + return CalculationMethod.ISNA + elif lng >= -30 and lng < 35 and lat >= -35 and lat <= 35: + #EGYPT + return CalculationMethod.EGYPT + elif lng >= 35 and lng < 60 and lat >= 10 and lat <= 30: + #MAKKAH + return CalculationMethod.MAKKAH + elif lng >= 60 and lng < 95 and lat >= 5 and lat <= 40: + #KAR + return CalculationMethod.KAR + else: + #MWL + return CalculationMethod.MWL + + +def GetDailyPrayerTimes(lat, lng, date_str): + """Gets the daily prayer times from 'aladhan.com'. + + Performs a POST request on the aladhan.com prayer times API + + Args: + lat: a double representing the latitude + lng: a double representing the longitude + date_str: a string representing the requested date in YYYY-MM-DD + + Returns: a dict containing of daily prayer times and an day difference integer + """ + # set up the parameters in the format expected by 'aladhan.com' + post_data = { + 'latitude': lat, + 'longitude': lng, + 'method' : GetCalcMethod(lat, lng), + } + + current_user_timestamp = util.GetCurrentUserTime(lat, lng) + + timestamp = current_user_timestamp + date_time_format = "%Y-%m-%d %H:%M:%S" + day_difference = 0 + + if date_str and date_str != "None": + try: + agent_date = util.GetCurrentUserTime(37, -121).date() + requested_date = datetime.strptime(date_str, "%Y-%m-%d").date() + day_difference = int((requested_date - agent_date).days) + + if day_difference > 0: + timestamp = current_user_timestamp + timedelta(days=day_difference) + except BaseException: + pass + + try: + timestamp_UTC = str(int(time.mktime(timestamp.timetuple()))) + except BaseException: + timestamp_UTC = 0 + + #print 'post_data = ', post_data + for request_try in range(3): + try: + request = requests.get(_ALADHAN_API_URL+timestamp_UTC, params=post_data, timeout=15) + if request.status_code == requests.codes.ok: + break + elif request_try == 2: + return (None, None) + except BaseException: + if request_try == 2: + return (None, None) + continue + + response = json.loads(request.text).get("data").get("timings") + return (response, day_difference) + diff --git a/app.py b/app.py index 0463100..47629b2 100644 --- a/app.py +++ b/app.py @@ -7,7 +7,6 @@ from flask import Flask, request, render_template, redirect from oauth2.tokengenerator import URandomTokenGenerator -from fake_db import FakeDb from db import Database from prayer_info import PrayerInfo from intent_handler import IntentHandler @@ -16,117 +15,111 @@ # pylint: disable-msg=C0103 app = Flask(__name__) _prayer_info = PrayerInfo() -_fake_db = FakeDb() _db = Database() _token_generator = URandomTokenGenerator(20) -_intent_handler = IntentHandler(_prayer_info, _fake_db, _db) +_intent_handler = IntentHandler(_prayer_info, _db) @app.route('/') def home(): - """GET handler for home page.""" - return 'Welcome to the Islam Buddy API!' + """GET handler for home page.""" + return 'Welcome to the Islam Buddy API!' @app.route('/table', methods=['GET']) def table(): - id = request.args.get('id') - command = request.args.get('command') - response = {} - if command == 'add': - response = 'add is disabled' - """ + id = request.args.get('id') + command = request.args.get('command') + response = {} + if command == 'add': + response = 'add is disabled' + """ _db.AddOrUpdateUser(id, { 'user_info': {'foo': id}, 'city': request.args.get('city') }) response = 'user ', id, ' was added' """ - elif command == 'get': - response = _db.GetUser(id) - elif command == 'delete': - _db.DeleteUser(id) - response = 'user ', id, ' was deleted' - return util.JsonResponse(response) + elif command == 'get': + response = _db.GetUser(id) + elif command == 'delete': + _db.DeleteUser(id) + response = 'user ', id, ' was deleted' + return util.JsonResponse(response) @app.route('/salah', methods=['POST', 'GET']) def salah(): - """GET and POST handler for /salah page.""" - if request.method == 'GET': - #print 'received GET request' - params = { - 'lat': request.args.get('lat'), - 'lng': request.args.get('lng'), - 'prayer': request.args.get('prayer'), - } - #print 'params = ', params - - if not params.get('lat') or not params.get('lng'): - return util.JsonError('Please provide a lat and lng.') - - prayer_times = \ - PrayerInfo.GetPrayerTimes(params.get('lat'), params.get('lng')) - if prayer_times == {}: - return util.JsonResponse( - "Error, the latitude and longitude entered might be wrong..") - - # convert from map to map - output_prayer_times = {} - for key in prayer_times: - output_prayer_times[util.GetPrayerKeyName(key)] = prayer_times[key] - - return util.JsonResponse(output_prayer_times) - - elif request.method == 'POST': - #print 'received POST request' - - post_params = request.get_json(silent=True, force=True) - #print 'post_params = \n', json.dumps(post_params, indent=2) - - post_intent_name = post_params.get('result').get('metadata').get( - 'intentName') - #print 'intent_name = ', post_intent_name - - if post_intent_name in IntentHandler.INTENTS_HANDLED: - server_response = _intent_handler.HandleIntent(post_params) - elif post_intent_name == 'CLEAR_LOCATION': - user_id = post_params.get('originalRequest').get('data').get('user').get( - 'userId') - _fake_db.DeleteUser(user_id) - server_response = { - "speech": "OK, your location has been cleared.", - } - else: - server_response = { - "speech": "Sorry, Prayer Pal cannot process this request." \ - " Please try again later.", - } - - #print 'server response = ', server_response - return util.JsonResponse(server_response) + """GET and POST handler for /salah page.""" + if request.method == 'GET': + #print 'received GET request' + params = { + 'lat': request.args.get('lat'), + 'lng': request.args.get('lng'), + 'prayer': request.args.get('prayer'), + } + #print 'params = ', params + + if not params.get('lat') or not params.get('lng'): + return util.JsonError('Please provide a lat and lng.') + + prayer_times = \ + PrayerInfo.GetPrayerTimes(params.get('lat'), params.get('lng'), None) + if prayer_times == {}: + return util.JsonResponse( + "Error, the latitude and longitude entered might be wrong..") + + # convert from map to map + output_prayer_times = {} + for key in prayer_times: + output_prayer_times[util.GetPrayerKeyName(key)] = prayer_times[key] + + return util.JsonResponse(output_prayer_times) + + elif request.method == 'POST': + post_params = request.get_json(silent=True, force=True) + + post_intent_name = post_params.get('result').get('metadata').get( + 'intentName') + + if post_intent_name in IntentHandler.INTENTS_HANDLED: + server_response = _intent_handler.HandleIntent(post_params) + elif post_intent_name == 'CLEAR_LOCATION': + user_id = post_params.get('originalRequest').get('data').get('user').get( + 'userId') + _db.DeleteUser(user_id) + server_response = { + "speech": "OK, your location has been cleared.", + } + else: + server_response = { + "speech": "Sorry, Prayer Pal cannot process this request." + " Please try again later.", + } + + return util.JsonResponse(server_response) @app.route('/auth', methods=['GET']) def authenticate(): - """Authentication handler.""" - redirect_uri = request.args.get('redirect_uri') - state = request.args.get('state') - access_token = _token_generator.generate() - full_redirect_uri = '{}#access_token={}&token_type=bearer&state={}'.format( - redirect_uri, access_token, state) + """Authentication handler.""" + redirect_uri = request.args.get('redirect_uri') + state = request.args.get('state') + access_token = _token_generator.generate() + full_redirect_uri = '{}#access_token={}&token_type=bearer&state={}'.format( + redirect_uri, access_token, state) - #print 'FULL REDIRECT URI: ', full_redirect_uri + #print 'FULL REDIRECT URI: ', full_redirect_uri - return redirect(full_redirect_uri) + return redirect(full_redirect_uri) @app.route('/privacy', methods=['GET']) def render_privacy(): - """Privacy handler.""" - return render_template('privacy.html') + """Privacy handler.""" + return render_template('privacy.html') if __name__ == '__main__': - app.run() + app.run() diff --git a/common.py b/common.py index 1e645e9..0a94be8 100644 --- a/common.py +++ b/common.py @@ -28,3 +28,19 @@ class Locality(object): CITY = 1 MASJID = 2 + +class CalculationMethod(object): + UNSPECIFIED = 0 + KAR = 1 + ISNA = 2 + MWL = 3 + MAKKAH = 4 + EGYPT = 5 + TEHRAN = 7 + GULF = 8 + KUWAIT = 9 + QATAR = 10 + SINGAPORE = 11 + FRANCE = 12 + TURKEY = 13 + diff --git a/gmaps_client.py b/gmaps_client.py index ee94a0c..cc0a353 100644 --- a/gmaps_client.py +++ b/gmaps_client.py @@ -2,6 +2,8 @@ import json import time +from datetime import datetime +import math import requests _GMAPS_API_GEOCODE_URL = 'https://maps.googleapis.com/maps/api/geocode/json' @@ -11,8 +13,6 @@ #_GMAPS_API_KEY = 'AIzaSyDSyoJU5z8L5Y2OBE7m79Cex5lCa4Cet_c' # Use for Production GAE -#_GMAPS_API_KEY = 'AIzaSyBTm8Tq2_27EHG9sylGxpcwZk2B4ynjiJU' -#_GMAPS_API_KEY = 'AIzaSyB0q4g_n43g75VmiwdQVTbnnngbE-cwWVw' _GMAPS_API_KEY = 'AIzaSyCfOgYzn3P5hg_L7nK_IM2Qfb-v-bHLpHQ' def GetGeocode(city, state, country): @@ -50,7 +50,7 @@ def GetGeocode(city, state, country): break elif request_try == 2: return None - except: + except BaseException: if request_try == 2: return None continue @@ -58,13 +58,13 @@ def GetGeocode(city, state, country): try: response = json.loads( request.text).get("results")[0].get("geometry").get("location") - except: + except BaseException: return None #print 'response from GMAPS Geocode', response return response -def ReverseGeocodeCity(lat, lng): +def ReverseGeocode(lat, lng): """Returns city from the Google Maps API based on Lat and Lng. Performs a POST request on the Google Maps API @@ -74,7 +74,7 @@ def ReverseGeocodeCity(lat, lng): lat: a double representing the latitude lng: a double representing the longitude - Returns: a string containing the city + Returns: API response """ address_params = ('%.16f' % lat) + ',' + ('%.16f' % lng) @@ -92,7 +92,7 @@ def ReverseGeocodeCity(lat, lng): break elif request_try == 2: return None - except: + except BaseException: if request_try == 2: return None continue @@ -100,16 +100,60 @@ def ReverseGeocodeCity(lat, lng): try: response = json.loads( request.text).get("results")[0].get("address_components") - except: + except BaseException: return None - for address in response: - if address.get("types")[0] == "locality": - return address.get("long_name") - elif address.get("types")[0] == "administrative_area_level_2": - return address.get("long_name") - elif address.get("types")[0] == "administrative_area_level_1": - return address.get("long_name") + return response + + +def ReverseGeocodeCountry(lat, lng): + """Returns city from the Google Maps API based on Lat and Lng. + + Performs a POST request on the Google Maps API + to get the city from the provided latitude and longitude + + Args: + lat: a double representing the latitude + lng: a double representing the longitude + + Returns: a string containing the country + """ + + response = ReverseGeocode(lat, lng) + + if response: + for address in response: + if address.get("types")[0] == "country": + return address.get("long_name") + + # if no address returned, return None + return None + + +def ReverseGeocodeCity(lat, lng): + """Returns city from the Google Maps API based on Lat and Lng. + + Performs a POST request on the Google Maps API + to get the city from the provided latitude and longitude + + Args: + lat: a double representing the latitude + lng: a double representing the longitude + + Returns: a string containing the city + """ + + response = ReverseGeocode(lat, lng) + + if response: + for address in response: + if address.get("types")[0] == "locality": + return address.get("long_name") + elif address.get("types")[0] == "administrative_area_level_2": + return address.get("long_name") + elif address.get("types")[0] == "administrative_area_level_1": + return address.get("long_name") + # if no address returned, return None return None @@ -128,11 +172,12 @@ def GetTimezone(lat, lng): """ address_params = ('%.16f' % lat) + ',' + ('%.16f' % lng) + time_stamp = time.time() # set up the parameters in the format expected by the Google Maps Geocode API post_params = { 'location': address_params, - 'timestamp': time.time(), + 'timestamp': time_stamp, 'key': _GMAPS_API_KEY, } #print 'GMAPS timezone post_params = ', post_params @@ -143,14 +188,15 @@ def GetTimezone(lat, lng): break elif request_try == 2: return None - except: + except BaseException: if request_try == 2: return None continue #print 'GMAPS timezone response = ', request.text try: - response = json.loads(request.text).get("timeZoneId") - except: + time_zone_id = json.loads(request.text).get("timeZoneId") + except BaseException: return None - return str(response) + return str(time_zone_id) + diff --git a/intent_handler.py b/intent_handler.py index 51fc596..d9d1322 100644 --- a/intent_handler.py +++ b/intent_handler.py @@ -17,7 +17,7 @@ def _GetContext(post_params, context_name): def _MakeSpeechResponse(canonical_prayer, desired_prayer, prayer_time, prayer_time_prop, - locality): + day_difference, locality): # prayer_time contains [0] desired prayer time diff, [1] next prayer, [2] next prayer time, # [3] next prayer time diff if prayer_time_prop is set; otherwise it is desired prayer time @@ -26,9 +26,21 @@ def _MakeSpeechResponse(canonical_prayer, desired_prayer, prayer_time, prayer_ti preposition = "in" if locality[0] == Locality.CITY else "at" location = locality[1] if locality[0] == Locality.CITY else GetMasjidDisplayName(locality[1]) + try: + day_difference + except BaseException: + return _DefaultErrorResponse() + else: + if day_difference == 1: + day_str = 'Tomorrow, ' + elif day_difference > 1: + day_str = str(day_difference)+' days from now, ' + else: + day_str = '' + try: location = location.decode('utf-8') - except: + except BaseException: location = 'your location' if prayer_time_prop and prayer_time_prop.lower() == 'time until': @@ -49,13 +61,15 @@ def _MakeSpeechResponse(canonical_prayer, desired_prayer, prayer_time, prayer_ti if prayer_time[0]['HOURS'] == 1: hour_string = 'Hour' - if prayer_time[0]['MINUTES'] == 1: + if prayer_time[0]['MINUTES'] <= 1: minute_string = 'Minute' if prayer_time[0]['HOURS'] > 0: time_str = '%s %s and %s %s' % (prayer_time[0]['HOURS'], hour_string, prayer_time[0]['MINUTES'], minute_string) elif prayer_time[0]['MINUTES'] > 1: time_str = '%s %s' % (prayer_time[0]['MINUTES'], minute_string) + elif prayer_time[0]['SECONDS'] >= 1: + time_str = '%s %s' % ('1', minute_string) if desired_prayer.lower() == 'suhur': pronunciation_prayer = 'Suhur' @@ -73,7 +87,7 @@ def _MakeSpeechResponse(canonical_prayer, desired_prayer, prayer_time, prayer_ti return _DefaultErrorResponse() if ((prayer_time[1] - canonical_prayer == 1) or (prayer_time[1] - canonical_prayer == -5) - or (prayer_time[0]['HOURS'] == 0 and prayer_time[0]['MINUTES'] == 0)): + or (prayer_time[0]['HOURS'] == 0 and prayer_time[0]['MINUTES'] == 0 and prayer_time[0]['SECONDS'] == 0)): if desired_prayer.lower() == 'suhur': speech = 'The time for %s %s %s has ended.' % ( pronunciation_prayer, preposition, location) @@ -115,25 +129,44 @@ def _MakeSpeechResponse(canonical_prayer, desired_prayer, prayer_time, prayer_ti if not prayer_time[0] or not prayer_time[1] or not locality[0] == Locality.CITY: return _DefaultErrorResponse() - speech = 'Fasting starts from %s and ends at %s in %s.' % ( - prayer_time[0], prayer_time[1], location) - display_text = 'Fasting starts from %s and ends at %s in %s.' % ( - prayer_time[0], prayer_time[1], location) + if day_str and day_str != '': + start_str = 'will start' + end_str = 'will end' + else: + start_str = 'starts' + end_str = 'ends' + + speech = '%sFasting %s from %s and %s at %s in %s.' % ( + day_str, start_str, prayer_time[0], end_str, prayer_time[1], location) + display_text = '%sFasting %s from %s and %s at %s in %s.' % ( + day_str, start_str, prayer_time[0], end_str, prayer_time[1], location) elif canonical_prayer and not canonical_prayer == 'NA': time_str = '%s %s %s' % (prayer_time, preposition, location) pronunciation_prayer = util.GetPronunciation(canonical_prayer) display_prayer = util.GetDisplayText(canonical_prayer) - if desired_prayer.lower() == 'suhur': - return {'speech': 'Suhur ends at %s.' % time_str} - elif desired_prayer.lower() == 'iftar': - return {'speech': 'Today, Iftar is at %s.' % time_str} + if day_str and day_str != '': + if desired_prayer.lower() == 'suhur': + return {'speech': '%sSuhur will end at %s.' % (day_str, time_str)} + elif desired_prayer.lower() == 'iftar': + return {'speech': '%sIftar will be at %s.' % (day_str, time_str)} + + speech = '%sthe time for %s will be %s.' % ( + day_str, pronunciation_prayer, time_str) + display_text = '%sthe time for %s will be %s.' % ( + day_str, display_prayer, time_str) + else: + if desired_prayer.lower() == 'suhur': + return {'speech': 'Suhur ends at %s.' % time_str} + elif desired_prayer.lower() == 'iftar': + return {'speech': 'Today, Iftar is at %s.' % time_str} + + speech = 'The time for %s is %s.' % ( + pronunciation_prayer, time_str) + display_text = 'The time for %s is %s.' % ( + display_prayer, time_str) - speech = 'The time for %s is %s.' % ( - pronunciation_prayer, time_str) - display_text = 'The time for %s is %s.' % ( - display_prayer, time_str) else: return _DefaultErrorResponse() else: @@ -155,13 +188,13 @@ def _RespondWithIqamaTime(masjid, desired_prayer): #print 'masjid: ', masjid if not desired_prayer or not masjid: return _MakeSpeechResponse(None, None, None, None, - (None, None)) + None, (None, None)) canonical_prayer = util.StringToDailyPrayer(desired_prayer) if desired_prayer and not desired_prayer.lower() == 'suhur': iqama_time = GetIqamaTime(canonical_prayer, masjid) #print 'iqama_time[', desired_prayer, "] = ", iqama_time return _MakeSpeechResponse(canonical_prayer, desired_prayer, iqama_time, None, - (Locality.MASJID, masjid)) + None, (Locality.MASJID, masjid)) return {'speech': 'Sorry, suhur time is not supported for masjids.'} @@ -178,48 +211,55 @@ class IntentHandler(object): 'PERMISSION_INTENT', ] - def __init__(self, prayer_info, fake_db, db): + def __init__(self, prayer_info, db): self.prayer_info_ = prayer_info - self.fake_db_ = fake_db self.db_ = db def HandleIntent(self, post_params): """Returns a server response as a dictionary.""" - # filled if we have the user's city, country and/or state - params = post_params.get('result').get('parameters') - city = params.get('geo-city') - - # filled if the user calls for a masjid - masjid = params.get('MasjidName') - - # filled if we have the user's lat/lng - device_params = {} - if 'originalRequest' in post_params: - device_params = post_params.get('originalRequest').get('data').get( - 'device') - has_location = device_params and 'location' in device_params - # this will only be populated if the intent type is PERMISSION_REQUEST - permission_context = None - - # filled if the user would like to know the time before a prayer or the time for - # the next prayer - prayer_time_prop = params.get('prayer-time-prop') - - if not has_location: - # this should always be filled since its a required parameter to the intent - # the only time it won't be filled is on PERMISSION_REQUEST intents - desired_prayer = params.get('PrayerName') - else: - # this should be filled on PERMISSION_REQUEST intents in the relevant context - permission_context = _GetContext(post_params, 'requ') - #print 'permission context = ', permission_context - desired_prayer = permission_context.get('parameters').get('PrayerName') - prayer_time_prop = permission_context.get('parameters').get('prayer-time-prop') - - # this should also always be available - user_id = post_params.get('originalRequest').get('data').get('user').get( - 'userId') + try: + # filled if we have the user's city, country and/or state + params = post_params.get('result').get('parameters') + city = params.get('geo-city') + + # filled if the user calls for a masjid + masjid = params.get('MasjidName') + + # filled if we have the user's lat/lng + device_params = {} + if 'originalRequest' in post_params: + device_params = post_params.get('originalRequest').get('data').get( + 'device') + has_location = device_params and 'location' in device_params + # this will only be populated if the intent type is PERMISSION_REQUEST + permission_context = None + + # filled if the user would like to know the time before a prayer or the time for + # the next prayer + prayer_time_prop = params.get('prayer-time-prop') + + # filled if the user would like to know the prayer time on a specific date + date_str = params.get('date') + + if not has_location: + # this should always be filled since its a required parameter to the intent + # the only time it won't be filled is on PERMISSION_REQUEST intents + desired_prayer = params.get('PrayerName') + else: + # this should be filled on PERMISSION_REQUEST intents in the relevant context + permission_context = _GetContext(post_params, 'requ') + #print 'permission context = ', permission_context + desired_prayer = permission_context.get('parameters').get('PrayerName') + prayer_time_prop = permission_context.get('parameters').get('prayer-time-prop') + date_str = params.get('date') + + # this should also always be available + user_id = post_params.get('originalRequest').get('data').get('user').get( + 'userId') + except BaseException: + return _MakeSpeechResponse(None, None, None, None, + None, (None, None)) # if we have a masjid name then call GetIqamaTime to obtain it from scraper if masjid: @@ -229,19 +269,19 @@ def HandleIntent(self, post_params): # so request the user for permissions to use their location if not (city or has_location): return self._LookupOrRequestInformation(post_params, params, - desired_prayer, user_id, prayer_time_prop) + desired_prayer, user_id, date_str, prayer_time_prop) # if we have a city, then use this if city: - return self._RespondToCityRequest(params, desired_prayer, prayer_time_prop) + return self._RespondToCityRequest(params, desired_prayer, date_str, prayer_time_prop) # if we have a device location, then use it elif has_location: return self._RespondToLocationRequest(device_params, permission_context, - user_id, desired_prayer, prayer_time_prop) + user_id, desired_prayer, date_str, prayer_time_prop) def _LookupOrRequestInformation(self, post_params, params, desired_prayer, - user_id, prayer_time_prop): + user_id, date_str, prayer_time_prop): # do not ask for permission if we've already asked for it before permission_context = _GetContext(post_params, 'actions_intent_permission') if (permission_context and @@ -280,14 +320,14 @@ def _LookupOrRequestInformation(self, post_params, params, desired_prayer, lat = user_info.get('lat') lng = user_info.get('lng') city = user_info.get('city') - return self._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, prayer_time_prop) + return self._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) #print('Could not find location in request, ' # 'so responding with a permission request.') return response_builder.RequestLocationPermission() def _RespondToLocationRequest(self, device_params, permission_context, - user_id, desired_prayer, prayer_time_prop): + user_id, desired_prayer, date_str, prayer_time_prop): if permission_context: #print 'permission context' location = device_params.get('location') @@ -305,9 +345,9 @@ def _RespondToLocationRequest(self, device_params, permission_context, #else: # print 'Could not find relevant context!' - return self._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, prayer_time_prop) + return self._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) - def _RespondToCityRequest(self, params, desired_prayer, prayer_time_prop): + def _RespondToCityRequest(self, params, desired_prayer, date_str, prayer_time_prop): city = util.EncodeParameter(params.get('geo-city'), True) country = util.EncodeParameter(params.get('geo-country'), True) state = util.EncodeParameter(params.get('geo-state-us'), True) @@ -315,11 +355,11 @@ def _RespondToCityRequest(self, params, desired_prayer, prayer_time_prop): location_coordinates = gmaps_client.GetGeocode(city, country, state) if not location_coordinates: return _MakeSpeechResponse(None, None, None, None, - (None, None)) + None, (None, None)) lat = location_coordinates.get('lat') lng = location_coordinates.get('lng') - return self._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, prayer_time_prop) + return self._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) def _ComputePrayerTimeProperty(self, canonical_prayer, all_prayer_times, lat, lng): """Computes the desired prayer's time difference as well as the @@ -359,18 +399,23 @@ def _ComputePrayerTimeProperty(self, canonical_prayer, all_prayer_times, lat, ln else: return None - def _ComputePrayerTimeAndRespond(self, desired_prayer, lat, lng, city, prayer_time_prop): + def _ComputePrayerTimeAndRespond(self, desired_prayer, lat, lng, city, date_str, prayer_time_prop): if not city: city = 'your location' - all_prayer_times = self.prayer_info_.GetPrayerTimes(lat, lng) + if prayer_time_prop and prayer_time_prop.lower() != 'fasting times': + date_str = None + (all_prayer_times, day_difference) = self.prayer_info_.GetPrayerTimes(lat, lng, date_str) + if not all_prayer_times: + return _MakeSpeechResponse(None, None, None, None, + None, (None, None)) canonical_prayer = 'NA' if desired_prayer: canonical_prayer = util.StringToDailyPrayer(desired_prayer) - if prayer_time_prop and prayer_time_prop.lower() != 'fasting times': + if prayer_time_prop and (prayer_time_prop.lower() == 'next prayer' or prayer_time_prop.lower() == 'time until'): computed_prayer_time_property = self._ComputePrayerTimeProperty(canonical_prayer, all_prayer_times, lat, lng) return _MakeSpeechResponse(canonical_prayer, desired_prayer, computed_prayer_time_property, - prayer_time_prop, (Locality.CITY, city)) + prayer_time_prop, 0, (Locality.CITY, city)) if prayer_time_prop and prayer_time_prop.lower() == 'fasting times': fasting_times = [] suhur_canonical_prayer = util.StringToDailyPrayer('suhur') @@ -378,9 +423,9 @@ def _ComputePrayerTimeAndRespond(self, desired_prayer, lat, lng, city, prayer_ti fasting_times.append(all_prayer_times.get(suhur_canonical_prayer)) fasting_times.append(all_prayer_times.get(iftar_canonical_prayer)) return _MakeSpeechResponse(canonical_prayer, desired_prayer, fasting_times, prayer_time_prop, - (Locality.CITY, city)) + day_difference, (Locality.CITY, city)) prayer_time = all_prayer_times.get(canonical_prayer) #print 'prayer_times[', desired_prayer, "] = ", prayer_time return _MakeSpeechResponse(canonical_prayer, desired_prayer, prayer_time, prayer_time_prop, - (Locality.CITY, city)) + day_difference, (Locality.CITY, city)) diff --git a/intent_handler_tester.py b/intent_handler_tester.py new file mode 100644 index 0000000..dc672cf --- /dev/null +++ b/intent_handler_tester.py @@ -0,0 +1,300 @@ +# -*- coding: utf-8 -*- + +from prayer_info import PrayerInfo +from intent_handler import IntentHandler + +_prayer_info = PrayerInfo() +_intent_handler = IntentHandler(_prayer_info, None, None) + +desired_prayer = 'fajr' +lat = 40.715856 +lng = -73.8300517 +city = 'Queens County' +date_str = None +prayer_time_prop = None + +print 'default' +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +date_str = '2018-06-01' + +print date_str +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +date_str = '2018-06-02' + +print date_str +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +date_str = '2018-06-03' + +print date_str +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +date_str = '2018-06-05' + +print date_str +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +desired_prayer = 'maghrib' + +print desired_prayer +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +desired_prayer = 'fajr' +prayer_time_prop = 'fasting times' + +print prayer_time_prop +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +prayer_time_prop = 'next prayer' + +print prayer_time_prop +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +prayer_time_prop = 'time until' + +print prayer_time_prop +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +prayer_time_prop = 'time until' +desired_prayer = 'dhuhr' + +print prayer_time_prop + ' ' + desired_prayer +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +prayer_time_prop = 'invalid prayer time prop' + +print prayer_time_prop +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +desired_prayer = 'invalid desired prayer' + +print desired_prayer +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +desired_prayer = 'fajr' +lat = 30 +lng = 30 +city = 'Markaz El-Hamam' +date_str = None +prayer_time_prop = None + +print city +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +date_str = '2018-06-01' + +print date_str +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +date_str = '2018-06-02' + +print date_str +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +date_str = '2018-06-03' + +print date_str +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +date_str = '2018-06-05' + +print date_str +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +desired_prayer = 'maghrib' + +print desired_prayer +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +desired_prayer = 'fajr' +prayer_time_prop = 'fasting times' + +print prayer_time_prop +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +prayer_time_prop = 'next prayer' + +print prayer_time_prop +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +prayer_time_prop = 'time until' + +print prayer_time_prop +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +prayer_time_prop = 'time until' +desired_prayer = 'dhuhr' + +print prayer_time_prop + ' ' + desired_prayer +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +desired_prayer = 'fajr' +lat = 45.5 +lng = -75.5 +city = 'Montréal' +date_str = None +prayer_time_prop = None + +print city +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +date_str = '06-02/2018' + +print 'invalid date string' +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +date_str = 'invalid' + +print 'invalid date string' +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +desired_prayer = 'isha' +lat = 30.375321 +lng = 69.34511599999999 +city = None +date_str = None +prayer_time_prop = None + +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +lat = 33.93911 +lng = 67.7 + +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +lat = 20.593684 +lng = 78.96288 + +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +lat = 23.684994 +lng = 90.356331 + +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +lat = 34.8020745 +lng = 38.996815 + +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +lat = 33.854721 +lng = 35.862285 + +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +lat = 4.210484 +lng = 101.975766 + +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +lat = 32.427908 +lng = 53.688046 + +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +lat = 32.427908 +lng = 53.688046 + +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +lat = 26.0667 +lng = 50.5577 + +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +lat = 33.223191 +lng = 43.679291 + +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +lat = 21.4735329 +lng = 55.975413 + +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +lat = 15.552727 +lng = 48.516388 + +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +lat = 23.424076 +lng = 53.847818 + +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +lat = 29.31166 +lng = 47.481766 + +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +lat = 25.354826 +lng = 51.183884 + +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +lat = 1.352083 +lng = 103.819836 + +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +lat = 1.352083 +lng = 103.819836 + +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +lat = 46.227638 +lng = 2.213749 + +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] + +lat = 38.963745 +lng = 35.243322 + +output_str = _intent_handler._ComputePrayerTimeAndRespond(desired_prayer, lat, lng, city, date_str, prayer_time_prop) +print output_str['displayText'] diff --git a/masjid_util.py b/masjid_util.py index cc01b47..2b18c8b 100644 --- a/masjid_util.py +++ b/masjid_util.py @@ -37,30 +37,31 @@ def GetMasjidID(masjid): - """Gets the masjid id from Iqamah.net for a given masjid + """Gets the masjid id from Iqamah.net for a given masjid - Args: - masjid: a string representing the masjid of intereset from the - masjid-entity + Args: + masjid: a string representing the masjid of intereset from the + masjid-entity - Returns: an integer containing the masjid id - """ + Returns: an integer containing the masjid id + """ - if _MASJID_METADATA.get(masjid): - return _MASJID_METADATA.get(masjid).get('id') - return None + if _MASJID_METADATA.get(masjid): + return _MASJID_METADATA.get(masjid).get('id') + return None def GetMasjidDisplayName(masjid): - """Gets the masjid display_name from _MASJID_METADATA + """Gets the masjid display_name from _MASJID_METADATA - Args: - masjid: a string representing the masjid of intereset from the - masjid-entity + Args: + masjid: a string representing the masjid of intereset from the + masjid-entity - Returns: a string containing the masjid name to be displayed to the user - """ + Returns: a string containing the masjid name to be displayed to the user + """ + + if _MASJID_METADATA.get(masjid): + return _MASJID_METADATA.get(masjid).get('display_name') + return None - if _MASJID_METADATA.get(masjid): - return _MASJID_METADATA.get(masjid).get('display_name') - return None diff --git a/prayer_info.py b/prayer_info.py index c34df75..f596635 100644 --- a/prayer_info.py +++ b/prayer_info.py @@ -1,39 +1,35 @@ """Computes daily salah times based on location.""" - -import salah_com_fetcher +import aladhan_com_fetcher import util # pylint: disable-msg=r0903 class PrayerInfo(object): - """Gets and packages prayer information.""" + """Gets and packages prayer information.""" - @classmethod - def GetPrayerTimes(cls, lat, lng): - """Gets the daily prayer times for a given lat/lng. + @classmethod + def GetPrayerTimes(cls, lat, lng, date_str): + """Gets the daily prayer times for a given lat/lng. - Args: - lat: a double representing the latitude - lng: a double representing the longitude + Args: + lat: a double representing the latitude + lng: a double representing the longitude + date_str: a string representing the requested date in YYYY-MM-DD - Returns: a dict containing (DailyPrayer -> string) of daily - prayer times - """ - #print "[enter][GetPrayerTimes]" + Returns: a dict containing (DailyPrayer -> string) of daily + prayer times + """ - prayer_times = salah_com_fetcher.GetDailyPrayerTimes(lat, lng) - if prayer_times == {}: - return {} - #print '[GetPrayerTimes] salah.com scrape result = ', prayer_times - result = {} + (prayer_times, day_difference) = aladhan_com_fetcher.GetDailyPrayerTimes(lat, lng, date_str) + if not prayer_times or prayer_times == {}: + return (None, None) - for key in prayer_times: - prayer = util.StringToDailyPrayer(key) - if prayer: - result[prayer] = prayer_times[key] + result = {} - #print '[GetPrayerTimes] prayer times = ', result + for key in prayer_times: + prayer = util.StringToDailyPrayer(key) + if prayer: + result[prayer] = util.ConvertTimeToAMPM(prayer_times[key]) - #print "[exit][GetPrayerTimes]" - return result + return (result, day_difference) diff --git a/salah_com_fetcher_test.py b/salah_com_fetcher_test.py deleted file mode 100644 index 3a24aba..0000000 --- a/salah_com_fetcher_test.py +++ /dev/null @@ -1,11 +0,0 @@ -"""Tests for salah_com_fetcher.""" - -import salah_com_fetcher - - -def TestFetcher(): - """Tests that the fetcher gets data from salah.com""" - print salah_com_fetcher.GetDailyPrayerTimes(37.3541079, -121.9552355) - - -TestFetcher() diff --git a/util.py b/util.py index a8d2a13..26ef402 100644 --- a/util.py +++ b/util.py @@ -3,33 +3,31 @@ from datetime import datetime, timedelta import pytz from flask import make_response -from common import DailyPrayer +from common import DailyPrayer, CalculationMethod from gmaps_client import GetTimezone _GEONAMES_URL = 'http://api.geonames.org/timezoneJSON?formatted=true' + def EncodeParameter(param, spaced=False): - """Returns param encoded to utf-8""" - if spaced: - return ' '.join(param).encode('utf-8') - return ''.join(param).encode('utf-8') + """Returns param encoded to utf-8""" + if spaced: + return ' '.join(param).encode('utf-8') + return ''.join(param).encode('utf-8') def JsonResponse(response_dict): - """Constructs a JSON response object.""" - #print 'JsonResponse' - response = make_response(json.dumps(response_dict, indent=4)) - #print 'JsonResponse' - response.headers['Content-Type'] = 'application/json' - #print 'JsonResponse' - return response + """Constructs a JSON response object.""" + response = make_response(json.dumps(response_dict, indent=4)) + response.headers['Content-Type'] = 'application/json' + return response def JsonError(error_text): - """Constructs a JSON response from an error.""" - response = make_response(json.dumps({'error': error_text}, indent=4)) - response.headers['Content-Type'] = 'application/json' - return response + """Constructs a JSON response from an error.""" + response = make_response(json.dumps({'error': error_text}, indent=4)) + response.headers['Content-Type'] = 'application/json' + return response _PRAYER_METADATA = { @@ -88,60 +86,100 @@ def JsonError(error_text): 'unspecified': DailyPrayer.UNSPECIFIED, } +_COUNTRY_TO_CALCULATION_METHOD = { + 'pakistan': CalculationMethod.KAR, + 'india': CalculationMethod.KAR, + 'afghanistan': CalculationMethod.KAR, + 'bangladesh': CalculationMethod.KAR, + 'egypt': CalculationMethod.EGYPT, + 'syria': CalculationMethod.EGYPT, + 'lebanon': CalculationMethod.EGYPT, + 'malaysia': CalculationMethod.EGYPT, + 'iran': CalculationMethod.TEHRAN, + 'bahrain': CalculationMethod.GULF, + 'iraq': CalculationMethod.GULF, + 'yemen': CalculationMethod.GULF, + 'oman': CalculationMethod.GULF, + 'united arab emirates': CalculationMethod.GULF, + 'kuwait': CalculationMethod.KUWAIT, + 'qatar': CalculationMethod.QATAR, + 'singapore': CalculationMethod.SINGAPORE, + 'france': CalculationMethod.FRANCE, + 'turkey': CalculationMethod.TURKEY, + 'unspecified': CalculationMethod.UNSPECIFIED, +} def GetPrayerKeyName(daily_prayer): - """Gets the name of a daily prayer (ex: "fajr").""" - return _PRAYER_METADATA.get(daily_prayer).get('key_name') + """Gets the name of a daily prayer (ex: "fajr").""" + return _PRAYER_METADATA.get(daily_prayer).get('key_name') def _StringToEnum(str_value, str_to_enum, default): - """Converts a string to an enum based on provided dict.""" - str_value = str(str_value).lower() - if str_value in str_to_enum: - return str_to_enum[str_value] - return default + """Converts a string to an enum based on provided dict.""" + str_value = str(str_value).lower() + if str_value in str_to_enum: + return str_to_enum[str_value] + return default def StringToDailyPrayer(prayer_str): - """Infers a DailyPrayer out of a string.""" - prayer_str = str(prayer_str).lower() - if prayer_str in _KEY_NAME_TO_PRAYER: - return _KEY_NAME_TO_PRAYER[prayer_str] - return '' + """Infers a DailyPrayer out of a string.""" + prayer_str = str(prayer_str).lower() + if prayer_str in _KEY_NAME_TO_PRAYER: + return _KEY_NAME_TO_PRAYER[prayer_str] + return '' + + +def CountryToCalculationMethod(country_str): + """Infers a CalculationMethod out of a string.""" + country_str = str(country_str).lower() + if country_str in _COUNTRY_TO_CALCULATION_METHOD: + return _COUNTRY_TO_CALCULATION_METHOD[country_str] + return 0 + + +def ConvertTimeToAMPM(time_str): + """Converts Time from 24H to 12H AM/PM""" + org_time_format = '%H:%M' + convert_time_format = '%I:%M %p' + + return datetime.strptime(time_str, org_time_format).strftime(convert_time_format) def GetPronunciation(daily_prayer): - """Gets TTS for a daily prayer.""" - #print 'GetPronunciation: ', _PRAYER_METADATA[daily_prayer] - return _PRAYER_METADATA[daily_prayer].get('pronunciation') + """Gets TTS for a daily prayer.""" + #print 'GetPronunciation: ', _PRAYER_METADATA[daily_prayer] + return _PRAYER_METADATA[daily_prayer].get('pronunciation') def GetDisplayText(daily_prayer): - """Gets display text for a daily prayer.""" - return _PRAYER_METADATA[daily_prayer].get('display_name') + """Gets display text for a daily prayer.""" + return _PRAYER_METADATA[daily_prayer].get('display_name') def GetCurrentUserTime(user_lat, user_lng): - """Returns the current time in the user's timezone.""" - gmaps_timezone_str = GetTimezone(user_lat, user_lng) - if gmaps_timezone_str is None: - return None - user_timezone = pytz.timezone(gmaps_timezone_str) - user_time = datetime.now(user_timezone) - return user_time + """Returns the current time in the user's timezone.""" + gmaps_timezone_str = GetTimezone(user_lat, user_lng) + if gmaps_timezone_str is None or gmaps_timezone_str == 'None': + return None + user_timezone = pytz.timezone(gmaps_timezone_str) + user_time = datetime.now(user_timezone) + return user_time def GetTimeDifference(user_time_datetime, prayer_time): - """Returns the time difference in hours and minutes - between the current user time and the given prayer time.""" - prayer_time_format = '%I:%M %p' - prayer_time_datetime = datetime.strptime(prayer_time, prayer_time_format) - start_time = datetime.combine(datetime.min, user_time_datetime.time()) - end_time = datetime.combine(datetime.min, prayer_time_datetime.time()) - if start_time > end_time: - end_time += timedelta(1) - time_diff = (end_time - start_time).total_seconds() - result = {} - result['HOURS'] = int(time_diff//3600) - result['MINUTES'] = int((time_diff%3600) // 60) - return result + """Returns the time difference in hours and minutes + between the current user time and the given prayer time.""" + prayer_time_format = '%I:%M %p' + prayer_time_datetime = datetime.strptime(prayer_time, prayer_time_format) + start_time = datetime.combine(datetime.min, user_time_datetime.time()) + end_time = datetime.combine(datetime.min, prayer_time_datetime.time()) + if start_time > end_time: + end_time += timedelta(1) + time_diff = (end_time - start_time).total_seconds() + result = {} + result['HOURS'] = int(time_diff//3600) + result['MINUTES'] = int((time_diff%3600) // 60) + result['SECONDS'] = int((time_diff%60)) + return result +