diff --git a/seasonal_clock/__init__.py b/seasonal_clock/__init__.py index 6772c02..4fda4ca 100644 --- a/seasonal_clock/__init__.py +++ b/seasonal_clock/__init__.py @@ -2,14 +2,14 @@ __version__ = '0.1.0' -from datetime import datetime, timedelta -from typing import List, Tuple, Union +from datetime import datetime -from astral import Depression, LocationInfo, SunDirection, moon, sun +from astral import Depression, LocationInfo, moon from pytz import UTC from .config import load_config from .hours import seasonal_hours +from .times import collect_day_parts, get_rahukaalam def get_moon_phase_text(moon_phase: float) -> str: @@ -37,130 +37,6 @@ def get_moon_phase_text(moon_phase: float) -> str: return name -def collect_day_parts( - observer: LocationInfo, date: datetime -) -> List[Tuple[str, datetime, str, str]]: - """Collect timestamp for all parts of the day on date""" - - day_parts = [] - - midnight = sun.midnight(observer, date=date) - - if midnight.date() < date.date(): - midnight = sun.midnight(observer, date=date + timedelta(days=1)) - elif midnight.date() > date.date(): - midnight = sun.midnight(observer, date=date - timedelta(days=1)) - - day_parts.append(('midnight', midnight, 'Night', 'Midnight')) - - try: - morning_blue_start = sun.blue_hour( - observer, date=date, direction=SunDirection.RISING - )[0] - except ValueError: - # At certain times and latitudes there might be no blue hour - pass - else: - day_parts.append( - ( - 'morning_blue_start', - morning_blue_start, - 'Morning blue hour', - 'Morning golden hour', - ) - ) - - try: - golden_start, golden_end = sun.golden_hour( - observer, date=date, direction=SunDirection.RISING - ) - except ValueError: - # At certain times and latitudes there might be no golden hour - pass - else: - day_parts.append( - ('morning_golden_start', golden_start, 'Morning golden hour', 'Full Daytime') - ) - day_parts.append(('morning_golden_end', golden_end, 'Morning', 'Noon')) - - day_parts.append(('noon', sun.noon(observer, date=date), 'Afternoon', 'Noon')) - - try: - evening_golden_start = sun.golden_hour(observer, date=date, direction=SunDirection.SETTING)[0] - except ValueError: - # At certain times and latitudes there might be no golden hour - pass - else: - day_parts.append( - ( - 'evening_golden_start', - evening_golden_start, - 'Evening golden hour', - 'Evening blue hour', - ) - ) - - try: - blue_start, blue_end = sun.blue_hour( - observer, date=date, direction=SunDirection.SETTING - ) - except ValueError: - # At certain times and latitudes there might be no blue hour - pass - else: - day_parts.append(('evening_blue_start', blue_start, 'Evening blue hour', 'Night')) - day_parts.append(('evening_blue_end', blue_end, 'Night', 'Midnight')) - - day_parts.sort(key=lambda elem: elem[1]) - - return day_parts - - -def get_rahukaalam(observer: LocationInfo, date: datetime) -> Tuple[bool, datetime]: - """Get the time of the next Rāhukāla or, if we are in the middle of one, the time of its end""" - - yesterday = date - timedelta(days=1) - tomorrow = date + timedelta(days=1) - times: List[Tuple[datetime, datetime]] = [] - - for day in (yesterday, date, tomorrow): - try: - daytime_rahukaalam = sun.rahukaalam(observer, date=day, daytime=False) - except ValueError: - pass - else: - times.append(daytime_rahukaalam) - - try: - night_rahukaalam = sun.rahukaalam(observer, date=day, daytime=True) - except ValueError: - pass - else: - times.append(night_rahukaalam) - - times.sort(key=lambda items: items[0]) - active: bool = False - next_time: datetime = None - - for start, end in times: - if date < start: - active = False - next_time = start - - break - - if start < date < end: - active = True - next_time = end - - break - - if next_time is None: - return None, None - - return active, next_time - - def main() -> None: """The Main Thing™""" diff --git a/seasonal_clock/times.py b/seasonal_clock/times.py new file mode 100644 index 0000000..904d5ae --- /dev/null +++ b/seasonal_clock/times.py @@ -0,0 +1,139 @@ +from datetime import datetime, timedelta +from typing import List, Optional, Tuple + +from astral import LocationInfo, SunDirection, sun + + +def collect_day_parts( + observer: LocationInfo, date: datetime +) -> List[Tuple[str, datetime, str, str]]: + """Collect timestamp for all parts of the day on date""" + + day_parts = [] + + midnight = sun.midnight(observer, date=date) + + if midnight.date() < date.date(): + midnight = sun.midnight(observer, date=date + timedelta(days=1)) + elif midnight.date() > date.date(): + midnight = sun.midnight(observer, date=date - timedelta(days=1)) + + day_parts.append(('midnight', midnight, 'Night', 'Midnight')) + + try: + morning_blue_start = sun.blue_hour( + observer, date=date, direction=SunDirection.RISING + )[0] + except ValueError: + # At certain times and latitudes there might be no blue hour + pass + else: + day_parts.append( + ( + 'morning_blue_start', + morning_blue_start, + 'Morning blue hour', + 'Morning golden hour', + ) + ) + + try: + golden_start, golden_end = sun.golden_hour( + observer, date=date, direction=SunDirection.RISING + ) + except ValueError: + # At certain times and latitudes there might be no golden hour + pass + else: + day_parts.append( + ( + 'morning_golden_start', + golden_start, + 'Morning golden hour', + 'Full Daytime', + ) + ) + day_parts.append(('morning_golden_end', golden_end, 'Morning', 'Noon')) + + day_parts.append(('noon', sun.noon(observer, date=date), 'Afternoon', 'Noon')) + + try: + evening_golden_start = sun.golden_hour( + observer, date=date, direction=SunDirection.SETTING + )[0] + except ValueError: + # At certain times and latitudes there might be no golden hour + pass + else: + day_parts.append( + ( + 'evening_golden_start', + evening_golden_start, + 'Evening golden hour', + 'Evening blue hour', + ) + ) + + try: + blue_start, blue_end = sun.blue_hour( + observer, date=date, direction=SunDirection.SETTING + ) + except ValueError: + # At certain times and latitudes there might be no blue hour + pass + else: + day_parts.append( + ('evening_blue_start', blue_start, 'Evening blue hour', 'Night') + ) + day_parts.append(('evening_blue_end', blue_end, 'Night', 'Midnight')) + + day_parts.sort(key=lambda elem: elem[1]) + + return day_parts + + +def get_rahukaalam( + observer: LocationInfo, date: datetime +) -> Tuple[Optional[bool], datetime]: + """Get the time of the next Rāhukāla or, if we are in the middle of one, the time of its end""" + + yesterday = date - timedelta(days=1) + tomorrow = date + timedelta(days=1) + times: List[Tuple[datetime, datetime]] = [] + + for day in (yesterday, date, tomorrow): + try: + daytime_rahukaalam = sun.rahukaalam(observer, date=day, daytime=False) + except ValueError: + pass + else: + times.append(daytime_rahukaalam) + + try: + night_rahukaalam = sun.rahukaalam(observer, date=day, daytime=True) + except ValueError: + pass + else: + times.append(night_rahukaalam) + + times.sort(key=lambda items: items[0]) + active: bool = False + next_time: Optional[datetime] = None + + for start, end in times: + if date < start: + active = False + next_time = start + + break + + if start < date < end: + active = True + next_time = end + + break + + if next_time is None: + return None, None + + return active, next_time