The script calls the sunrise-sunset API to get one of the possible values, then converts it to 24-Hour format and MET time (as the times from the API are 12-hour and UTC). At the end, it joins the list to a string and prints it. I know this isn't commented very well, but are there any significant flaws in this code? I neither have any experience with Python nor with programming in general, this is just for a personal project and Python seemed to be the best way to do this, so I'm open for any advice and help.
import json
import urllib.request as request
def apiGetList(key):
""" Function twilightApiGetList(key):
Calls the sunrise-sunset api to return the value of a given key
Possible keys: sunrise, sunset, solar_noon, day_length, civil_twilight_begin, civil_twilight_end,
nautical_twilight_begin, nautical_twilight_end, astronomical_twilight_begin, astronomical_twilight_end
All times returned are a list in 12-hour format, UTC time
"""
with request.urlopen('https://api.sunrise-sunset.org/json?lat=44.244622&lng=-7.768863&date=today') as response:
if response.getcode() == 200:
source = response.read()
data = json.loads(source)
out = list(f"{data['results'][key]}")
if len(out) == 10:
out.insert(0, '0')
else:
pass
return(out)
else:
print("Not successful")
return
def convert12To24(lst):
""" Function convert12To24(lst):
Converts from 12-hour format to 24-hour format, input and output types are lists
"""
if lst[9] == "A" and "".join(lst[0:2]) == "12":
del lst[8:12]
lst[0:2] = '00'
elif lst[9] == "A":
del lst[8:12]
elif lst[9] == "P" and "".join(lst[0:2]) == "12":
del lst[8:12]
else:
del lst[8:12]
lst[0:2] = str(int("".join(lst[0:2])) + 12)
return(lst)
def convertUtcToMet(time):
""" Function convertUtcToMet(time):
Converts from UTC time to MET time by adding two hours. Input and output time is in 24-hour format, type is a list
"""
if int("".join(time[0:2])) < 8:
time[0:2] = str(int("".join(time[0:2])) + 2)
time.insert(0, '0')
elif "".join(time[0:2]) == '22':
time[0:2] = '00'
elif "".join(time[0:2]) == '23':
time[0:2] = '01'
else:
time[0:2] = str(int("".join(time[0:2])) + 2)
return(time)
if __name__ == "__main__":
ctb = apiGetList("civil_twilight_begin")
cte = apiGetList("civil_twilight_end")
print("".join(convertUtcToMet(convert12To24(ctb))))
print("".join(convertUtcToMet(convert12To24(cte))))
-
\$\begingroup\$ Is MET Middle-European Time? \$\endgroup\$Reinderien– Reinderien2020年04月13日 15:18:42 +00:00Commented Apr 13, 2020 at 15:18
-
\$\begingroup\$ If so, MET only has a one-hour offset from UTC, not 2.... \$\endgroup\$Reinderien– Reinderien2020年04月13日 15:22:43 +00:00Commented Apr 13, 2020 at 15:22
-
\$\begingroup\$ Also, are you on a boat? Those coordinates are in the Atlantic Ocean north of Portugal - which is not in MET. \$\endgroup\$Reinderien– Reinderien2020年04月13日 16:05:03 +00:00Commented Apr 13, 2020 at 16:05
-
\$\begingroup\$ I'm guessing now, but it might be that you have an accidental negative sign in your longitude - the positive longitude would put you in Italy south of Turin, which is probably (?) in the timezone that you indicate. \$\endgroup\$Reinderien– Reinderien2020年04月13日 16:16:31 +00:00Commented Apr 13, 2020 at 16:16
-
\$\begingroup\$ @Reinderien Don't worry about these coordinates, I changed the real location for random numbers so that I wouldn't reveal my location! I'm actually located in Germany. Also, you are right, I didn't look up the time difference between UTC and MET because I thought I remembered it correctly, thanks for clarifying! I will work through your answer and try to understand it correctly before accepting it, but already thanks a lot for the help! \$\endgroup\$Jogius– Jogius2020年04月14日 08:12:10 +00:00Commented Apr 14, 2020 at 8:12
1 Answer 1
Welcome to CodeReview! This is a great first question.
Do not do your own time math
...nor your own formatting when possible. Tell Python to do it for you. Some example code:
from dataclasses import dataclass
from datetime import timedelta, datetime, timezone
import requests, pytz
@dataclass(frozen=True)
class DayInfo:
day_length: timedelta
sunrise: datetime
sunset: datetime
solar_noon: datetime
civil_twilight_begin: datetime
civil_twilight_end: datetime
nautical_twilight_begin: datetime
nautical_twilight_end: datetime
astronomical_twilight_begin: datetime
astronomical_twilight_end: datetime
@classmethod
def get(cls, lat: float, long: float, tz: timezone) -> 'DayInfo':
""" Function twilightApiGetList(key):
Calls the sunrise-sunset api to return the value of a given key
All times returned are in the provided timezone.
"""
with requests.get(
'https://api.sunrise-sunset.org/json',
params={
'lat': lat,
'lng': long,
'date': 'today', # technically this can be omitted
'formatted': 0, # we want ISO8601 ("machine-readable")
},
) as response:
response.raise_for_status()
data = response.json()
if data['status'] != 'OK':
raise requests.HTTPError(data['status'], response=response)
results = data['results']
return cls(
day_length=timedelta(seconds=int(results['day_length'])),
**{
k: datetime.fromisoformat(results[k]).astimezone(tz)
for k in (
'sunrise',
'sunset',
'solar_noon',
'civil_twilight_begin',
'civil_twilight_end',
'nautical_twilight_begin',
'nautical_twilight_end',
'astronomical_twilight_begin',
'astronomical_twilight_end',
)
},
)
if __name__ == "__main__":
day_info = DayInfo.get(44.244622, -7.768863, pytz.timezone('MET'))
print(f'{day_info.civil_twilight_begin:%H:%m}')
print(f'{day_info.civil_twilight_end:%H:%m}')
Notes:
- You didn't parameterize the right things. Parameters should be coordinates and timezone.
- Ask the API for machine-readable (ISO) dates.
- Might as well parse everything from the API.
- Do not use string manipulation to get your desired format. What is shown is string interpolation with standard Python time fields.
- Use
requests
- it has a lot of niceties that make this easier. - Only issue one call to the API, returning an object that has both of the keys you care about. If you're never, ever going to use the other keys, you can delete them from this class, but they're inexpensive to generate - compared to a second HTTP call, which is much more expensive.