Skip to content

Commit

Permalink
Add MidnightSunException, PolarNightException
Browse files Browse the repository at this point in the history
Instead of just raising SunTimeException, report
whether we have midnight sun or polar night.

Implemented in a backwards-compatible way by
subclassing SunTimeException.

That catching SunTimeException still works as before
is verified by extending the tests.

Fixes SatAgro#32
  • Loading branch information
rfjakob committed Jul 11, 2024
1 parent b9fe1a8 commit 0b59d7b
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 14 deletions.
2 changes: 1 addition & 1 deletion suntime/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from .suntime import Sun, SunTimeException
from .suntime import Sun, SunTimeException, MidnightSunException, PolarNightException

__version__ = '1.3.2'
__author__ = 'Krzysztof Stopa'
Expand Down
28 changes: 18 additions & 10 deletions suntime/suntime.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,20 @@ class SunTimeException(Exception):
pass


class MidnightSunException(SunTimeException):
"""
Sun is always up (24h of daylight)
"""
pass


class PolarNightException(SunTimeException):
"""
Sun is always down (0h of daylight)
"""
pass


class Sun:
"""
Approximated calculation of sunrise and sunset datetimes. Adapted from:
Expand All @@ -30,10 +44,7 @@ def get_sunrise_time(self, at_date=datetime.now(), time_zone=timezone.utc):
:raises: SunTimeException when there is no sunrise and sunset on given location and date.
"""
time_delta = self.get_sun_timedelta(at_date, time_zone=time_zone, is_rise_time=True)
if time_delta is None:
raise SunTimeException('The sun never rises on this location (on the specified date)')
else:
return datetime.combine(at_date, time(tzinfo=time_zone)) + time_delta
return datetime.combine(at_date, time(tzinfo=time_zone)) + time_delta

def get_sunset_time(self, at_date=datetime.now(), time_zone=timezone.utc):
"""
Expand All @@ -44,10 +55,7 @@ def get_sunset_time(self, at_date=datetime.now(), time_zone=timezone.utc):
:raises: SunTimeException when there is no sunrise and sunset on given location and date.
"""
time_delta = self.get_sun_timedelta(at_date, time_zone=time_zone, is_rise_time=False)
if time_delta is None:
raise SunTimeException('The sun never rises on this location (on the specified date)')
else:
return datetime.combine(at_date, time(tzinfo=time_zone)) + time_delta
return datetime.combine(at_date, time(tzinfo=time_zone)) + time_delta

def get_local_sunrise_time(self, at_date=datetime.now(), time_zone=None):
""" DEPRECATED: Use get_sunrise_time() instead. """
Expand Down Expand Up @@ -100,9 +108,9 @@ def get_sun_timedelta(self, at_date, time_zone, is_rise_time=True, zenith=90.8):
cosH = (math.cos(TO_RAD*zenith) - (sinDec * math.sin(TO_RAD*self._lat))) / (cosDec * math.cos(TO_RAD*self._lat))

if cosH > 1:
return None # The sun never rises on this location (on the specified date)
raise PolarNightException("The sun is always down on this location on the specified date")
if cosH < -1:
return None # The sun never sets on this location (on the specified date)
raise MidnightSunException("The sun is always up on this location on the specified date")

# 4c. finish calculating H and convert into hours
if is_rise_time:
Expand Down
20 changes: 17 additions & 3 deletions tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from datetime import datetime
from dateutil import tz

from suntime import Sun, SunTimeException
from suntime import Sun, SunTimeException, MidnightSunException, PolarNightException

_SF_LAT = 37.7749
_SF_LON = -122.4194
Expand Down Expand Up @@ -92,13 +92,27 @@ def setUp(self):

def test_get_sunrise_time(self):
# Test for no sunrise
# Winter solstice in the northern hemisphere
d = datetime(2024, 12, 21)
with self.assertRaisesRegex(SunTimeException, 'The sun'):
self.sun.get_sunrise_time(datetime(2024, 12, 21)) # Winter solstice in the northern hemisphere
self.sun.get_sunrise_time(d)

# Should throw specific PolarNightException which is derived
# from SunTimeException
with self.assertRaisesRegex(PolarNightException, 'The sun'):
self.sun.get_sunrise_time(d)

def test_get_sunset_time(self):
# Test for no sunset
# Summer solstice in the northern hemisphere
d = datetime(2024, 6, 21)
with self.assertRaisesRegex(SunTimeException, 'The sun'):
self.sun.get_sunset_time(datetime(2024, 6, 21)) # Summer solstice in the northern hemisphere
self.sun.get_sunset_time(d)

# Should throw specific MidnightSunException which is derived
# from SunTimeException
with self.assertRaisesRegex(MidnightSunException, 'The sun'):
self.sun.get_sunset_time(d)


if __name__ == '__main__':
Expand Down

0 comments on commit 0b59d7b

Please sign in to comment.