2022-03-28 13:32:52 +00:00
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
2022-03-29 06:18:11 +00:00
|
|
|
|
def get_rahukaalam_times(
|
|
|
|
|
observer: LocationInfo,
|
|
|
|
|
date: datetime,
|
|
|
|
|
surrounding_days: bool = False
|
|
|
|
|
) -> List[Tuple[datetime, datetime]]:
|
|
|
|
|
"""Get today’s Răhukăla times"""
|
|
|
|
|
|
|
|
|
|
if surrounding_days:
|
|
|
|
|
yesterday = date - timedelta(days=1)
|
|
|
|
|
tomorrow = date + timedelta(days=1)
|
|
|
|
|
dates = [yesterday, date, tomorrow]
|
|
|
|
|
else:
|
|
|
|
|
dates = [date]
|
2022-03-28 13:32:52 +00:00
|
|
|
|
|
|
|
|
|
times: List[Tuple[datetime, datetime]] = []
|
|
|
|
|
|
2022-03-29 06:18:11 +00:00
|
|
|
|
for day in dates:
|
2022-03-28 13:32:52 +00:00
|
|
|
|
try:
|
2022-03-29 06:18:11 +00:00
|
|
|
|
daytime_rahukaala = sun.rahukaalam(observer, date=day, daytime=True)
|
2022-03-28 13:32:52 +00:00
|
|
|
|
except ValueError:
|
|
|
|
|
pass
|
|
|
|
|
else:
|
2022-03-29 06:18:11 +00:00
|
|
|
|
times.append(daytime_rahukaala)
|
2022-03-28 13:32:52 +00:00
|
|
|
|
|
|
|
|
|
try:
|
2022-03-29 06:18:11 +00:00
|
|
|
|
night_rahukaala = sun.rahukaalam(observer, date=day, daytime=False)
|
2022-03-28 13:32:52 +00:00
|
|
|
|
except ValueError:
|
|
|
|
|
pass
|
|
|
|
|
else:
|
2022-03-29 06:18:11 +00:00
|
|
|
|
times.append(night_rahukaala)
|
2022-03-28 13:32:52 +00:00
|
|
|
|
|
|
|
|
|
times.sort(key=lambda items: items[0])
|
2022-03-29 06:18:11 +00:00
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
2022-03-28 13:32:52 +00:00
|
|
|
|
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
|