Given a string representing the hour and minute, where: 00:00 <= time <= 23:59, the program should output the number of angles the sun is above the horizon.
- When time is "06:00" the sun angles are 0o
- At "12:00" the sun is at 90o
- At "18:00" the sun goes to 180o
- After "18:00" and before "06:00" the program should output "I don't see the sun!"
Examples:
- sun_angle("07:00") == 15
- sun_angle("01:23") == "I don't see the sun!"
- sun_angle("12:15") == 93.75
The code:
import datetime as dt
def check_you_dont_see_sun(time_dt, end_dt, start_dt):
return ((time_dt > start_dt and time_dt < end_dt)
or (time_dt > start_dt or time_dt < end_dt))
def calculate_sun_angle(time_dt, end_dt):
difference = time_dt - end_dt
hours_of_difference = (difference.seconds / 60) / 60
angle_increase_each_hour = 15
return hours_of_difference * angle_increase_each_hour
def sun_angle(time):
start_dt = dt.datetime.strptime('18:00', '%H:%M')
end_dt = dt.datetime.strptime('06:00', '%H:%M')
time_dt = dt.datetime.strptime(time, '%H:%M')
if check_you_dont_see_sun(time_dt,end_dt,start_dt):
return "I don't see the sun!"
else:
return calculate_sun_angle(time_dt, end_dt)
What could we improve?
-
1\$\begingroup\$ The task involves calculating some kind of angle, but it certainly isn't calculating the angle of the sun above the horizon! \$\endgroup\$200_success– 200_success2019年05月25日 19:05:06 +00:00Commented May 25, 2019 at 19:05
1 Answer 1
One immediate thing I would improve is the naming of your variables. While in general very descriptive, it took me a while to realize that start_dt
is actually the time of sunset and end_dt
the time of sunrise, instead of the other way around. I would also make these variables global constants and use those as default values. This way you can do it all in one still short and readable function.
I would add some docstring
describing what your function(s) do and use a compound comparison instead of two comparisons to determine if the time is day or night.
The datetime
module is often imported as from datetime import datetime
, although your import is also OK.
The calling of the code should happen under a if __name__ == "__main__":
guard, where I would also put at least some very rudimentary testing code.
from datetime import datetime
SUNRISE = datetime.strptime('06:00', '%H:%M')
SUNSET = datetime.strptime('18:00', '%H:%M')
def sun_angle(time, sunrise=SUNRISE, sunset=SUNSET):
"""Return the angle of the sun at `time`.
Assumes that the sun moves 180 degrees between `sunrise` and `sunset`.
During night return 'I don\'t see the sun!'.
"""
time = datetime.strptime(time, '%H:%M')
if not sunrise <= time <= sunset:
return "I don't see the sun!"
angle_per_hour = 180 / (sunset - sunrise).seconds * 3600
time_since_sunrise = (time - sunrise).seconds / 3600
return time_since_sunrise * angle_per_hour
if __name__ == "__main__":
test_cases = [("07:00", 15),
("01:23", "I don't see the sun!"),
("12:15", 93.75)]
for time, expected in test_cases:
output = sun_angle(time)
print(f"solar_angle({time!r}) == {output!r}")
assert output == expected, f"Failed: expected {expected!r}!"
The calculation of the sun angle could probably still be a bit better in order to be able to be extended for different latitudes in the future.
If this is not a class exercise or programming challenge, I would also recommend to change the interface of the function a bit. Make time
always a datetime
object and instead of returning a string in case of invalid input raise a custom exception:
class NightTimeException(ValueError):
pass
...
if not sunrise <= time <= sunset:
raise NightTimeException("I don't see the sun!")