"""Bounded UTC daily/weekly recurrence preview; never schedules or sends anything.""" import datetime as dt,re,json,argparse DAYS={'MO':0,'TU':1,'WE':2,'TH':3,'FR':4,'SA':5,'SU':6} def utc(value): if not isinstance(value,str) or not re.fullmatch(r'\d{8}T\d{6}Z',value):raise ValueError('UTC date-time required') return dt.datetime.strptime(value,'%Y%m%dT%H%M%SZ').replace(tzinfo=dt.timezone.utc) def positive(value,maximum): if not re.fullmatch(r'[0-9]+',value):raise ValueError('Positive integer required') number=int(value) if not 1<=number<=maximum:raise ValueError('Outside supported profile bounds') return number def preview(start,rule): first=utc(start) if not isinstance(rule,str) or len(rule.encode())>500:raise ValueError('Rule maximum 500 bytes') if rule.startswith('RRULE:'):rule=rule[6:] pairs={} for part in rule.split(';'): if part.count('=')!=1:raise ValueError('Expected name=value') key,value=part.split('=') if key in pairs:raise ValueError('Duplicate rule part') if key not in {'FREQ','INTERVAL','COUNT','UNTIL','BYDAY','WKST'}:raise ValueError('Unsupported rule part') pairs[key]=value frequency=pairs.get('FREQ') if frequency not in {'DAILY','WEEKLY'}:raise ValueError('Only DAILY/WEEKLY supported') interval=positive(pairs.get('INTERVAL','1'),12) if ('COUNT' in pairs)==('UNTIL' in pairs):raise ValueError('Require exactly one finite COUNT or UNTIL') count=positive(pairs['COUNT'],100) if 'COUNT' in pairs else None until=utc(pairs['UNTIL']) if 'UNTIL' in pairs else None if until and untiluntil:ended=True;break selected=offset%interval==0 if frequency=='DAILY' else (value.weekday() in weekdays and ((value.date()-week_origin).days//7)%interval==0) if not selected:continue if len(values)==12:truncated=True;reason='12 occurrence output limit';break values.append(value.strftime('%Y%m%dT%H%M%SZ')) if count and len(values)==count:ended=True;break if not ended and not truncated:truncated=True;reason='366 day preview horizon; later recurrence unexamined' return {'dtstart':start,'rrule':rule,'occurrences_utc':values,'preview_complete':ended,'truncated':truncated,'truncation_reason':reason,'supported_profile':'UTC DAILY/WEEKLY, interval1-12, finite COUNT1-100 or UTC UNTIL, weekly unique unnumbered BYDAY, Monday week start;12 outputs/366-day horizon','full_rfc_validation':False,'native_dot_tested':False,'schedule_created':False} if __name__=='__main__': p=argparse.ArgumentParser();p.add_argument('--dtstart',required=True);p.add_argument('--rrule',required=True);a=p.parse_args();print(json.dumps(preview(a.dtstart,a.rrule),indent=2))