Calculate sunrise or sunset for a specific location.

    This function calculates the time sunrise or sunset, or optionally the
    beginning or end of a specified twilight period.

    Source::

        Almanac for Computers, 1990
        published by Nautical Almanac Office
        United States Naval Observatory
        Washington, DC 20392

    Args:
        latitude (float): Location's latitude
        longitude (float): Location's longitude
        date (datetime.date): Calculate rise or set for given date
        mode (str): Which time to calculate
        timezone (int): Offset from UTC in minutes
        zenith (str): Calculate rise/set events, or twilight times

    Returns:
        datetime.time or None: The time for the given event in the specified
            timezone, or ``None`` if the event doesn't occur on the given date

    Raises:
        ValueError: Unknown value for ``mode``

def sun_rise_set(latitude, longitude, date, mode='rise', timezone=0,
                 zenith=None):
    """Calculate sunrise or sunset for a specific location.

    This function calculates the time sunrise or sunset, or optionally the
    beginning or end of a specified twilight period.

    Source::

        Almanac for Computers, 1990
        published by Nautical Almanac Office
        United States Naval Observatory
        Washington, DC 20392

    Args:
        latitude (float): Location's latitude
        longitude (float): Location's longitude
        date (datetime.date): Calculate rise or set for given date
        mode (str): Which time to calculate
        timezone (int): Offset from UTC in minutes
        zenith (str): Calculate rise/set events, or twilight times

    Returns:
        datetime.time or None: The time for the given event in the specified
            timezone, or ``None`` if the event doesn't occur on the given date

    Raises:
        ValueError: Unknown value for ``mode``
    """
    if not date:
        date = datetime.date.today()

    zenith = ZENITH[zenith]

    # First calculate the day of the year
    # Thanks, datetime this would have been ugly without you!!!
    n = (date - datetime.date(date.year - 1, 12, 31)).days

    # Convert the longitude to hour value and calculate an approximate time
    lng_hour = longitude / 15

    if mode == 'rise':
        t = n + ((6 - lng_hour) / 24)
    elif mode == 'set':
        t = n + ((18 - lng_hour) / 24)
    else:
        raise ValueError('Unknown mode value %r' % mode)

    # Calculate the Sun's mean anomaly
    m = (0.9856 * t) - 3.289

    # Calculate the Sun's true longitude
    l = m + 1.916 * math.sin(math.radians(m)) + 0.020 \
        * math.sin(2 * math.radians(m)) + 282.634
    l = abs(l) % 360

    # Calculate the Sun's right ascension
    ra = math.degrees(math.atan(0.91764 * math.tan(math.radians(l))))

    # Right ascension value needs to be in the same quadrant as L
    l_quandrant = (math.floor(l / 90)) * 90
    ra_quandrant = (math.floor(ra / 90)) * 90
    ra = ra + (l_quandrant - ra_quandrant)

    # Right ascension value needs to be converted into hours
    ra = ra / 15

    # Calculate the Sun's declination
    sin_dec = 0.39782 * math.sin(math.radians(l))
    cos_dec = math.cos(math.asin(sin_dec))

    # Calculate the Sun's local hour angle
    cos_h = (math.radians(zenith) -
             (sin_dec * math.sin(math.radians(latitude)))) \
        / (cos_dec * math.cos(math.radians(latitude)))

    if cos_h > 1:
        # The sun never rises on this location (on the specified date)
        return None
    elif cos_h < -1:
        # The sun never sets on this location (on the specified date)
        return None

    # Finish calculating H and convert into hours
    if mode == 'rise':
        h = 360 - math.degrees(math.acos(cos_h))
    else:
        h = math.degrees(math.acos(cos_h))
    h = h / 15

    # Calculate local mean time of rising/setting
    t = h + ra - (0.06571 * t) - 6.622

    # Adjust back to UTC
    utc = t - lng_hour

    # Convert UT value to local time zone of latitude/longitude
    local_t = utc + timezone / 60
    if local_t < 0:
        local_t += 24
    elif local_t > 23:
        local_t -= 24

    hour = int(local_t)
    if hour == 0:
        minute = int(60 * local_t)
    else:
        minute = int(60 * (local_t % hour))
    if minute < 0:
        minute += 60
    return datetime.time(hour, minute)