3
\$\begingroup\$

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 0º
  • At "12:00" the sun is at 90º
  • At "18:00" the sun goes to 180º
  • After "18:00" and before "06:00" the program should output "I don't see the sun!"

sun angles

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?

\$\endgroup\$
  • 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 May 25 '19 at 19:05
3
\$\begingroup\$

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!")
| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.