119 lines
3.6 KiB
Python

import datetime as dt
import re, logging
import zoneinfo
from .sync import Event
class IcalHelper:
_WEEKDAY_MAP = {
'Mon': 0,
'Tue': 1,
'Wed': 2,
'Thu': 3,
'Fri': 4,
'Sat': 5,
'Sun': 6
}
tzDE = zoneinfo.ZoneInfo('Europe/Berlin')
deltaWeek = dt.timedelta(weeks=1)
deltaDay = dt.timedelta(days=1)
firstDay = dt.date(year=dt.datetime.now().year, month=1, day=1)
def __init__(self):
self._l = logging.getLogger(__name__)
self.reTime = re.compile(r'(\d{1,2}):(\d{2})')
def getStart(self, event: Event, holidays):
firstDay = self._getFirstOccurence(event, holidays)
if firstDay is None:
return None, None
return firstDay, dt.datetime.combine(firstDay, self._getTime(event.start), tzinfo=self.tzDE)
def _getFirstWeekdayInYear(self, weekday):
candidate = self.firstDay
while candidate.weekday() != self._WEEKDAY_MAP[weekday]:
candidate += self.deltaDay
self._l.log(5, 'First %s in year is %s', weekday, candidate)
return candidate
def _getSortedHolidays(self, holidays):
return sorted(holidays['holidays'], key=lambda h: h['from'])
def _getSortedFeasts(self, holidays):
return sorted(holidays['feasts'])
def _isFeast(self, candidate, feasts):
return candidate in feasts
def _isHoliday(self, candidate, holidays):
for h in holidays:
if h['from'] <= candidate <= h['to']:
return True
return False
def _getLastHolidayException(self, holidays):
holidayList = list(self._getSortedHolidays(holidays))
holidayList.reverse()
lastHoliday = holidayList[0]
lastHolidayDay = lastHoliday['to']
feastList = list(self._getSortedFeasts(holidays))
feastList.reverse()
lastFeast = feastList[0]
lastFeastDay = lastFeast
return max(lastHolidayDay, lastFeastDay)
def _getFirstOccurence(self, event: Event, holidays):
firstWeekday = self._getFirstWeekdayInYear(event.day)
candidate = firstWeekday
while candidate.year == firstWeekday.year:
if self._isFeast(candidate, holidays['feasts']):
self._l.log(5, 'Found feast %s', candidate)
candidate += self.deltaWeek
continue
if self._isHoliday(candidate, holidays['holidays']):
self._l.log(5, 'Found holiday %s', candidate)
candidate += self.deltaWeek
continue
self._l.log(5, 'Found first occurence %s', candidate)
return candidate
return None
# firstWeekday.tzinfo = dt.timezone.tzname('Europe/Berlin')
def _getTime(self, startStr):
match = self.reTime.match(startStr)
return dt.time(int(match.group(1)), int(match.group(2)))
def getHolidayExceptions(self, event: Event, startDay, holidays):
lastHolidayDay = self._getLastHolidayException(holidays)
pointer = startDay
exeptions = []
while pointer <= lastHolidayDay:
ex = dt.datetime.combine(pointer, self._getTime(event.start), tzinfo=self.tzDE)
if self._isFeast(pointer, holidays['feasts']):
exeptions.append(ex)
if self._isHoliday(pointer, holidays['holidays']) and not event.external:
exeptions.append(ex)
pointer += self.deltaWeek
if len(exeptions) > 0:
return exeptions
return None