Skip to content

Instantly share code, notes, and snippets.

@ewaldbenes
Last active December 3, 2025 14:53
Show Gist options
  • Select an option

  • Save ewaldbenes/0067b79250b4dc65591bc606325ce90e to your computer and use it in GitHub Desktop.

Select an option

Save ewaldbenes/0067b79250b4dc65591bc606325ce90e to your computer and use it in GitHub Desktop.
Removes all events preceeding a given year and month from an .ics calendar file.
#!/bin/bash
# Usage: ./trim-icalendar-ics foo-bar.ics 2024 06
# Removes all events before 2024 and month May (or keeps everything from May 2024 onwards)
# and saves the remaining events into the file foo-bar.ics.out
# Note: current working directory must be the one where the ics file resides!
# Note for Mac and BSD users: this script requires the GNU version of csplit and sed!
# first argument - the calendar file.
# second argument - the year like 2024.
# third argument - the month as 01,02,03,...,09,10,11,12.
CALENDAR_FILE="$1"
YEAR="$2"
MONTH="$3"
temp_dir=temp
temp_files_digits=5
mkdir -p $temp_dir
cd $temp_dir
# split the calendar file into separate files for each event. This script creates multiple files in the form of xx00000
total_files=`csplit -n $temp_files_digits ../"$CALENDAR_FILE" '/BEGIN:VEVENT/' {*} | wc -l`
echo "total events found: " $total_files
# filters the split event files by year and month and reassembles the remaining ones into one file
grep -R DTSTART . \
| sed -s "s/\.\/\(xx[0-9]\+\).*:\([0-9]\{4\}\)\([0-9]\{2\}\).*/\1 \2 \3/g" \
| awk -v year="$YEAR" -v month="$MONTH" '{if($2>year || ($2==year && $3>=month)) print $1;}' \
| xargs -L 1 cat > events
# creates the final shrunk ics file with the header and footer files
cat xx00000 events xx`printf "%05d" $((total_files-1))` > ../"$CALENDAR_FILE".out
cd ..
rm -r $temp_dir
@ewaldbenes
Copy link
Author

Thanks for pointing out the error @szpak! I will correct the script.

@maelmadon
Copy link

Hi there! Thanks for the useful script.

I encountered a problem when using it: sometimes, the attribute DSTART was spread into two lines, probably when the timezone information is too long, for example in:

BEGIN:VEVENT
LAST-MODIFIED:20240108T131530Z
 0100000007B29D3DF1AD815479E335748BED212EA
SUMMARY:FOO
PRIORITY:5
STATUS:CONFIRMED
DTSTART;TZID="(UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna"
 :20240517T160000
DTEND;TZID="(UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna":2
 0240517T170000
DESCRIPTION;LANGUAGE=sv-SE:BAR
CLASS:PUBLIC
END:VEVENT

In this case, the ICS file seems to have automatic line break every 75 characters...

I am not a sed expert, @ewaldbenes would you know how to allow for multiple lines?
For my use case, I will handle by hand.

@ewaldbenes
Copy link
Author

ewaldbenes commented Dec 3, 2025

You are correct, @maelmadon; RFC 5545 recommends line folding above 75 octets.

Regarding timezones, this script is strictly limited to DTSTART:2023... formats and does not handle complex datetime strings. Adding full iCal compliance would significantly increase the script's complexity.

While this implementation suffices for my specific requirements, production environments should use a dedicated library. For JS/TS, I recommend ical.js.

@maelmadon
Copy link

Agreed. Thanks for the quick answer!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment