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, $dta2 ] ); printf("Required Date Range: %s through %s\n", $dta1->dmy(), $dta2->dmy()); # ---- 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: Summary ('Subject') defined? $summary = $event->property('summary')->[0]->value; } else { $summary = "[ MISSING ]"; } if ( defined($event->property('description')) ) { # Check: 'Description' defined? $description = $event->property('description')->[0]->value; } else { $description = "None"; } if (defined($event->property('rrule'))) { # Check: Recurrence Rules defined? $rrule_exists = 1; $rrule = $event->property('rrule')->[0]->value; } else { $rrule_exists = 0; $rrule = "None"; } if ( defined($event->property('location')) ) { # Check: 'Location' defined? $location = $event->property('location')->[0]->value; } else { $location = "None"; } if ( @{$event->entries} ) { # Check: Sub-entries 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 THE DATE if there's no RRULE if ( $reqd_range_set->contains($event->start) ) { # printf("no RRULE: Event %d ..include: %s\n", $event_ID, $event->start->dmy("-")); push(@{$HoA{$event->start->ymd("-")}}, $event_ID); # HoA{date}->[ 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, ev2, ...] } $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);