Calendar-Schedule
view release on metacpan or search on metacpan
Schedule.pm view on Meta::CPAN
# Calendar::Schedule - Manage calendar schedules
# (c) 2002-2020 Vlado Keselj http://web.cs.dal.ca/~vlado vlado@dnlp.ca
# and contributing authors
#
# Some parts are updated with Starfish during development, such as the version
# number: <? read_starfish_conf !>
package Calendar::Schedule;
use strict;
require Exporter;
use POSIX;
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); # Exporter vars
our @ISA = qw(Exporter);
our %EXPORT_TAGS = ( 'all' => [ qw( parse_time ) ] );
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
our @EXPORT = qw(new);
#<?echo "our \$VERSION = '$Meta->{version}';"!>#+
our $VERSION = '1.21';#-
# non-exported package globals
use vars qw( $REweekday3 $REmonth3 $RE1st );
$RE1st = qr/first|second|third|fourth|fifth|last|1st|2nd|3rd|4th|5th/;
$REweekday3 = qr/Mon|Tue|Wed|Thu|Fri|Sat|Sun/;
$REmonth3 = qr/Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec/;
=head1 NAME
Calendar::Schedule - manage calendar schedules
=head1 SYNOPSIS
use Calendar::Schedule qw/:all/;
my $TTable = Calendar::Schedule->new();
# manually adding an entry
$TTable->add_entry('2003-09-09 Tue 18-20 Some meeting');
# reading entries from a file
$TTable->add_entries_from("$ENV{'HOME'}/.calendar");
# producing entries in HTML tables, one table per week
$TTable->set_first_week('now');
print "<p>\n" . $TTable->generate_table();
print "<p>\n" . $TTable->generate_table();
print "<p>\n" . $TTable->generate_table();
# for more examples, see EXAMPLES section
The file .calendar may look like this:
# comments can start with #
* lines starting with * are treated as general todo entries ...
# empty lines are acceptable and ignored:
Mon 9:00-10:00 this is a weekly entry
Mon 13-14 a biweekly entry :biweekly :start Mar 8, 2004
Mon,Wed,Fri 15:30-16:30 several-days-a-week entry
Wed :biweekly garbage collection
2004-03-06 Sat 14-16 fixed entry. The week day is redundant, but may\
help to detect errors (error will be reported if a wrong\
weekday is entered). BTW, an entry can go for several lines as\
long as there is a backslash at the end of each line.
May 6 birthday (yearly entry)
# more examples in "Example entries" section
=head1 DESCRIPTION
The module is created with a purpose to provide functionality for handling a
personal calendar schedule in a transparent and simple way. The calendar
data is assumed to be kept in a plain file in a format easy to edit and
understand. It was inspired by the C<calendar> program on older Unix-like
systems, which used C<~/.calendar> file to produce entries for each day
and send them in the morning by email.
Inspired by the C<~/.calendar> file, the format for recording scheduled
events is very simple, mostly contained in one line of text.
The module currently supports generation of HTML weekly tables with visual
representation of scheduled events. The generated table is generated in
a simple HTML table, with a use of C<colspan> and C<rolspan> attributes to
represent overlapping events in parallel in the table.
=head2 Planned Future Work
In the development of the recording format for the event, there is an attempt
to model the data representation of the iCalendar standard (RFC2445).
Examples of the iCalendar fields are: DTSTART, DTEND, SUMMARY,
RRULE (e.g. RRULE:FREQ=WEEKLY, RRULE:FREQ=WEEKLY;INTERVAL=2 for
biweekly, RRULE:FREQ=WEEKLY;UNTIL=20040408 ) etc.
More examples:
RRULE:FREQ=MONTHLY;BYDAY=TU;BYSETPOS=3
Every third Tuesday in a month.
=head1 EXAMPLES
First example:
use Calendar::Schedule qw/:all/;
my $TTable = Calendar::Schedule->new();
# manually adding an entry
$TTable->add_entry('2003-09-09 Tue 18-20 Some meeting');
# reading entries from a file
$TTable->add_entries_from("$ENV{'HOME'}/.calendar");
# producing entries in HTML tables
$TTable->set_first_week('2003-12-15');
print "<p>\n" . $TTable->generate_table();
print "<p>\n" . $TTable->generate_table();
print "<p>\n" . $TTable->generate_table();
Example with generating a weekly schedule (example2):
use Calendar::Schedule;
$TTable = Calendar::Schedule->new();
$TTable->{'ColLabel'} = "%A";
$TTable->add_entries(<<EOT
Mon 15:30-16:30 Teaching (CSCI 3136)
Tue 10-11:30 Teaching (ECMM 6014)
Wed 13:30-14:30 DNLP
Wed 15:30-16:30 Teaching (CSCI 3136) :until Apr 8, 2005
Thu 10-11:30 Teaching (ECMM 6014)
Thu 16-17 WIFL
Fri 14:30-15:30 MALNIS
Fri 15:30-16:30 Teaching (CSCI 3136)
EOT
);
print "<p>\n" . $TTable->generate_table();
This will produce the following HTML code (if run before Apr 8, 2005):
=for html
<p>
<table width=100% border=2 cellspacing=1 cellpadding=1>
<tr>
<td valign=top> </td>
<th>Monday</th>
<th>Tuesday</th>
<th>Wednesday</th>
<th>Thursday</th>
<th>Friday</th>
<th>Saturday</th>
<th>Sunday</th>
</tr>
<tr><td>08:00</td>
<td align=center> </td>
<td align=center> </td>
<td align=center> </td>
<td align=center> </td>
<td align=center> </td>
<td align=center> </td>
<td align=center> </td>
</tr>
<tr><td>10:00</td>
<td align=center> </td>
<td align=center bgcolor=yellow>Teaching (ECMM 6014)</td>
<td align=center> </td>
<td align=center bgcolor=yellow>Teaching (ECMM 6014)</td>
<td align=center> </td>
<td align=center> </td>
<td align=center> </td>
</tr>
<tr><td>11:30</td>
<td align=center> </td>
Schedule.pm view on Meta::CPAN
return $self;
}
=item set_first_week(time)
sets start time at the last Monday before given date. It is used in generate_table.
Examples:
$TTable = Calendar::Schedule->new();
$TTable->set_first_week('now');
$TTable->set_first_week('2016-02-19');
See parse_time for examples for specifying time.
=cut
sub set_first_week {
my $self = shift;
my $arg = shift;
my $starttime = &parse_time($arg);
$self->{'StartTime'} = $self->{'ContextTime'} =
&find_week_start($starttime);
}
=item set_ColLabel(pattern)
sets C<strftime> pattern for column (day) labels. The default pattern
is "C<%AE<lt>brE<gt>%Y-%m-%d>", which produces labels like:
Friday
2003-12-19
In order to have just a weekday name, use "C<%A>".
=cut
sub set_ColLabel {
my $self = shift;
my $arg = shift;
$self->{'ColLabel'} = $arg;
}
sub find_week_start {
my $starttime = shift;
while ((localtime($starttime))[6] != 1)
{ $starttime -= 86400 }
while ((localtime($starttime))[2] != 0)
{ $starttime -= 3600 }
while ((localtime($starttime))[1] != 0)
{ $starttime -= 60 }
while ((localtime($starttime))[0] != 0)
{ $starttime -- }
return $starttime;
}
=item parse_time(time_specification[,prefix])
Parses time specification and returns the calendar time (see mktime in
Perl). The functions dies if the time cannot be completely recognized.
If prefix is set to true (1), then only a prefix of the string can be
a time specification. If prefix is set to 1, then in an array context
it will return a 2-element list: the calendar time and the
remainder of the string. Format examples:
2004-03-17
now
Mar 8, 2004
1-Jul-2005
=cut
#mktime(sec,min,hour,mday,mon,year,wday=0,yday=0,isdst=0)
#mon,wday,yday start with 0,wday starts with Sun,year starts with 1900
# usually set last 3 to -1
# ('YYYY-MM-DD') now
sub parse_time {
my $time = shift;
my $prefix = shift;
my $endrex = ( $prefix ? qr// : qr/\s*$/ );
my ($ret, $ret2);
my $monrex = $REmonth3;
if ($time =~ /^(\d\d\d\d)-(\d\d)-(\d\d) (\d\d?):(\d\d)$endrex/)
{ $ret = mktime(0,$5,$4,$3,$2-1,$1-1900,-1,-1,-1) }
elsif ($time =~ /^(\d\d\d\d)-(\d\d)-(\d\d)$endrex/)
{ $ret = mktime(0,0,0,$3,$2-1,$1-1900,-1,-1,-1) }
elsif ($time =~ /^(\d\d)-(\d\d)-(\d\d\d\d)$endrex/)
{ $ret = mktime(0,0,0,$1,$2-1,$3-1900,-1,-1,-1) }
elsif ($time =~ /^(\d?\d)-($monrex)-(\d\d\d\d)\b$endrex/)
{ $ret = mktime(0,0,0,$1,&month_to_digits($2),$3-1900,-1,-1,-1) }
elsif ($time =~ /^($monrex) (\d?\d), (\d\d\d\d)\b$endrex/)
{ $ret = mktime(0,0,0,$2,&month_to_digits($1),$3-1900,-1,-1,-1) }
elsif ($time =~ /^\d+$endrex/) { $ret = $time }
elsif ($time =~/^now\b$endrex/) { $ret = time }
else { use Carp; confess "cannot parse time:($time)" }
$ret2 = $';
return wantarray ? ($ret, $ret2) : $ret;
}
=item add_entries_from(file_name)
Adds entries from a file. See method add_entries and add_entry for format explanation.
=cut
sub add_entries_from {
my $self = shift;
my $fname = shift;
return $self->add_entries(scalar(_getfile($fname)));
}
=item add_entries(list_of_entries)
Adds more entries. Each entry may contain several entries separated
by a new-line, except if the line ends with \.
Empty lines and lines that start with \s*# are ignored.
See add_entry for further explanation of format.
=cut
sub add_entries {
my $self = shift;
while ($#_ > -1) {
my $entries = shift;
foreach my $en (split(/(?<!\\)\n/, $entries)) {
next if $en =~ /^\s*$/;
Schedule.pm view on Meta::CPAN
$epr->{$col, $row} = $des;
foreach my $r (@rows)
{ $epr->{$col, $r} = 'continue' }
} else {
$epr->{$col, $row, $overlap} = $des;
foreach my $r (@rows)
{ $epr->{$col, $r, $overlap } = 'continue';
#$epr->{$col, $r} .= " -CONFLICT- continue";
}
}
}
sub _table_get {
my $self = shift;
my $epr = shift;
my $col = shift;
my $row = shift;
my $overlap = shift; $overlap = 0 if !defined($overlap);
my $ret = $overlap > 0 ? $epr->{$col, $row, $overlap} : $epr->{$col, $row};
return defined($ret) ? $ret : '';
}
=pod
=cut
sub _getfile($) {
my $f = shift;
local *F;
open(F, "<$f") or die "getfile:cannot open $f:$!";
my @r = <F>;
close(F);
return wantarray ? @r : join ('', @r);
}
1;
__END__
=head1 CONTRIBUTORS
I would like to thank Stefan Goebel for his report and detailed analysis of
a bug and suggestions, Mike Vasiljevs for his suggestions and patches for
ISO8601 format, Mohammad S Anwar for correction regarding missing license
field, Slaven Rezic from the CPAN testers for useful bug reports, Gabor Szabo
for the initial GitHub CI code.
=head1 AUTHOR
Copyright 2002-2020 Vlado Keselj (vlado@dnlp.ca http://vlado.ca)
and the contributors (section CONTRIBUTORS).
This script is provided "as is" without expressed or implied warranty.
This is free software; you can redistribute it, modify it, or both under
the same terms as Perl itself.
The latest version can be found at
L<http://vlado.ca/srcperl/Calendar-Schedule/>.
=head1 SEE ALSO
There are some Perl modules for different types of calendar, and
likely may more in other programming languages. I could not find any
existing calendars including the particular features that I needed, so
this module was created. Below are some modules with similar
functionality:
=over 4
=item [HTML::CalendarMonthSimple] - Perl Module for Generating HTML Calendars
The module is written as a simplifed version of HTML::CalendarMonth.
The intention for this, Calendar::Schedule module, is not to tie it essentially
for HTML. The events specification is described in a simple textual format.
=item [HTML::CalendarMonth] - Generate and manipulate HTML calendar months
The module HTML::CalendarMonth is a subclass of HTML::ElementTable,
which makes it a part of larger project--the Date-Time Perl project at
F<http://datetime.perl.org>.
=back
=cut
( run in 0.575 second using v1.01-cache-2.11-cpan-0d23b851a93 )