Skip to content

Instantly share code, notes, and snippets.

@yeiichi
Created December 14, 2024 11:47
Show Gist options
  • Save yeiichi/1e38c3653885d0d35b18a53435401f67 to your computer and use it in GitHub Desktop.
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.
#!/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