#!/usr/bin/perl -w
use Time::Local;
use File::Copy;
use strict 'vars';
# Define how old events must be before they are considered stale
my $MONTH = 2592000;
# Todays date for comparison and archive filename
my $now = time();
my($day,$month,$year) = (localtime($now))[3..5];
if ($day < 10) { $day = "0$day"; }
if (++$month < 10) { $month = "0$month"; }
$year += 1900;
# Open directory and process each .ics file
opendir(DIR, '.') or die "can't open directory: $!";
while (defined(my $file = readdir(DIR))) {
# Skip old archived calendars
next if $file =~ /^\d{4}(-\d{2}){2}_.+\.ics$/;
my $buffer = '';
my @lines = ();
my $line = '';
# Archive existing calendar
copy($file, "$year-$month-$day" . "_$file");
# Read calendar into buffer
open(CALENDAR, "< $file") or die "Couldn't open file: $!\n";
while(defined($line = <CALENDAR>)) {
$buffer .= $line;
}
close(CALENDAR);
# Put calendar into array and trim each line
@lines = split(/\n(?!\s)/, $buffer);
@lines = map { s/^\s+//g; $_ } @lines;
@lines = map { s/\s+$//g; $_ } @lines;
# Reset buffer variable
$buffer = '';
# Process the array
for (my $i=0,my $r=$#lines+1; $i<$r; $i++) {
$line = $lines[$i];
# Look for the start of events
if ($line !~ m/BEGIN:VEVENT/) {
# Write to buffer
$buffer .= "$line\n";
} else {
my $skip = 0;
my $stale = FALSE;
my $event = '';
# Gather event details
while(defined($line = $lines[++$i]) && ($line !~ /END:VEVENT/)) {
my($key,$val) = split(':', $line);
# Trim whitespace from start of value
$val =~ s/^\s+//g;
# Look for the start date and check if older than a month
if (($key =~ /^DTSTART/) && defined($val)) {
if ($val =~ /^\d+$/) {
# DTSTART;VALUE=DATE:20050324
$val = timelocal(0, 0, 0, substr($val, 6, 2), substr($val, 4, 2)-1, substr($val, 0, 4)-1900);
} else {
# DTSTART:20050513T083000Z
$val = timelocal(substr($val, 13, 2), substr($val, 11, 2), substr($val, 9, 2), substr($val, 6, 2), substr($val, 4, 2)-1, substr($val, 0, 4)-1900);
}
$stale = TRUE if (($now - $val) > $MONTH);
}
$event .= "$line\n";
# Check for repeating events without end dates
# TODO: check UNTIL and/or COUNT end date have expired
if ($line =~ /RRULE/) {
$skip = (($line =~ /COUNT/) || ($line =~ /UNTIL/)) ? 1:2;
}
}
# Skip old events and write cromulent ones to the buffer
next if (($stale eq TRUE) && ($skip < 2));
$buffer .= "BEGIN:VEVENT\n" . $event . "END:VEVENT\n";
}
}
# Write the buffer to the original filename
open(CALENDAR, "> $file") or die "Couldn't open file: $!\n";
print CALENDAR $buffer;
close(CALENDAR);
}
# Close directory and quit
closedir(DIR);
exit;

This work is licenced under a Creative Commons Licence.