From 0b59d7b20470f174e2eef5631c2a99d813978820 Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Thu, 11 Jul 2024 11:55:54 +0200 Subject: [PATCH] Add MidnightSunException, PolarNightException 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 https://github.com/SatAgro/suntime/issues/32 --- suntime/__init__.py | 2 +- suntime/suntime.py | 28 ++++++++++++++++++---------- tests.py | 20 +++++++++++++++++--- 3 files changed, 36 insertions(+), 14 deletions(-) diff --git a/suntime/__init__.py b/suntime/__init__.py index 8899189..36c3962 100644 --- a/suntime/__init__.py +++ b/suntime/__init__.py @@ -1,4 +1,4 @@ -from .suntime import Sun, SunTimeException +from .suntime import Sun, SunTimeException, MidnightSunException, PolarNightException __version__ = '1.3.2' __author__ = 'Krzysztof Stopa' diff --git a/suntime/suntime.py b/suntime/suntime.py index 99bbf0e..5f9dafe 100644 --- a/suntime/suntime.py +++ b/suntime/suntime.py @@ -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: @@ -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): """ @@ -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. """ @@ -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: diff --git a/tests.py b/tests.py index d21c4b8..ddeb57f 100644 --- a/tests.py +++ b/tests.py @@ -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 @@ -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__':