Skip to content

Instantly share code, notes, and snippets.

@peteristhegreat
Created April 4, 2024 00:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save peteristhegreat/55a2357321dee2ca41074a0b5d157282 to your computer and use it in GitHub Desktop.
Save peteristhegreat/55a2357321dee2ca41074a0b5d157282 to your computer and use it in GitHub Desktop.
Convert Outlook Calendar CSV export to ICS (aka ical)
import pandas as pd
from icalendar import Calendar, Event, vText, vDatetime
from datetime import datetime, timedelta
import pytz
print("starting conversion")
# Load CSV file
df = pd.read_csv('C:\\Users\\user\\outlook\\calendar.CSV') # Update the path accordingly
def parse_datetime(date_str, time_str, all_day):
if all_day: # If all_day is True, return a date object
return datetime.strptime(date_str, '%m/%d/%Y')
else: # For specific times, adjust to parse as 12-hour time with AM/PM, including seconds
# Note the change to '%m/%d/%Y %I:%M:%S %p' to include seconds
return datetime.strptime(f'{date_str} {time_str}', '%m/%d/%Y %I:%M:%S %p')
# Create a new calendar
cal = Calendar()
cal.add('prodid', '-//My Company//My Calendar Product//EN')
cal.add('version', '2.0')
cal.add('calscale', 'GREGORIAN')
cal.add('x-wr-calname', 'My Custom Calendar')
cal.add('x-wr-timezone', 'America/Chicago')
for index, row in df.iterrows():
event = Event()
event.add('summary', row['Subject'])
start_dt = parse_datetime(row['Start Date'], row['Start Time'], row['All day event'])
end_dt = parse_datetime(row['End Date'], row['End Time'], row['All day event'])
event.add('dtstart', start_dt)
event.add('dtend', end_dt)
event.add('dtstamp', datetime.now().replace(tzinfo=pytz.utc))
if row['All day event']: # Directly checks the Boolean value
event.add('X-MICROSOFT-CDO-ALLDAYEVENT', 'TRUE')
event.add('X-MICROSOFT-CDO-BUSYSTATUS', 'FREE')
if row['Reminder on/off']:
reminder_date = parse_datetime(row['Reminder Date'], row['Reminder Time'], 'false')
reminder_delta = start_dt - reminder_date
event.add('begin', 'VALARM')
event.add('TRIGGER', -reminder_delta)
event.add('ACTION', 'DISPLAY')
event.add('DESCRIPTION', 'Reminder')
event.add('end', 'VALARM')
event.add('description', row['Description'])
event.add('location', vText(row['Location']))
event.add('organizer', vText(row['Meeting Organizer']))
event.add('attendee', vText(row['Required Attendees']))
if pd.notna(row['Optional Attendees']):
event.add('attendee', vText(row['Optional Attendees']))
if pd.notna(row['Categories']):
event.add('categories', vText(row['Categories']))
# Add more fields as needed, following the pattern above.
cal.add_component(event)
# Save the ical file
with open('C:\\Users\\user\\outlook\\calendar2.ics', 'wb') as icsfile:
icsfile.write(cal.to_ical())
print("done converting")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment