in reply to How to Extract Calendar Events in a Specified Date Range from 'Internet Calendaring' (.vcs, .ics) Files

Ok, I've managed to get something sort-of happening now... at least, it will let me get moving on my project... even if! it looks a bit ugly (I don't really know of any other way to deal with non-existent elements of the structures.. .*erk*). I understand that this code doesn't extract info about the alarms and "Sub-Eentires" but I'm not worried about that.

The code:-

use strict; use warnings; use Data::Dumper; use Data::ICal; use Data::ICal::DateTime; use DateTime; use DateTime::Event::Recurrence; $| = 1; # ---- my $data_file = "test.ics"; # "data.ics"; # .ics format input file my $cal = ""; # ICal object we use for the file my $event = ""; # an ICal event my $num_events = 0; # Total events in the file my $summary = ""; # 'Interesting' attributes of an event my $location = ""; my $description = ""; my $rrule = ""; my $sub_entries = ""; my $reqd_range_set = ""; # Date range of interest my $event_range_set = ""; # Date range for an event my $event_it = ""; # Set iterator my $rrule_exists = 0; # Flag; some events have no repeats my @events = (); # list of event (structures) my %HoA = (); # hash{date}->[ ev1, ev2, ... ] # ---- Create a 'set' for the required date range # being 1-Sep-2018 through 31-Dec-2018 my $dta1 = DateTime->new(year => 2018, month => 9, day => 1); my $dta2 = DateTime->new(year => 2018, month => 12, day => 31); $reqd_range_set = DateTime::Set->from_datetimes( dates => [ $dta1, $dt +a2 ] ); printf("Required Date Range: %s through %s\n", $dta1->dmy(), $dta2->dm +y()); # ---- Load and process events from file $cal = Data::ICal->new(filename => $data_file); @events = $cal->events(); $num_events = @events; printf("Total Events: %d\n", $num_events); # ---- my $event_ID = 0; foreach $event (@events) { # For each VEVENT... printf("%s\n", "-"x60); printf(" Event: %d\n", $event_ID); # ---- if ( defined($event->property('summary')) ) { # Check: Summar +y ('Subject') defined? $summary = $event->property('summary')->[0]->value; } else { $summary = "[ MISSING ]"; } if ( defined($event->property('description')) ) { # Check: 'Descr +iption' defined? $description = $event->property('description')->[0]->value; } else { $description = "None"; } if (defined($event->property('rrule'))) { # Check: Recurr +ence Rules defined? $rrule_exists = 1; $rrule = $event->property('rrule')->[0]->value; } else { $rrule_exists = 0; $rrule = "None"; } if ( defined($event->property('location')) ) { # Check: 'Locat +ion' defined? $location = $event->property('location')->[0]->value; } else { $location = "None"; } if ( @{$event->entries} ) { # Check: Sub-en +tries defined? $sub_entries = "Exist"; } else { $sub_entries = "None"; } # ---- printf(" Summary: %s\n", $summary); printf(" Start Date: %s\n", $event->start->dmy("-")); printf(" End Date: %s\n", $event->end->dmy("-")); printf("Description: %s\n", $description); printf(" Repeats: %s\n", $rrule); printf("Sub-Entries: %s\n", $sub_entries); printf(" Location: %s\n", $location); print "\n"; # ---- unless ($rrule_exists) { # Just check TH +E DATE if there's no RRULE if ( $reqd_range_set->contains($event->start) ) { # printf("no RRULE: Event %d ..include: %s\n", $event_ID, $eve +nt->start->dmy("-")); push(@{$HoA{$event->start->ymd("-")}}, $event_ID); # HoA{da +te}->[ ev1, ev2, ...] } $event_ID++; next; } # ---- If we're here, we'll process the RRULEs $event_range_set = $event->recurrence; # Create a 'set +' where the Recurrence Rules apply $event_it = $event_range_set->iterator(start => $dta1, end => $dta2 +); while ( my $dt = $event_it->next() ) { # printf("Using RRULE: Event %d: ..normal include: %s\n", $event_ +ID, $dt->dmy("-")); push(@{$HoA{$dt->ymd("-")}}, $event_ID); # HoA{date}->[ ev1, e +v2, ...] } $event_ID++; } # end: process another VEVENT printf("\n"); # ---- We now have all the events mapped into structures printf("OUTPUT %s\n\n", "-"x40); foreach my $ky (sort keys %HoA) { my $buf = ""; printf("%s: ", $ky); foreach (@{$HoA{$ky}}) { $buf .= $_ . ","; } chop($buf); printf("%s\n", $buf); } # ---- exit(0);

...and some sample output:-

Required Date Range: 01-09-2018 through 31-12-2018 Total Events: 5 ------------------------------------------------------------ Event: 0 Summary: BIRTHDAY: Fred Nurk Start Date: 22-10-2008 End Date: 22-10-2008 Description: 1953 Repeats: FREQ=YEARLY;INTERVAL=1 Sub-Entries: None Location: 2008 ------------------------------------------------------------ Event: 1 Summary: Father's Day Start Date: 07-09-1997 End Date: 07-09-1997 Description: None Repeats: FREQ=MONTHLY;BYDAY=1SU;INTERVAL=12 Sub-Entries: None Location: None ------------------------------------------------------------ Event: 2 Summary: *Work: Trivia Notes... Start Date: 17-12-2018 End Date: 17-12-2018 Description: -info 1 -info 2 -info 3 Repeats: None Sub-Entries: None Location: None ------------------------------------------------------------ Event: 3 Summary: Android: Purge Calendar Events Start Date: 04-03-2001 End Date: 04-03-2001 Description: None Repeats: FREQ=MONTHLY;BYDAY=1SU;INTERVAL=2 Sub-Entries: None Location: None ------------------------------------------------------------ Event: 4 Summary: Take Out Rubbish Bin Start Date: 23-01-2002 End Date: 23-01-2008 Description: None Repeats: FREQ=WEEKLY;BYDAY=WE;INTERVAL=2 Sub-Entries: Exist Location: None OUTPUT ---------------------------------------- 2018-09-02: 1,3 2018-09-12: 4 2018-09-26: 4 2018-10-10: 4 2018-10-22: 0 2018-10-24: 4 2018-11-04: 3 2018-11-07: 4 2018-11-21: 4 2018-12-05: 4 2018-12-19: 4

It took me a long time to get my head around 'sets' and the DateTime items and how the 'recurrence' works... but I now have something that I think will work.

As always, I appreciate the pointers... and the clues about something more about Perl that turns out to be very useful to know :)

Fanx! again.

  • Comment on Re: How to Extract Calendar Events in a Specified Date Range from 'Internet Calendaring' (.vcs, .ics) Files
  • Select or Download Code