Created
May 27, 2025 20:53
-
-
Save mecaneer23/7671fc3e7d230cdfea356b82f6360df0 to your computer and use it in GitHub Desktop.
Script to convert a list of events to an ICS calendar file
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| """Generate an ICS calendar file for a provided schedule.""" | |
| from datetime import datetime, timedelta | |
| from pathlib import Path | |
| from events import full_events | |
| full_events: list[tuple[str, str, str, str, str, str, str]] | |
| YEAR = 2025 | |
| TIMEZONE = "-05:00" # Central Daylight Time offset | |
| def create_ics_event( # noqa: PLR0913 | |
| uid: str, | |
| dtstart: datetime, | |
| dtend: datetime, | |
| summary: str, | |
| priority: str, | |
| gate_open: str, | |
| extra_info: str = "", | |
| ) -> str: | |
| """Create an ICS event string with the given parameters.""" | |
| return f"""BEGIN:VEVENT | |
| UID:{uid} | |
| DTSTAMP:{dtstart.strftime("%Y%m%dT%H%M%SZ")} | |
| DTSTART:{dtstart.strftime("%Y%m%dT%H%M%S")} | |
| DTEND:{dtend.strftime("%Y%m%dT%H%M%S")} | |
| DESCRIPTION:{" " + priority + "\\n" if priority else ""} | |
| Shift start: {dtstart.strftime("%I:%M %p") + "\\n" if dtstart else ""} | |
| Gate open: {gate_open + "\\n"}{ | |
| "Extra information: " + extra_info if extra_info else "" | |
| } | |
| SUMMARY:{summary} | |
| END:VEVENT | |
| """ | |
| def main() -> None: | |
| """Generate the ICS calendar file for the provided schedule.""" | |
| ics_content = "BEGIN:VCALENDAR\nVERSION:2.0\nCALSCALE:GREGORIAN\n" | |
| weekdays = { | |
| 0: "Monday", | |
| 1: "Tuesday", | |
| 2: "Wednesday", | |
| 3: "Thursday", | |
| 4: "Friday", | |
| 5: "Saturday", | |
| 6: "Sunday", | |
| } | |
| for idx, ( | |
| date_str, | |
| day, | |
| title, | |
| gate_open_time, | |
| concert_time_str, | |
| special_scheduling, | |
| start_time_str, | |
| ) in enumerate( | |
| full_events, | |
| ): | |
| extra_info = "" | |
| date = datetime.strptime( | |
| f"{date_str}, {YEAR} {TIMEZONE}", | |
| "%B %d, %Y %z", | |
| ) | |
| if weekdays.get(date.weekday(), None) != day: | |
| msg = ( | |
| f"Mismatch between date {date_str} and day {day}. " | |
| f"Calculated weekday: {weekdays.get(date.weekday())}" | |
| ) | |
| raise ValueError(msg) | |
| start_time = datetime.strptime( | |
| start_time_str + TIMEZONE, | |
| "%I:%M %p%z", | |
| ).time() | |
| start_datetime = datetime.combine(date.date(), start_time) | |
| if concert_time_str: | |
| concert_time = datetime.strptime( | |
| concert_time_str + TIMEZONE, | |
| "%I:%M %p%z", | |
| ).time() | |
| end_datetime = datetime.combine(date.date(), concert_time) | |
| else: | |
| end_datetime = start_datetime + timedelta(hours=3) | |
| extra_info = ( | |
| "No event length specified, defaulting to 3-hour duration." | |
| ) | |
| uid = f"event-{idx}" | |
| ics_content += create_ics_event( | |
| uid, | |
| start_datetime, | |
| end_datetime, | |
| title, | |
| special_scheduling, | |
| gate_open_time, | |
| extra_info=extra_info, | |
| ) | |
| ics_content += "END:VCALENDAR" | |
| ics_path = "schedule.ics" | |
| with Path(ics_path).open("w", encoding="utf-8") as f: | |
| f.write(ics_content) | |
| if __name__ == "__main__": | |
| main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment