The following code is intended to parse a string of the following format and return whether the current time falls in that window:
start_time-stop_time [(day|day-day[, ...])][; ...]
For example,
0900-1200 (mon-wed, sat); 0100-0200 (sun, tue)
The code for parsing that type of string is here:
days = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']
#grammar definition
hour = pp.Regex('[01]\d|2[0-3]')
minute = pp.Regex('[0-5]\d')
miltime = hour.setResultsName('hour') + minute.setResultsName('minute')
dayrange = pp.oneOf(days) + pp.Suppress('-') + pp.oneOf(days) #day-day
dayspec = '(' + pp.delimitedList(pp.Group(dayrange | pp.oneOf(days)), delim=',').setResultsName('dayspec') + ')'
window = miltime.setResultsName('start') + '-' + miltime.setResultsName('end') + pp.Optional(dayspec)
spec = pp.StringStart() + pp.delimitedList( pp.Group(window), delim=';' ) + pp.StringEnd()
#parse and act
#return True instead of return condition so that when it fails, it tries the next window
uptime_spec = uptime_spec.strip().lower()
for window in spec.parseString(uptime_spec):
start = time(int(window.start.hour), int(window.start.minute))
end = time(int(window.end.hour), int(window.end.minute))
if start > end:
raise pp.ParseBaseException('Start time after end time')
if start < datetime.now().time() < end:
if not window.dayspec: #if there's no dayspec, any day is fine
return True
else:
for day in window.dayspec:
if len(day.asList()) == 1: #a single day
if datetime.now().strftime('%a').lower() == day[0]:
return True
else: #a range
start = days.index(day[0])
end = days.index(day[1])
if start <= end: #the range doesn't wrap
if start <= datetime.now().weekday() <= end:
return True
else: #the range wraps, check that today isn't outside the range
if not (end < datetime.now().weekday() < start):
return True
return False
While this solution works, the parsing bit seems rather ugly, especially how I deal with days and day ranges. That part would be easier if I could just test if today's day of the week was in an allowed set of days, and I feel like that might be possible using setParseAction, but I have no idea how to do it.
Any other suggestions? I'm rather new at this parsing thing.