py-seasonal-hours-clock/seasonal_clock/times.py

158 lines
4.2 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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_times(
observer: LocationInfo,
date: datetime,
surrounding_days: bool = False
) -> List[Tuple[datetime, datetime]]:
"""Get todays Răhukăla times"""
if surrounding_days:
yesterday = date - timedelta(days=1)
tomorrow = date + timedelta(days=1)
dates = [yesterday, date, tomorrow]
else:
dates = [date]
times: List[Tuple[datetime, datetime]] = []
for day in dates:
try:
daytime_rahukaala = sun.rahukaalam(observer, date=day, daytime=True)
except ValueError:
pass
else:
times.append(daytime_rahukaala)
try:
night_rahukaala = sun.rahukaalam(observer, date=day, daytime=False)
except ValueError:
pass
else:
times.append(night_rahukaala)
times.sort(key=lambda items: items[0])
return times
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"""
times = get_rahukaalam_times(observer, date, surrounding_days=True)
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