Created
December 14, 2024 11:47
-
-
Save yeiichi/1e38c3653885d0d35b18a53435401f67 to your computer and use it in GitHub Desktop.
Extract dates, locations, and summaries of events within a specified period from an ICS file and save them as a CSV 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
#!/usr/bin/env python3 | |
from datetime import datetime | |
from pathlib import Path | |
import pandas as pd | |
from icalendar import Calendar | |
def extract_vevents(ics_file, from_yymmdd='1677-09-21', to_yymmdd='2262-04-11'): | |
"""Extract dates, locations, and summaries of events within a specified period | |
from an ICS file and save them as a CSV file. | |
Args: | |
ics_file (str or Path): | |
from_yymmdd (str): Beginning of the target period. | |
to_yymmdd (str): Ending of the target period. | |
Returns: | |
pandas.DataFrame: | |
References: | |
https://icalendar.readthedocs.io/en/latest/index.html | |
https://datatracker.ietf.org/doc/html/rfc5545.html | |
""" | |
src_path = Path(ics_file) | |
# For keyboard inputs | |
from_yymmdd = '1677-09-21' if from_yymmdd == '' else from_yymmdd | |
to_yymmdd = '2262-04-11' if to_yymmdd == '' else to_yymmdd | |
# Convert to datetime.date | |
from_date = datetime.strptime(from_yymmdd, '%Y-%m-%d').date() | |
to_date = datetime.strptime(to_yymmdd, '%Y-%m-%d').date() | |
# Prepare an event list. | |
with src_path.open() as f: | |
calendar = Calendar.from_ical(f.read()) | |
events = calendar.walk('VEVENT') # <class 'list'> | |
outer = [] | |
for event in events: | |
start_dt = event.get('dtstart').dt # Basically <datetime.datetime> but sometimes <datetime.date> | |
# Align data types to <class 'datetime.date'> for comparison. | |
base_date = start_dt.date() if isinstance(start_dt, datetime) else start_dt | |
# Skip dates_ out of the range. | |
if not from_date <= base_date <= to_date: | |
continue | |
# Rest of the items | |
end_dt = event.get('dtend').dt | |
location = event.get('LOCATION') | |
summary = event.get('SUMMARY') | |
outer.append([str(start_dt), str(end_dt), location, summary]) # Cast into str for sorting. | |
# Construct a DataFrame | |
df = pd.DataFrame( | |
outer, | |
columns=['dtstart', 'dtend', 'LOCATION', 'SUMMARY']).sort_values( | |
by=['dtstart', 'dtend'], ignore_index=True) | |
df.dtstart = df.dtstart.apply(pd.to_datetime) | |
df.dtend = df.dtstart.apply(pd.to_datetime) | |
# Sava as a CSV file. | |
date_max, date_min = df.dtstart.iat[0].date(), df.dtstart.iat[-1].date() | |
fname = f'{src_path.stem}_{date_max}_{date_min}.csv' | |
fpath = Path('.').absolute() / fname | |
df.to_csv(fpath, index=False) | |
print(f'\033[93mSaved: {fpath}\033[0m') | |
return df | |
if __name__ == '__main__': | |
extract_vevents( | |
input('ICS file? >> '), | |
input('Date FROM (yyyy-mm-dd) >> '), | |
input('Date TO (yyyy-mm-dd) >> ') | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment